diff --git a/docs/cluster_spec.md b/docs/cluster_spec.md index f63ff4425d..7139f77655 100644 --- a/docs/cluster_spec.md +++ b/docs/cluster_spec.md @@ -203,6 +203,21 @@ spec: disableSecurityGroupIngress: true ``` +### registryMirrors + +If you have a bunch of Docker instances (physicsal or vm) running, each time one of them pulls an image that is not present on the host, it will fetch it from the internet (DockerHub). By caching these images, you can keep the traffic within your local network and avoid egress bandwidth usage. +This setting benefits not only cluster provisioning but also image pulling. + +@see [Cache-Mirror Dockerhub For Speed](https://hackernoon.com/mirror-cache-dockerhub-locally-for-speed-f4eebd21a5ca) +@see [Configure the Docker daemon](https://docs.docker.com/registry/recipes/mirror/#configure-the-docker-daemon). + +```yaml +spec: + docker: + registryMirrors: + - https://registry.example.com +``` + #### WARNING: this works only for Kubernetes version above 1.7.0. For avoid to create security group per each elb, you can specify security group id, that will be assigned to your LoadBalancer. It must be security group id, not name. Also, security group must be empty, because Kubernetes will add rules per ports that are specified in service file. diff --git a/pkg/apis/kops/dockerconfig.go b/pkg/apis/kops/dockerconfig.go index c66bd4413d..2db00db46b 100644 --- a/pkg/apis/kops/dockerconfig.go +++ b/pkg/apis/kops/dockerconfig.go @@ -30,7 +30,10 @@ type DockerConfig struct { Storage *string `json:"storage,omitempty" flag:"storage-driver"` InsecureRegistry *string `json:"insecureRegistry,omitempty" flag:"insecure-registry"` - MTU *int32 `json:"mtu,omitempty" flag:"mtu"` + + // Set mirrors for dockerd, benefiting cluster provisioning and image pulling + RegistryMirrors []string `json:"registryMirrors,omitempty" flag:"registry-mirror,repeat"` + MTU *int32 `json:"mtu,omitempty" flag:"mtu"` // The bridge cidr (--bip) flag BridgeIP *string `json:"bridgeIP,omitempty" flag:"bip"` diff --git a/pkg/apis/kops/v1alpha1/dockerconfig.go b/pkg/apis/kops/v1alpha1/dockerconfig.go index 9ba12c4b66..051a9a9a33 100644 --- a/pkg/apis/kops/v1alpha1/dockerconfig.go +++ b/pkg/apis/kops/v1alpha1/dockerconfig.go @@ -30,7 +30,10 @@ type DockerConfig struct { Storage *string `json:"storage,omitempty" flag:"storage-driver"` InsecureRegistry *string `json:"insecureRegistry,omitempty" flag:"insecure-registry"` - MTU *int32 `json:"mtu,omitempty" flag:"mtu"` + + // Set mirrors for dockerd, benefiting cluster provisioning and image pulling + RegistryMirrors []string `json:"registryMirrors,omitempty" flag:"registry-mirror,repeat"` + MTU *int32 `json:"mtu,omitempty" flag:"mtu"` // The bridge cidr (--bip) flag BridgeIP *string `json:"bridgeIP,omitempty" flag:"bip"` diff --git a/pkg/apis/kops/v1alpha1/zz_generated.conversion.go b/pkg/apis/kops/v1alpha1/zz_generated.conversion.go index 5186c87fa9..d4387748fb 100644 --- a/pkg/apis/kops/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/kops/v1alpha1/zz_generated.conversion.go @@ -207,6 +207,7 @@ func autoConvert_v1alpha1_AuthenticationSpec_To_kops_AuthenticationSpec(in *Auth return nil } +// Convert_v1alpha1_AuthenticationSpec_To_kops_AuthenticationSpec is an autogenerated conversion function. func Convert_v1alpha1_AuthenticationSpec_To_kops_AuthenticationSpec(in *AuthenticationSpec, out *kops.AuthenticationSpec, s conversion.Scope) error { return autoConvert_v1alpha1_AuthenticationSpec_To_kops_AuthenticationSpec(in, out, s) } @@ -224,6 +225,7 @@ func autoConvert_kops_AuthenticationSpec_To_v1alpha1_AuthenticationSpec(in *kops return nil } +// Convert_kops_AuthenticationSpec_To_v1alpha1_AuthenticationSpec is an autogenerated conversion function. func Convert_kops_AuthenticationSpec_To_v1alpha1_AuthenticationSpec(in *kops.AuthenticationSpec, out *AuthenticationSpec, s conversion.Scope) error { return autoConvert_kops_AuthenticationSpec_To_v1alpha1_AuthenticationSpec(in, out, s) } @@ -867,6 +869,7 @@ func autoConvert_v1alpha1_DockerConfig_To_kops_DockerConfig(in *DockerConfig, ou out.LogOpt = in.LogOpt out.Storage = in.Storage out.InsecureRegistry = in.InsecureRegistry + out.RegistryMirrors = in.RegistryMirrors out.MTU = in.MTU out.BridgeIP = in.BridgeIP out.Version = in.Version @@ -889,6 +892,7 @@ func autoConvert_kops_DockerConfig_To_v1alpha1_DockerConfig(in *kops.DockerConfi out.LogOpt = in.LogOpt out.Storage = in.Storage out.InsecureRegistry = in.InsecureRegistry + out.RegistryMirrors = in.RegistryMirrors out.MTU = in.MTU out.BridgeIP = in.BridgeIP out.Version = in.Version @@ -1280,6 +1284,7 @@ func autoConvert_v1alpha1_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationS return nil } +// Convert_v1alpha1_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec is an autogenerated conversion function. func Convert_v1alpha1_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec(in *KopeioAuthenticationSpec, out *kops.KopeioAuthenticationSpec, s conversion.Scope) error { return autoConvert_v1alpha1_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec(in, out, s) } @@ -1288,6 +1293,7 @@ func autoConvert_kops_KopeioAuthenticationSpec_To_v1alpha1_KopeioAuthenticationS return nil } +// Convert_kops_KopeioAuthenticationSpec_To_v1alpha1_KopeioAuthenticationSpec is an autogenerated conversion function. func Convert_kops_KopeioAuthenticationSpec_To_v1alpha1_KopeioAuthenticationSpec(in *kops.KopeioAuthenticationSpec, out *KopeioAuthenticationSpec, s conversion.Scope) error { return autoConvert_kops_KopeioAuthenticationSpec_To_v1alpha1_KopeioAuthenticationSpec(in, out, s) } @@ -1327,12 +1333,12 @@ func autoConvert_v1alpha1_KubeAPIServerConfig_To_kops_KubeAPIServerConfig(in *Ku out.BasicAuthFile = in.BasicAuthFile out.TLSCertFile = in.TLSCertFile out.TLSPrivateKeyFile = in.TLSPrivateKeyFile - out.KubeletClientCertificate = in.KubeletClientCertificate - out.KubeletClientKey = in.KubeletClientKey out.TokenAuthFile = in.TokenAuthFile out.AllowPrivileged = in.AllowPrivileged out.APIServerCount = in.APIServerCount out.RuntimeConfig = in.RuntimeConfig + out.KubeletClientCertificate = in.KubeletClientCertificate + out.KubeletClientKey = in.KubeletClientKey out.AnonymousAuth = in.AnonymousAuth out.KubeletPreferredAddressTypes = in.KubeletPreferredAddressTypes out.StorageBackend = in.StorageBackend @@ -1567,10 +1573,10 @@ func Convert_kops_KubeSchedulerConfig_To_v1alpha1_KubeSchedulerConfig(in *kops.K func autoConvert_v1alpha1_KubeletConfigSpec_To_kops_KubeletConfigSpec(in *KubeletConfigSpec, out *kops.KubeletConfigSpec, s conversion.Scope) error { out.APIServers = in.APIServers out.AnonymousAuth = in.AnonymousAuth + out.ClientCAFile = in.ClientCAFile out.KubeconfigPath = in.KubeconfigPath out.RequireKubeconfig = in.RequireKubeconfig out.LogLevel = in.LogLevel - out.ClientCAFile = in.ClientCAFile out.PodManifestPath = in.PodManifestPath out.HostnameOverride = in.HostnameOverride out.AllowPrivileged = in.AllowPrivileged @@ -1618,10 +1624,10 @@ func Convert_v1alpha1_KubeletConfigSpec_To_kops_KubeletConfigSpec(in *KubeletCon func autoConvert_kops_KubeletConfigSpec_To_v1alpha1_KubeletConfigSpec(in *kops.KubeletConfigSpec, out *KubeletConfigSpec, s conversion.Scope) error { out.APIServers = in.APIServers out.AnonymousAuth = in.AnonymousAuth + out.ClientCAFile = in.ClientCAFile out.KubeconfigPath = in.KubeconfigPath out.RequireKubeconfig = in.RequireKubeconfig out.LogLevel = in.LogLevel - out.ClientCAFile = in.ClientCAFile out.PodManifestPath = in.PodManifestPath out.HostnameOverride = in.HostnameOverride out.AllowPrivileged = in.AllowPrivileged diff --git a/pkg/apis/kops/v1alpha2/dockerconfig.go b/pkg/apis/kops/v1alpha2/dockerconfig.go index 918c9761c2..64fece38ac 100644 --- a/pkg/apis/kops/v1alpha2/dockerconfig.go +++ b/pkg/apis/kops/v1alpha2/dockerconfig.go @@ -30,7 +30,10 @@ type DockerConfig struct { Storage *string `json:"storage,omitempty" flag:"storage-driver"` InsecureRegistry *string `json:"insecureRegistry,omitempty" flag:"insecure-registry"` - MTU *int32 `json:"mtu,omitempty" flag:"mtu"` + + // Set mirrors for dockerd, benefiting cluster provisioning and image pulling + RegistryMirrors []string `json:"registryMirrors,omitempty" flag:"registry-mirror,repeat"` + MTU *int32 `json:"mtu,omitempty" flag:"mtu"` // The bridge cidr (--bip) flag BridgeIP *string `json:"bridgeIP,omitempty" flag:"bip"` diff --git a/pkg/apis/kops/v1alpha2/zz_generated.conversion.go b/pkg/apis/kops/v1alpha2/zz_generated.conversion.go index f90fa001d9..fbf1f61d60 100644 --- a/pkg/apis/kops/v1alpha2/zz_generated.conversion.go +++ b/pkg/apis/kops/v1alpha2/zz_generated.conversion.go @@ -213,6 +213,7 @@ func autoConvert_v1alpha2_AuthenticationSpec_To_kops_AuthenticationSpec(in *Auth return nil } +// Convert_v1alpha2_AuthenticationSpec_To_kops_AuthenticationSpec is an autogenerated conversion function. func Convert_v1alpha2_AuthenticationSpec_To_kops_AuthenticationSpec(in *AuthenticationSpec, out *kops.AuthenticationSpec, s conversion.Scope) error { return autoConvert_v1alpha2_AuthenticationSpec_To_kops_AuthenticationSpec(in, out, s) } @@ -230,6 +231,7 @@ func autoConvert_kops_AuthenticationSpec_To_v1alpha2_AuthenticationSpec(in *kops return nil } +// Convert_kops_AuthenticationSpec_To_v1alpha2_AuthenticationSpec is an autogenerated conversion function. func Convert_kops_AuthenticationSpec_To_v1alpha2_AuthenticationSpec(in *kops.AuthenticationSpec, out *AuthenticationSpec, s conversion.Scope) error { return autoConvert_kops_AuthenticationSpec_To_v1alpha2_AuthenticationSpec(in, out, s) } @@ -955,6 +957,7 @@ func autoConvert_v1alpha2_DockerConfig_To_kops_DockerConfig(in *DockerConfig, ou out.LogOpt = in.LogOpt out.Storage = in.Storage out.InsecureRegistry = in.InsecureRegistry + out.RegistryMirrors = in.RegistryMirrors out.MTU = in.MTU out.BridgeIP = in.BridgeIP out.Version = in.Version @@ -977,6 +980,7 @@ func autoConvert_kops_DockerConfig_To_v1alpha2_DockerConfig(in *kops.DockerConfi out.LogOpt = in.LogOpt out.Storage = in.Storage out.InsecureRegistry = in.InsecureRegistry + out.RegistryMirrors = in.RegistryMirrors out.MTU = in.MTU out.BridgeIP = in.BridgeIP out.Version = in.Version @@ -1388,6 +1392,7 @@ func autoConvert_v1alpha2_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationS return nil } +// Convert_v1alpha2_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec is an autogenerated conversion function. func Convert_v1alpha2_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec(in *KopeioAuthenticationSpec, out *kops.KopeioAuthenticationSpec, s conversion.Scope) error { return autoConvert_v1alpha2_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec(in, out, s) } @@ -1396,6 +1401,7 @@ func autoConvert_kops_KopeioAuthenticationSpec_To_v1alpha2_KopeioAuthenticationS return nil } +// Convert_kops_KopeioAuthenticationSpec_To_v1alpha2_KopeioAuthenticationSpec is an autogenerated conversion function. func Convert_kops_KopeioAuthenticationSpec_To_v1alpha2_KopeioAuthenticationSpec(in *kops.KopeioAuthenticationSpec, out *KopeioAuthenticationSpec, s conversion.Scope) error { return autoConvert_kops_KopeioAuthenticationSpec_To_v1alpha2_KopeioAuthenticationSpec(in, out, s) } @@ -1435,12 +1441,12 @@ func autoConvert_v1alpha2_KubeAPIServerConfig_To_kops_KubeAPIServerConfig(in *Ku out.BasicAuthFile = in.BasicAuthFile out.TLSCertFile = in.TLSCertFile out.TLSPrivateKeyFile = in.TLSPrivateKeyFile - out.KubeletClientCertificate = in.KubeletClientCertificate - out.KubeletClientKey = in.KubeletClientKey out.TokenAuthFile = in.TokenAuthFile out.AllowPrivileged = in.AllowPrivileged out.APIServerCount = in.APIServerCount out.RuntimeConfig = in.RuntimeConfig + out.KubeletClientCertificate = in.KubeletClientCertificate + out.KubeletClientKey = in.KubeletClientKey out.AnonymousAuth = in.AnonymousAuth out.KubeletPreferredAddressTypes = in.KubeletPreferredAddressTypes out.StorageBackend = in.StorageBackend @@ -1675,10 +1681,10 @@ func Convert_kops_KubeSchedulerConfig_To_v1alpha2_KubeSchedulerConfig(in *kops.K func autoConvert_v1alpha2_KubeletConfigSpec_To_kops_KubeletConfigSpec(in *KubeletConfigSpec, out *kops.KubeletConfigSpec, s conversion.Scope) error { out.APIServers = in.APIServers out.AnonymousAuth = in.AnonymousAuth + out.ClientCAFile = in.ClientCAFile out.KubeconfigPath = in.KubeconfigPath out.RequireKubeconfig = in.RequireKubeconfig out.LogLevel = in.LogLevel - out.ClientCAFile = in.ClientCAFile out.PodManifestPath = in.PodManifestPath out.HostnameOverride = in.HostnameOverride out.AllowPrivileged = in.AllowPrivileged @@ -1726,10 +1732,10 @@ func Convert_v1alpha2_KubeletConfigSpec_To_kops_KubeletConfigSpec(in *KubeletCon func autoConvert_kops_KubeletConfigSpec_To_v1alpha2_KubeletConfigSpec(in *kops.KubeletConfigSpec, out *KubeletConfigSpec, s conversion.Scope) error { out.APIServers = in.APIServers out.AnonymousAuth = in.AnonymousAuth + out.ClientCAFile = in.ClientCAFile out.KubeconfigPath = in.KubeconfigPath out.RequireKubeconfig = in.RequireKubeconfig out.LogLevel = in.LogLevel - out.ClientCAFile = in.ClientCAFile out.PodManifestPath = in.PodManifestPath out.HostnameOverride = in.HostnameOverride out.AllowPrivileged = in.AllowPrivileged diff --git a/upup/pkg/fi/cloudup/populatecluster_test.go b/upup/pkg/fi/cloudup/populatecluster_test.go index 129c7808dc..60a057f344 100644 --- a/upup/pkg/fi/cloudup/populatecluster_test.go +++ b/upup/pkg/fi/cloudup/populatecluster_test.go @@ -98,6 +98,7 @@ func TestPopulateCluster_Docker_Spec(t *testing.T) { c.Spec.Docker = &api.DockerConfig{ MTU: fi.Int32(5678), InsecureRegistry: fi.String("myregistry.com:1234"), + RegistryMirrors: []string{"https://registry.example.com"}, LogOpt: []string{"env=FOO"}, } @@ -121,6 +122,10 @@ func TestPopulateCluster_Docker_Spec(t *testing.T) { t.Fatalf("Unexpected Docker InsecureRegistry: %v", full.Spec.Docker.InsecureRegistry) } + if strings.Join(full.Spec.Docker.RegistryMirrors, "!") != "https://registry.example.com" { + t.Fatalf("Unexpected Docker RegistryMirrors: %v", full.Spec.Docker.RegistryMirrors) + } + if strings.Join(full.Spec.Docker.LogOpt, "!") != "env=FOO" { t.Fatalf("Unexpected Docker LogOpt: %v", full.Spec.Docker.LogOpt) }