概述
关于 kubeadm 的配置,个人觉得是比较繁琐的,既可以有本地文件,还可以合并一些命令行输入的参数和配置,因为 kubeadm 负责启动的组件实在太多,某些组件的参数多的不得了,还不算各种 feature-gate,本文尝试简单分析一下,并且最后会给一份简单够用的配置文件清单。
初始化集群/组件的基本配置
一共四种类型的配置文件。
- InitConfiguration: 初始化的配置
- ClusterConfiguration: 集群配置
- KubeletConfiguration: 针对kubelet
- KubeProxyConfiguration: 针对kube-proxy
InitConfiguration
通过下面的注释,希望大家理解一下 InitConfiguration
和 ClusterConfiguration
的区别,这里就不赘述了,下面有些注释解读一下,基本上这个 InitConfiguration
里面的这些配置,如果机器初始化的合适的话,其实完全就可以不填了,以免跟其他配置混淆和冲突。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
// InitConfiguration contains a list of fields that are specifically "kubeadm init"-only runtime
// information. The cluster-wide config is stored in ClusterConfiguration. The InitConfiguration
// object IS NOT uploaded to the kubeadm-config ConfigMap in the cluster, only the
// ClusterConfiguration is.
type InitConfiguration struct {
metav1.TypeMeta
// ClusterConfiguration holds the cluster-wide information, and embeds that struct (which can be (un)marshalled separately as well)
// When InitConfiguration is marshalled to bytes in the external version, this information IS NOT preserved (which can be seen from
// the `json:"-"` tag in the external variant of these API types.
// 这里可以看到ClusterConfiguration实际上跟InitConfiguration是平级的,所以这里可以不用填
ClusterConfiguration `json:"-"`
// BootstrapTokens is respected at `kubeadm init` time and describes a set of Bootstrap Tokens to create.
// 这个肯定可以不填
BootstrapTokens []BootstrapToken
// NodeRegistration holds fields that relate to registering the new control-plane node to the cluster
// 这个参数比较重要,但其实也可以预先不填,让系统自己找,主要涉及的Node的name/taints/crisocket这些信息
// 如果机器配置是统一的,这里是可以不填的
NodeRegistration NodeRegistrationOptions
// LocalAPIEndpoint represents the endpoint of the API server instance that's deployed on this control plane node
// In HA setups, this differs from ClusterConfiguration.ControlPlaneEndpoint in the sense that ControlPlaneEndpoint
// is the global endpoint for the cluster, which then loadbalances the requests to each individual API server. This
// configuration object lets you customize what IP/DNS name and port the local API server advertises it's accessible
// on. By default, kubeadm tries to auto-detect the IP of the default interface and use that, but in case that process
// fails you may set the desired value here.
// 按照注释,其实可以不填,因为control plane会自己找,注意跟ClusterConfiguration.ControlPlaneEndpoint的区别
LocalAPIEndpoint APIEndpoint
// CertificateKey sets the key with which certificates and keys are encrypted prior to being uploaded in
// a secret in the cluster during the uploadcerts init phase.
// 可以不填
CertificateKey string
}
|
ClusterConfiguration
这个配置才是核心精华,里面有一些配置最好是在配置文件里强势给出,以免因为没有自定义而被后面的默认配置给覆盖了,注意这里用的 kubeadm v1beta2 的版本的定义,不要看错了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
// ClusterConfiguration contains cluster-wide configuration for a kubeadm cluster
type ClusterConfiguration struct {
metav1.TypeMeta `json:",inline"`
// Etcd holds configuration for etcd.
// Etcd分为外部和内部的部署的方式,这里主要关注跟kube-apiserver混部的内部的方式即可也就是LocalEtcd
// 可以用默认的
Etcd Etcd `json:"etcd,omitempty"`
// Networking holds configuration for the networking topology of the cluster.
// 主要包括ServiceSubnet/PodSubnet/DNSDomain,其中PodSubnet针对不同网络插件是有区别的,如果确认好是什么类型的网络,这里其实可以不给
Networking Networking `json:"networking,omitempty"`
// KubernetesVersion is the target version of the control plane.
// 需要强指定,这样kubeadm init的时候可以少传一个版本参数
KubernetesVersion string `json:"kubernetesVersion,omitempty"`
// ControlPlaneEndpoint sets a stable IP address or DNS name for the control plane; it
// can be a valid IP address or a RFC-1123 DNS subdomain, both with optional TCP port.
// In case the ControlPlaneEndpoint is not specified, the AdvertiseAddress + BindPort
// are used; in case the ControlPlaneEndpoint is specified but without a TCP port,
// the BindPort is used.
// Possible usages are:
// e.g. In a cluster with more than one control plane instances, this field should be
// assigned the address of the external load balancer in front of the
// control plane instances.
// e.g. in environments with enforced node recycling, the ControlPlaneEndpoint
// could be used for assigning a stable DNS to the control plane.
// 这个最好填内部域名,或者七层负载的地址等,如果私有化的公司有需要,就填上
ControlPlaneEndpoint string `json:"controlPlaneEndpoint,omitempty"`
// APIServer contains extra settings for the API server control plane component
// 需要整一下,一些关键的推荐参数
APIServer APIServer `json:"apiServer,omitempty"`
// ControllerManager contains extra settings for the controller manager control plane component
// 需要整一下,一些关键的推荐参数
ControllerManager ControlPlaneComponent `json:"controllerManager,omitempty"`
// Scheduler contains extra settings for the scheduler control plane component
// 需要整一下,一些关键的推荐参数
Scheduler ControlPlaneComponent `json:"scheduler,omitempty"`
// DNS defines the options for the DNS add-on installed in the cluster.
// 一般就不用搞了
DNS DNS `json:"dns,omitempty"`
// CertificatesDir specifies where to store or look for all required certificates.
// 一般就不用搞了
CertificatesDir string `json:"certificatesDir,omitempty"`
// ImageRepository sets the container registry to pull images from.
// If empty, `k8s.gcr.io` will be used by default; in case of kubernetes version is a CI build (kubernetes version starts with `ci/` or `ci-cross/`)
// `gcr.io/k8s-staging-ci-images` will be used as a default for control plane components and for kube-proxy, while `k8s.gcr.io`
// will be used for all the other images.
// 一般就不用搞了,因为镜像全部是本地加载的,不要画蛇添足
ImageRepository string `json:"imageRepository,omitempty"`
// UseHyperKubeImage controls if hyperkube should be used for Kubernetes components instead of their respective separate images
// DEPRECATED: As hyperkube is itself deprecated, this fields is too. It will be removed in future kubeadm config versions, kubeadm
// will print multiple warnings when set to true, and at some point it may become ignored.
// 这个基本用不上
UseHyperKubeImage bool `json:"useHyperKubeImage,omitempty"`
// FeatureGates enabled by the user.
// 需要整一下,一些关键的推荐参数
FeatureGates map[string]bool `json:"featureGates,omitempty"`
// The cluster name
// 给个名字,比如lx-private-cluster?
ClusterName string `json:"clusterName,omitempty"`
}
|
KubeletConfiguration
关于 KubeletConfiguration
的定义内容实在太多,就不放文章里了,这里主要分析一下 kubeadm init
的时候是怎么设置一些默认值的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
func (kc *kubeletConfig) Default(cfg *kubeadmapi.ClusterConfiguration, _ *kubeadmapi.APIEndpoint, nodeRegOpts *kubeadmapi.NodeRegistrationOptions) {
const kind = "KubeletConfiguration"
...
// Static Pod的路径
if kc.config.StaticPodPath == "" {
kc.config.StaticPodPath = kubeadmapiv1beta2.DefaultManifestsDir
} else if kc.config.StaticPodPath != kubeadmapiv1beta2.DefaultManifestsDir {
warnDefaultComponentConfigValue(kind, "staticPodPath", kubeadmapiv1beta2.DefaultManifestsDir, kc.config.StaticPodPath)
}
// Require all clients to the kubelet API to have client certs signed by the cluster CA
// 下面是证书的读取
clientCAFile := filepath.Join(cfg.CertificatesDir, constants.CACertName)
if kc.config.Authentication.X509.ClientCAFile == "" {
kc.config.Authentication.X509.ClientCAFile = clientCAFile
} else if kc.config.Authentication.X509.ClientCAFile != clientCAFile {
warnDefaultComponentConfigValue(kind, "authentication.x509.clientCAFile", clientCAFile, kc.config.Authentication.X509.ClientCAFile)
}
if kc.config.Authentication.Anonymous.Enabled == nil {
kc.config.Authentication.Anonymous.Enabled = utilpointer.BoolPtr(kubeletAuthenticationAnonymousEnabled)
} else if *kc.config.Authentication.Anonymous.Enabled != kubeletAuthenticationAnonymousEnabled {
warnDefaultComponentConfigValue(kind, "authentication.anonymous.enabled", kubeletAuthenticationAnonymousEnabled, *kc.config.Authentication.Anonymous.Enabled)
}
// On every client request to the kubelet API, execute a webhook (SubjectAccessReview request) to the API server
// and ask it whether the client is authorized to access the kubelet API
if kc.config.Authorization.Mode == "" {
kc.config.Authorization.Mode = kubeletconfig.KubeletAuthorizationModeWebhook
} else if kc.config.Authorization.Mode != kubeletconfig.KubeletAuthorizationModeWebhook {
warnDefaultComponentConfigValue(kind, "authorization.mode", kubeletconfig.KubeletAuthorizationModeWebhook, kc.config.Authorization.Mode)
}
// Let clients using other authentication methods like ServiceAccount tokens also access the kubelet API
if kc.config.Authentication.Webhook.Enabled == nil {
kc.config.Authentication.Webhook.Enabled = utilpointer.BoolPtr(kubeletAuthenticationWebhookEnabled)
} else if *kc.config.Authentication.Webhook.Enabled != kubeletAuthenticationWebhookEnabled {
warnDefaultComponentConfigValue(kind, "authentication.webhook.enabled", kubeletAuthenticationWebhookEnabled, *kc.config.Authentication.Webhook.Enabled)
}
// Serve a /healthz webserver on localhost:10248 that kubeadm can talk to
if kc.config.HealthzBindAddress == "" {
kc.config.HealthzBindAddress = kubeletHealthzBindAddress
} else if kc.config.HealthzBindAddress != kubeletHealthzBindAddress {
warnDefaultComponentConfigValue(kind, "healthzBindAddress", kubeletHealthzBindAddress, kc.config.HealthzBindAddress)
}
if kc.config.HealthzPort == nil {
kc.config.HealthzPort = utilpointer.Int32Ptr(constants.KubeletHealthzPort)
} else if *kc.config.HealthzPort != constants.KubeletHealthzPort {
warnDefaultComponentConfigValue(kind, "healthzPort", constants.KubeletHealthzPort, *kc.config.HealthzPort)
}
...
// We cannot show a warning for RotateCertificates==false and we must hardcode it to true.
// There is no way to determine if the user has set this or not, given the field is a non-pointer.
kc.config.RotateCertificates = kubeletRotateCertificates
// TODO: Conditionally set CgroupDriver to either `systemd` or `cgroupfs` for CRI other than Docker
// 这里就是根据CRISocket来默认写入的CgroupDriver,这里还是最好通过自定义的配置来覆盖比较好,systemd是当前比较推荐的参数值
if nodeRegOpts.CRISocket == constants.DefaultDockerCRISocket {
driver, err := kubeadmutil.GetCgroupDriverDocker(utilsexec.New())
if err != nil {
klog.Warningf("cannot automatically set CgroupDriver when starting the Kubelet: %v", err)
} else {
// if we can parse the right cgroup driver from docker info,
// we should always override CgroupDriver here no matter user specifies this value explicitly or not
if kc.config.CgroupDriver != "" && kc.config.CgroupDriver != driver {
klog.Warningf("detected %q as the Docker cgroup driver, the provided value %q in %q will be overrided", driver, kc.config.CgroupDriver, kind)
}
kc.config.CgroupDriver = driver
}
}
...
}
|
KubeProxyConfiguration
同样关于 KubeProxyConfiguration
的定义内容实在太多,就不放文章里了,这里主要分析一下 kubeadm init
的时候是怎么设置一些默认值的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
func (kp *kubeProxyConfig) Default(cfg *kubeadmapi.ClusterConfiguration, localAPIEndpoint *kubeadmapi.APIEndpoint, _ *kubeadmapi.NodeRegistrationOptions) {
const kind = "KubeProxyConfiguration"
...
if kp.config.ClusterCIDR == "" && cfg.Networking.PodSubnet != "" {
kp.config.ClusterCIDR = cfg.Networking.PodSubnet
} else if cfg.Networking.PodSubnet != "" && kp.config.ClusterCIDR != cfg.Networking.PodSubnet {
warnDefaultComponentConfigValue(kind, "clusterCIDR", cfg.Networking.PodSubnet, kp.config.ClusterCIDR)
}
if kp.config.ClientConnection.Kubeconfig == "" {
kp.config.ClientConnection.Kubeconfig = kubeproxyKubeConfigFileName
} else if kp.config.ClientConnection.Kubeconfig != kubeproxyKubeConfigFileName {
warnDefaultComponentConfigValue(kind, "clientConnection.kubeconfig", kubeproxyKubeConfigFileName, kp.config.ClientConnection.Kubeconfig)
}
...
}
|
所有默认配置
通过下面注释的命令,一次打印所有默认的配置文件看看,本地的这些配置即使有些配置对不填,kubeadm 都会自动给加上默认值的,所以这里如果需要定制的话,可以考虑默认值是否符合要求的前提下,只给出一些一定要改的配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# kubeadm config print init-defaults --component-configs KubeletConfiguration,KubeProxyConfiguration
# 上文说过了,现在看来这个配置是完全可以不用的
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 1.2.3.4
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: node
taints: null
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: 1.21.0
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
scheduler: {}
---
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 0s
cacheUnauthorizedTTL: 0s
cgroupDriver: cgroupfs
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
logging: {}
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
rotateCertificates: true
runtimeRequestTimeout: 0s
shutdownGracePeriod: 0s
shutdownGracePeriodCriticalPods: 0s
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
bindAddressHardFail: false
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
qps: 0
clusterCIDR: ""
configSyncPeriod: 0s
conntrack:
maxPerCore: null
min: null
tcpCloseWaitTimeout: null
tcpEstablishedTimeout: null
detectLocalMode: ""
enableProfiling: false
healthzBindAddress: ""
hostnameOverride: ""
iptables:
masqueradeAll: false
masqueradeBit: null
minSyncPeriod: 0s
syncPeriod: 0s
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
strictARP: false
syncPeriod: 0s
tcpFinTimeout: 0s
tcpTimeout: 0s
udpTimeout: 0s
kind: KubeProxyConfiguration
metricsBindAddress: ""
mode: ""
nodePortAddresses: null
oomScoreAdj: null
portRange: ""
showHiddenMetricsForVersion: ""
udpIdleTimeout: 0s
winkernel:
enableDSR: false
networkName: ""
sourceVip: ""
|
纯命令行给参数行不行
实际上,我在执行 kubeadm init
的时候是执行了下面两个命令的,第一步是生产一个默认的集群初始化的配置文件,第二步才是真正执行 kubeadm init
的地方。
1
2
3
|
# 这个命令只会给出
kubeadm config print init-defaults --kubeconfig ClusterConfiguration > kubeadm.yaml
kubeadm init --config=kubeadm.yaml --upload-certs | tee kubeadm-init.log
|
一般来说,直接一条 kubeadm init
基本是创建不出想要的东西的,所以多少都得带点参数,或者通过一个预设的初始化配置文件,结合一定的参数来构建最终的配置,所以就会有上述两条命令了,当然作为程序员了,总是想一步到位或者自动化,所以还是得研究一下这些参数的,我们可以通过命令 kubeadm init --help
主要看一下 flags 的部分,建议大家花时间每条都看一下,大概熟悉一些有什么参数是可以配置的,这里面的参数主要是针对 kube-apiserver 以及一些通用参数。
这里需要说一下,比如想直接修改 KubeProxyConfiguration
中的 mode
参数为 ipvs
命令行的 kubeadm init
应该没有可以直接传递的参数(如果说错了烦请指正)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
Flags:
--apiserver-advertise-address string The IP address the API Server will advertise it's listening on. If not set the default network interface will be used.
--apiserver-bind-port int32 Port for the API Server to bind to. (default 6443)
--apiserver-cert-extra-sans strings Optional extra Subject Alternative Names (SANs) to use for the API Server serving certificate. Can be both IP addresses and DNS names.
--cert-dir string The path where to save and store the certificates. (default "/etc/kubernetes/pki")
--certificate-key string Key used to encrypt the control-plane certificates in the kubeadm-certs Secret.
--config string Path to a kubeadm configuration file.
--control-plane-endpoint string Specify a stable IP address or DNS name for the control plane.
--cri-socket string Path to the CRI socket to connect. If empty kubeadm will try to auto-detect this value; use this option only if you have more than one CRI installed or if you have non-standard CRI socket.
--dry-run Don't apply any changes; just output what would be done.
--feature-gates string A set of key=value pairs that describe feature gates for various features. Options are:
PublicKeysECDSA=true|false (ALPHA - default=false)
RootlessControlPlane=true|false (ALPHA - default=false)
UnversionedKubeletConfigMap=true|false (BETA - default=true)
-h, --help help for init
--ignore-preflight-errors strings A list of checks whose errors will be shown as warnings. Example: 'IsPrivilegedUser,Swap'. Value 'all' ignores errors from all checks.
--image-repository string Choose a container registry to pull control plane images from (default "k8s.gcr.io")
--kubernetes-version string Choose a specific Kubernetes version for the control plane. (default "stable-1")
--node-name string Specify the node name.
--patches string Path to a directory that contains files named "target[suffix][+patchtype].extension". For example, "kube-apiserver0+merge.yaml" or just "etcd.json". "target" can be one of "kube-apiserver", "kube-controller-manager", "kube-scheduler", "etcd". "patchtype" can be one of "strategic", "merge" or "json" and they match the patch formats supported by kubectl. The default "patchtype" is "strategic". "extension" must be either "json" or "yaml". "suffix" is an optional string that can be used to determine which patches are applied first alpha-numerically.
--pod-network-cidr string Specify range of IP addresses for the pod network. If set, the control plane will automatically allocate CIDRs for every node.
--service-cidr string Use alternative range of IP address for service VIPs. (default "10.96.0.0/12")
--service-dns-domain string Use alternative domain for services, e.g. "myorg.internal". (default "cluster.local")
--skip-certificate-key-print Don't print the key used to encrypt the control-plane certificates.
--skip-phases strings List of phases to be skipped
--skip-token-print Skip printing of the default bootstrap token generated by 'kubeadm init'.
--token string The token to use for establishing bidirectional trust between nodes and control-plane nodes. The format is [a-z0-9]{6}\.[a-z0-9]{16} - e.g. abcdef.0123456789abcdef
--token-ttl duration The duration before the token is automatically deleted (e.g. 1s, 2m, 3h). If set to '0', the token will never expire (default 24h0m0s)
--upload-certs Upload control-plane certificates to the kubeadm-certs Secret.
Global Flags:
--add-dir-header If true, adds the file directory to the header of the log messages
--log-file string If non-empty, use this log file
--log-file-max-size uint Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
--one-output If true, only write logs to their native severity level (vs also writing to each lower severity level)
--rootfs string [EXPERIMENTAL] The path to the 'real' host root filesystem.
--skip-headers If true, avoid header prefixes in the log messages
--skip-log-headers If true, avoid headers when opening log files
-v, --v Level number for the log level verbosity
Use "kubeadm init [command] --help" for more information about a command.
|
默认情况下,大部分参数都不需要调整什么的,回到文章的主体,就是 config 是怎么同时通过文件和 kubeadm init
的选项传入的,主要参考下面的代码。
1
2
3
4
5
6
|
// Either use the config file if specified, or convert public kubeadm API to the internal InitConfiguration
// and validates InitConfiguration
cfg, err := configutil.LoadOrDefaultInitConfiguration(options.cfgPath, options.externalInitCfg, options.externalClusterCfg)
if err != nil {
return nil, err
}
|
在读取了文件和传入的选项之后,在经过层层的参数的 Validate 之后,最终会返回下面这个结构体的实例,可以见到,大部分的参数都浓缩到 cfg
了里。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 这个是最重要的数据结构
// initData defines all the runtime information used when running the kubeadm init workflow;
// this data is shared across all the phases that are included in the workflow.
type initData struct {
cfg *kubeadmapi.InitConfiguration
skipTokenPrint bool
dryRun bool
kubeconfigDir string
kubeconfigPath string
ignorePreflightErrors sets.String
certificatesDir string
dryRunDir string
externalCA bool
client clientset.Interface
outputWriter io.Writer
uploadCerts bool
skipCertificateKeyPrint bool
patchesDir string
}
|
下面总结一条基本上可以满足要求的初始化命令,受限于网络条件,基本上把镜像仓库一改,就可以了,并且最后,留下日志,不然以后 token 找不着了,要加节点的时候就尴尬了。
1
2
3
4
5
6
|
kubeadm init --upload-certs --image-repository registry.aliyuncs.com/google_containers | tee kubeadm-init.log
# flannel的话需要加一个参数
kubeadm init --upload-certs \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version 1.24.1 \
--pod-network-cidr=10.244.0.0/16 | tee kubeadm-init.log
|
如果不满意某个步骤创建的一些配置文件,举个例子,比如忘记设置 Kubernetes 的版本,导致初始化的时候用了最新稳定的版本,可以通过下面这样的命令来修改。
1
2
3
4
5
|
# kubeadm init phase control-plane all --kubernetes-version 1.24.1 --image-repository registry.aliyuncs.com/google_containers --pod-network-cidr=10.244.0.0/16
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
|
参考配置文件
下面给出一份个人觉得完全够用的配置文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: 1.21.7
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
scheduler: {}
---
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 0s
cacheUnauthorizedTTL: 0s
cgroupDriver: systemd
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
logging: {}
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
rotateCertificates: true
runtimeRequestTimeout: 0s
shutdownGracePeriod: 0s
shutdownGracePeriodCriticalPods: 0s
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
bindAddressHardFail: false
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
qps: 0
clusterCIDR: ""
configSyncPeriod: 0s
conntrack:
maxPerCore: null
min: null
tcpCloseWaitTimeout: null
tcpEstablishedTimeout: null
detectLocalMode: ""
enableProfiling: false
healthzBindAddress: ""
hostnameOverride: ""
iptables:
masqueradeAll: false
masqueradeBit: null
minSyncPeriod: 0s
syncPeriod: 0s
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
strictARP: false
syncPeriod: 0s
tcpFinTimeout: 0s
tcpTimeout: 0s
udpTimeout: 0s
kind: KubeProxyConfiguration
metricsBindAddress: ""
mode: "ipvs"
nodePortAddresses: null
oomScoreAdj: null
portRange: ""
showHiddenMetricsForVersion: ""
udpIdleTimeout: 0s
winkernel:
enableDSR: false
networkName: ""
sourceVip: ""
|
警告
本文最后更新于 2022年3月20日,文中内容可能已过时,请谨慎参考。