--- title: kubeadm init content_template: templates/concept weight: 20 --- {{% capture overview %}} 此命令初始化一个 Kubernetes master 节点 {{% /capture %}} {{% capture body %}} {{< include "generated/kubeadm_init.md" >}} ### Init 命令的工作流程 {#init-workflow} `kubeadm init` 命令通过执行下列步骤来启动一个 Kubernetes master 节点。 1. 在做出变更前运行一系列的预检项来验证系统状态。 一些检查项目仅仅触发警告,其它的则会被视为错误并且退出 kubeadm,除非问题被解决或者用户指定了 `--ignore-preflight-errors=` 参数。 2. 生成一个自签名的 CA证书 (或者使用现有的证书,如果提供的话) 来为集群中的每一个组件建立身份标识。如果用户已经通过 `--cert-dir` 配置的证书目录(缺省值为 `/etc/kubernetes/pki`)提供了他们自己的 CA证书 以及/或者 密钥, 那么将会跳过这个步骤,正如文档[使用自定义证书](#custom-certificates)中所描述的那样。 如果指定了 `--apiserver-cert-extra-sans` 参数, APIServer 的证书将会有额外的 SAN 条目,如果必要的话,将会被转为小写。 1. 将 kubeconfig 文件写入 `/etc/kubernetes/` 目录以便 kubelet、controller-manager 和 scheduler 用来连接到 API server,它们每一个都有自己的身份标识,同时生成一个名为 admin.conf 的独立的 kubeconfig 文件,用于管理操作。 4. 如果 kubeadm 被调用时附带了 `--feature-gates=DynamicKubeletConfig` 参数, 它会将 kubelet 的初始化配置写入 `/var/lib/kubelet/config/init/kubelet` 文件中。 参阅 [通过配置文件设置 Kubelet 参数](/docs/tasks/administer-cluster/kubelet-config-file/)以及 [在一个现有的集群中重新配置节点的 Kubelet 设置](/docs/tasks/administer-cluster/reconfigure-kubelet/)来获取更多关于动态配置 Kubelet 的信息。 这个功能现在是默认关闭的,正如你所见它通过一个功能开关控制开闭, 但是在未来的版本中很有可能会默认启用。 5. 为 API server、controller manager 和 scheduler 生成静态 Pod 的清单文件。假使没有提供一个外部的 etcd 服务的话,也会为 etcd 生成一份额外的静态 Pod 清单文件。 静态 Pod 的清单文件被写入到 `/etc/kubernetes/manifests` 目录; kubelet 会监视这个目录以便在系统启动的时候创建 Pods。 一旦 control plane 的 Pods 都运行起来, `kubeadm init` 的工作流程就继续往下执行。 1. 如果 kubeadm 被调用时附带了 `--feature-gates=DynamicKubeletConfig` 参数, 它将创建一份 ConfigMap 和一些便于 kubelet 访问这份 ConfigMap 的 RBAC 规则,并且通过将 `Node.spec.configSource` 指向到新创建的 ConfigMap 来更新节点设置。这样它就完成了对 Kubelet 的动态配置。 这个功能现在是默认关闭的,正如你所见它通过一个功能开关控制开闭, 但是在未来的版本中很有可能会默认启用。 2. 对 master 节点应用 labels 和 taints 以便不会在它上面运行其它的工作负载。 3. 生成令牌以便其它节点以后可以使用这个令牌向 master 节点注册它们自己。 可选的,用户可以通过 `--token` 提供一个令牌, 正如文档[kubeadm 的令牌](/docs/reference/setup-tools/kubeadm/kubeadm-token/) 描述的那样。 4. 为了使得节点能够遵照 [Bootstrap Tokens](/docs/reference/access-authn-authz/bootstrap-tokens/) 和 [TLS Bootstrap](/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/)这两份文档中描述的机制加入到集群中,kubeadm 会执行所有的必要配置: - 创建一份 ConfigMap 提供添加集群节点所需的信息,并为该 ConfigMap 设置相关的 RBAC 访问规则。 - 使得 Bootstrap Tokens 可以访问 CSR 签名 API。 - 对新的 CSR 请求配置为自动签发。 查阅 [kubeadm join](/docs/reference/setup-tools/kubeadm/kubeadm-join/) 文档以获取更多信息。 1. 通过 API server 安装一个 DNS 服务器 (CoreDNS) 和 kube-proxy 附加组件。 在 1.11 版本以及更新版本的 Kubernetes 中 CoreDNS 是默认的 DNS 服务器。 如果要安装 kube-dns 而不是 CoreDNS, 你需要在调用 kubeadm 的时候附加 `--feature-gates=CoreDNS=false` 参数。请注意,尽管 DNS 服务器已经被部署了,它并不会被调度直到你安装好了 CNI 网络插件。 2. 如果调用 `kubeadm init` 命令时启用了 alpha 状态的 self-hosting 功能(`--feature-gates=SelfHosting=true`),基于静态 Pod 的 control plane 将被转换为 [self-hosted control plane](#self-hosting)。 ### 结合一份配置文件来使用 kubeadm init {#config-file} {{< caution >}} **注意:** 配置文件的功能仍然处于 alpha 状态并且在将来的版本中可能会改变。 {{< /caution >}} 通过一份配置文件而不是使用命令行参数来配置 `kubeadm init` 命令是可能的,并且一些更加高级的功能只能够通过配置文件设定。 这份配置文件通过 `--config` 选项参数指定。 在 Kubernetes 1.11 以及之后的版本中,默认的配置可以通过 [kubeadm config print-default](/docs/reference/setup-tools/kubeadm/kubeadm-config/) 命令打印出来。 **推荐**使用 [kubeadm config migrate](/docs/reference/setup-tools/kubeadm/kubeadm-config/) 命令将你的旧的 `v1alpha3` 版本的配置迁移到 `v1beta1` 版本。因为在 Kubernetes 1.14 版本中将会移除对 `v1alpha3` 这个版本的支持。 如果你想获取 `v1beta1` 版本配置中每个字段的细节说明,你可以查看我们的[API reference 页面]。 (https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1) ### 添加 kube-proxy 参数 {#kube-proxy} kubeadm 配置中有关 kube-proxy 的说明请查看: - [kube-proxy](https://godoc.org/k8s.io/kubernetes/pkg/proxy/apis/config#KubeProxyConfiguration) 使用 kubeadm 启用 IPVS 模式的说明请查看: - [IPVS](https://github.com/kubernetes/kubernetes/blob/master/pkg/proxy/ipvs/README.md) ### 向 control plane 组件传递自定义的 flags {#control-plane-flags} 有关向 control plane 组件传递 flags 的说明请查看: - [control-plane-flags](/docs/setup/independent/control-plane-flags/) ### 使用自定义的镜像 {#custom-images} 默认情况下, kubeadm 会从 `k8s.gcr.io` 仓库拉取镜像, 除非请求的 Kubernetes 版本是一个持续集成版本。这这种情况下,则会使用 `gcr.io/kubernetes-ci-images` 仓库。 你可以通过这份文档里描述的方法 [结合一份配置文件来使用 kubeadm](#config-file) 来改变镜像拉取的策略。 允许的自定义功能有: * 提供一个替代的镜像仓库 `imageRepository` 而不是使用 `k8s.gcr.io`。 * 提供一个统一的 Control Plane 镜像 `unifiedControlPlaneImage` 而不是对每一个 control plane 组件使用不同的镜像。 * 提供一个指定的 etcd 服务的镜像 `etcd.image` 而不是在 `k8s.gcr.io` 仓库中的可用镜像。 请注意配置文件中的配置项 `kubernetesVersion` 或者命令行参数 `--kubernetes-version` 会影响到镜像的版本。 ### 使用自定义的证书 {#custom-certificates} 默认情况下, kubeadm 会生成运行一个集群所需的全部证书。 你可以通过提供你自己的证书来改变这个行为策略。 如果要这样做, 你必须将证书文件放置在通过 `--cert-dir` 命令行参数或者配置文件里的 `CertificatesDir` 配置项指明的目录中。默认的值是 `/etc/kubernetes/pki`。 如果给定的证书和密钥对已经存在,kubeadm 将会跳过生成证书的步骤并且直接将已经存在的文件用于规定的案例中。也就是说你可以拷贝一份已存在的 CA 文件到 `/etc/kubernetes/pki/ca.crt` 和 `/etc/kubernetes/pki/ca.key`,kubeadm将会使用这份 CA 来签发其余的证书。 #### 外部 CA 模式 {#external-ca-mode} 如果只提供了 `ca.crt` 文件但是没有提供 `ca.key` 文件也是可以的 (这只对 CA 根证书可用,其它证书不可用)。 如果所有的其它证书和 kubeconfig 文件已就位, kubeadm 检测到满足以上条件就会激活 "外部 CA" 模式。 kubeadm 将会在没有 CA 密钥文件的情况下继续执行。 否则, kubeadm 将独立运行 controller-manager,附加一个 `--controllers=csrsigner` 的参数,并且指明 CA 证书和密钥。 ### 管理 kubeadm 为 kubelet 提供的 systemd 配置文件 {#kubelet-drop-in} kubeadm 包自带了关于 kubelet 应该如何运行的配置文件。请注意 `kubeadm` 客户端命令行工具永远不会修改这份 systemd 配置文件。这份 systemd 配置文件属于 kubeadm deb/rpm 包。 这份文件应该看起来像这样: ``` [Service] Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" Environment="KUBELET_SYSTEM_PODS_ARGS=--pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=true" Environment="KUBELET_NETWORK_ARGS=--network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin" Environment="KUBELET_DNS_ARGS=--cluster-dns=10.96.0.10 --cluster-domain=cluster.local" Environment="KUBELET_AUTHZ_ARGS=--authorization-mode=Webhook --client-ca-file=/etc/kubernetes/pki/ca.crt" Environment="KUBELET_CADVISOR_ARGS=" Environment="KUBELET_CERTIFICATE_ARGS=--rotate-certificates=true --cert-dir=/var/lib/kubelet/pki" ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_SYSTEM_PODS_ARGS $KUBELET_NETWORK_ARGS $KUBELET_DNS_ARGS $KUBELET_AUTHZ_ARGS $KUBELET_CADVISOR_ARGS $KUBELET_CERTIFICATE_ARGS $KUBELET_EXTRA_ARGS ``` 以下是这份文件的详解: * `--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf` 一份 kubeconfig 文件的路径,在加入节点时这份文件被 kubelet 用于获取客户端证书。如果证书获取成功, 一份 kubeconfig 文件将会被写入到由 `--kubeconfig` 参数指明的路径。 * `--kubeconfig=/etc/kubernetes/kubelet.conf` 指向 kubeconfig 文件,这份文件为 kubelet 指明 API server 的地址。这份文件也包含了 kubelet 的证书。 * `--pod-manifest-path=/etc/kubernetes/manifests` 指明从哪里读取静态 Pod 的清单文件用于启动 control plane。 * `--allow-privileged=true` 允许 kubelet 运行 privileged Pods。 * `--network-plugin=cni` 使用 CNI 网络。 * `--cni-conf-dir=/etc/cni/net.d` 指明从哪里查找[CNI 规格文件](https://github.com/containernetworking/cni/blob/master/SPEC.md)。 * `--cni-bin-dir=/opt/cni/bin` 指明从哪里查找实际使用的 CNI 二进制文件。 * `--cluster-dns=10.96.0.10` 使用这个集群内部的 DNS 服务器作为 Pods 内 `/etc/resolv.conf` 文件中`nameserver` 的设定值。 * `--cluster-domain=cluster.local` 使用这个集群内部的 DNS 域名作为 Pods 内 `/etc/resolv.conf` 文件中`search` 的设定值。 * `--client-ca-file=/etc/kubernetes/pki/ca.crt` 使用这个 CA 证书认证发往 Kubelet API 的请求。 * `--authorization-mode=Webhook` 通过 `POST` 方法向 API server 发送一个 `SubjectAccessReview` 对象来授权发往 Kubelet API 的请求。 * `--rotate-certificates` 当证书临近过期的时候,通过从 `kube-apiserver` 请求新证书来自动替换 kubelet 客户端证书。 * `--cert-dir` TLS 证书所在的目录。 ### 结合 CRI 运行时使用 kubeadm 从v1.6.0版本开始, Kubernetes 默认启用了 CRI, 容器运行时接口。 默认使用的容器运行时是 Docker, 这通过 `kubelet` 内置的 `dockershim` CRI 实现支持。 其它的基于 CRI 的运行时包括: - [cri-containerd](https://github.com/containerd/cri-containerd) - [cri-o](https://github.com/kubernetes-incubator/cri-o) - [frakti](https://github.com/kubernetes/frakti) - [rkt](https://github.com/kubernetes-incubator/rktlet) 查阅 [CRI 安装指南](/docs/setup/cri) 获取更多信息。 在你成功安装了 `kubeadm` 和 `kubelet` 工具后, 执行这两个额外的步骤: 1. 遵照以上列出的 runtime shim 项目中的安装文档,在每一个节点上安装 runtime shim。 2. 配置 kubelet 使用远程 CRI 运行时。对应你自己环境,请记得改变 `RUNTIME_ENDPOINT` 的值,这个值类似 `/var/run/{your_runtime}.sock`: ```shell cat > /etc/systemd/system/kubelet.service.d/20-cri.conf < 现在 `kubelet` 已经准备好使用指定的 CRI 运行时了, 你可以继续使用 `kubeadm init` 和 `kubeadm join` 工作流来部署你的 Kubernetes 集群。 当使用一个外部的 CRI 实现时, 你也许也想为 `kubeadm init` 和 `kubeadm reset` 设置 `--cri-socket`。 ### 在你的集群中使用内网 IP 为了配置一个 master 与 worker 节点间使用内网 IP 地址通信的集群(而不是使用公网地址),执行以下操作。 1. 当运行 init 命令的时候, 你必须为 API server 指定一个内网 IP 作为监听地址,像这样: `kubeadm init --apiserver-advertise-address=` 2. 当一个 master 或者 worker 节点可供使用时,向 `/etc/systemd/system/kubelet.service.d/10-kubeadm.conf` 文件添加一个标记指明 worker 节点的私有 IP。 `--node-ip=` 3. 最后, 当你运行 `kubeadm join` 的时候, 确保你提供了正确的 API server 所在的、步骤 1 中定义的私有 IP。 ### 设置节点的名称 默认情况下, `kubeadm` 基于机器的 host 地址分配一个节点名称。你可以使用 `--node-name` 参数覆盖这个设置。 这个参数会向 kubelet 传递相应的 [`--hostname-override`](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/#options) 参数。 注意覆盖主机名称可能会 [干扰到云服务提供商](https://github.com/kubernetes/website/pull/8873)。 ### Self-hosting Kubernetes control plane {#self-hosting} 从1.8开始, 你可以试验性地创建一个 _self-hosted_ Kubernetes control plane. 这意味着诸如 API server、controller manager、 以及 scheduler 这些关键组件将作为通过 Kubernetes API 配置的 [DaemonSet pods](/docs/concepts/workloads/controllers/daemonset/) 运行,而不是在 kubelet 中通过静态文件配置的 [static pods](/docs/tasks/administer-cluster/static-pod/)。 若要创建一个 self-hosted 的集群, 向 `kubeadm init` 命令传递 `--feature-gates=SelfHosting=true` 参数。 {{< caution >}} **小心:** `SelfHosting` 还是一个 alpha 功能。它在 1.12 版本中被标记为废弃,并且将在 1.13 版本中移除。 {{< /caution >}} {{< warning >}} **警告:** 查看有关 self-hosted 的注意事项和限制。 {{< /warning >}} #### 注意事项 1.8 版本中的 Self-hosting 功能有一些重要的限制。特别的, 一个 self-hosted 的集群如果不手动介入的话 _不能够从 master node 的重新启动中恢复_ 。 这个以及其它的一些限制被期望在 self-hosting 功能从 alpha 状态毕业前解决。 默认情况下, self-hosted control plane Pods 依赖位于 [`hostPath`](https://kubernetes.io/docs/concepts/storage/volumes/#hostpath) 数据卷中的证书。除了初始化创建证书的过程, 这些证书不被 kubeadm 管理。你可以使用 `--feature-gates=StoreCertsInSecrets=true` 参数来启用一个试验性的模式,在这个模式中 control plane 证书从 Secrets 加载。 这要求对你的集群进行非常小心的对鉴权和授权配置的控制, 并且可能并不适合你的环境。 {{< caution >}} **小心:** `StoreCertsInSecrets` 是一个 alpha 功能。 它在 1.12 版本中被标记为废弃,并且将在 1.13 版本中移除。 {{< /caution >}} 在 kubeadm 1.8 版本中, control plane 的 self-hosted 的组件并不包含 etcd,它仍然是作为静态 Pod 运行的。 #### 流程 self-hosting 集群的启动过程写在了这份 [kubeadm 设计文档](https://github.com/kubernetes/kubeadm/blob/master/docs/design/design_v1.9.md#optional-self-hosting) 文档中。 总的说来, `kubeadm init --feature-gates=SelfHosting=true` 是按照以下步骤工作的: 1. 等待 control plane 的相关组件成功运行起来。这与没有启用 self-hosting 的 `kubeadm init` 指令的流程是一致的。 2. 使用静态的 control plane Pod 清单文件构建一个 DaemonSet 清单文件用来运行 self-hosted control plane。有时也会在必要的时候修改这些清单文件,比如为 secrets 添加新的数据卷。 3. 在 `kube-system` 命名空间下创建 DaemonSets 并且等待相应的 Pods 运行起来。 4. 一旦 self-hosted Pods 可供使用了, 它们相关的静态 Pods 就会被删除并且 kubeadm 继续安装下一个组件。这将触发 kubelet 停止这些静态 Pods。 5. 当原始的 static control plane 停止的时候, 新创建的 self-hosted control plane 就能够绑定到端口并且可供使用。 这个过程 (3-6步) 也可以通过 `kubeadm phase selfhosting convert-from-staticpods` 指令触发。 ### 在没有互联网连接的情况下运行 kubeadm 如果要在没有网络的情况下运行 kubeadm,你需要预先拉取所选版本的主要镜像: | Image Name | v1.10 release branch version | |--------------------------------------------|------------------------------| | k8s.gcr.io/kube-apiserver-${ARCH} | v1.10.x | | k8s.gcr.io/kube-controller-manager-${ARCH} | v1.10.x | | k8s.gcr.io/kube-scheduler-${ARCH} | v1.10.x | | k8s.gcr.io/kube-proxy-${ARCH} | v1.10.x | | k8s.gcr.io/etcd-${ARCH} | 3.1.12 | | k8s.gcr.io/pause-${ARCH} | 3.1 | | k8s.gcr.io/k8s-dns-sidecar-${ARCH} | 1.14.8 | | k8s.gcr.io/k8s-dns-kube-dns-${ARCH} | 1.14.8 | | k8s.gcr.io/k8s-dns-dnsmasq-nanny-${ARCH} | 1.14.8 | | coredns/coredns | 1.0.6 | 此处 `v1.10.x` 意为 "v1.10 分支上的最新的 patch release"。 `${ARCH}` 可以是以下的值: `amd64`, `arm`, `arm64`, `ppc64le` 或者 `s390x`。 如果你运行1.10或者更早版本的 Kubernetes,并且你设置了 `--feature-gates=CoreDNS=true`, 你必须也使用 `coredns/coredns` 镜像, 而不是使用三个 `k8s-dns-*` 镜像。 在 Kubernetes 1.11版本以及之后的版本中,你可以使用 `kubeadm config images` 的子命令来列出和拉取相关镜像: ``` kubeadm config images list kubeadm config images pull ``` 从 Kubernetes 1.12 版本开始, `k8s.gcr.io/kube-*`、 `k8s.gcr.io/etcd` 和 `k8s.gcr.io/pause` 镜像不再要求 `-${ARCH}` 后缀。 ### kubeadm 自动化 与其如文档 [kubeadm 基础教程](/docs/setup/independent/create-cluster-kubeadm/) 所述,将从 `kubeadm init` 取得的令牌拷贝到每一个节点, 倒不如你可以使用更加简单的自动化的方式将令牌并行地分发出去。如果要实现这个自动化,你必须要知道 master node 启动后的 IP 地址。 1. 生成一个令牌. 这个令牌必须具有以下格式:`<6个字符的字符串>.<16字符的字符串>`。更加正式地说法是,它必须符合以下正则表达式: `[a-z0-9]{6}\.[a-z0-9]{16}`。 kubeadm 可以为你生成一个令牌: ```bash kubeadm token generate ``` 2. 使用这个令牌同时启动 master node 和 worker nodes。它们一旦运行起来应该就会互相寻找对方并且建立集群。同样的 `--token` 参数可以同时用于 `kubeadm init` 和 `kubeadm join` 命令。 一旦集群启动起来,你就可以从 master node 的 `/etc/kubernetes/admin.conf` 文件获取管理凭证,然后你就可以使用这个凭证同集群通信了。 注意这种搭建集群的方式在安全保证上会有一些宽松,因为这种方式不允许使用 `--discovery-token-ca-cert-hash` 来验证根 CA 的哈希值(因为当配置节点的时候,它还没有被生成)。如需更多信息,请参阅 [kubeadm join](/docs/reference/setup-tools/kubeadm/kubeadm-join/) 文档。 {{% /capture %}} {{% capture whatsnext %}} * [kubeadm join](/docs/reference/setup-tools/kubeadm/kubeadm-join/) 启动一个 Kubernetes worker node 并且将其加入到集群 * [kubeadm upgrade](/docs/reference/setup-tools/kubeadm/kubeadm-upgrade/) 将 Kubernetes 集群升级到新版本 * [kubeadm reset](/docs/reference/setup-tools/kubeadm/kubeadm-reset/) 使用 `kubeadm init` 或者 `kubeadm join`来恢复对节点的改变 {{% /capture %}}