@@ -89,6 +89,8 @@ func (d *Driver) Create() error {
8989 OCIBinary : d .NodeConfig .OCIBinary ,
9090 APIServerPort : d .NodeConfig .APIServerPort ,
9191 GPUs : d .NodeConfig .GPUs ,
92+ IPFamily : strings .ToLower (d .NodeConfig .IPFamily ),
93+ IPv6 : d .NodeConfig .StaticIPv6 ,
9294 }
9395 if params .Memory != "0" {
9496 params .Memory += "mb"
@@ -98,41 +100,102 @@ func (d *Driver) Create() error {
98100 if networkName == "" {
99101 networkName = d .NodeConfig .ClusterName
100102 }
103+
101104 staticIP := d .NodeConfig .StaticIP
102- if gateway , err := oci .CreateNetwork (d .OCIBinary , networkName , d .NodeConfig .Subnet , staticIP ); err != nil {
105+
106+ gateway , err := oci .CreateNetworkWithIPFamily (
107+ d .OCIBinary ,
108+ networkName ,
109+ d .NodeConfig .Subnet ,
110+ d .NodeConfig .Subnetv6 ,
111+ staticIP ,
112+ d .NodeConfig .StaticIPv6 ,
113+ params .IPFamily ,
114+ )
115+ if err != nil {
103116 msg := "Unable to create dedicated network, this might result in cluster IP change after restart: {{.error}}"
104117 args := out.V {"error" : err }
105- if staticIP != "" {
118+ if staticIP != "" || d .NodeConfig .StaticIPv6 != "" {
119+ // If the user requested a static IP on either family, failing
120+ // to create the dedicated network should be fatal.
106121 exit .Message (reason .IfDedicatedNetwork , msg , args )
107122 }
108123 out .WarningT (msg , args )
109- } else if gateway != nil && staticIP != "" {
110- params .Network = networkName
111- params .IP = staticIP
112- } else if gateway != nil {
124+ } else {
125+ // Only attach to the user-defined network when creation/reuse
126+ // succeeded. For IPv6-only networks, gateway may legitimately be nil.
113127 params .Network = networkName
114- ip := gateway .To4 ()
115- // calculate the container IP based on guessing the machine index
116- index := driver .IndexFromMachineName (d .NodeConfig .MachineName )
117- if int (ip [3 ])+ index > 253 { // reserve last client ip address for multi-control-plane loadbalancer vip address in ha cluster
118- return fmt .Errorf ("too many machines to calculate an IP" )
128+ }
129+
130+ // Now decide static IPs per family based on the gateway (if any).
131+ switch params .IPFamily {
132+ case "ipv6" :
133+ if d .NodeConfig .StaticIPv6 != "" {
134+ params .IPv6 = d .NodeConfig .StaticIPv6
135+ }
136+
137+ case "dual" :
138+ // IPv4 part (only if Docker reported a v4 gateway)
139+ if g4 := gateway .To4 (); g4 != nil {
140+ if staticIP != "" {
141+ params .IP = staticIP
142+ } else {
143+ ip := make (net.IP , len (g4 ))
144+ copy (ip , g4 )
145+ index := driver .IndexFromMachineName (d .NodeConfig .MachineName )
146+ if int (ip [3 ])+ index > 253 {
147+ return fmt .Errorf ("too many machines to calculate an IPv4" )
148+ }
149+ ip [3 ] += byte (index )
150+ klog .Infof ("calculated static IPv4 %q for the %q container" , ip .String (), d .NodeConfig .MachineName )
151+ params .IP = ip .String ()
152+ }
153+ }
154+ if d .NodeConfig .StaticIPv6 != "" {
155+ params .IPv6 = d .NodeConfig .StaticIPv6
156+ }
157+
158+ default : // ipv4
159+ if staticIP != "" {
160+ params .IP = staticIP
161+ } else if gateway != nil {
162+ if g4 := gateway .To4 (); g4 != nil {
163+ ip := make (net.IP , len (g4 ))
164+ copy (ip , g4 )
165+ index := driver .IndexFromMachineName (d .NodeConfig .MachineName )
166+ if int (ip [3 ])+ index > 253 {
167+ return fmt .Errorf ("too many machines to calculate an IP" )
168+ }
169+ ip [3 ] += byte (index )
170+ klog .Infof ("calculated static IP %q for the %q container" , ip .String (), d .NodeConfig .MachineName )
171+ params .IP = ip .String ()
172+ }
119173 }
120- ip [3 ] += byte (index )
121- klog .Infof ("calculated static IP %q for the %q container" , ip .String (), d .NodeConfig .MachineName )
122- params .IP = ip .String ()
123174 }
124- drv := d .DriverName ()
125175
176+ drv := d .DriverName ()
177+ // Default listen address: v4 localhost for ipv4, v6 localhost for ipv6-only
126178 listAddr := oci .DefaultBindIPV4
179+ // IPv6-only clusters must publish on IPv6 loopback so the host can reach them
180+ if params .IPFamily == "ipv6" {
181+ listAddr = "::1"
182+ }
183+
127184 if d .NodeConfig .ListenAddress != "" && d .NodeConfig .ListenAddress != listAddr {
128185 out .Step (style .Tip , "minikube is not meant for production use. You are opening non-local traffic" )
129186 out .WarningT ("Listening to {{.listenAddr}}. This is not recommended and can cause a security vulnerability. Use at your own risk" ,
130187 out.V {"listenAddr" : d .NodeConfig .ListenAddress })
131188 listAddr = d .NodeConfig .ListenAddress
132189 } else if oci .IsExternalDaemonHost (drv ) {
133- out .WarningT ("Listening to 0.0.0.0 on external docker host {{.host}}. Please be advised" ,
134- out.V {"host" : oci .DaemonHost (drv )})
135- listAddr = "0.0.0.0"
190+ if params .IPFamily == "ipv6" {
191+ out .WarningT ("Listening to :: on external docker host {{.host}}. Please be advised" ,
192+ out.V {"host" : oci .DaemonHost (drv )})
193+ listAddr = "::"
194+ } else {
195+ out .WarningT ("Listening to 0.0.0.0 on external docker host {{.host}}. Please be advised" ,
196+ out.V {"host" : oci .DaemonHost (drv )})
197+ listAddr = "0.0.0.0"
198+ }
136199 }
137200
138201 // control plane specific options
@@ -293,18 +356,38 @@ func (d *Driver) DriverName() string {
293356
294357// GetIP returns an IP or hostname that this host is available at
295358func (d * Driver ) GetIP () (string , error ) {
296- ip , _ , err := oci .ContainerIPs (d .OCIBinary , d .MachineName )
297- return ip , err
359+ ip4 , ip6 , err := oci .ContainerIPs (d .OCIBinary , d .MachineName )
360+ if err != nil {
361+ return "" , err
362+ }
363+ switch strings .ToLower (d .NodeConfig .IPFamily ) {
364+ case "ipv6" :
365+ if ip6 != "" {
366+ return ip6 , nil
367+ }
368+ }
369+ // default / dual prefers IPv4 for backward compat
370+ return ip4 , nil
298371}
299372
300373// GetExternalIP returns an IP which is accessible from outside
301374func (d * Driver ) GetExternalIP () (string , error ) {
302- return oci .DaemonHost (d .DriverName ()), nil
375+ host := oci .DaemonHost (d .DriverName ())
376+ // For local daemons and IPv6-only clusters, ports are published on ::1
377+ if strings .ToLower (d .NodeConfig .IPFamily ) == "ipv6" && ! oci .IsExternalDaemonHost (d .DriverName ()) {
378+ return "::1" , nil
379+ }
380+ return host , nil
303381}
304382
305383// GetSSHHostname returns hostname for use with ssh
306384func (d * Driver ) GetSSHHostname () (string , error ) {
307- return oci .DaemonHost (d .DriverName ()), nil
385+ host := oci .DaemonHost (d .DriverName ())
386+ // For local daemons and IPv6-only clusters, ports are published on ::1
387+ if strings .ToLower (d .NodeConfig .IPFamily ) == "ipv6" && ! oci .IsExternalDaemonHost (d .DriverName ()) {
388+ return "::1" , nil
389+ }
390+ return host , nil
308391}
309392
310393// GetSSHPort returns port for use with ssh
0 commit comments