Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: support kubeadm.k8s.io/v1beta4 #3675

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions pkg/cluster/internal/create/actions/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package config implements the kubeadm config action
package config

import (
"log"
"sigs.k8s.io/kind/pkg/cluster/internal/kubeadm"
internalencoding "sigs.k8s.io/kind/pkg/internal/apis/config/encoding"
"sigs.k8s.io/kind/pkg/internal/patch"
"strings"
"testing"
)

func TestConfig(t *testing.T) {
cases := []struct {
Name string
Input string
SubString string
}{
{
Name: "Check if extraEnvs takes effect",
Input: `kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 6443
hostPort: 6443
protocol: TCP
- role: worker
kubeadmConfigPatches:
- |
kind: ClusterConfiguration
apiServer:
certSANs:
- localhost
extraEnvs:
- name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
value: http://10.230.205.190:5080/api/default/traces
`, SubString: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
},
}

for _, tc := range cases {
tc := tc // capture tc
t.Run(tc.Name, func(t *testing.T) {
t.Parallel()

cfg, err := internalencoding.Parse([]byte(tc.Input))
data := kubeadm.ConfigData{
ClusterName: "test",
KubernetesVersion: "v1.31.0",
}
cf, err := kubeadm.Config(data)
if err != nil {
log.Fatalln(err)
}
clusterPatches, clusterJSONPatches := allPatchesFromConfig(cfg)
// apply cluster-level patches first
patchedConfig, err := patch.KubeYAML(cf, clusterPatches, clusterJSONPatches)
if err != nil {
log.Fatalln(err)
}
// if needed, apply current node's patches
if len(cfg.KubeadmConfigPatches) > 0 || len(cfg.KubeadmConfigPatchesJSON6902) > 0 {
patchedConfig, _ = patch.KubeYAML(patchedConfig, cfg.KubeadmConfigPatches, cfg.KubeadmConfigPatchesJSON6902)
}
if !strings.Contains(patchedConfig, tc.SubString) {
log.Fatalln(tc.Name, "invalid")
}
})
}

}g
171 changes: 169 additions & 2 deletions pkg/cluster/internal/kubeadm/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ nodeRegistration:
node-labels: "{{ .NodeLabels }}"
{{ if .InitSkipPhases -}}
skipPhases:
{{ range $phase := .InitSkipPhases -}}
{{- range $phase := .InitSkipPhases }}
- "{{ $phase }}"
{{- end }}
{{- end }}
Expand Down Expand Up @@ -480,6 +480,170 @@ conntrack:
{{end}}{{end}}
`

// ConfigTemplateBetaV4 is the kubeadm config template for API version v1beta4
const ConfigTemplateBetaV4 = `# config generated by kind
apiVersion: kubeadm.k8s.io/v1beta4
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any changes we need to be aware of ...?

Copy link
Author

@ls-2018 ls-2018 Jul 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are some of the changes, such as :

  • When I redeploy the cluster using kind, I need to pass some env to apiserver, which is not supported by the current beta3 version, but is supported by beta4. Of course, the template I provide in pr may not cover all scenarios, which will need to be added later
  • When trace is enabled on apiserver and authentication is required on the back end, some information needs to be specified in env

v1beta3

// ControlPlaneComponent holds settings common to control plane component of the cluster
type ControlPlaneComponent struct {
	// ExtraArgs is an extra set of flags to pass to the control plane component.
	// A key in this map is the flag name as it appears on the
	// command line except without leading dash(es).
	// TODO: This is temporary and ideally we would like to switch all components to
	// use ComponentConfig + ConfigMaps.
	// +optional
	ExtraArgs map[string]string `json:"extraArgs,omitempty"`

	// ExtraVolumes is an extra set of host volumes, mounted to the control plane component.
	// +optional
	ExtraVolumes []HostPathMount `json:"extraVolumes,omitempty"`
}

v1beta4

// ControlPlaneComponent holds settings common to control plane component of the cluster
type ControlPlaneComponent struct {
	// ExtraArgs is an extra set of flags to pass to the control plane component.
	// A key in this map is the flag name as it appears on the
	// command line except without leading dash(es).
	// TODO: This is temporary and ideally we would like to switch all components to
	// use ComponentConfig + ConfigMaps.
	// +optional
	ExtraArgs map[string]string `json:"extraArgs,omitempty"`

	// ExtraVolumes is an extra set of host volumes, mounted to the control plane component.
	// +optional
	ExtraVolumes []HostPathMount `json:"extraVolumes,omitempty"`

	// ExtraEnvs is an extra set of environment variables to pass to the control plane component.
	// Environment variables passed using ExtraEnvs will override any existing environment variables, or *_proxy environment variables that kubeadm adds by default.
	// +optional
	ExtraEnvs []corev1.EnvVar `json:"extraEnvs,omitempty"`
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I redeploy the cluster using kind, I need to pass some env to apiserver, which is not supported by the current beta3 version, but is supported by beta4. Of course, the template I provide in pr may not cover all scenarios, which will need to be added later

There's no question that we will adopt v1beta4, my question is are there any breaking changes or other changes we should be aware of when adopting it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find anything else

Copy link
Member

@neolit123 neolit123 Jul 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the above v1beta4 struct is not correct in terms of extra args for v1beta4. in the new versions they are a slice of key-value pairs. breaking changes are enumerated here:
https://groups.google.com/g/kubernetes-sig-cluster-lifecycle/c/9HgtTf0W1hk

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing extraArgs like this makes sense but a lot of kind configs will need to start targeting specific kubeadm versions when we roll this out because they've been patching extraArgs portably across versions as a subset of the config patched

@ls-2018 that includes

create_cluster() {

which will be somewhat complicated.

kind: ClusterConfiguration
metadata:
name: config
kubernetesVersion: {{.KubernetesVersion}}
clusterName: "{{.ClusterName}}"
{{ if .KubeadmFeatureGates}}featureGates:
{{ range $key, $value := .KubeadmFeatureGates }}
"{{ (StructuralData $key) }}": {{ $value }}
{{end}}{{end}}
controlPlaneEndpoint: "{{ .ControlPlaneEndpoint }}"
# on docker for mac we have to expose the api server via port forward,
# so we need to ensure the cert is valid for localhost so we can talk
# to the cluster after rewriting the kubeconfig to point to localhost
apiServer:
certSANs: [localhost, "{{.APIServerAddress}}"]
extraArgs:
- name: "runtime-config"
value: "{{ .RuntimeConfigString }}"
{{ if .FeatureGates }}
- name: "feature-gates"
value: "{{ .FeatureGatesString }}"
{{ end }}

controllerManager:
extraArgs:
{{ if .FeatureGates }}
- name: "feature-gates"
value: "{{ .FeatureGatesString }}"
{{ end }}
- name: enable-hostpath-provisioner
value: "true"
# configure ipv6 default addresses for IPv6 clusters
{{ if .IPv6 -}}
- name: bind-address
value: "::"
{{- end }}

scheduler:
extraArgs:
{{ if .FeatureGates }}
- name: "feature-gates":
value: "{{ .FeatureGatesString }}"
{{ end }}
# configure ipv6 default addresses for IPv6 clusters
{{ if .IPv6 -}}
- name: bind-address
value: "::1"
{{- end }}
networking:
podSubnet: "{{ .PodSubnet }}"
serviceSubnet: "{{ .ServiceSubnet }}"
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
metadata:
name: config
# we use a well know token for TLS bootstrap
bootstrapTokens:
- token: "{{ .Token }}"
# we use a well know port for making the API server discoverable inside docker network.
# from the host machine such port will be accessible via a random local port instead.
localAPIEndpoint:
advertiseAddress: "{{ .AdvertiseAddress }}"
bindPort: {{.APIBindPort}}
nodeRegistration:
criSocket: "unix:///run/containerd/containerd.sock"
kubeletExtraArgs:
node-ip: "{{ .NodeAddress }}"
provider-id: "kind://{{.NodeProvider}}/{{.ClusterName}}/{{.NodeName}}"
node-labels: "{{ .NodeLabels }}"
{{ if .InitSkipPhases -}}
skipPhases:
{{- range $phase := .InitSkipPhases}}
- "{{ $phase }}"
{{- end }}
{{- end }}
---
# no-op entry that exists solely so it can be patched
apiVersion: kubeadm.k8s.io/v1beta4
kind: JoinConfiguration
metadata:
name: config
{{ if .ControlPlane -}}
controlPlane:
localAPIEndpoint:
advertiseAddress: "{{ .AdvertiseAddress }}"
bindPort: {{.APIBindPort}}
{{- end }}
nodeRegistration:
criSocket: "unix:///run/containerd/containerd.sock"
kubeletExtraArgs:
node-ip: "{{ .NodeAddress }}"
provider-id: "kind://{{.NodeProvider}}/{{.ClusterName}}/{{.NodeName}}"
node-labels: "{{ .NodeLabels }}"
discovery:
bootstrapToken:
apiServerEndpoint: "{{ .ControlPlaneEndpoint }}"
token: "{{ .Token }}"
unsafeSkipCAVerification: true
{{ if .JoinSkipPhases -}}
skipPhases:
{{ range $phase := .JoinSkipPhases -}}
- "{{ $phase }}"
{{- end }}
{{- end }}
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
metadata:
name: config
cgroupDriver: {{ .CgroupDriver }}
cgroupRoot: /kubelet
failSwapOn: false
# configure ipv6 addresses in IPv6 mode
{{ if .IPv6 -}}
address: "::"
healthzBindAddress: "::"
{{- end }}
# disable disk resource management by default
# kubelet will see the host disk that the inner container runtime
# is ultimately backed by and attempt to recover disk space. we don't want that.
imageGCHighThresholdPercent: 100
evictionHard:
nodefs.available: "0%"
nodefs.inodesFree: "0%"
imagefs.available: "0%"
{{if .FeatureGates}}featureGates:
{{ range $index, $gate := .SortedFeatureGates }}
"{{ (StructuralData $gate.Name) }}": {{ $gate.Value }}
{{end}}{{end}}
{{if ne .KubeProxyMode "none"}}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
metadata:
name: config
mode: "{{ .KubeProxyMode }}"
{{if .FeatureGates}}featureGates:
{{ range $index, $gate := .SortedFeatureGates }}
"{{ (StructuralData $gate.Name) }}": {{ $gate.Value }}
{{end}}{{end}}
iptables:
minSyncPeriod: 1s
conntrack:
# Skip setting sysctl value "net.netfilter.nf_conntrack_max"
# It is a global variable that affects other namespaces
maxPerCore: 0
# Set sysctl value "net.netfilter.nf_conntrack_tcp_be_liberal"
# for nftables proxy (theoretically for kernels older than 6.1)
# xref: https://github.com/kubernetes/kubernetes/issues/117924
{{if and (eq .KubeProxyMode "nftables") (not .RootlessProvider)}}
tcpBeLiberal: true
{{end}}
{{if .RootlessProvider}}
# Skip setting "net.netfilter.nf_conntrack_tcp_timeout_established"
tcpEstablishedTimeout: 0s
# Skip setting "net.netfilter.nf_conntrack_tcp_timeout_close"
tcpCloseWaitTimeout: 0s
{{end}}{{end}}
`

// Config returns a kubeadm config generated from config data, in particular
// the kubernetes version
func Config(data ConfigData) (config string, err error) {
Expand All @@ -503,7 +667,10 @@ func Config(data ConfigData) (config string, err error) {
}

// assume the latest API version, then fallback if the k8s version is too low
templateSource := ConfigTemplateBetaV3
templateSource := ConfigTemplateBetaV4
if ver.LessThan(version.MustParseSemantic("v1.31.0")) {
templateSource = ConfigTemplateBetaV3
}
if ver.LessThan(version.MustParseSemantic("v1.23.0")) {
templateSource = ConfigTemplateBetaV2
}
Expand Down
Loading