diff --git a/cmd/kops/create_cluster.go b/cmd/kops/create_cluster.go index 803914a3fe57f..65f0cba53a77d 100644 --- a/cmd/kops/create_cluster.go +++ b/cmd/kops/create_cluster.go @@ -172,6 +172,9 @@ type CreateClusterOptions struct { DryRun bool // Output type during a DryRun Output string + + // CiliumEtcdManagd makes Cilium use etcd as kvstore managed by etcd-manager + CiliumEtcdManaged bool } func (o *CreateClusterOptions) InitDefaults() { @@ -331,6 +334,7 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command { cmd.Flags().StringVar(&options.Image, "image", options.Image, "Image to use for all instances.") cmd.Flags().StringVar(&options.Networking, "networking", options.Networking, "Networking mode to use. kubenet (default), classic, external, kopeio-vxlan (or kopeio), weave, flannel-vxlan (or flannel), flannel-udp, calico, canal, kube-router, romana, amazon-vpc-routed-eni, cilium, cni.") + cmd.Flags().BoolVar(&options.CiliumEtcdManaged, "cilium-etcd-managed", false, "Use etcd as cilium kvstore") cmd.Flags().StringVar(&options.DNSZone, "dns-zone", options.DNSZone, "DNS hosted zone to use (defaults to longest matching zone)") cmd.Flags().StringVar(&options.OutDir, "out", options.OutDir, "Path to write any local output") @@ -793,47 +797,7 @@ func RunCreateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Cr } for _, etcdCluster := range cloudup.EtcdClusters { - etcd := &api.EtcdClusterSpec{} - etcd.Name = etcdCluster - - // if this is the main cluster, we use 200 millicores by default. - // otherwise we use 100 millicores by default. 100Mi is always default - // for event and main clusters. This is changeable in the kops cluster - // configuration. - if etcd.Name == "main" { - cpuRequest := resource.MustParse("200m") - etcd.CPURequest = &cpuRequest - } else { - cpuRequest := resource.MustParse("100m") - etcd.CPURequest = &cpuRequest - } - memoryRequest := resource.MustParse("100Mi") - etcd.MemoryRequest = &memoryRequest - - var names []string - for _, ig := range masters { - name := ig.ObjectMeta.Name - // We expect the IG to have a `master-` prefix, but this is both superfluous - // and not how we named things previously - name = strings.TrimPrefix(name, "master-") - names = append(names, name) - } - - names = trimCommonPrefix(names) - - for i, ig := range masters { - m := &api.EtcdMemberSpec{} - if c.EncryptEtcdStorage { - m.EncryptedVolume = &c.EncryptEtcdStorage - } - if len(c.EtcdStorageType) > 0 { - m.VolumeType = fi.String(c.EtcdStorageType) - } - m.Name = names[i] - - m.InstanceGroup = fi.String(ig.ObjectMeta.Name) - etcd.Members = append(etcd.Members, m) - } + etcd := createEtcdCluster(etcdCluster, masters, c.EncryptEtcdStorage, c.EtcdStorageType) cluster.Spec.EtcdClusters = append(cluster.Spec.EtcdClusters, etcd) } } @@ -1080,6 +1044,15 @@ func RunCreateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Cr klog.V(4).Infof("networking mode=%s => %s", c.Networking, fi.DebugAsJsonString(cluster.Spec.Networking)) + if c.CiliumEtcdManaged { + if cluster.Spec.Networking.Cilium == nil { + return fmt.Errorf("--cilium-etcd-managed can only be enabled when --networking=cilium") + } + cluster.Spec.Networking.Cilium.EtcdManaged = true + etcd := createEtcdCluster("cilium", masters, c.EncryptEtcdStorage, c.EtcdStorageType) + cluster.Spec.EtcdClusters = append(cluster.Spec.EtcdClusters, etcd) + } + if c.NetworkCIDR != "" { cluster.Spec.NetworkCIDR = c.NetworkCIDR } @@ -1612,3 +1585,49 @@ func loadSSHPublicKeys(sshPublicKey string) (map[string][]byte, error) { } return sshPublicKeys, nil } + +func createEtcdCluster(etcdCluster string, masters []*api.InstanceGroup, encryptEtcdStorage bool, etcdStorageType string) *api.EtcdClusterSpec { + etcd := &api.EtcdClusterSpec{} + etcd.Name = etcdCluster + + // if this is the main cluster, we use 200 millicores by default. + // otherwise we use 100 millicores by default. 100Mi is always default + // for event and main clusters. This is changeable in the kops cluster + // configuration. + if etcd.Name == "main" { + cpuRequest := resource.MustParse("200m") + etcd.CPURequest = &cpuRequest + } else { + cpuRequest := resource.MustParse("100m") + etcd.CPURequest = &cpuRequest + } + memoryRequest := resource.MustParse("100Mi") + etcd.MemoryRequest = &memoryRequest + + var names []string + for _, ig := range masters { + name := ig.ObjectMeta.Name + // We expect the IG to have a `master-` prefix, but this is both superfluous + // and not how we named things previously + name = strings.TrimPrefix(name, "master-") + names = append(names, name) + } + + names = trimCommonPrefix(names) + + for i, ig := range masters { + m := &api.EtcdMemberSpec{} + if encryptEtcdStorage { + m.EncryptedVolume = &encryptEtcdStorage + } + if len(etcdStorageType) > 0 { + m.VolumeType = fi.String(etcdStorageType) + } + m.Name = names[i] + + m.InstanceGroup = fi.String(ig.ObjectMeta.Name) + etcd.Members = append(etcd.Members, m) + } + return etcd + +} diff --git a/cmd/kops/create_cluster_test.go b/cmd/kops/create_cluster_test.go index 483b61303f4a4..b62954fa6f3c6 100644 --- a/cmd/kops/create_cluster_test.go +++ b/cmd/kops/create_cluster_test.go @@ -18,6 +18,9 @@ package main import ( "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/kops/pkg/apis/kops" ) func TestParseCloudLabels(t *testing.T) { @@ -46,3 +49,20 @@ func checkParse(t *testing.T, s string, expect map[string]string, shouldErr bool } } } + +func TestCreateEtcdCluster(t *testing.T) { + masters := []*kops.InstanceGroup{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "master1", + }, + }, + } + name := "foo" + etcd := createEtcdCluster(name, masters, false, "") + + if name != etcd.Name { + t.Errorf("Expected: %v, Got: %v", name, etcd.Name) + } + +} diff --git a/docs/cli/kops_create_cluster.md b/docs/cli/kops_create_cluster.md index b0d4ed5631644..d456dcb7eca97 100644 --- a/docs/cli/kops_create_cluster.md +++ b/docs/cli/kops_create_cluster.md @@ -72,6 +72,7 @@ kops create cluster [flags] --authorization string Authorization mode to use: AlwaysAllow or RBAC (default "RBAC") --bastion Pass the --bastion flag to enable a bastion instance group. Only applies to private topology. --channel string Channel for default versions and configuration to use (default "stable") + --cilium-etcd-managed Use etcd as cilium kvstore --cloud string Cloud provider to use - gce, aws, vsphere, openstack --cloud-labels string A list of KV pairs used to tag all instance groups in AWS (e.g. "Owner=John Doe,Team=Some Team"). --container-runtime string Container runtime to use: containerd, docker (default "docker")