2018-08-27 10:21:43 -07:00
/ *
Copyright 2018 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 kubeadm
import (
"bytes"
2020-01-16 15:31:43 -08:00
"fmt"
"sort"
2018-08-27 10:21:43 -07:00
"strings"
2022-09-06 11:25:32 -07:00
"github.com/google/safetext/yamltemplate"
2019-06-21 19:20:11 +02:00
2019-09-11 15:42:01 -07:00
"sigs.k8s.io/kind/pkg/errors"
2021-11-16 16:00:10 -08:00
2021-04-01 20:23:58 +02:00
"sigs.k8s.io/kind/pkg/internal/apis/config"
2021-11-16 16:00:10 -08:00
"sigs.k8s.io/kind/pkg/internal/version"
2018-08-27 10:21:43 -07:00
)
// ConfigData is supplied to the kubeadm config template, with values populated
// by the cluster package
type ConfigData struct {
ClusterName string
KubernetesVersion string
2019-06-16 18:01:42 +02:00
// The ControlPlaneEndpoint, that is the address of the external loadbalancer
// if defined or the bootstrap node
2019-01-18 22:44:19 +01:00
ControlPlaneEndpoint string
// The Local API Server port
2018-10-18 18:21:00 -07:00
APIBindPort int
2019-05-29 14:32:42 -07:00
// The API server external listen IP (which we will port forward)
APIServerAddress string
2020-08-24 16:12:21 -07:00
// this should really be used for the --provider-id flag
// ideally cluster config should not depend on the node backend otherwise ...
NodeProvider string
2019-06-14 16:27:48 +02:00
// ControlPlane flag specifies the node belongs to the control plane
ControlPlane bool
2021-03-26 10:41:41 +01:00
// The IP address or comma separated list IP addresses of of the node
2019-06-14 16:27:48 +02:00
NodeAddress string
2020-08-24 16:12:21 -07:00
// The name for the node (not the address)
NodeName string
2018-12-10 16:13:56 +01:00
// The Token for TLS bootstrap
Token string
2020-08-24 16:12:21 -07:00
2024-04-11 14:47:54 +00:00
// KubeProxyMode defines the kube-proxy mode between iptables, ipvs or nftables
2020-05-14 20:25:32 -03:00
KubeProxyMode string
2019-05-07 01:46:24 -07:00
// The subnet used for pods
PodSubnet string
2019-05-15 14:01:47 +02:00
// The subnet used for services
ServiceSubnet string
2020-08-24 16:12:21 -07:00
// Kubernetes FeatureGates
2020-01-16 15:31:43 -08:00
FeatureGates map [ string ] bool
2020-08-24 16:12:21 -07:00
2020-08-26 10:14:56 -07:00
// Kubernetes API Server RuntimeConfig
RuntimeConfig map [ string ] string
2021-04-01 20:23:58 +02:00
// IPFamily of the cluster, it can be IPv4, IPv6 or DualStack
IPFamily config . ClusterIPFamily
2020-08-24 16:12:21 -07:00
2020-11-18 12:34:55 +05:30
// Labels are the labels, in the format "key1=val1,key2=val2", with which the respective node will be labeled
NodeLabels string
2022-07-31 22:07:19 -07:00
// RootlessProvider is true if kind is running with rootless mode
2020-11-19 03:53:24 +09:00
RootlessProvider bool
2022-07-31 22:07:19 -07:00
// DisableLocalStorageCapacityIsolation is typically set true based on RootlessProvider
// based on the Kubernetes version, if true kubelet localStorageCapacityIsolation is set false
DisableLocalStorageCapacityIsolation bool
// DerivedConfigData contains fields computed from the other fields for use
// in the config templates and should only be populated by calling Derive()
DerivedConfigData
2018-08-27 10:21:43 -07:00
}
2018-09-02 00:47:40 -07:00
// DerivedConfigData fields are automatically derived by
// ConfigData.Derive if they are not specified / zero valued
type DerivedConfigData struct {
2021-03-26 10:41:41 +01:00
// AdvertiseAddress is the first address in NodeAddress
AdvertiseAddress string
2018-08-27 10:21:43 -07:00
// DockerStableTag is automatically derived from KubernetesVersion
DockerStableTag string
2022-09-06 11:59:31 -07:00
// SortedFeatureGates allows us to iterate FeatureGates deterministically
SortedFeatureGates [ ] FeatureGate
2020-01-16 15:31:43 -08:00
// FeatureGatesString is of the form `Foo=true,Baz=false`
FeatureGatesString string
2020-08-26 10:14:56 -07:00
// RuntimeConfigString is of the form `Foo=true,Baz=false`
RuntimeConfigString string
2021-04-01 20:23:58 +02:00
// KubeadmFeatureGates contains Kubeadm only feature gates
KubeadmFeatureGates map [ string ] bool
// IPv4 values take precedence over IPv6 by default, if true set IPv6 default values
IPv6 bool
2022-05-03 11:22:46 -07:00
// kubelet cgroup driver, based on kubernetes version
CgroupDriver string
2024-05-20 22:59:21 -05:00
// JoinSkipPhases are the skipPhases values for the JoinConfiguration.
JoinSkipPhases [ ] string
// InitSkipPhases are the skipPhases values for the InitConfiguration.
InitSkipPhases [ ] string
2018-08-27 10:21:43 -07:00
}
2022-09-06 11:59:31 -07:00
type FeatureGate struct {
Name string
Value bool
}
2018-09-02 00:47:40 -07:00
// Derive automatically derives DockerStableTag if not specified
func ( c * ConfigData ) Derive ( ) {
2022-05-03 11:22:46 -07:00
// default cgroup driver
// TODO: refactor and move all deriving logic to this method
c . CgroupDriver = "systemd"
2021-03-26 10:41:41 +01:00
// get the first address to use it as the API advertised address
c . AdvertiseAddress = strings . Split ( c . NodeAddress , "," ) [ 0 ]
2018-08-27 10:21:43 -07:00
if c . DockerStableTag == "" {
c . DockerStableTag = strings . Replace ( c . KubernetesVersion , "+" , "_" , - 1 )
}
2020-01-16 15:31:43 -08:00
2021-04-01 20:23:58 +02:00
// get the IP addresses family for defaulting components
c . IPv6 = c . IPFamily == config . IPv6Family
2020-01-16 15:31:43 -08:00
// get sorted list of FeatureGate keys
featureGateKeys := make ( [ ] string , 0 , len ( c . FeatureGates ) )
for k := range c . FeatureGates {
featureGateKeys = append ( featureGateKeys , k )
}
sort . Strings ( featureGateKeys )
// create a sorted key=value,... string of FeatureGates
2022-09-06 11:59:31 -07:00
c . SortedFeatureGates = make ( [ ] FeatureGate , 0 , len ( c . FeatureGates ) )
featureGates := make ( [ ] string , 0 , len ( c . FeatureGates ) )
2020-01-16 15:31:43 -08:00
for _ , k := range featureGateKeys {
v := c . FeatureGates [ k ]
featureGates = append ( featureGates , fmt . Sprintf ( "%s=%t" , k , v ) )
2022-09-06 11:59:31 -07:00
c . SortedFeatureGates = append ( c . SortedFeatureGates , FeatureGate {
Name : k ,
Value : v ,
} )
2020-01-16 15:31:43 -08:00
}
c . FeatureGatesString = strings . Join ( featureGates , "," )
2020-08-26 10:14:56 -07:00
// create a sorted key=value,... string of RuntimeConfig
// first get sorted list of FeatureGate keys
runtimeConfigKeys := make ( [ ] string , 0 , len ( c . RuntimeConfig ) )
for k := range c . RuntimeConfig {
runtimeConfigKeys = append ( runtimeConfigKeys , k )
}
2020-08-26 17:29:10 -07:00
sort . Strings ( runtimeConfigKeys )
2020-08-26 10:14:56 -07:00
// stringify
var runtimeConfig [ ] string
for _ , k := range runtimeConfigKeys {
v := c . RuntimeConfig [ k ]
// TODO: do we need to quote / escape these in the future?
// Currently runtime config is in practice booleans, no special characters
runtimeConfig = append ( runtimeConfig , fmt . Sprintf ( "%s=%s" , k , v ) )
}
c . RuntimeConfigString = strings . Join ( runtimeConfig , "," )
2024-05-20 22:59:21 -05:00
// skip preflight checks, as these have undesirable side effects
// and don't tell us much. requires kubeadm 1.22+
c . JoinSkipPhases = [ ] string { "preflight" }
c . InitSkipPhases = [ ] string { "preflight" }
if c . KubeProxyMode == string ( config . NoneProxyMode ) {
c . InitSkipPhases = append ( c . InitSkipPhases , "addon/kube-proxy" )
}
2018-08-27 10:21:43 -07:00
}
2018-12-03 11:10:27 -08:00
// See docs for these APIs at:
// https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm#pkg-subdirectories
// EG:
// https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1
2021-01-06 22:03:09 -05:00
// ConfigTemplateBetaV2 is the kubeadm config template for API version v1beta2
2019-06-01 17:31:04 +02:00
const ConfigTemplateBetaV2 = ` # config generated by kind
apiVersion : kubeadm . k8s . io / v1beta2
kind : ClusterConfiguration
metadata :
name : config
kubernetesVersion : { { . KubernetesVersion } }
clusterName : "{{.ClusterName}}"
2021-04-01 20:23:58 +02:00
{ { if . KubeadmFeatureGates } } featureGates :
{ { range $ key , $ value := . KubeadmFeatureGates } }
2022-09-20 17:05:24 -07:00
"{{ (StructuralData $key) }}" : { { $ value } }
2021-04-01 20:23:58 +02:00
{ { end } } { { end } }
2019-06-21 13:03:43 -07:00
controlPlaneEndpoint : "{{ .ControlPlaneEndpoint }}"
2019-06-01 17:31:04 +02:00
# 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 :
2019-05-15 14:01:47 +02:00
certSANs : [ localhost , "{{.APIServerAddress}}" ]
2020-01-16 15:31:43 -08:00
extraArgs :
2020-08-26 10:14:56 -07:00
"runtime-config" : "{{ .RuntimeConfigString }}"
{ { if . FeatureGates } }
2020-01-16 15:31:43 -08:00
"feature-gates" : "{{ .FeatureGatesString }}"
2020-08-26 10:14:56 -07:00
{ { end } }
2019-06-01 17:31:04 +02:00
controllerManager :
extraArgs :
2020-03-03 13:33:21 -08:00
{ { if . FeatureGates } }
2020-01-16 15:31:43 -08:00
"feature-gates" : "{{ .FeatureGatesString }}"
2020-03-03 13:33:21 -08:00
{ { end } }
2019-06-01 17:31:04 +02:00
enable - hostpath - provisioner : "true"
2019-05-15 14:01:47 +02:00
# configure ipv6 default addresses for IPv6 clusters
{ { if . IPv6 - } }
bind - address : "::"
{ { - end } }
scheduler :
extraArgs :
2020-03-03 13:33:21 -08:00
{ { if . FeatureGates } }
2020-01-16 15:31:43 -08:00
"feature-gates" : "{{ .FeatureGatesString }}"
2020-03-03 13:33:21 -08:00
{ { end } }
2019-05-15 14:01:47 +02:00
# configure ipv6 default addresses for IPv6 clusters
{ { if . IPv6 - } }
bind - address : "::1"
{ { - end } }
2019-06-01 17:31:04 +02:00
networking :
podSubnet : "{{ .PodSubnet }}"
2019-05-15 14:01:47 +02:00
serviceSubnet : "{{ .ServiceSubnet }}"
2019-06-01 17:31:04 +02:00
-- -
apiVersion : kubeadm . k8s . io / v1beta2
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 :
2021-03-26 10:41:41 +01:00
advertiseAddress : "{{ .AdvertiseAddress }}"
2019-06-01 17:31:04 +02:00
bindPort : { { . APIBindPort } }
nodeRegistration :
2020-06-24 20:21:03 -07:00
criSocket : "unix:///run/containerd/containerd.sock"
2019-06-14 16:27:48 +02:00
kubeletExtraArgs :
node - ip : "{{ .NodeAddress }}"
2020-08-24 15:54:08 -07:00
provider - id : "kind://{{.NodeProvider}}/{{.ClusterName}}/{{.NodeName}}"
2020-11-18 12:34:55 +05:30
node - labels : "{{ .NodeLabels }}"
2019-06-01 17:31:04 +02:00
-- -
# no - op entry that exists solely so it can be patched
apiVersion : kubeadm . k8s . io / v1beta2
kind : JoinConfiguration
metadata :
name : config
2019-06-14 16:27:48 +02:00
{ { if . ControlPlane - } }
controlPlane :
2019-06-16 18:01:42 +02:00
localAPIEndpoint :
2021-03-26 10:41:41 +01:00
advertiseAddress : "{{ .AdvertiseAddress }}"
2019-06-16 18:01:42 +02:00
bindPort : { { . APIBindPort } }
2019-06-14 16:27:48 +02:00
{ { - end } }
2019-06-01 17:31:04 +02:00
nodeRegistration :
2020-06-24 20:21:03 -07:00
criSocket : "unix:///run/containerd/containerd.sock"
2019-06-14 16:27:48 +02:00
kubeletExtraArgs :
node - ip : "{{ .NodeAddress }}"
2020-08-24 15:54:08 -07:00
provider - id : "kind://{{.NodeProvider}}/{{.ClusterName}}/{{.NodeName}}"
2020-11-18 12:34:55 +05:30
node - labels : "{{ .NodeLabels }}"
2019-06-14 16:27:48 +02:00
discovery :
bootstrapToken :
apiServerEndpoint : "{{ .ControlPlaneEndpoint }}"
token : "{{ .Token }}"
unsafeSkipCAVerification : true
2019-06-01 17:31:04 +02:00
-- -
apiVersion : kubelet . config . k8s . io / v1beta1
kind : KubeletConfiguration
metadata :
name : config
2022-05-03 11:22:46 -07:00
cgroupDriver : { { . CgroupDriver } }
2022-05-12 15:44:03 -07:00
cgroupRoot : / kubelet
2022-05-12 15:48:33 -07:00
failSwapOn : false
2019-05-15 14:01:47 +02:00
# configure ipv6 addresses in IPv6 mode
{ { if . IPv6 - } }
address : "::"
healthzBindAddress : "::"
{ { - end } }
2019-06-01 17:31:04 +02:00
# 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%"
2020-01-16 15:31:43 -08:00
{ { if . FeatureGates } } featureGates :
2022-09-06 11:59:31 -07:00
{ { range $ index , $ gate := . SortedFeatureGates } }
2022-09-20 17:05:24 -07:00
"{{ (StructuralData $gate.Name) }}" : { { $ gate . Value } }
2020-01-16 15:31:43 -08:00
{ { end } } { { end } }
2024-04-22 08:40:31 +00:00
{ { if ne . KubeProxyMode "none" } }
2019-06-01 17:31:04 +02:00
-- -
apiVersion : kubeproxy . config . k8s . io / v1alpha1
kind : KubeProxyConfiguration
metadata :
name : config
2020-05-14 20:25:32 -03:00
mode : "{{ .KubeProxyMode }}"
2020-01-16 15:31:43 -08:00
{ { if . FeatureGates } } featureGates :
2022-09-06 11:59:31 -07:00
{ { range $ index , $ gate := . SortedFeatureGates } }
2022-09-20 17:05:24 -07:00
"{{ (StructuralData $gate.Name) }}" : { { $ gate . Value } }
2020-01-16 15:31:43 -08:00
{ { end } } { { end } }
2020-07-06 18:38:21 +02:00
iptables :
minSyncPeriod : 1 s
2021-05-11 22:12:13 +02:00
conntrack :
2020-11-19 03:53:24 +09:00
# Skip setting sysctl value "net.netfilter.nf_conntrack_max"
2021-05-11 22:12:13 +02:00
# It is a global variable that affects other namespaces
2020-11-19 03:53:24 +09:00
maxPerCore : 0
2024-04-22 08:40:44 +00:00
# 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 } }
2021-05-11 22:12:13 +02:00
{ { if . RootlessProvider } }
2020-11-19 03:53:24 +09:00
# Skip setting "net.netfilter.nf_conntrack_tcp_timeout_established"
tcpEstablishedTimeout : 0 s
# Skip setting "net.netfilter.nf_conntrack_tcp_timeout_close"
tcpCloseWaitTimeout : 0 s
{ { end } } { { end } }
2019-06-01 17:31:04 +02:00
`
2022-01-07 16:34:27 -08:00
// ConfigTemplateBetaV3 is the kubeadm config template for API version v1beta3
const ConfigTemplateBetaV3 = ` # config generated by kind
apiVersion : kubeadm . k8s . io / v1beta3
kind : ClusterConfiguration
metadata :
name : config
kubernetesVersion : { { . KubernetesVersion } }
clusterName : "{{.ClusterName}}"
{ { if . KubeadmFeatureGates } } featureGates :
{ { range $ key , $ value := . KubeadmFeatureGates } }
2022-09-20 17:05:24 -07:00
"{{ (StructuralData $key) }}" : { { $ value } }
2022-01-07 16:34:27 -08:00
{ { 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 :
"runtime-config" : "{{ .RuntimeConfigString }}"
{ { if . FeatureGates } }
"feature-gates" : "{{ .FeatureGatesString }}"
{ { end } }
controllerManager :
extraArgs :
{ { if . FeatureGates } }
"feature-gates" : "{{ .FeatureGatesString }}"
{ { end } }
enable - hostpath - provisioner : "true"
# configure ipv6 default addresses for IPv6 clusters
{ { if . IPv6 - } }
bind - address : "::"
{ { - end } }
scheduler :
extraArgs :
{ { if . FeatureGates } }
"feature-gates" : "{{ .FeatureGatesString }}"
{ { end } }
# configure ipv6 default addresses for IPv6 clusters
{ { if . IPv6 - } }
bind - address : "::1"
{ { - end } }
networking :
podSubnet : "{{ .PodSubnet }}"
serviceSubnet : "{{ .ServiceSubnet }}"
-- -
apiVersion : kubeadm . k8s . io / v1beta3
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 }}"
2024-05-20 22:59:21 -05:00
{ { if . InitSkipPhases - } }
skipPhases :
{ { range $ phase := . InitSkipPhases - } }
- "{{ $phase }}"
{ { - end } }
{ { - end } }
2022-01-07 16:34:27 -08:00
-- -
# no - op entry that exists solely so it can be patched
apiVersion : kubeadm . k8s . io / v1beta3
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
2024-05-20 22:59:21 -05:00
{ { if . JoinSkipPhases - } }
skipPhases :
{ { range $ phase := . JoinSkipPhases - } }
- "{{ $phase }}"
{ { - end } }
{ { - end } }
2022-01-07 16:34:27 -08:00
-- -
apiVersion : kubelet . config . k8s . io / v1beta1
kind : KubeletConfiguration
metadata :
name : config
2022-05-03 11:22:46 -07:00
cgroupDriver : { { . CgroupDriver } }
2022-05-12 15:44:03 -07:00
cgroupRoot : / kubelet
2022-05-12 15:48:33 -07:00
failSwapOn : false
2022-01-07 16:34:27 -08:00
# 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 :
2022-09-06 11:59:31 -07:00
{ { range $ index , $ gate := . SortedFeatureGates } }
2022-09-20 17:05:24 -07:00
"{{ (StructuralData $gate.Name) }}" : { { $ gate . Value } }
2022-01-07 16:34:27 -08:00
{ { end } } { { end } }
2022-08-04 16:20:35 -07:00
{ { if . DisableLocalStorageCapacityIsolation } } localStorageCapacityIsolation : false { { end } }
2024-04-22 08:40:31 +00:00
{ { if ne . KubeProxyMode "none" } }
2022-01-07 16:34:27 -08:00
-- -
apiVersion : kubeproxy . config . k8s . io / v1alpha1
kind : KubeProxyConfiguration
metadata :
name : config
mode : "{{ .KubeProxyMode }}"
{ { if . FeatureGates } } featureGates :
2022-09-06 11:59:31 -07:00
{ { range $ index , $ gate := . SortedFeatureGates } }
2022-09-20 17:05:24 -07:00
"{{ (StructuralData $gate.Name) }}" : { { $ gate . Value } }
2022-01-07 16:34:27 -08:00
{ { end } } { { end } }
iptables :
minSyncPeriod : 1 s
conntrack :
# Skip setting sysctl value "net.netfilter.nf_conntrack_max"
# It is a global variable that affects other namespaces
maxPerCore : 0
2024-04-22 08:40:44 +00:00
# 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 } }
2022-01-07 16:34:27 -08:00
{ { if . RootlessProvider } }
# Skip setting "net.netfilter.nf_conntrack_tcp_timeout_established"
tcpEstablishedTimeout : 0 s
# Skip setting "net.netfilter.nf_conntrack_tcp_timeout_close"
tcpCloseWaitTimeout : 0 s
{ { end } } { { end } }
`
2018-10-25 16:29:29 -07:00
// Config returns a kubeadm config generated from config data, in particular
// the kubernetes version
func Config ( data ConfigData ) ( config string , err error ) {
ver , err := version . ParseGeneric ( data . KubernetesVersion )
if err != nil {
return "" , err
}
2018-12-03 11:10:27 -08:00
2020-04-17 14:37:49 -07:00
// ensure featureGates is non-nil, as we may add entries
if data . FeatureGates == nil {
data . FeatureGates = make ( map [ string ] bool )
}
2021-08-08 16:16:46 +09:00
if data . RootlessProvider {
if ver . LessThan ( version . MustParseSemantic ( "v1.22.0" ) ) {
// rootless kind v0.12.x supports Kubernetes v1.22 with KubeletInUserNamespace gate.
// rootless kind v0.11.x supports older Kubernetes with fake procfs.
return "" , errors . Errorf ( "version %q is not compatible with rootless provider (hint: kind v0.11.x may work with this version)" , ver )
}
data . FeatureGates [ "KubeletInUserNamespace" ] = true
2021-11-04 18:25:13 +09:00
// For avoiding err="failed to get rootfs info: failed to get device for dir \"/var/lib/kubelet\": could not find device with major: 0, minor: 41 in cached partitions map"
// https://github.com/kubernetes-sigs/kind/issues/2524
2022-07-31 22:07:19 -07:00
if ver . LessThan ( version . MustParseSemantic ( "v1.25.0-alpha.3.440+0064010cddfa00" ) ) {
// this feature gate was removed in v1.25 and replaced by an opt-out to disable
data . FeatureGates [ "LocalStorageCapacityIsolation" ] = false
} else {
// added in v1.25 https://github.com/kubernetes/kubernetes/pull/111513
data . DisableLocalStorageCapacityIsolation = true
}
2021-08-08 16:16:46 +09:00
}
2018-12-03 11:10:27 -08:00
// assume the latest API version, then fallback if the k8s version is too low
2022-01-07 16:34:27 -08:00
templateSource := ConfigTemplateBetaV3
2022-09-06 21:42:07 -07:00
if ver . LessThan ( version . MustParseSemantic ( "v1.23.0" ) ) {
2022-01-07 16:34:27 -08:00
templateSource = ConfigTemplateBetaV2
2018-08-27 10:21:43 -07:00
}
2018-12-03 11:10:27 -08:00
2022-09-06 11:25:32 -07:00
t , err := yamltemplate . New ( "kubeadm-config" ) . Parse ( templateSource )
2018-08-27 10:21:43 -07:00
if err != nil {
return "" , errors . Wrap ( err , "failed to parse config template" )
}
2018-12-03 11:10:27 -08:00
2018-08-27 10:21:43 -07:00
// derive any automatic fields if not supplied
2018-09-02 00:47:40 -07:00
data . Derive ( )
2018-12-03 11:10:27 -08:00
2021-04-01 20:23:58 +02:00
// Kubeadm has its own feature-gate for dual stack
// we need to enable it for Kubernetes version 1.20 only
// dual-stack is only supported in 1.20+
// TODO: remove this when 1.20 is EOL or we no longer support
// dual-stack for 1.20 in KIND
if ver . LessThan ( version . MustParseSemantic ( "v1.21.0" ) ) &&
ver . AtLeast ( version . MustParseSemantic ( "v1.20.0" ) ) {
data . KubeadmFeatureGates = make ( map [ string ] bool )
data . KubeadmFeatureGates [ "IPv6DualStack" ] = true
}
2022-05-03 11:22:46 -07:00
// before 1.24 kind uses cgroupfs
// after 1.24 kind uses systemd starting in kind v0.13.0
// before kind v0.13.0 kubernetes 1.24 wasn't released yet
if ver . LessThan ( version . MustParseSemantic ( "v1.24.0" ) ) {
data . CgroupDriver = "cgroupfs"
}
2018-08-27 10:21:43 -07:00
// execute the template
var buff bytes . Buffer
err = t . Execute ( & buff , data )
if err != nil {
return "" , errors . Wrap ( err , "error executing config template" )
2019-06-21 13:03:43 -07:00
}
2018-08-27 10:21:43 -07:00
return buff . String ( ) , nil
}