- 1 核心设计原则
- 2 常量和众所周知的值和路径
- 3 kubeadm init 工做流程内部设计
- 3.1 预检检查
- 3.2 生成必要的证书
- 3.3 为控制平面组件生成 kubeconfig 文件
- 3.4 为控制平面组件生成静态 Pod 清单
- 3.5 为本地 etcd 生成静态 Pod 清单
- 3.6 (可选,1.9 版本中为 alpha)编写 init kubelet 配置
- 3.7 等待控制平面启动
- 3.8 (可选,1.9 版本中为 alpha)编写基本 kubelet 配置
- 3.9 将 kubeadm MasterConfiguration 保存在 ConfigMap 中供之后参考
- 3.10 标记 master
- 3.11 配置 TLS-引导 以加入节点
- 3.12 安装插件
- 3.13 (可选,v1.9 中是 alpha)自托管
- 4 kubeadm join 阶段的内部设计
- 5 TLS 引导
kubeadm init 和 kubeadm join 为从头开始建立一个 Kubernetes 集群的最佳实践共同提供了一个很好的用户体验。可是,kubeadm 如何 作到这一点可能并不明显。前端
本文档提供了有关发生了什么事情的更多详细信息,旨在分享关于 Kubernetes 集群最佳实践的知识。node
核心设计原则
使用 kubeadm init 和 kubeadm join 设置的集群应该:linux
- 安全:
- 它应该采用最新的最佳作法,如:
- 强制实施 RBAC
- 使用节点受权器
- 控制平面组件之间使用安全通讯
- API server 和 kubelet 之间使用安全通讯
- 锁定 kubelet API
- 锁定对系统组件(如 kube-proxy 和 kube-dns)的 API 访问权限
- 锁定引导令牌能够访问的内容
- 等等
- 它应该采用最新的最佳作法,如:
- 使用方便:
- 用户只需运行几个命令便可:
- kubeadm init
- export KUBECONFIG=/etc/kubernetes/admin.conf
- kubectl apply -f <network-of-choice.yaml>
- kubeadm join --token <token> <master-ip>:<master-port>
- 用户只需运行几个命令便可:
- 可扩展:
- 例如,它 不 应该支持任何网络提供商,相反,配置网络应该是超出了它的范围
- 应该提供使用配置文件自定义各类参数的可能性
常量和众所周知的值和路径
为了下降复杂性并简化 kubeadm 实施的部署解决方案的开发,kubeadm 使用一组有限的常量值,用于众所周知的路径和文件名。git
Kubernetes 目录 /etc/kubernetes 在应用中是一个常量,由于它明显是大多数状况下的给定路径,也是最直观的位置; 其余常量路径和文件名是:github
- /etc/kubernetes/manifests 做为 kubelet 寻找静态 Pod 的路径。静态 Pod 清单的名称是:
- etcd.yaml
- kube-apiserver.yaml
- kube-controller-manager.yaml
- kube-scheduler.yaml
- /etc/kubernetes/ 做为存储具备控制平面组件标识的 kubeconfig 文件的路径。kubeconfig 文件的名称是:
- kubelet.conf (bootstrap-kubelet.conf - 在 TLS 引导期间)
- controller-manager.conf
- scheduler.conf
- admin.conf 用于集群管理员和 kubeadm 自己
- 证书和密钥文件的名称:
- ca.crt,ca.key 为 Kubernetes 证书颁发机构
- apiserver.crt,apiserver.key 用于 API server 证书
- apiserver-kubelet-client.crt,apiserver-kubelet-client.key 用于由 API server 安全地链接到 kubelet 的客户端证书
- sa.pub,sa.key 用于签署 ServiceAccount 时控制器管理器使用的密钥
- front-proxy-ca.crt,front-proxy-ca.key 用于前台代理证书颁发机构
- front-proxy-client.crt,front-proxy-client.key 用于前端代理客户端
kubeadm init 工做流程内部设计
kubeadm init 内部工做流程 由一系列要执行的原子工做任务组成,如 kubeadm init 所述。web
kubeadm alpha phase 命令容许用户单独调用每一个任务,并最终提供可重用和可组合的 API/工具箱,可供其余 Kubernetes 引导工具、任何 IT 自动化工具或高级用户建立自定义集群使用。docker
预检检查
Kubeadm 在启动 init 以前执行一组预检检查,目的是验证先决条件并避免常见的集群启动问题。在任何状况下,用户均可以使用 --ignore-preflight-errors 选项跳过特定的预检检查(或最终全部预检检查)。json
- [警告]若是要使用的 Kubernetes 版本(与 --kubernetes-version 标记一块儿指定)至少比 kubeadm CLI 版本高一个次要版本
- Kubernetes 系统要求:
- 若是在 Linux 上运行:
- [错误] 若是不是 Kernel 3.10+ 或具备特定 KernelSpec 的 4+
- [错误] 若是须要的 cgroups 子系统没有设置
- 若是使用 docker:
- [警告/错误] 若是 Docker 服务不存在,若是它被禁用,若是它不是 active 状态
- [错误] 若是 Docker 端点不存在或不起做用
- [警告] 若是 docker 版本 > 17.03
- 若是使用其余 cri 引擎:
- [错误] 若是 crictl 没有响应
- 若是在 Linux 上运行:
- [错误] 若是用户不是root用户
- [错误] 若是机器主机名不是有效的 DNS 子域
- [警告] 若是经过网络查找没法到达主机名
- [错误] 若是 kubelet 版本低于 kubeadm 支持的最小 kubelet 版本(当前小版本 -1)
- [错误] 若是 kubelet 版本至少比所需的控制平面版本更高一些(不受支持的版本)
- [警告] 若是 kubelet 服务不存在或禁用
- [警告] 若是 firewalld 处于活动状态
- [错误] 若是 API server 的 bindPort 或者 port 10250/10251/10252 已经被使用
- [错误] 若是/etc/kubernetes/manifest 文件夹已经存在,而且非空
- [错误] 若是 /proc/sys/net/bridge/bridge-nf-call-iptables 文件不存在或者不包含 1
- [错误] 若是发布地址是 ipv6 而且 /proc/sys/net/bridge/bridge-nf-call-ip6tables 不存在或者不包含 1
- [错误] 若是 swap 打开
- [错误] 若是 ip、iptables、mount 或者 nsenter 命令没有出如今命令路径中
- [警告] 若是 ebtables、ethtool、socat、tc、touch 和 crictl 命令没有出如今命令路径中
- [警告] 若是 API server、Controller-manager、Scheduler 的额外参数中包含一些无效的选项
- [警告] 若是链接到 https://API.AdvertiseAddress:API.BindPort 须要经过代理
- [警告] 若是链接到服务子网须要经过代理(只检查第一个地址)
- [警告] 若是链接到 pod 子网须要经过代理(只检查第一个地址)
- 若是提供外部 etcd:
- [错误] 若是 etcd 版本低于 3.0.14
- [错误] 若是指定了 etcd 证书或密钥,但未提供
- 若是不提供外部 etcd(所以将安装本地 etcd):
- [错误] 若是使用端口 2379
- [错误] 若是 Etcd.DataDir 文件夹已经存在而且不是空的
- 若是受权模式是 ABAC:
- [错误] 若是 abac_policy.json 不存在
- 若是受权模式是 WebHook:
- [错误] 若是 webhook_authz.conf 不存在
请注意:bootstrap
- 预检检查能够经过 kubeadm alpha phase preflight 命令单独调用
生成必要的证书
Kubeadm 为不一样目的生成证书和私钥对:
- Kubernetes 集群的自签名证书颁发机构保存到 ca.crt 文件和 ca.key 私钥文件中
- API server 的服务证书,使用 ca.crt 做为 CA 生成,并保存到 apiserver.crt 文件中,并带有其私钥 apiserver.key。此证书应包含如下其余名称:
- Kubernetes 服务的内部 clusterIP(服务 CIDR 中的第一个地址,例如,若是服务子网是 10.96.0.0/12 则为 10.96.0.1)
- Kubernetes DNS 名称,例如,若是 --service-dns-domain 标志的值为 cluster.local,则为 kubernetes.default.svc.cluster.local,再加上默认的 DNS 名称 kubernetes.default.svc、kubernetes.default 和 kubernetes
- 节点名称
- --apiserver-advertise-address
- 由用户指定的其余替代名称
- 用于 API server 的安全链接到 kubelet 的客户端证书,使用 ca.crt 做为 CA 生成并使用私钥 apiserver-kubelet-client.key 保存到文件 apiserver-kubelet-client.crt中。这个证书应该在 system:masters 组织中
- 一个用于签名 ServiceAccount 令牌的私钥,该令牌与它的公钥 sa.pub 一块儿保存到 sa.key 文件中。
- 前端代理的证书颁发机构保存到 front-proxy-ca.crt 文件中,其密钥为 front-proxy-ca.key
- 前端代理客户端的客户证书,使用 front-proxy-ca.crt 做为 CA 生成,并使用其私钥 front-proxy-client.key 保存到 front-proxy-client.crt 文件中
证书默认存储在 /etc/kubernetes/pki 中,但该目录可以使用 --cert-dir 标志进行配置。
请注意:
- 若是给定的证书和私钥对都存在,而且其内容评估符合上述规范,则将使用现有文件并跳过给定证书的生成阶段。这意味着用户能够将现有 CA 复制到 /etc/kubernetes/pki/ca.{crt,key},而后 kubeadm 将使用这些文件来签署剩余的证书。请参与 使用自定义证书
- 只有 CA 能够提供 ca.crt 文件,但不提供 ca.key 文件,若是全部其余证书和 kubeconfig 文件已就位,kubeadm 会识别此状况并激活 ExternalCA,这也意味着 controller-manager 中的 csrsigner 控制器将不会启动
- 若是 kubeadm 在 ExternalCA 模式下运行; 全部的证书都必须由用户提供,由于 kubeadm 自己不能生成它们
- 在 --dry-run 模式中执行 kubeadm 的状况下,证书文件被写入临时文件夹中
- 使用 kubeadm alpha phase certs all 命令能够单独调用证书生成动做
为控制平面组件生成 kubeconfig 文件
具备控制平面组件标识的 Kubeadm kubeconfig 文件:
- kubelet 使用的 kubeconfig 文件:/etc/kubernetes/kubelet.conf; 在这个文件内嵌入一个具备 kubelet 身份的客户端证书。这个客户证书应该:
- 在 system:nodes 组织中,符合 节点受权 模块的要求
- 有 CN system:node:<hostname-lowercased>
- controller-manager 使用的 kubeconfig 文件:/etc/kubernetes/controller-manager.conf; 在这个文件内嵌入一个带有 controller-manager 身份的客户端证书。此客户端证书应具备 CN system:kube-controller-manager,默认由 RBAC 核心组件角色 定义
- scheduler 使用的 kubeconfig 文件:/etc/kubernetes/scheduler.conf; 在这个文件内嵌入一个带有 scheduler 标识的客户端证书。此客户端证书应具备 CN system:kube-scheduler,默认由 RBAC 核心组件角色 定义
此外,生成一个 kubeadm 去使用它本身以及管理员使用的 kubeconfig 文件,并保存到 /etc/kubernetes/admin.conf 文件中。这里的 “管理员” 定义了正在管理集群并但愿彻底控制(root)集群的实际人员。管理员的嵌入式客户端证书应该:
- 在 system:masters 组织中,默认由 RBAC 用户所面对的角色绑定 定义
- 包括一个 CN,但能够是任何东西。Kubeadm 使用 kubernetes-admin CN
请注意:
- ca.crt 证书嵌入在全部 kubeconfig 文件中。
- 若是给定的 kubeconfig 文件存在,而且其内容的评估符合上述规范,则将使用现有文件,并跳过给定 kubeconfig 的生成阶段
- 若是 kubeadm 以 ExternalCA 模式运行,则全部必需的 kubeconfig 也必须由用户提供,由于 kubeadm 自己不能生成它们中的任何一个
- 若是在 --dry-run 模式下执行 kubeadm ,kubeconfig 文件将写入临时文件夹中
- 使用 kubeadm alpha phase kubeconfig all 命令能够单独调用 Kubeconfig 文件生成动做
为控制平面组件生成静态 Pod 清单
kubeadm 将控制平面组件的静态 Pod 清单文件写入 /etc/kubernetes/manifests; Kubelet 会监控这个目录,在启动时建立 pod。
静态 Pod 清单共享一组通用属性:
- 全部静态 Pod 都部署在 kube-system 命名空间上
- 全部静态 Pod 均可以获取 tier:control-plane 和 component:{component-name} 标记
- 全部的静态 Pod 都会得到 scheduler.alpha.kubernetes.io/critical-pod 注解(这将转移到适当的解决方案,即在准备就绪时使用 pod 优先级和抢占)
- 在全部静态 Pod 上设置 hostNetwork: true,以便在网络配置以前容许控制平面启动; 所以:
- controller-manager 和 scheduler 使用来指代该 API server 的地址为 127.0.0.1
- 若是使用本地 etcd 服务器,etcd-servers 地址将被设置为 127.0.0.1:2379
- controller-manager 和 scheduler 均启用选举
- controller-manager 和 scheduler 将引用 kubeconfig 文件及其各自的惟一标识
- 全部静态 Pod 都会得到用户指定的额外标志,如 将自定义参数传递给控制平面组件 所述
- 全部静态 Pod 都会获取用户指定的任何额外卷(主机路径)
请注意:
- --kubernetes-version 当前体系结构中的全部镜像 将从中 gcr.io/google_containers 中拉取; 若是指定了其余镜像仓库库或 CI 镜像仓库,则将使用此仓库; 若是一个特定的容器镜像应该被用于全部控制平面组件,那么这个特定镜像将被使用。请参阅 使用自定义镜像 了解更多详情
- 若是在 --dry-run 模式下执行 kubeadm,则将静态 Pod 文件写入临时文件夹
- 可使用 kubeadm alpha phase controlplane all 命令单独调用生成主组件的静态 Pod 清单
API server
API server 的静态 Pod 清单受用户提供的如下参数的影响:
- 须要指定要绑定到的 apiserver-advertise-address 和 apiserver-bind-port;若是没有提供,这些值分别默认为机器上默认网络接口的 IP 地址和端口 6443
- service-cluster-ip-range 用于服务
- 若是指定了外部 etcd 服务器,则要设定 etcd-servers 地址和相关的 TLS 设置(etcd-cafile、etcd-certfile、etcd-keyfile); 若是不提供外部 etcd 服务器,则会使用本地 etcd(经过主机网络)
- 若是指定了云提供商,则要配置相应的 --cloud-provider,若是这样的文件存在,还要配置 --cloud-config 路径(这是实验性的、alpha 功能,将在将来的版本中删除)
- 若是 kubeadm 被调用为 --feature-gates=HighAvailability,则标志 --endpoint-reconciler-type=lease 被设置,从而启用内部 API server VIP 的 endpoints 的自动协调
- 若是 kubeadm 被调用为 --feature-gates=DynamicKubeletConfig,则 API 服务器上的相应功能将经过 --feature-gates=DynamicKubeletConfig=true 标志激活
其余无条件设置的 API server 标志是:
- --insecure-port=0 避免与 api server 的不安全链接
- --enable-bootstrap-token-auth=true 启用 BootstrapTokenAuthenticator 验证模块。有关更多详细信息,请参阅 TLS 引导
- --allow-privileged 为 true (如 kube proxy 所要求的)
- --requestheader-client-ca-file 为 front-proxy-ca.crt
- --admission-control 为:
- Initializers 启用 动态准入控制
- NamespaceLifecycle 例如避免删除系统保留的命名空间
- LimitRanger 和 ResourceQuota 强制限制命名空间
- ServiceAccount 强制执行服务账户自动化
- PersistentVolumeLabel 将区域或区域标签附加到由云提供商定义的 PersistentVolumes (此准入控制器已被弃用,并将在将来的版本中被删除。没有明确选择使用 gce 或 aws 做为云提供商时,它在默认状况下跟 1.9 版本同样,并非由 kubeadm 部署)
- DefaultStorageClass 在 PersistentVolumeClaim 对象上强制执行默认存储类
- DefaultTolerationSeconds
- NodeRestriction 限制 kubelet 能够修改的内容(例如,只有该节点上的 pod)
- --kubelet-preferred-address-types 为 InternalIP,ExternalIP,Hostname;,这使得 kubectl logs 和其余 api server-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 Aggregation)通讯的其余标志:
- --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
Controller manager
API server 的静态 Pod 清单受用户提供的如下参数的影响:
- 若是调用 kubeadm 时指定一个 --pod-network-cidr,某些 CNI 网络插件所需的子网管理器功能能够经过设置来启用:
- --allocate-node-cidrs=true
- --cluster-cidr 和 --node-cidr-mask-size 根据给定的 CIDR 标志
- 若是指定了云提供商,则要配置相应的 --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,若是外部 CA 模式被禁用,则返回 ""
- --cluster-signing-key-file 为 ca.key,若是外部 CA 模式被禁用,则返回 ""
- --service-account-private-key-file 为 sa.key
Scheduler
Scheduler 的静态 Pod 清单不受用户提供的参数的影响。
为本地 etcd 生成静态 Pod 清单
若是用户指定了外部 etcd,则此步骤将被跳过,不然 kubeadm 将生成一个静态的 Pod 清单文件,用于建立在 Pod 中运行的本地 etcd 实例,其中包含如下属性:
- 监听 localhost:2379 并使用 HostNetwork=true
- 作一个 hostPath,从 dataDir 挂载到 主机文件系统
- 任何由用户指定的额外标志
请注意:
- etcd 镜像将从中 gcr.io/google_containers 中拉取; 若是指定了其余镜像仓库库,则将使用此仓库; 若是一个特定的容器镜像应该被用于全部控制平面组件,那么这个特定镜像将被使用。请参阅 使用自定义镜像 了解更多详情
- 若是在 --dry-run 模式下执行 kubeadm,则将静态 Pod 文件写入临时文件夹
- 可使用 kubeadm alpha phase etcd local 命令为本地 etcd 生成的静态 Pod 清单
(可选,1.9 版本中为 alpha)编写 init kubelet 配置
若是 kubeadm 被调用为 --feature-gates=DynamicKubeletConfig,它会将 kubelet init 配置写入 /var/lib/kubelet/config/init/kubelet 文件。
init 配置用于在此特定节点上启动 kubelet,为 kubelet 插入文件提供替代方案; 这种配置将被如下步骤中所述的 Kubelet 基本配置替代。请参阅 经过配置文件设置 Kubelet 参数 以获取更多信息。
请注意:
- 要使动态 kubelet 配置正常工做,应该在 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 中指定标志 --dynamic-config-dir=/var/lib/kubelet/config/dynamic
- 经过设置.kubeletConfiguration.baseConfig,Kubelet init 配置能够经过使用 kubeadm MasterConfiguration 文件进行修改。请参阅 在配置文件中使用 kubelet init 以获取更多信息。
等待控制平面启动
这是 kubeadm 集群的关键时刻。kubeadm 等待 localhost:6443/healthz 返回 ok,可是为了检测死锁状况,若是localhost:10255/healthz(kubelet liveness)或 localhost:10255/healthz/syncloop(kubelet readiness)分别在 40 秒和 60 秒后不返回 ok,kubeadm 就会快速失败。
kubeadm 依靠 kubelet 来拉取控制平面镜像,并以静态 Pod 的形式正确运行它们。控制平面启动后,kubeadm 完成如下段落中描述的任务。
(可选,1.9 版本中为 alpha)编写基本 kubelet 配置
若是 kubeadm 被调用为 --feature-gates=DynamicKubeletConfig:
- 将 kubelet 基本配置写入命名空间 kube-system 的 kubelet-base-config-v1.9 ConfigMap 中
- 建立 RBAC 规则来授予该 ConfigMap 对全部引导令牌和全部 kubelet 实例(即组 system:bootstrappers:kubeadm:default-node-token 和 system:nodes)的读访问权限
- 经过将 Node.spec.configSource 指向新建立的 ConfigMap 来为初始主节点启用动态 kubelet 配置功能
将 kubeadm MasterConfiguration 保存在 ConfigMap 中供之后参考
kubeadm 将 kubeadm init 经过标志或配置文件传递给 ConfigMap 的配置保存在 kube-system 命名空间下的 kubeadm-config ConfigMap 中。
这将确保未来(例如 kubeadm upgrade)执行的 kubeadm 行动将可以肯定 实际/当前 的集群状态并基于该数据作出新的决定。
请注意:
- 在上传以前,敏感信息(例如令牌)会从配置中删除
- 主配置的上传能够经过 kubeadm alpha phase upload-config 命令单独调用
- 若是您使用 kubeadm v1.7.x 或更低版本初始化集群,则必须在使用 kubeadm upgrade 到 v1.8 以前手动建立 master 的配置 ConfigMap 。为了促进这项任务,kubeadm config upload (from-flags|from-file) 已经实施
标记 master
一旦控制平面可用,kubeadm 将执行如下操做:
- 用 node-role.kubernetes.io/master="" 给 master 增长标签
- 用 node-role.kubernetes.io/master:NoSchedule 给 master 增长污点
请注意:
- 标记 master 阶段能够经过 kubeadm alpha phase mark-master 命令单独调用
配置 TLS-引导 以加入节点
Kubeadm 使用 引导令牌进行身份验证 将新节点链接到现有集群; 欲了解更多详情,请参阅 设计方案。
kubeadm init 确保为此过程正确配置全部内容,这包括如下步骤以及设置 API server 和控制器标志,如前面几个段落中所述。
请注意:
- 可使用 kubeadm alpha phase bootstrap-token all 命令配置节点的 TLS 引导,执行如下段落中描述的全部配置步骤; 或者,每一个步骤均可以单独调用
建立一个引导令牌
kubeadm init 建立第一个引导令牌,能够自动生成或由用户使用 --token 标志提供; 在引导令牌规范中,令牌应该保存为命名空间 kube-system 下的 bootstrap-token-<token-id> secret 中。
请注意:
- 经过 kubeadm init 建立的默认令牌将用于 TLS 在引导过程当中验证临时用户;这些用户将成为 system:bootstrappers:kubeadm:default-node-token 组的成员
- 令牌的有效期有限,默认 24 小时(间隔可使用 —token-ttl 标志变动)
- 额外的令牌可使用 kubeadm token 命令建立,它还能够为令牌管理提供其余有用的功能
容许加入节点来调用 CSR API
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 来实现的。
建立公共集群信息 ConfigMap
此阶段在 kube-public 命名空间中建立 cluster-info ConfigMap。
此外,还建立了一个角色和一个 RoleBinding,为未经身份验证的用户授予对 ConfigMap 的访问权(即 RBAC 组中的用户 system:unauthenticated)
请注意:
- 访问 cluster-info ConfigMap 是不 受限制的。若是您将您的主机暴露在互联网上,这多是问题,也可能不是问题;最坏的状况是 DoS 攻击,攻击者使用 Kube-apiserver 能够处理的全部请求来为 cluster-info ConfigMap 提供服务。
安装插件
Kubeadm 经过 API server 安装内部 DNS 服务和 kube-proxy 插件组件。
请注意:
- 这个阶段能够经过 kubeadm alpha phase addon all 命令单独调用
代理
在命名空间 kube-system 下为 kube-proxy 建立一个 ServiceAccount;而后使用 DaemonSet 部署 kube-proxy:
- master 的凭证(ca.crt 和 token)来自 ServiceAccount
- master 的位置来自 ConfigMap
- kube-proxy ServiceAccount 绑定到 system:node-proxier ClusterRole 中的权限
DNS
在命名空间 kube-system 下为 kube-dns 建立一个 ServiceAccount。
部署 kube-dns 的 Deployment 和 Service:
- 这是相对上游来讲没有修改的 kube-dns 部署
- kube-dns ServiceAccount 绑定到 system:kube-dns ClusterRole 中的权限
请注意:
- 若是 kubeadm 被调用为 --feature-gates=CoreDNS,则会安装 CoreDNS 而不是 kube-dns
(可选,v1.9 中是 alpha)自托管
只有在 kubeadm init 被调用为 —features-gates=selfHosting 才执行此阶段
自托管阶段基本上用 DaemonSet 取代控制平面组件的静态 Pod; 这是经过执行 API server、scheduler 和 controller manager 静态 Pod 的如下过程来实现的:
- 从磁盘加载静态 Pod 规格
- 从静态的 Pod 清单文件中提取 PodSpec
- 改变 PodSpec 与自托管兼容,更详细的内容:
- 为带有 node-role.kubernetes.io/master="" 标签的节点增长节点选择器属性
- 为污点 node-role.kubernetes.io/master:NoSchedule 增长一个容忍
- 设置 spec.DNSPolicy 为 ClusterFirstWithHostNet
- 为有问题的自托管组件构建一个新的 DaemonSet 对象。使用上面提到的 PodSpec
- 在 kube-system 命名空间中建立 DaemonSet 资源。等到 Pod 运行。
- 删除静态的 Pod 清单文件。kubelet 将中止正在运行的原始静态 Pod 托管组件
请注意:
- 自托管还没有恢复到节点从新启动的能力; 这能够经过外部检查点或控制平面 Pod 的 kubelet 检查点来修正。有关更多详细信息,请参阅 自托管。
- 若是被调用为 —features-gates=StoreCertsInSecrets,如下附加步骤将被执行
- 在 kube-system 命名空间下使用各自的证书和秘钥建立 ca、apiserver、apiserver-kubelet-client、sa、front-proxy-ca、front-proxy-client TLS secrets 。重要!将 CA 密钥存储在 Secret 中可能会产生安全隐患
- 使用各自的 kubeconfig 文件在命名空间 kube-system 中建立 schedler.conf 和 controller-manager.conf secret
- 经过将主机路径卷替换为上述 secret 中的投影卷,对全部 POD 规范进行变动
- 这个阶段能够经过 kubeadm alpha phase selfhosting convert-from-staticpods 命令单独调用
kubeadm join 阶段的内部设计
与 kubeadm init 相似,kubeadm join 内部工做流也是由一系列要执行的原子工做任务组成。
这分为发现(有 Node 信任 Kubernetes Master)和 TLS 引导(有 Kubernetes Master 信任 Node)。
请参阅 使用引导令牌进行身份验证 或相应的 设计方案。
预检检查
kubeadm 在开始链接以前执行一组预检检查,目的是验证先决条件并避免常见的集群启动问题。
请注意:
- kubeadm join 预检检查基本上是一个 kubeadm init 预检检查的子集
- 从 1.9 开始,kubeadm 为 CRI 泛型功能提供了更好的支持; 在这种状况下,docker 特定的控件将被跳过或替换为 crictl 相似控件
- 从 1.9 开始,kubeadm 支持加入运行在 Windows 上的节点; 在这种状况下,会跳过 linux 特定的控制
- 在任何状况下,用户均可以使用该 --ignore-preflight-errors 选项跳过特定的预检检查(或最终全部预检检查)
发现集群信息
有两个主要的发现方案。首先是使用共享令牌以及 API server 的 IP 地址。第二个是提供一个文件(标准 kubeconfig 文件的一个子集)。
共享令牌发现
若是 kubeadm join 被调用为 --discovery-token,则使用令牌发现; 在这种状况下,节点基本上从命名空间 kube-public 下 cluster-info ConfigMap 中检索集群 CA 证书 。
为了防止 “中间人” 攻击,采起了几个步骤:
- 首先,经过不安全的链接检索 CA 证书(这是可能的,由于 kubeadm init 对 system:unauthenticated 授予了访问 cluster-info 用户的权限)
- 而后 CA 证书经过如下验证步骤:
- 基本验证:针对 JWT 签名使用令牌 ID
- 发布密钥验证:使用提供的 --discovery-token-ca-cert-hash。此值可在 kubeadm init 的输出中获取,也可使用标准工具计算(散列是在 SPKI(Subject Public Key Info)对象的字节上计算的,如 RFC 7469 中所示)。--discovery-token-ca-cert-hash 标志能够重复屡次,以容许多个公钥。 -做为附加验证,CA 证书经过安全链接进行检索,而后与最初检索的 CA 进行比较
请注意:
- 经过 --discovery-token-unsafe-skip-ca-verification 标志能够跳过发布密钥验证; 这削弱了 kubeadm 安全模型,由于其余人可能潜在模仿 Kubernetes Master。
文件/https 发现
若是 kubeadm join 被调用为 --discovery-file,则使用文件发现; 此文件能够是本地文件或经过 HTTPS URL 下载; 在 HTTPS 的状况下,主机安装的 CA 用于验证链接。
经过文件发现,集群 CA 证书被提供到文件自己; 事实上,发现的文件是一个 kubeconfig 文件,其中只设置了 server 和 certificate-authority-data 属性,如 kubeadm join 参考文档中所述; 当与集群创建链接时,kubeadm 尝试访问 cluster-info ConfigMap,若是可用,则使用它。
TLS 引导
一旦知道了集群信息,就会编写文件 bootstrap-kubelet.conf,从而容许 kubelet 执行 TLS 引导(相反,直到 v1.7 TLS 引导被 kubeadm 管理)。
TLS 引导机制使用共享令牌临时向 Kubernetes Master 进行身份验证,以提交本地建立的密钥对的证书签名请求(CSR)。
而后自动批准该请求,而且该操做完成保存 ca.crt 文件和用于加入集群的 kubelet.conf 文件,而 bootstrap-kubelet.conf 被删除。
请注意:
- 临时验证是根据 kubeadm init 过程当中保存的令牌进行验证的(或者使用 kubeadm token 建立的附加令牌)
- 对 kubeadm init 过程当中被授予访问 CSR api 的 system:bootstrappers:kubeadm:default-node-token 组的用户成员的临时身份验证解析
- 自动 CSR 审批由 csrapprover 控制器管理,与 kubeadm init 过程的配置相一致
(可选,1.9 版本中为 alpha)编写init kubelet配置
若是 kubeadm 被调用为 --feature-gates=DynamicKubeletConfig:
- 使用引导令牌凭据从 kube-system 命名空间中的 kubelet-base-config-v1.9 ConfigMap 中读取 kubelet 基本配置,并将其写入磁盘,做为 kubelet init 配置文件 /var/lib/kubelet/config/init/kubelet
- 当 kubelet 以节点本身的凭据(/etc/kubernetes/kubelet.conf)开始时,更新当前节点配置,指定 node/kubelet 配置的源是上面的 ConfigMap。
请注意:
- 要使动态 kubelet 配置正常工做,应在 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 中指定标志 --dynamic-config-dir=/var/lib/kubelet/config/dynamic
译者:chentao1596 / 原文连接