容器编排技术 -- kubeadm 实现细节

  • 1 核心设计原则
  • 2 常量和众所周知的值和路径
  • 3 kubeadm init 工作流程内部设计
    • 3.1 预检检查
    • 3.2 生成必要的证书
    • 3.3 为控制平面组件生成 kubeconfig 文件
    • 3.4 为控制平面组件生成静态 Pod 清单
      • 3.4.1 API server
      • 3.4.2 Controller manager
      • 3.4.3 Scheduler
    • 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.11.1 创建一个引导令牌
      • 3.11.2 允许加入节点来调用 CSR API
      • 3.11.3 为新的引导令牌设置自动批准
      • 3.11.4 通过自动批准设置节点证书轮换
      • 3.11.5 创建公共集群信息 ConfigMap
    • 3.12 安装插件
      • 3.12.1 代理
      • 3.12.2 DNS
    • 3.13 (可选,v1.9 中是 alpha)自托管
  • 4 kubeadm join 阶段的内部设计
    • 4.1 预检检查
    • 4.2 发现集群信息
      • 4.2.1 共享令牌发现
      • 4.2.2 文件/https 发现
  • 5 TLS 引导
    • 5.1 (可选,1.9 版本中为 alpha)编写init kubelet配置

kubeadm init 和 kubeadm join 为从头开始创建一个 Kubernetes 集群的最佳实践共同提供了一个很好的用户体验。但是,kubeadm 如何 做到这一点可能并不明显。

本文档提供了有关发生了什么事情的更多详细信息,旨在分享关于 Kubernetes 集群最佳实践的知识。

核心设计原则

使用 kubeadm init 和 kubeadm join 设置的集群应该:

  • 安全:

    • 它应该采用最新的最佳做法,如:

      • 强制实施 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 使用一组有限的常量值,用于众所周知的路径和文件名。

Kubernetes 目录 /etc/kubernetes 在应用中是一个常量,因为它明显是大多数情况下的给定路径,也是最直观的位置; 其他常量路径和文件名是:

  • /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 所述。

kubeadm alpha phase 命令允许用户单独调用每个任务,并最终提供可重用和可组合的 API/工具箱,可供其他 Kubernetes 引导工具、任何 IT 自动化工具或高级用户创建自定义集群使用。

预检检查

Kubeadm 在启动 init 之前执行一组预检检查,目的是验证先决条件并避免常见的集群启动问题。在任何情况下,用户都可以使用 --ignore-preflight-errors 选项跳过特定的预检检查(或最终所有预检检查)。

  • [警告]如果要使用的 Kubernetes 版本(与 --kubernetes-version 标记一起指定)至少比 kubeadm CLI 版本高一个次要版本
  • Kubernetes 系统要求:
    • 如果在 Linux 上运行:

      • [错误] 如果不是 Kernel 3.10+ 或具有特定 KernelSpec 的 4+
      • [错误] 如果需要的 cgroups 子系统没有设置
    • 如果使用 docker:
      • [警告/错误] 如果 Docker 服务不存在,如果它被禁用,如果它不是 active 状态
      • [错误] 如果 Docker 端点不存在或不起作用
      • [警告] 如果 docker 版本 > 17.03
    • 如果使用其他 cri 引擎:
      • [错误] 如果 crictl 没有响应
  • [错误] 如果用户不是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 不存在

请注意:

  1. 预检检查可以通过 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 标志进行配置。

请注意:

  1. 如果给定的证书和私钥对都存在,并且其内容评估符合上述规范,则将使用现有文件并跳过给定证书的生成阶段。这意味着用户可以将现有 CA 复制到 /etc/kubernetes/pki/ca.{crt,key},然后 kubeadm 将使用这些文件来签署剩余的证书。请参与 使用自定义证书
  2. 只有 CA 可以提供 ca.crt 文件,但不提供 ca.key 文件,如果所有其他证书和 kubeconfig 文件已就位,kubeadm 会识别此情况并激活 ExternalCA,这也意味着 controller-manager 中的 csrsigner 控制器将不会启动
  3. 如果 kubeadm 在 ExternalCA 模式下运行; 所有的证书都必须由用户提供,因为 kubeadm 本身不能生成它们
  4. 在 --dry-run 模式中执行 kubeadm 的情况下,证书文件被写入临时文件夹中
  5. 使用 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

请注意:

  1. ca.crt 证书嵌入在所有 kubeconfig 文件中。
  2. 如果给定的 kubeconfig 文件存在,并且其内容的评估符合上述规范,则将使用现有文件,并跳过给定 kubeconfig 的生成阶段
  3. 如果 kubeadm 以 ExternalCA 模式运行,则所有必需的 kubeconfig 也必须由用户提供,因为 kubeadm 本身不能生成它们中的任何一个
  4. 如果在 --dry-run 模式下执行 kubeadm ,kubeconfig 文件将写入临时文件夹中
  5. 使用 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 都会获取用户指定的任何额外卷(主机路径)

请注意:

  1. --kubernetes-version 当前体系结构中的所有镜像 将从中 gcr.io/google_containers 中拉取; 如果指定了其他镜像仓库库或 CI 镜像仓库,则将使用此仓库; 如果一个特定的容器镜像应该被用于所有控制平面组件,那么这个特定镜像将被使用。请参阅 使用自定义镜像 了解更多详情
  2. 如果在 --dry-run 模式下执行 kubeadm,则将静态 Pod 文件写入临时文件夹
  3. 可以使用 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 挂载到 主机文件系统
  • 任何由用户指定的额外标志

请注意:

  1. etcd 镜像将从中 gcr.io/google_containers 中拉取; 如果指定了其他镜像仓库库,则将使用此仓库; 如果一个特定的容器镜像应该被用于所有控制平面组件,那么这个特定镜像将被使用。请参阅 使用自定义镜像 了解更多详情
  2. 如果在 --dry-run 模式下执行 kubeadm,则将静态 Pod 文件写入临时文件夹
  3. 可以使用 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 参数 以获取更多信息。

请注意:

  1. 要使动态 kubelet 配置正常工作,应该在 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 中指定标志 --dynamic-config-dir=/var/lib/kubelet/config/dynamic
  2. 通过设置.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:

  1. 将 kubelet 基本配置写入命名空间 kube-system 的 kubelet-base-config-v1.9 ConfigMap 中
  2. 创建 RBAC 规则来授予该 ConfigMap 对所有引导令牌和所有 kubelet 实例(即组 system:bootstrappers:kubeadm:default-node-token 和 system:nodes)的读访问权限
  3. 通过将 Node.spec.configSource 指向新创建的 ConfigMap 来为初始主节点启用动态 kubelet 配置功能

将 kubeadm MasterConfiguration 保存在 ConfigMap 中供以后参考

kubeadm 将 kubeadm init 通过标志或配置文件传递给 ConfigMap 的配置保存在 kube-system 命名空间下的 kubeadm-config ConfigMap 中。

这将确保将来(例如 kubeadm upgrade)执行的 kubeadm 行动将能够确定 实际/当前 的集群状态并基于该数据做出新的决定。

请注意:

  1. 在上传之前,敏感信息(例如令牌)会从配置中删除
  2. 主配置的上传可以通过 kubeadm alpha phase upload-config 命令单独调用
  3. 如果您使用 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 增加污点

请注意:

  1. 标记 master 阶段可以通过 kubeadm alpha phase mark-master 命令单独调用

配置 TLS-引导 以加入节点

Kubeadm 使用 引导令牌进行身份验证 将新节点连接到现有集群; 欲了解更多详情,请参阅 设计方案。

kubeadm init 确保为此过程正确配置所有内容,这包括以下步骤以及设置 API server 和控制器标志,如前面几个段落中所述。

请注意:

  1. 可以使用 kubeadm alpha phase bootstrap-token all 命令配置节点的 TLS 引导,执行以下段落中描述的所有配置步骤; 或者,每个步骤都可以单独调用

创建一个引导令牌

kubeadm init 创建第一个引导令牌,可以自动生成或由用户使用 --token 标志提供; 在引导令牌规范中,令牌应该保存为命名空间 kube-system 下的 bootstrap-token-<token-id> secret 中。

请注意:

  1. 通过 kubeadm init 创建的默认令牌将用于 TLS 在引导过程中验证临时用户;这些用户将成为 system:bootstrappers:kubeadm:default-node-token 组的成员
  2. 令牌的有效期有限,默认 24 小时(间隔可以使用 —token-ttl 标志变更)
  3. 额外的令牌可以使用 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)

请注意:

  1. 访问 cluster-info ConfigMap 是不 受限制的。如果您将您的主机暴露在互联网上,这可能是问题,也可能不是问题;最坏的情况是 DoS 攻击,攻击者使用 Kube-apiserver 可以处理的所有请求来为 cluster-info ConfigMap 提供服务。

安装插件

Kubeadm 通过 API server 安装内部 DNS 服务和 kube-proxy 插件组件。

请注意:

  1. 这个阶段可以通过 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 中的权限

请注意:

  1. 如果 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 托管组件

请注意:

  1. 自托管尚未恢复到节点重新启动的能力; 这可以通过外部检查点或控制平面 Pod 的 kubelet 检查点来修正。有关更多详细信息,请参阅 自托管。
  2. 如果被调用为 —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 规范进行变更
  3. 这个阶段可以通过 kubeadm alpha phase selfhosting convert-from-staticpods 命令单独调用

kubeadm join 阶段的内部设计

与 kubeadm init 类似,kubeadm join 内部工作流也是由一系列要执行的原子工作任务组成。

这分为发现(有 Node 信任 Kubernetes Master)和 TLS 引导(有 Kubernetes Master 信任 Node)。

请参阅 使用引导令牌进行身份验证 或相应的 设计方案。

预检检查

kubeadm 在开始连接之前执行一组预检检查,目的是验证先决条件并避免常见的集群启动问题。

请注意:

  1. kubeadm join 预检检查基本上是一个 kubeadm init 预检检查的子集
  2. 从 1.9 开始,kubeadm 为 CRI 泛型功能提供了更好的支持; 在这种情况下,docker 特定的控件将被跳过或替换为 crictl 类似控件
  3. 从 1.9 开始,kubeadm 支持加入运行在 Windows 上的节点; 在这种情况下,会跳过 linux 特定的控制
  4. 在任何情况下,用户都可以使用该 --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 进行比较

请注意:

  1. 通过 --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:

  1. 使用引导令牌凭据从 kube-system 命名空间中的 kubelet-base-config-v1.9 ConfigMap 中读取 kubelet 基本配置,并将其写入磁盘,作为 kubelet init 配置文件 /var/lib/kubelet/config/init/kubelet
  2. 当 kubelet 以节点自己的凭据(/etc/kubernetes/kubelet.conf)开始时,更新当前节点配置,指定 node/kubelet 配置的源是上面的 ConfigMap。

请注意:

  1. 要使动态 kubelet 配置正常工作,应在 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 中指定标志 --dynamic-config-dir=/var/lib/kubelet/config/dynamic

译者:chentao1596 / 原文链接

容器编排技术 -- kubeadm 实现细节相关推荐

  1. 容器编排技术 -- Kubernetes DNS Pod 与 Service 介绍

    容器编排技术 -- Kubernetes DNS Pod 与 Service 介绍 1 介绍 2 怎样获取 DNS 名字? 3 支持的 DNS 模式 3.1 Service 3.1.1 A 记录 3. ...

  2. 容器编排技术 -- Kubernetes 调试 Service

    容器编排技术 -- Kubernetes 调试 Service 1 约定 2 在 pod 中运行命令 3 安装 4 Service 存在吗? 5 Service 是否通过 DNS 工作? 5.1 DN ...

  3. 容器编排技术 -- Kubernetes Service

    容器编排技术 -- Kubernetes Service 1 定义 Service 1.1 没有 selector 的 Service 2 VIP 和 Service 代理 2.1 userspace ...

  4. 容器编排技术 -- Kubernetes Ingress解析

    容器编排技术 -- Kubernetes Ingress解析 前言 这是kubernete官方文档中Ingress Resource的翻译,因为最近工作中用到,文章也不长,也很好理解,索性翻译一下,也 ...

  5. 容器编排技术 -- Kubernetes Volume

    容器编排技术 -- Kubernetes Volume 1 背景 2 Volume 类型 2.1 emptyDir 2.2 hostPath 2.3 gcePersistentDisk 2.4 aws ...

  6. 容器编排技术 -- Kubernetes从零开始搭建自定义集群

    容器编排技术 -- Kubernetes从零开始搭建自定义集群 1 设计和准备 1.1 学习 1.2 Cloud Provider 1.3 节点 1.4 网络 1.4.1 网络连接 1.4.2 网络策 ...

  7. 容器编排技术 -- Kubernetes 设计理念

    容器编排技术 -- Kubernetes 设计理念 1 Kubernetes 设计理念 1.1 Kubernetes设计理念与分布式系统 1.2 API设计原则 1.3 控制机制设计原则 2 Kube ...

  8. 容器编排技术 -- AWS EC2快速入门

    容器编排技术 -- AWS EC2快速入门 前提条件 1.您需要一个AWS账户,访问http://aws.amazon.com获得. 2.安装并配置AWS命令行界面. 3.你需要一个拥有EC2全部权限 ...

  9. 容器编排技术 -- Google Computer Engine入门

    容器编排技术 --  Google Computer Engine入门 下面的例子用4个节点虚拟机和1个主虚拟机(也就是说集群中使用了5个虚拟机)创建了一个Kubernetes集群.您可以在您的工作站 ...

最新文章

  1. Unable to inject views for 包名.activity
  2. 【转载】混合高斯模型(Mixtures of Gaussians)和EM算法
  3. 菜鸟教程 php跨域,PHP Ajax 跨域问题最佳解决方案
  4. 前端之javaScript
  5. 华为服务器bmc默认地址_智能数据中心和智慧园区:华为的单点突破与全局效应...
  6. 【C++】异常 Exception
  7. C# 循环语句 for
  8. 利用python自动清除Android工程中的多余资源
  9. Linux学习之CentOS6下Mysql数据库的安装与配置
  10. Spring(一):简介
  11. Shell脚步学习指南提点
  12. hibernate教程笔记5
  13. Java基础编程题(API阶段测试)
  14. 暑期作息时间表模板_最新暑假作息时间表excel模板-暑假作息时间模板
  15. 新网银行模型竞赛点评-小微风控算法大赛-早期风险识别
  16. Pygame制作音乐播放器
  17. 如何才能降低亚马逊账号关联?
  18. AirPods pro 连接Macbook pro左耳无声音
  19. 【C语言入门】笔记八 (数组中)
  20. 贝勒大学计算机专业,详细介绍美国贝勒大学之计算机科学

热门文章

  1. 用dynamic增强C#泛型表达力
  2. Python读取PDF
  3. redis——redis事务相关处理
  4. linux之RAID知识总结
  5. 【今日CV 计算机视觉论文速览】Thu, 28 Mar 2019
  6. Ubuntu 16.04 卸载vmware
  7. 草稿 ktv 航版 1211 rs ga 打开文件控件 文件的复制操作
  8. 双层循环嵌套打印矩形 java
  9. 下载chrome驱动 for selenium库
  10. 一个在PDO数据绑定上踩的坑