From 7aeb8c2af36f29dce525c0c5dba65b816e58ae23 Mon Sep 17 00:00:00 2001 From: Ciprian Hacman Date: Sun, 24 Jan 2021 18:30:38 +0200 Subject: [PATCH] Add back support for kubenet style networking with containerd --- cmd/kops/BUILD.bazel | 1 - cmd/kops/create_cluster.go | 4 -- nodeup/pkg/model/containerd.go | 43 +++++++++++++++++++ .../tests/containerdbuilder/simple/tasks.yaml | 26 +++++++++++ pkg/apis/kops/validation/validation.go | 12 ------ pkg/model/components/containerd.go | 6 +++ 6 files changed, 75 insertions(+), 17 deletions(-) diff --git a/cmd/kops/BUILD.bazel b/cmd/kops/BUILD.bazel index ce2a4eef38193..21c2a26b6b2ce 100644 --- a/cmd/kops/BUILD.bazel +++ b/cmd/kops/BUILD.bazel @@ -79,7 +79,6 @@ go_library( "//pkg/kopscodecs:go_default_library", "//pkg/kubeconfig:go_default_library", "//pkg/kubemanifest:go_default_library", - "//pkg/model/components:go_default_library", "//pkg/pki:go_default_library", "//pkg/pretty:go_default_library", "//pkg/resources:go_default_library", diff --git a/cmd/kops/create_cluster.go b/cmd/kops/create_cluster.go index 48fb88bb93e39..c91f1ee94c982 100644 --- a/cmd/kops/create_cluster.go +++ b/cmd/kops/create_cluster.go @@ -40,7 +40,6 @@ import ( "k8s.io/kops/pkg/featureflag" "k8s.io/kops/pkg/kubeconfig" "k8s.io/kops/pkg/kubemanifest" - "k8s.io/kops/pkg/model/components" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi/cloudup" "k8s.io/kops/upup/pkg/fi/utils" @@ -489,9 +488,6 @@ func RunCreateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Cr if c.ContainerRuntime != "" { cluster.Spec.ContainerRuntime = c.ContainerRuntime } - if c.ContainerRuntime == "containerd" && components.UsesKubenet(cluster.Spec.Networking) { - return fmt.Errorf("--networking with CNI plugin is required for containerd") - } if c.NetworkCIDR != "" { cluster.Spec.NetworkCIDR = c.NetworkCIDR diff --git a/nodeup/pkg/model/containerd.go b/nodeup/pkg/model/containerd.go index c9e2c154bf46d..e137351d68df8 100644 --- a/nodeup/pkg/model/containerd.go +++ b/nodeup/pkg/model/containerd.go @@ -27,6 +27,7 @@ import ( "k8s.io/kops/nodeup/pkg/model/resources" "k8s.io/kops/pkg/apis/kops" "k8s.io/kops/pkg/flagbuilder" + "k8s.io/kops/pkg/model/components" "k8s.io/kops/pkg/systemd" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi/nodeup/nodetasks" @@ -96,6 +97,14 @@ func (b *ContainerdBuilder) Build(c *fi.ModelBuilderContext) error { // Add configuration file for easier use of crictl b.addCrictlConfig(c) + + // Using containerd with Kubenet requires special configuration. + // This is a temporary backwards-compatible solution for kubenet users and will be deprecated when Kubenet is deprecated: + // https://github.com/containerd/containerd/blob/master/docs/cri/config.md#cni-config-template + if components.UsesKubenet(b.Cluster.Spec.Networking) { + b.buildCNIConfigTemplateFile(c) + } + } var containerRuntimeVersion string @@ -294,3 +303,37 @@ runtime-endpoint: unix:///run/containerd/containerd.sock Type: nodetasks.FileType_File, }) } + +// buildCNIConfigTemplateFile is responsible for creating a special template for setups using Kubenet +func (b *ContainerdBuilder) buildCNIConfigTemplateFile(c *fi.ModelBuilderContext) { + contents := `{ + "cniVersion": "0.4.0", + "name": "containerd-net", + "plugins": [ + { + "type": "bridge", + "bridge": "cni0", + "isGateway": true, + "ipMasq": true, + "promiscMode": true, + "ipam": { + "type": "host-local", + "ranges": [[{"subnet": "{{.PodCIDR}}"}]], + "routes": [{ "dst": "0.0.0.0/0" }] + } + }, + { + "type": "portmap", + "capabilities": {"portMappings": true} + } + ] +} +` + klog.V(8).Infof("Built containerd CNI config template\n%s", contents) + + c.AddTask(&nodetasks.File{ + Path: "/etc/containerd/config-cni.template", + Contents: fi.NewStringResource(contents), + Type: nodetasks.FileType_File, + }) +} diff --git a/nodeup/pkg/model/tests/containerdbuilder/simple/tasks.yaml b/nodeup/pkg/model/tests/containerdbuilder/simple/tasks.yaml index 76ed3fafbdfd7..0d82801c9fcf2 100644 --- a/nodeup/pkg/model/tests/containerdbuilder/simple/tasks.yaml +++ b/nodeup/pkg/model/tests/containerdbuilder/simple/tasks.yaml @@ -1,3 +1,29 @@ +contents: | + { + "cniVersion": "0.4.0", + "name": "containerd-net", + "plugins": [ + { + "type": "bridge", + "bridge": "cni0", + "isGateway": true, + "ipMasq": true, + "promiscMode": true, + "ipam": { + "type": "host-local", + "ranges": [[{"subnet": "{{.PodCIDR}}"}]], + "routes": [{ "dst": "0.0.0.0/0" }] + } + }, + { + "type": "portmap", + "capabilities": {"portMappings": true} + } + ] + } +path: /etc/containerd/config-cni.template +type: file +--- contents: "" path: /etc/containerd/config-kops.toml type: file diff --git a/pkg/apis/kops/validation/validation.go b/pkg/apis/kops/validation/validation.go index 43ad34e5d5bce..3dfe0ce8b49a7 100644 --- a/pkg/apis/kops/validation/validation.go +++ b/pkg/apis/kops/validation/validation.go @@ -517,16 +517,10 @@ func validateNetworking(cluster *kops.Cluster, v *kops.NetworkingSpec, fldPath * } if v.Kubenet != nil { - if c.ContainerRuntime == "containerd" { - allErrs = append(allErrs, field.Invalid(fldPath, "kubenet", "kubenet networking is not supported with containerd")) - } optionTaken = true } if v.External != nil { - if c.ContainerRuntime == "containerd" { - allErrs = append(allErrs, field.Invalid(fldPath, "external", "external networking is not supported with containerd")) - } if optionTaken { allErrs = append(allErrs, field.Forbidden(fldPath.Child("external"), "only one networking option permitted")) } @@ -541,9 +535,6 @@ func validateNetworking(cluster *kops.Cluster, v *kops.NetworkingSpec, fldPath * } if v.Kopeio != nil { - if c.ContainerRuntime == "containerd" { - allErrs = append(allErrs, field.Invalid(fldPath, "kopeio", "kopeio networking is not supported with containerd")) - } if optionTaken { allErrs = append(allErrs, field.Forbidden(fldPath.Child("kopeio"), "only one networking option permitted")) } @@ -628,9 +619,6 @@ func validateNetworking(cluster *kops.Cluster, v *kops.NetworkingSpec, fldPath * } if v.GCE != nil { - if c.ContainerRuntime == "containerd" { - allErrs = append(allErrs, field.Invalid(fldPath, "gce", "gce networking is not supported with containerd")) - } if optionTaken { allErrs = append(allErrs, field.Forbidden(fldPath.Child("gce"), "only one networking option permitted")) } diff --git a/pkg/model/components/containerd.go b/pkg/model/components/containerd.go index 1b3eb1dfadba0..a4f2e684d9cb8 100644 --- a/pkg/model/components/containerd.go +++ b/pkg/model/components/containerd.go @@ -62,6 +62,12 @@ func (b *ContainerdOptionsBuilder) BuildOptions(o interface{}) error { config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "registry", "mirrors", name, "endpoint"}, endpoints) } config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", "runc", "runtime_type"}, "io.containerd.runc.v2") + if UsesKubenet(clusterSpec.Networking) { + // Using containerd with Kubenet requires special configuration. + // This is a temporary backwards-compatible solution for kubenet users and will be deprecated when Kubenet is deprecated: + // https://github.com/containerd/containerd/blob/master/docs/cri/config.md#cni-config-template + config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "cni", "conf_template"}, "/etc/containerd/config-cni.template") + } containerd.ConfigOverride = fi.String(config.String()) }