Kubernetes v1.10 [stable]
kubeadm init 和 kubeadm join 结合在一起为从头开始创建最基本的 Kubernetes
集群提供了良好的用户体验,这与最佳实践一致。
但是,kubeadm 如何做到这一点可能并不明显。
本文档提供了更多幕后的详细信息,旨在分享有关 Kubernetes 集群最佳实践的知识。
kubeadm init 和 kubeadm join 设置的集群该是:
kubeadm initexport KUBECONFIG=/etc/kubernetes/admin.confkubectl apply -f <所选网络插件.yaml>kubeadm join --token <令牌> <端点>:<端口>为了降低复杂性并简化基于 kubeadm 的高级工具的开发,对于众所周知的路径和文件名, kubeadm 使用了一组有限的常量值。
Kubernetes 目录 /etc/kubernetes 在应用程序中是一个常量,
因为在大多数情况下它显然是给定的路径,并且是最直观的位置;其他路径常量和文件名有:
/etc/kubernetes/manifests 作为 kubelet 查找静态 Pod 清单的路径。
静态 Pod 清单的名称为:
etcd.yamlkube-apiserver.yamlkube-controller-manager.yamlkube-scheduler.yaml/etc/kubernetes/ 作为带有控制平面组件身份标识的 kubeconfig 文件的路径。
kubeconfig 文件的名称为:
kubelet.conf(在 TLS 引导时名称为 bootstrap-kubelet.conf)controller-manager.confscheduler.confadmin.conf 用于集群管理员和 kubeadm 本身super-admin.conf 用于可以绕过 RBAC 的集群超级管理员证书和密钥文件的名称:
ca.crt、ca.key 用于 Kubernetes 证书颁发机构apiserver.crt、apiserver.key 用于 API 服务器证书apiserver-kubelet-client.crt、apiserver-kubelet-client.key
用于 API 服务器安全地连接到 kubelet 的客户端证书sa.pub、sa.key 用于控制器管理器签署 ServiceAccount 时使用的密钥front-proxy-ca.crt、front-proxy-ca.key 用于前端代理证书颁发机构front-proxy-client.crt、front-proxy-client.key 用于前端代理客户端大多数 kubeadm 命令支持 --config 标志,允许将磁盘上的配置文件传递给命令。
配置文件格式遵循常见的 Kubernetes API apiVersion / kind 方案,
但被视为组件配置格式。包括 kubelet 在内的几个 Kubernetes 组件也支持基于文件的配置。
不同的 kubeadm 子命令需要不同 kind 的配置文件。
例如,kubeadm init 需要 InitConfiguration,kubeadm join 需要 JoinConfiguration,
kubeadm upgrade 需要 UpgradeConfiguration,而 kubeadm reset 需要 ResetConfiguration。
命令 kubeadm config migrate 可用于将旧格式的配置文件迁移到更新(当前)的配置格式。
kubeadm 工具仅支持从已弃用的配置格式迁移到当前格式。
更多详情,请参阅 kubeadm 配置参考页面。
kubeadm init 内部工作流程
包含一系列要执行的原子性工作任务,如 kubeadm init 中所述。
kubeadm init phase
命令允许用户分别调用每个任务,并最终提供可重用且可组合的 API 或工具箱,
其他 Kubernetes 引导工具、任何 IT 自动化工具和高级用户都可以使用它来创建自定义集群。
kubeadm 在启动 init 之前执行一组预检,目的是验证先决条件并避免常见的集群启动问题。
用户可以使用 --ignore-preflight-errors 选项跳过特定的预检或全部检查。
--kubernetes-version 标志指定)比 kubeadm CLI
版本至少高一个小版本。/etc/kubernetes/manifest 文件夹已经存在并且不为空ip、iptables、mount、nsenter 命令ethtool、tc、touch 命令可以使用 kubeadm init phase preflight
命令单独触发预检。
kubeadm 生成用于不同目的的证书和私钥对:
ca.crt 文件和 ca.key 私钥文件中用于 API 服务器的服务证书,使用 ca.crt 作为 CA 生成,并将证书保存到 apiserver.crt
文件中,私钥保存到 apiserver.key 文件中。该证书应包含以下备用名称:
10.96.0.0/12,则为 10.96.0.1)--service-dns-domain 标志值是 cluster.local,
则为 kubernetes.default.svc.cluster.local;
加上默认的 DNS 名称 kubernetes.default.svc、kubernetes.default 和 kubernetes--apiserver-advertise-address用于 API 服务器安全连接到 kubelet 的客户端证书,使用 ca.crt 作为 CA 生成,
并保存到 apiserver-kubelet-client.crt,私钥保存到 apiserver-kubelet-client.key
文件中。该证书应该在 system:masters 组织中。
用于签名 ServiceAccount 令牌的私钥保存到 sa.key 文件中,公钥保存到 sa.pub 文件中。
用于前端代理的证书颁发机构保存到 front-proxy-ca.crt 文件中,私钥保存到
front-proxy-ca.key 文件中
前端代理客户端的客户端证书,使用 front-proxy-ca.crt 作为 CA 生成,并保存到
front-proxy-client.crt 文件中,私钥保存到 front-proxy-client.key 文件中
证书默认情况下存储在 /etc/kubernetes/pki 中,但是该目录可以使用 --cert-dir 标志进行配置。
请注意:
/etc/kubernetes/pki/ca.{crt,key},
kubeadm 将使用这些文件对其余证书进行签名。
请参阅使用自定义证书。ca.crt 文件,
而不提供 ca.key 文件。
kubeadm 能够识别出这种情况并启用 ExternalCA,这也意味着了控制器管理器中的
csrsigner 控制器将不会启动。--dry-run 模式下执行 kubeadm,证书文件将写入一个临时文件夹中。kubeadm init phase certs all
命令单独生成证书。kubeadm 生成具有用于控制平面组件身份标识的 kubeconfig 文件:
供 kubelet 在 TLS 引导期间使用的 kubeconfig 文件 —— /etc/kubernetes/bootstrap-kubelet.conf。
在此文件中,有一个引导令牌或内嵌的客户端证书,向集群表明此节点身份。
此客户端证书应:
system:nodes 组织system:node:<小写主机名>/etc/kubernetes/controller-manager.conf;
在此文件中嵌入了一个具有控制器管理器身份标识的客户端证书。
此客户端证书应具有 CN:system:kube-controller-manager,
该 CN 由 RBAC 核心组件角色
默认定义的。/etc/kubernetes/scheduler.conf;
此文件中嵌入了具有调度器身份标识的客户端证书。此客户端证书应具有 CN:system:kube-scheduler,
该 CN 由 RBAC 核心组件角色
默认定义的。此外,还会生成将 kubeadm 作为管理实体的 kubeconfig 文件并将其保存到 /etc/kubernetes/admin.conf 中。
该文件包含一个带有 Subject: O = kubeadm:cluster-admins, CN = kubernetes-admin
的证书。kubeadm:cluster-admins 是一个由 kubeadm 管理的组,
它在 kubeadm init 期间通过使用 super-admin.conf 文件绑定到
cluster-admin ClusterRole,不需要 RBAC。
此 admin.conf 文件必须保留在控制平面节点上,并且不得与其他用户共享。
在 kubeadm init 期间,会生成另一个 kubeconfig 文件并将其存储在 /etc/kubernetes/super-admin.conf 中。
该文件包含一个带有 Subject: O = system:masters, CN = kubernetes-super-admin 的证书。
system:masters 是一个绕过 RBAC 的超级用户组,使 super-admin.conf
在紧急情况下非常有用,因为 RBAC 配置错误导致集群被锁定。
super-admin.conf 文件可以存储在安全位置,并且不会与其他用户共享。
有关 RBAC 和内置 ClusterRoles 和组的其他信息, 请参阅面向用户的 RBAC 角色绑定。
你可以运行 kubeadm kubeconfig user
来为额外的用户生成 kubeconfig 文件。
生成的配置文件包含嵌入的认证密钥,你应当将其视为机密内容。
另外请注意:
ca.crt 证书内嵌在所有 kubeconfig 文件中。--dry-run 模式下执行 kubeadm,则 kubeconfig 文件将写入一个临时文件夹中。kubeadm init phase kubeconfig all
命令分别生成 kubeconfig 文件。kubeadm 将用于控制平面组件的静态 Pod 清单文件写入 /etc/kubernetes/manifests 目录。
kubelet 启动后会监视这个目录以便创建 Pod。
静态 Pod 清单有一些共同的属性:
所有静态 Pod 都部署在 kube-system 名字空间
所有静态 Pod 都打上 tier:control-plane 和 component:{组件名称} 标签
所有静态 Pod 均使用 system-node-critical 优先级
所有静态 Pod 都设置了 hostNetwork:true,使得控制平面在配置网络之前启动;结果导致:
127.0.0.1etcd-servers 地址将被设置为 127.0.0.1:2379请注意:
--dry-run 模式下执行 kubeadm,则静态 Pod 文件写入一个临时文件夹中。kubeadm init phase control-plane all
命令分别生成主控组件的静态 Pod 清单。API 服务器的静态 Pod 清单会受到用户提供的以下参数的影响:
apiserver-advertise-address 和 apiserver-bind-port;
如果未提供,则这些值默认为机器上默认网络接口的 IP 地址和 6443 端口。service-cluster-ip-range 给 Service 使用etcd-servers 地址和相关的 TLS 设置
(etcd-cafile、etcd-certfile、etcd-keyfile);
如果未提供外部 etcd 服务器,则将使用本地 etcd(通过主机网络)无条件设置的其他 API 服务器标志有:
--insecure-port=0 禁止到 API 服务器不安全的连接--enable-bootstrap-token-auth=true 启用 BootstrapTokenAuthenticator 身份验证模块。
更多细节请参见 TLS 引导。--allow-privileged 设为 true(诸如 kube-proxy 这些组件有此要求)--requestheader-client-ca-file 设为 front-proxy-ca.crt--enable-admission-plugins 设为:
NamespaceLifecycle
例如,避免删除系统保留的名字空间LimitRanger 和
ResourceQuota
对名字空间实施限制ServiceAccount
实施服务账户自动化PersistentVolumeLabel
将区域(Region)或区(Zone)标签附加到由云提供商定义的 PersistentVolumes
(此准入控制器已被弃用并将在以后的版本中删除)。
如果未明确选择使用 gce 或 aws 作为云提供商,则默认情况下,v1.9 以后的版本 kubeadm 都不会部署。DefaultStorageClass
在 PersistentVolumeClaim 对象上强制使用默认存储类型DefaultTolerationSecondsNodeRestriction
限制 kubelet 可以修改的内容(例如,仅此节点上的 Pod)--kubelet-preferred-address-types 设为 InternalIP,ExternalIP,Hostname;
这使得在节点的主机名无法解析的环境中,kubectl log 和 API 服务器与 kubelet
的其他通信可以工作使用在前面步骤中生成的证书的标志:
--client-ca-file 设为 ca.crt--tls-cert-file 设为 apiserver.crt--tls-private-key-file 设为 apiserver.key--kubelet-client-certificate 设为 apiserver-kubelet-client.crt--kubelet-client-key 设为 apiserver-kubelet-client.key--service-account-key-file 设为 sa.pub--requestheader-client-ca-file 设为 front-proxy-ca.crt--proxy-client-cert-file 设为 front-proxy-client.crt--proxy-client-key-file 设为 front-proxy-client.key其他用于保护前端代理( API 聚合层) 通信的标志:
--requestheader-username-headers=X-Remote-User--requestheader-group-headers=X-Remote-Group--requestheader-extra-headers-prefix=X-Remote-Extra---requestheader-allowed-names=front-proxy-client控制器管理器的静态 Pod 清单受用户提供的以下参数的影响:
如果调用 kubeadm 时指定了 --pod-network-cidr 参数,
则可以通过以下方式启用某些 CNI 网络插件所需的子网管理器功能:
--allocate-node-cidrs=true--cluster-cidr 和 --node-cidr-mask-size 标志--cloud-provider,如果存在这样的配置文件,
则指定 --cloud-config 路径(此为试验性特性,是 Alpha 版本,将在以后的版本中删除)。其他无条件设置的标志包括:
--controllers 为 TLS 引导程序启用所有默认控制器以及 BootstrapSigner 和
TokenCleaner 控制器。详细信息请参阅
TLS 引导
--use-service-account-credentials 设为 true
使用先前步骤中生成的证书的标志:
--root-ca-file 设为 ca.crt--cluster-signing-cert-file 设为 ca.crt,否则设为 ""--cluster-signing-key-file 设为 ca.key,否则设为 ""--service-account-private-key-file 设为 sa.key调度器的静态 Pod 清单不受用户提供的参数的影响。
如果你指定的是外部 etcd,则应跳过此步骤,否则 kubeadm 会生成静态 Pod 清单文件, 以创建在 Pod 中运行的、具有以下属性的本地 etcd 实例:
localhost:2379 上监听并使用 HostNetwork=truehostPath 从 dataDir 挂载到主机的文件系统请注意:
registry.gcr.io 拉取。有关自定义镜像仓库,
请参阅使用自定义镜像。--dry-run 模式执行 kubeadm 命令,etcd 的静态 Pod 清单将被写入一个临时文件夹。kubeadm init phase etcd local
命令为本地 etcd 直接调用静态 Pod 清单生成逻辑。在控制平面节点上,kubeadm 会等待最多4分钟,以确保控制平面组件和 kubelet 可用。
它通过检查相应组件的 /healthz 或 /livez 端点来进行健康检查。
控制平面启动后,kubeadm 将完成以下段落中描述的任务。
kubeadm 将传递给 kubeadm init 的配置保存在 kube-system 名字空间下名为
kubeadm-config 的 ConfigMap 中。
这将确保将来执行的 kubeadm 操作(例如 kubeadm upgrade)将能够确定实际/当前集群状态,
并根据该数据做出新的决策。
请注意:
kubeadm init phase upload-config
命令单独上传主控节点配置。一旦控制平面可用,kubeadm 将执行以下操作:
node-role.kubernetes.io/control-plane="" 标签,标记其为控制平面node-role.kubernetes.io/control-plane:NoSchedule 污点请注意,标记控制面的这个阶段可以单独通过
kubeadm init phase mark-control-plane
命令来实现。
kubeadm 使用引导令牌认证 将新节点连接到现有集群;更多的详细信息, 请参见设计提案。
kubeadm init 确保为该过程正确配置了所有内容,这包括以下步骤以及设置 API
服务器和控制器标志,如前几段所述。
可以使用 kubeadm init phase bootstrap-token
命令配置节点的 TLS 引导,执行以下段落中描述的所有配置步骤;
或者也可以单独执行各个步骤。
kubeadm init 创建第一个引导令牌,该令牌是自动生成的或由用户提供的 --token
标志的值;如引导令牌规范文档中所述,令牌应保存在 kube-system 名字空间下名为
bootstrap-token-<令牌 ID> 的 Secret 中。
请注意:
kubeadm init 创建的默认令牌将用于在 TLS 引导过程中验证临时用户;
这些用户会成为 system:bootstrappers:kubeadm:default-node-token 组的成员。-token-ttl 标志进行更改)。kubeadm token
命令创建其他令牌,这些令牌还提供其他有用的令牌管理功能。kubeadm 确保 system:bootstrappers:kubeadm:default-node-token 组中的用户能够访问证书签名 API。
这是通过在上述组与默认 RBAC 角色 system:node-bootstrapper 之间创建名为
kubeadm:kubelet-bootstrap 的 ClusterRoleBinding 来实现的。
kubeadm 确保 csrapprover 控制器自动批准引导令牌的 CSR 请求。
这是通过在 system:bootstrappers:kubeadm:default-node-token 用户组和
system:certificates.k8s.io:certificatesigningrequests:nodeclient 默认角色之间
创建名为 kubeadm:node-autoapprove-bootstrap 的 ClusterRoleBinding 来实现的。
还应创建 system:certificates.k8s.io:certificatesigningrequests:nodeclient 角色,
授予对 /apis/certificates.k8s.io/certificatesigningrequests/nodeclient
执行 POST 的权限。
kubeadm 确保节点启用了证书轮换,csrapprover 控制器将自动批准节点的新证书的 CSR 请求。
这是通过在 system:nodes 组和
system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
默认角色之间创建名为 kubeadm:node-autoapprove-certificate-rotation 的
ClusterRoleBinding 来实现的。
本步骤在 kube-public 名字空间中创建名为 cluster-info 的 ConfigMap。
另外,它创建一个 Role 和一个 RoleBinding,为未经身份验证的用户授予对 ConfigMap
的访问权限(即 RBAC 组 system:unauthenticated 中的用户)。
对 cluster-info ConfigMap 的访问不受速率限制。
如果你把 API 服务器暴露到外网,这可能是一个问题,也可能不是;
这里最坏的情况是 DoS 攻击,攻击者使用 kube-apiserver 可处理的所有当前请求来为
cluster-info ConfigMap 提供服务。
kubeadm 通过 API 服务器安装内部 DNS 服务器和 kube-proxy 插件。
此步骤可以通过 kubeadm init phase addon all
命令单独执行。
在 kube-system 名字空间中创建一个用于 kube-proxy 的 ServiceAccount;
然后以 DaemonSet 的方式部署 kube-proxy:
ca.crt 和 token)来自 ServiceAccountkube-proxy 的 ServiceAccount 绑定了 system:node-proxier ClusterRole 中的特权出于与旧版 kube-dns 插件的兼容性考虑,CoreDNS 服务被命名为 kube-dns。
在 kube-system 名字空间中创建 CoreDNS 的 ServiceAccount
coredns 的 ServiceAccount 绑定了 system:coredns ClusterRole 中的特权
在 Kubernetes 1.21 版本中,kubeadm 对 kube-dns 的支持被移除。
你可以在 kubeadm 使用 CoreDNS,即使相关的 Service 名字仍然是 kube-dns。
与 kubeadm init 类似,kubeadm join 内部工作流由一系列待执行的原子工作任务组成。
工作流分为发现(让该节点信任 Kubernetes 的 API 服务器)和 TLS 引导 (让 Kubernetes 的 API 服务器信任该节点)等步骤。
请参阅使用引导令牌进行身份验证 或相应的设计提案。
kubeadm 在开始执行之前执行一组预检,目的是验证先决条件,避免常见的集群启动问题。
另外请注意:
--ignore-preflight-errors
选项跳过特定的预检(或者进而跳过所有预检)。主要有两种发现方案。第一种是使用一个共享令牌以及 API 服务器的 IP 地址。 第二种是提供一个文件(它是标准 kubeconfig 文件的子集)。
如果带 --discovery-token 参数调用 kubeadm join,则使用了令牌发现功能;
在这种情况下,节点基本上从 kube-public 名字空间中的 cluster-info ConfigMap
中检索集群 CA 证书。
为了防止“中间人”攻击,采取了以下步骤:
首先,通过不安全连接检索 CA 证书(这是可能的,因为 kubeadm init 授予
system:unauthenticated 的用户对 cluster-info 访问权限)。
然后 CA 证书通过以下验证步骤:
--discovery-token-ca-cert-hash。这个值来自 kubeadm init 的输出,
或者可以使用标准工具计算(哈希值是按 RFC7469 中主体公钥信息(SPKI)对象的字节计算的)
--discovery-token-ca-cert-hash 标志可以重复多次,以允许多个公钥。你可以通过在命令行上指定 --discovery-token-unsafe-skip-ca-verification
标志来跳过 CA 验证。这会削弱 kubeadm 的安全模型,因为其他人可能冒充 Kubernetes API 服务器。
如果带 --discovery-file 参数调用 kubeadm join,则使用文件发现功能;
该文件可以是本地文件或通过 HTTPS URL 下载;对于 HTTPS,主机安装的 CA 包用于验证连接。
通过文件发现,集群 CA 证书是文件本身提供;事实上,这个发现文件是一个 kubeconfig 文件,
只设置了 server 和 certificate-authority-data 属性,
如 kubeadm join
参考文档中所述,当与集群建立连接时,kubeadm 尝试访问 cluster-info ConfigMap,
如果可用,就使用它。
知道集群信息后,kubeadm 将写入文件 bootstrap-kubelet.conf,从而允许 kubelet 执行
TLS 引导。
TLS 引导机制使用共享令牌对 Kubernetes API 服务器进行临时身份验证, 以便为本地创建的密钥对提交证书签名请求(CSR)。
该请求会被自动批准,并且该操作保存 ca.crt 文件和 kubelet.conf 文件,用于
kubelet 加入集群,同时删除 bootstrap-kubelet.conf。
kubeadm init 过程中保存的令牌进行验证(或者使用 kubeadm token 命令创建的其他令牌)system:bootstrappers:kubeadm:default-node-token 组的一个用户成员,
该成员在 kubeadm init 过程中被授予对 CSR API 的访问权kubeadm init 过程中给出的配置来管理kubeadm upgrade 包含若干子命令,用来处理由 kubeadm 创建的 Kubernetes 集群的升级。
你必须在控制平面节点上运行 kubeadm upgrade apply(你可以选择使用哪个节点),以启动升级过程。
然后,在所有剩余节点(包括工作节点和控制平面节点)上运行 kubeadm upgrade node。
kubeadm upgrade apply 和 kubeadm upgrade node 都有一个 phase 子命令,
用于提供对升级过程内部阶段的访问。更多详情,请参阅
kubeadm upgrade phase。
额外的实用升级命令包括 kubeadm upgrade plan 和 kubeadm upgrade diff。
所有升级子命令都支持传递配置文件。
你可以选择在运行 kubeadm upgrade apply 之前运行 kubeadm upgrade plan。
plan 子命令会检查有哪些版本可以用来升级,并验证你当前的集群是否可升级。
这条命令会显示将对控制平面节点的现有静态 Pod 清单作哪些修改。
获得更详细信息的一种做法是运行 kubeadm upgrade apply --dry-run
或 kubeadm upgrade node --dry-run。
kubeadm upgrade apply 为所有节点的升级做准备,同时也会升级运行此命令时所在的控制平面节点。
它所执行的步骤包括:
kubeadm init 和 kubeadm join,运行预检操作,确保容器镜像已被下载且集群处于可升级的良好状态。/etc/kubernetes/manifests 的控制平面清单文件,并在文件发生更改时等待 kubelet 重启组件。kubeadm-config 和 kubelet-config ConfigMap
中(都在 kube-system 命名空间内)。/var/lib/kubelet/config.yaml 中为此节点写入更新的 kubelet 配置,
并读取节点的 /var/lib/kubelet/instance-config.yaml 文件以及将此实例配置中的
containerRuntimeEndpoint 等补丁字段写入 /var/lib/kubelet/config.yaml。cluster-info ConfigMap 以用于 RBAC 规则。这一操作与 kubeadm init
阶段相同,确保集群继续支持使用引导令牌加入的节点。kubeadm upgrade node 在集群升级启动后(通过运行 kubeadm upgrade apply)升级单个控制平面或工作节点。
此命令通过检查文件 /etc/kubernetes/manifests/kube-apiserver.yaml 是否存在来检测节点是否为控制平面节点。
如果找到该文件,kubeadm 工具会推断此节点上正在运行 kube-apiserver Pod。
kubeadm upgrade apply,运行预检操作。/etc/kubernetes/manifests 的控制平面清单文件,
并在文件发生更改时等待 kubelet 重启组件。/var/lib/kubelet/config.yaml 中为此节点写入更新的 kubelet 配置,
并读取节点的 /var/lib/kubelet/instance-config.yaml 文件以及将此实例配置中的
containerRuntimeEndpoint 等补丁字段写入 /var/lib/kubelet/config.yaml。你可以在之前执行过 kubeadm 命令的节点上使用 kubeadm reset 子命令。
此子命令对节点执行尽力而为的清理。如果某些操作失败,你必须介入并执行手动清理。
此命令支持多个阶段。更多详情,请参阅
kubeadm reset phase。
此命令支持配置文件。
另外:
.kube/ 文件夹不会被清理。此命令包含以下阶段:
/var/lib/kubelet 中挂载的任何目录。/var/lib/kubelet 和 /etc/kubernetes 中由 kubeadm 管理的所有文件和目录。