pull/22061/merge
Kartik Joshi 2025-12-14 22:45:04 +00:00 committed by GitHub
commit d6753079ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 153 additions and 2 deletions

View File

@ -18,6 +18,7 @@ package cmd
import (
"fmt"
"net"
"runtime"
"strings"
"time"
@ -61,6 +62,7 @@ const (
kubernetesVersion = "kubernetes-version"
noKubernetes = "no-kubernetes"
hostOnlyCIDR = "host-only-cidr"
hostOnlyCIDRv6 = "host-only-cidr-v6"
containerRuntime = "container-runtime"
criSocket = "cri-socket"
networkPlugin = "network-plugin" // deprecated, use --cni instead
@ -84,6 +86,8 @@ const (
apiServerPort = "apiserver-port"
dnsDomain = "dns-domain"
serviceCIDR = "service-cluster-ip-range"
serviceCIDRv6 = "service-cluster-ip-range-v6"
ipFamily = "ip-family"
imageRepository = "image-repository"
imageMirrorCountry = "image-mirror-country"
mountString = "mount-string"
@ -144,8 +148,12 @@ const (
socketVMnetClientPath = "socket-vmnet-client-path"
socketVMnetPath = "socket-vmnet-path"
staticIP = "static-ip"
staticIPv6 = "static-ipv6"
gpus = "gpus"
autoPauseInterval = "auto-pause-interval"
subnetv6 = "subnet-v6"
podCIDR = "pod-cidr"
podCIDRv6 = "pod-cidr-v6"
)
var (
@ -209,6 +217,7 @@ func initMinikubeFlags() {
startCmd.Flags().Bool(disableMetrics, false, "If set, disables metrics reporting (CPU and memory usage), this can improve CPU usage. Defaults to false.")
startCmd.Flags().Bool(disableCoreDNSLog, false, "If set, disable CoreDNS verbose logging. Defaults to false.")
startCmd.Flags().String(staticIP, "", "Set a static IP for the minikube cluster, the IP must be: private, IPv4, and the last octet must be between 2 and 254, for example 192.168.200.200 (Docker and Podman drivers only)")
startCmd.Flags().String(staticIPv6, "", "Set a static IPv6 address for the minikube cluster, for example fd00::100 (Docker and Podman drivers only)")
startCmd.Flags().StringP(gpus, "g", "", "Allow pods to use your GPUs. Options include: [all,nvidia,amd] (Docker driver with Docker container-runtime only)")
startCmd.Flags().Duration(autoPauseInterval, time.Minute*1, "Duration of inactivity before the minikube VM is paused (default 1m0s)")
}
@ -260,6 +269,7 @@ func initDriverFlags() {
// virtualbox
startCmd.Flags().String(hostOnlyCIDR, "192.168.59.1/24", "The CIDR to be used for the minikube VM (virtualbox driver only)")
startCmd.Flags().String(hostOnlyCIDRv6, "fd00::1/64", "The IPv6 CIDR to be used for the minikube VM (virtualbox driver only)")
startCmd.Flags().Bool(dnsProxy, false, "Enable proxy for NAT DNS requests (virtualbox driver only)")
startCmd.Flags().Bool(hostDNSResolver, true, "Enable host resolver for NAT DNS requests (virtualbox driver only)")
startCmd.Flags().Bool(noVTXCheck, false, "Disable checking for the availability of hardware virtualization before the vm is started (virtualbox driver only)")
@ -282,6 +292,9 @@ func initDriverFlags() {
startCmd.Flags().String(listenAddress, "", "IP Address to use to expose ports (docker and podman driver only)")
startCmd.Flags().StringSlice(ports, []string{}, "List of ports that should be exposed (docker and podman driver only)")
startCmd.Flags().String(subnet, "", "Subnet to be used on kic cluster. If left empty, minikube will choose subnet address, beginning from 192.168.49.0. (docker and podman driver only)")
startCmd.Flags().String(subnetv6, "", "IPv6 subnet (CIDR) for the Docker/Podman network. If empty, minikube picks an internal ULA. (docker and podman driver only)")
startCmd.Flags().String(podCIDR, "", "IPv4 CIDR to use for pod IPs (bridge CNI).")
startCmd.Flags().String(podCIDRv6, "", "IPv6 CIDR to use for pod IPs (bridge CNI).")
// qemu
startCmd.Flags().String(qemuFirmwarePath, "", "Path to the qemu firmware file. Defaults: For Linux, the default firmware location. For macOS, the brew installation location. For Windows, C:\\Program Files\\qemu\\share")
@ -293,7 +306,9 @@ func initNetworkingFlags() {
startCmd.Flags().StringSliceVar(&registryMirror, "registry-mirror", nil, "Registry mirrors to pass to the Docker daemon")
startCmd.Flags().String(imageRepository, "", "Alternative image repository to pull docker images from. This can be used when you have limited access to gcr.io. Set it to \"auto\" to let minikube decide one for you. For Chinese mainland users, you may use local gcr.io mirrors such as registry.cn-hangzhou.aliyuncs.com/google_containers")
startCmd.Flags().String(imageMirrorCountry, "", "Country code of the image mirror to be used. Leave empty to use the global one. For Chinese mainland users, set it to cn.")
startCmd.Flags().String(serviceCIDR, constants.DefaultServiceCIDR, "The CIDR to be used for service cluster IPs.")
startCmd.Flags().String(serviceCIDR, constants.DefaultServiceCIDR, "The IPv4 CIDR to be used for service cluster IPs.")
startCmd.Flags().String(serviceCIDRv6, constants.DefaultServiceCIDRv6, "The IPv6 CIDR to be used for service cluster IPs.")
startCmd.Flags().String(ipFamily, "ipv4", "Cluster IP family mode: one of 'ipv4' (default), 'ipv6', or 'dual'.")
startCmd.Flags().StringArrayVar(&config.DockerEnv, "docker-env", nil, "Environment variables to pass to the Docker daemon. (format: key=value)")
startCmd.Flags().StringArrayVar(&config.DockerOpt, "docker-opt", nil, "Specify arbitrary flags to pass to the Docker daemon. (format: key=value)")
@ -494,6 +509,114 @@ func getNetwork(driverName string, options *run.CommandOptions) string {
return n
}
// normalizeAndValidateIPFamily sets defaults, validates CIDRs, and adds
// guardrails for IPv6/dual-stack on Docker.
func normalizeAndValidateIPFamily(cc *config.ClusterConfig) {
fam := strings.ToLower(strings.TrimSpace(cc.KubernetesConfig.IPFamily))
switch fam {
case "", "ipv4", "ipv6", "dual":
// ok
default:
exit.Message(reason.Usage,
"Invalid --ip-family {{.fam}}. Must be one of: ipv4, ipv6, dual.",
out.V{"fam": cc.KubernetesConfig.IPFamily})
}
// Default to ipv4 to keep existing behavior for old configs.
if fam == "" {
fam = "ipv4"
cc.KubernetesConfig.IPFamily = fam
}
// IPv6-capable families: ensure v6 defaults.
if fam != "ipv4" {
if cc.KubernetesConfig.ServiceCIDRv6 == "" {
cc.KubernetesConfig.ServiceCIDRv6 = constants.DefaultServiceCIDRv6
}
if cc.KubernetesConfig.PodCIDRv6 == "" {
cc.KubernetesConfig.PodCIDRv6 = constants.DefaultPodCIDRv6
}
}
// For ipv4 or dual-stack, keep the usual IPv4 pod CIDR default if none was set.
if fam != "ipv6" && cc.KubernetesConfig.PodCIDR == "" {
cc.KubernetesConfig.PodCIDR = cni.DefaultPodCIDR
}
// --- CIDR / address validation ---
// Helper: ensure a CIDR is v4 or v6 as expected.
checkCIDR := func(flag string, cidr string, wantV6 bool) {
ip, _, err := net.ParseCIDR(cidr)
if err != nil {
exit.Message(reason.Usage, "{{.flag}} must be a valid CIDR: {{.e}}",
out.V{"flag": flag, "e": err})
}
isV4 := ip.To4() != nil
if wantV6 && isV4 {
exit.Message(reason.Usage, "{{.flag}} must be a valid IPv6 CIDR: {{.e}}",
out.V{"flag": flag, "e": err})
}
if !wantV6 && !isV4 {
exit.Message(reason.Usage, "{{.flag}} must be a valid IPv4 CIDR: {{.e}}",
out.V{"flag": flag, "e": err})
}
}
// IPv6-only CIDR flags.
if cidr := cc.Subnetv6; cidr != "" {
checkCIDR("--subnet-v6", cidr, true)
}
if cidr := cc.KubernetesConfig.ServiceCIDRv6; cidr != "" {
checkCIDR("--service-cluster-ip-range-v6", cidr, true)
}
if cidr := cc.KubernetesConfig.PodCIDRv6; cidr != "" {
checkCIDR("--pod-cidr-v6", cidr, true)
}
// IPv4-only pod CIDR.
if cidr := cc.KubernetesConfig.PodCIDR; cidr != "" {
checkCIDR("--pod-cidr", cidr, false)
}
// validate static IPv6 if provided
if s := cc.StaticIPv6; s != "" {
ip := net.ParseIP(s)
if ip == nil || ip.To4() != nil {
exit.Message(reason.Usage, "--static-ipv6 must be a valid IPv6 address")
}
}
// Docker driver guardrails: Linux daemon for IPv6, warn on Desktop.
if driver.IsDocker(cc.Driver) && fam != "ipv4" {
// Desktop vs Linux daemon hint (we can't reliably detect IPv6 enabled here).
si, err := oci.CachedDaemonInfo(cc.Driver)
if err != nil {
si, err = oci.DaemonInfo(cc.Driver)
if err != nil {
exit.Message(reason.Usage, "Failed to query Docker daemon info: {{.e}}", out.V{"e": err})
}
}
// On non-Linux hosts we assume Docker Desktop; on Linux it's a native Engine
// unless DockerOS explicitly says "Docker Desktop".
isLinuxDaemon := runtime.GOOS == "linux" && si.DockerOS != "Docker Desktop"
if !isLinuxDaemon {
if fam == "ipv6" {
exit.Message(reason.Usage,
"IPv6 clusters require a Linux Docker daemon (Desktop is not supported). "+
"Use a Linux/WSL2 daemon or set --ip-family=ipv4.")
}
out.WarningT("Dual-stack on Docker Desktop may be limited. For full IPv6 support, use a Linux Docker daemon.")
}
// Friendly reminder about enabling daemon IPv6 (actual failure will occur during
// network create if the daemon/network really blocks IPv6 bridge networks).
out.Styled(style.Tip,
"If your Docker daemon/network blocks IPv6 bridge networks, enable IPv6 in /etc/docker/daemon.json and restart:\n {\"ipv6\": true, \"fixed-cidr-v6\": \"fd00:55:66::/64\"}")
}
}
func validateQemuNetwork(n string) string {
switch n {
case "socket_vmnet":
@ -576,6 +699,7 @@ func generateNewConfigFromFlags(cmd *cobra.Command, k8sVersion string, rtime str
KicBaseImage: viper.GetString(kicBaseImage),
Network: getNetwork(drvName, options),
Subnet: viper.GetString(subnet),
Subnetv6: viper.GetString(subnetv6),
Memory: getMemorySize(cmd, drvName),
CPUs: getCPUCount(drvName),
DiskSize: getDiskSize(),
@ -590,6 +714,7 @@ func generateNewConfigFromFlags(cmd *cobra.Command, k8sVersion string, rtime str
InsecureRegistry: insecureRegistry,
RegistryMirror: registryMirror,
HostOnlyCIDR: viper.GetString(hostOnlyCIDR),
HostOnlyCIDRv6: viper.GetString(hostOnlyCIDRv6),
HypervVirtualSwitch: viper.GetString(hypervVirtualSwitch),
HypervUseExternalSwitch: viper.GetBool(hypervUseExternalSwitch),
HypervExternalAdapter: viper.GetString(hypervExternalAdapter),
@ -631,6 +756,7 @@ func generateNewConfigFromFlags(cmd *cobra.Command, k8sVersion string, rtime str
SocketVMnetClientPath: detect.SocketVMNetClientPath(),
SocketVMnetPath: detect.SocketVMNetPath(),
StaticIP: viper.GetString(staticIP),
StaticIPv6: viper.GetString(staticIPv6),
KubernetesConfig: config.KubernetesConfig{
KubernetesVersion: k8sVersion,
ClusterName: ClusterFlagValue(),
@ -644,6 +770,10 @@ func generateNewConfigFromFlags(cmd *cobra.Command, k8sVersion string, rtime str
CRISocket: viper.GetString(criSocket),
NetworkPlugin: chosenNetworkPlugin,
ServiceCIDR: viper.GetString(serviceCIDR),
ServiceCIDRv6: viper.GetString(serviceCIDRv6),
PodCIDR: viper.GetString(podCIDR),
PodCIDRv6: viper.GetString(podCIDRv6),
IPFamily: viper.GetString(ipFamily),
ImageRepository: getRepository(cmd, k8sVersion),
ExtraOptions: getExtraOptions(),
ShouldLoadCachedImages: viper.GetBool(cacheImages),
@ -697,6 +827,8 @@ func generateNewConfigFromFlags(cmd *cobra.Command, k8sVersion string, rtime str
}
}
normalizeAndValidateIPFamily(&cc)
return cc
}
@ -831,11 +963,15 @@ func updateExistingConfigFromFlags(cmd *cobra.Command, existing *config.ClusterC
updateStringFromFlag(cmd, &cc.MinikubeISO, isoURL)
updateStringFromFlag(cmd, &cc.KicBaseImage, kicBaseImage)
updateStringFromFlag(cmd, &cc.Network, network)
updateStringFromFlag(cmd, &cc.Subnetv6, subnetv6)
updateStringFromFlag(cmd, &cc.KubernetesConfig.PodCIDR, podCIDR)
updateStringFromFlag(cmd, &cc.KubernetesConfig.PodCIDRv6, podCIDRv6)
updateStringFromFlag(cmd, &cc.HyperkitVpnKitSock, vpnkitSock)
updateStringSliceFromFlag(cmd, &cc.HyperkitVSockPorts, vsockPorts)
updateStringSliceFromFlag(cmd, &cc.NFSShare, nfsShare)
updateStringFromFlag(cmd, &cc.NFSSharesRoot, nfsSharesRoot)
updateStringFromFlag(cmd, &cc.HostOnlyCIDR, hostOnlyCIDR)
updateStringFromFlag(cmd, &cc.HostOnlyCIDRv6, hostOnlyCIDRv6)
updateStringFromFlag(cmd, &cc.HypervVirtualSwitch, hypervVirtualSwitch)
updateBoolFromFlag(cmd, &cc.HypervUseExternalSwitch, hypervUseExternalSwitch)
updateStringFromFlag(cmd, &cc.HypervExternalAdapter, hypervExternalAdapter)
@ -853,6 +989,7 @@ func updateExistingConfigFromFlags(cmd *cobra.Command, existing *config.ClusterC
updateDurationFromFlag(cmd, &cc.StartHostTimeout, waitTimeout)
updateStringSliceFromFlag(cmd, &cc.ExposedPorts, ports)
updateStringFromFlag(cmd, &cc.SSHIPAddress, sshIPAddress)
updateStringFromFlag(cmd, &cc.StaticIPv6, staticIPv6)
updateStringFromFlag(cmd, &cc.SSHUser, sshSSHUser)
updateStringFromFlag(cmd, &cc.SSHKey, sshSSHKey)
updateIntFromFlag(cmd, &cc.SSHPort, sshSSHPort)
@ -865,6 +1002,8 @@ func updateExistingConfigFromFlags(cmd *cobra.Command, existing *config.ClusterC
updateStringFromFlag(cmd, &cc.KubernetesConfig.CRISocket, criSocket)
updateStringFromFlag(cmd, &cc.KubernetesConfig.NetworkPlugin, networkPlugin)
updateStringFromFlag(cmd, &cc.KubernetesConfig.ServiceCIDR, serviceCIDR)
updateStringFromFlag(cmd, &cc.KubernetesConfig.ServiceCIDRv6, serviceCIDRv6)
updateStringFromFlag(cmd, &cc.KubernetesConfig.IPFamily, ipFamily)
updateBoolFromFlag(cmd, &cc.KubernetesConfig.ShouldLoadCachedImages, cacheImages)
updateDurationFromFlag(cmd, &cc.CertExpiration, certExpiration)
updateStringFromFlag(cmd, &cc.MountString, mountString)
@ -921,7 +1060,7 @@ func updateExistingConfigFromFlags(cmd *cobra.Command, existing *config.ClusterC
if cc.ScheduledStop != nil && time.Until(time.Unix(cc.ScheduledStop.InitiationTime, 0).Add(cc.ScheduledStop.Duration)) <= 0 {
cc.ScheduledStop = nil
}
normalizeAndValidateIPFamily(&cc)
return cc
}

View File

@ -50,6 +50,7 @@ type ClusterConfig struct {
InsecureRegistry []string
RegistryMirror []string
HostOnlyCIDR string // Only used by the virtualbox driver
HostOnlyCIDRv6 string // IPv6 CIDR for the virtualbox driver
HypervVirtualSwitch string
HypervUseExternalSwitch bool
HypervExternalAdapter string
@ -85,6 +86,7 @@ type ClusterConfig struct {
ListenAddress string // Only used by the docker and podman driver
Network string // only used by docker driver
Subnet string // only used by the docker and podman driver
Subnetv6 string // IPv6 subnet for docker and podman driver
MultiNodeRequested bool
ExtraDisks int // currently only implemented for hyperkit and kvm2
CertExpiration time.Duration
@ -105,6 +107,7 @@ type ClusterConfig struct {
SocketVMnetClientPath string
SocketVMnetPath string
StaticIP string
StaticIPv6 string // Static IPv6 address for the cluster
SSHAuthSock string
SSHAgentPID int
GPUs string
@ -126,6 +129,10 @@ type KubernetesConfig struct {
NetworkPlugin string
FeatureGates string // https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/
ServiceCIDR string // the subnet which Kubernetes services will be deployed to
ServiceCIDRv6 string // the IPv6 subnet which Kubernetes services will be deployed to
PodCIDR string // the IPv4 subnet which Kubernetes pods will be deployed to
PodCIDRv6 string // the IPv6 subnet which Kubernetes pods will be deployed to
IPFamily string // IP family mode: ipv4, ipv6, or dual
ImageRepository string
LoadBalancerStartIP string // currently only used by MetalLB addon
LoadBalancerEndIP string // currently only used by MetalLB addon
@ -143,6 +150,7 @@ type KubernetesConfig struct {
type Node struct {
Name string
IP string
IPv6 string // IPv6 address of the node
Port int
KubernetesVersion string
ContainerRuntime string

View File

@ -80,6 +80,10 @@ const (
ClusterDNSDomain = "cluster.local"
// DefaultServiceCIDR is The CIDR to be used for service cluster IPs
DefaultServiceCIDR = "10.96.0.0/12"
// DefaultServiceCIDRv6 is The IPv6 CIDR to be used for service cluster IPs
DefaultServiceCIDRv6 = "fd00::/108"
// DefaultPodCIDRv6 is The IPv6 CIDR to be used for pod IPs
DefaultPodCIDRv6 = "fd01::/64"
// HostAlias is a DNS alias to the container/VM host IP
HostAlias = "host.minikube.internal"
// ControlPlaneAlias is a DNS alias pointing to the apiserver frontend