1 - 运行于多可用区环境
本页描述如何跨多个区(Zone)中运行集群。
背景
Kubernetes 从设计上允许同一个 Kubernetes 集群跨多个失效区来运行, 通常这些去位于某个称作 区域(region) 逻辑分组中。 主要的云提供商都将区域定义为一组失效区的集合(也称作 可用区(Availability Zones)), 能够提供一组一致的功能特性:每个区域内,各个可用区提供相同的 API 和服务。
典型的云体系结构都会尝试降低某个区中的失效影响到其他区中服务的概率。
控制面行为
所有的控制面组件 都支持以一组可相互替换的资源池的形式来运行,每个组件都有多个副本。
当你部署集群控制面时,应将控制面组件的副本跨多个失效区来部署。 如果可用性是一个很重要的指标,应该选择至少三个失效区,并将每个 控制面组件(API 服务器、调度器、etcd、控制器管理器)复制多个副本, 跨至少三个失效区来部署。如果你在运行云控制器管理器,则也应该将 该组件跨所选的三个失效区来部署。
说明:Kubernetes 并不会为 API 服务器端点提供跨失效区的弹性。 你可以为集群 API 服务器使用多种技术来提升其可用性,包括使用 DNS 轮转、SRV 记录或者带健康检查的第三方负载均衡解决方案等等。
节点行为
Kubernetes 自动为负载资源(如Deployment 或 StatefulSet)) 跨集群中不同节点来部署其 Pods。 这种分布逻辑有助于降低失效带来的影响。
节点启动时,每个节点上的 kubelet 会向 Kubernetes API 中代表该 kubelet 的 Node 对象 添加 标签。 这些标签可能包含区信息。
如果你的集群跨了多个可用区或者地理区域,你可以使用节点标签,结合 Pod 拓扑分布约束 来控制如何在你的集群中多个失效域之间分布 Pods。这里的失效域可以是 地理区域、可用区甚至是特定节点。 这些提示信息使得调度器 能够更好地分布 Pods,以实现更好的可用性,降低因为某种失效给整个工作负载 带来的风险。
例如,你可以设置一种约束,确保某个 StatefulSet 中的三个副本都运行在 不同的可用区中,只要其他条件允许。你可以通过声明的方式来定义这种约束, 而不需要显式指定每个工作负载使用哪些可用区。
跨多个区分布节点
Kubernetes 的核心逻辑并不会帮你创建节点,你需要自行完成此操作,或者使用 类似 Cluster API 这类工具来替你管理节点。
使用类似 Cluster API 这类工具,你可以跨多个失效域来定义一组用做你的集群 工作节点的机器,以及当整个区的服务出现中断时如何自动治愈集群的策略。
为 Pods 手动指定区
你可以应用节点选择算符约束 到你所创建的 Pods 上,或者为 Deployment、StatefulSet 或 Job 这类工作负载资源 中的 Pod 模板设置此类约束。
跨区的存储访问
当创建持久卷时,PersistentVolumeLabel
准入控制器
会自动向那些链接到特定区的 PersistentVolume 添加区标签。
调度器通过其
NoVolumeZoneConflict
断言确保申领给定 PersistentVolume 的 Pods 只会
被调度到该卷所在的可用区。
你可以为 PersistentVolumeClaim 指定StorageClass 以设置该类中的存储可以使用的失效域(区)。 要了解如何配置能够感知失效域或区的 StorageClass,请参阅 可用的拓扑逻辑。
网络
Kubernetes 自身不提供与可用区相关的联网配置。
你可以使用网络插件
来配置集群的联网,该网络解决方案可能拥有一些与可用区相关的元素。
例如,如果你的云提供商支持 type=LoadBalancer
的 Service,则负载均衡器
可能仅会将请求流量发送到运行在负责处理给定连接的负载均衡器组件所在的区。
请查阅云提供商的文档了解详细信息。
对于自定义的或本地集群部署,也可以考虑这些因素 Service Ingress 的行为, 包括处理不同失效区的方法,在很大程度上取决于你的集群是如何搭建的。
失效恢复
在搭建集群时,你可能需要考虑当某区域中的所有失效区都同时掉线时,是否以及如何 恢复服务。例如,你是否要求在某个区中至少有一个节点能够运行 Pod? 请确保任何对集群很关键的修复工作都不要指望集群中至少有一个健康节点。 例如:当所有节点都不健康时,你可能需要运行某个修复性的 Job, 该 Job 要设置特定的容忍度 以便修复操作能够至少将一个节点恢复为可用状态。
Kubernetes 对这类问题没有现成的解决方案;不过这也是要考虑的因素之一。
接下来
要了解调度器如何在集群中放置 Pods 并遵从所配置的约束,可参阅 调度与驱逐。
2 - 创建大型集群
支持
在 v1.22 版本中, Kubernetes 支持的最大节点数为 5000。更具体地说,我们支持满足以下所有条件的配置:
- 节点数不超过 5000
- Pod 总数不超过 150000
- 容器总数不超过 300000
- 每个节点的 pod 数量不超过 100
设定
集群是一组运行着 Kubernetes 代理的节点(物理机或者虚拟机),这些节点由主控节点(集群级控制面)控制。
通常,集群中的节点数由特定于云平台的配置文件 config-default.sh
(可以参考 GCE 平台的 config-default.sh
)
中的 NUM_NODES
参数控制。
但是,在许多云供应商的平台上,仅将该值更改为非常大的值,可能会导致安装脚本运行失败。例如,在 GCE,由于配额问题,集群会启动失败。
因此,在创建大型 Kubernetes 集群时,必须考虑以下问题。
配额问题
为了避免遇到云供应商配额问题,在创建具有大规模节点的集群时,请考虑:
- 增加诸如 CPU,IP 等资源的配额。
- 例如,在 GCE,您需要增加以下资源的配额:
- CPUs
- VM 实例
- 永久磁盘总量
- 使用中的 IP 地址
- 防火墙规则
- 转发规则
- 路由
- 目标池
- 例如,在 GCE,您需要增加以下资源的配额:
- 由于某些云供应商会对虚拟机的创建进行流控,因此需要对设置脚本进行更改,使其以较小的批次启动新的节点,并且之间有等待时间。
Etcd 存储
为了提高大规模集群的性能,我们将事件存储在专用的 etcd 实例中。
在创建集群时,现有 salt 脚本可以:
- 启动并配置其它 etcd 实例
- 配置 API 服务器以使用 etcd 存储事件
主控节点大小和主控组件
在 GCE/Google Kubernetes Engine 和 AWS 上,kube-up
会根据节点数量自动为您集群中的 master 节点配置适当的虚拟机大小。在其它云供应商的平台上,您将需要手动配置它。作为参考,我们在 GCE 上使用的规格为:
- 1-5 个节点:n1-standard-1
- 6-10 个节点:n1-standard-2
- 11-100 个节点:n1-standard-4
- 101-250 个节点:n1-standard-8
- 251-500 个节点:n1-standard-16
- 超过 500 节点:n1-standard-32
在 AWS 上使用的规格为
- 1-5 个节点:m3.medium
- 6-10 个节点:m3.large
- 11-100 个节点:m3.xlarge
- 101-250 个节点:m3.2xlarge
- 251-500 个节点:c4.4xlarge
- 超过 500 节点:c4.8xlarge
说明:在 Google Kubernetes Engine 上,主控节点的大小会根据集群的大小自动调整。更多有关信息,请参阅 此博客文章。
在 AWS 上,主控节点的规格是在集群启动时设置的,并且,即使以后通过手动删除或添加节点的方式使集群缩容或扩容,主控节点的大小也不会更改。
插件资源
为了防止内存泄漏或 集群插件 中的其它资源问题导致节点上所有可用资源被消耗,Kubernetes 限制了插件容器可以消耗的 CPU 和内存资源 (请参阅 PR #10653 和 #10778)。
例如:
containers:
- name: fluentd-cloud-logging
image: k8s.gcr.io/fluentd-gcp:1.16
resources:
limits:
cpu: 100m
memory: 200Mi
除了 Heapster 之外,这些限制都是静态的,并且限制是基于 4 节点集群上运行的插件数据得出的(请参阅 #10335)。在大规模集群上运行时,插件会消耗大量资源(请参阅 #5880)。因此,如果在不调整这些值的情况下部署了大规模集群,插件容器可能会由于达到限制而不断被杀死。
为避免遇到集群插件资源问题,在创建大规模集群时,请考虑以下事项:
- 根据集群的规模,如果使用了以下插件,提高其内存和 CPU 上限(每个插件都有一个副本处理整个群集,因此内存和 CPU 使用率往往与集群的规模/负载成比例增长) :
- 根据集群的规模,如果使用了以下插件,调整其副本数量(每个插件都有多个副本,增加副本数量有助于处理增加的负载,但是,由于每个副本的负载也略有增加,因此也请考虑增加 CPU/内存限制):
- 根据集群的规模,如果使用了以下插件,限制其内存和 CPU 上限(这些插件在每个节点上都有一个副本,但是 CPU/内存使用量也会随集群负载/规模而略有增加):
Heapster 的资源限制与您集群的初始大小有关(请参阅 #16185 和 #22940)。如果您发现 Heapster 资源不足,您应该调整堆内存请求的计算公式(有关详细信息,请参阅相关 PR)。
关于如何检测插件容器是否达到资源限制,参见 计算资源的故障排除 部分。
未来,我们期望根据集群规模大小来设置所有群集附加资源限制,并在集群扩缩容时动态调整它们。 我们欢迎您来实现这些功能。
允许启动时次要节点失败
出于各种原因(更多详细信息,请参见 #18969),
在 kube-up.sh
中设置很大的 NUM_NODES
时,可能会由于少数节点无法正常启动而失败。
此时,您有两个选择:重新启动集群(运行 kube-down.sh
,然后再运行 kube-up.sh
),或者在运行 kube-up.sh
之前将环境变量 ALLOWED_NOTREADY_NODES
设置为您认为合适的任何值。采取后者时,即使运行成功的节点数量少于 NUM_NODES
,kube-up.sh
仍可以运行成功。根据失败的原因,这些节点可能会稍后加入集群,又或者群集的大小保持在 NUM_NODES-ALLOWED_NOTREADY_NODES
。
3 - 校验节点设置
节点一致性测试
节点一致性测试 是一个容器化的测试框架,提供了针对节点的系统验证和功能测试。
该测试主要检测节点是否满足 Kubernetes 的最低要求,通过检测的节点有资格加入 Kubernetes 集群。
节点的前提条件
要运行节点一致性测试,节点必须满足与标准 Kubernetes 节点相同的前提条件。节点至少应安装以下守护程序:
- 容器运行时 (Docker)
- Kubelet
运行节点一致性测试
要运行节点一致性测试,请执行以下步骤:
- 得出 kubelet 的
--kubeconfig
的值;例如:--kubeconfig=/var/lib/kubelet/config.yaml
. 由于测试框架启动了本地控制平面来测试 kubelet, 因此使用http://localhost:8080
作为API 服务器的 URL。 一些其他的 kubelet 命令行参数可能会被用到:--pod-cidr
: 如果使用kubenet
, 需要为 Kubelet 任意指定一个 CIDR, 例如--pod-cidr=10.180.0.0/24
。--cloud-provider
: 如果使用--cloud-provider=gce
,需要移除这个参数 来运行测试。
-
使用以下命令运行节点一致性测试:
# $CONFIG_DIR 是您 Kubelet 的 pod manifest 路径。 # $LOG_DIR 是测试的输出路径。 sudo docker run -it --rm --privileged --net=host \ -v /:/rootfs -v $CONFIG_DIR:$CONFIG_DIR -v $LOG_DIR:/var/result \ k8s.gcr.io/node-test:0.2
针对其他硬件体系结构运行节点一致性测试
Kubernetes 也为其他硬件体系结构的系统提供了节点一致性测试的 Docker 镜像:
架构 | 镜像 | |
---|---|---|
amd64 | node-test-amd64 | |
arm | node-test-arm | |
arm64 | node-test-arm64 |
运行特定的测试
要运行特定测试,请使用您希望运行的测试的特定表达式覆盖环境变量 FOCUS
。
sudo docker run -it --rm --privileged --net=host \
-v /:/rootfs:ro -v $CONFIG_DIR:$CONFIG_DIR -v $LOG_DIR:/var/result \
-e FOCUS=MirrorPod \ # Only run MirrorPod test
k8s.gcr.io/node-test:0.2
要跳过特定的测试,请使用您希望跳过的测试的常规表达式覆盖环境变量 SKIP
。
sudo docker run -it --rm --privileged --net=host \
-v /:/rootfs:ro -v $CONFIG_DIR:$CONFIG_DIR -v $LOG_DIR:/var/result \
-e SKIP=MirrorPod \ # 运行除 MirrorPod 测试外的所有一致性测试内容
k8s.gcr.io/node-test:0.2
节点一致性测试是节点端到端测试的容器化版本。
默认情况下,它会运行所有一致性测试。
理论上,只要合理地配置容器和挂载所需的卷,就可以运行任何的节点端到端测试用例。 但是这里强烈建议只运行一致性测试,因为运行非一致性测试需要很多复杂的配置。
注意
- 测试会在节点上遗留一些 Docker 镜像, 包括节点一致性测试本身的镜像和功能测试相关的镜像。
- 测试会在节点上遗留一些死的容器。这些容器是在功能测试的过程中创建的。
4 - PKI 证书和要求
Kubernetes 需要 PKI 证书才能进行基于 TLS 的身份验证。如果你是使用 kubeadm 安装的 Kubernetes, 则会自动生成集群所需的证书。你还可以生成自己的证书。 例如,不将私钥存储在 API 服务器上,可以让私钥更加安全。此页面说明了集群必需的证书。
集群是如何使用证书的
Kubernetes 需要 PKI 才能执行以下操作:
- Kubelet 的客户端证书,用于 API 服务器身份验证
- API 服务器端点的证书
- 集群管理员的客户端证书,用于 API 服务器身份认证
- API 服务器的客户端证书,用于和 Kubelet 的会话
- API 服务器的客户端证书,用于和 etcd 的会话
- 控制器管理器的客户端证书/kubeconfig,用于和 API 服务器的会话
- 调度器的客户端证书/kubeconfig,用于和 API 服务器的会话
- 前端代理 的客户端及服务端证书
说明: 只有当你运行 kube-proxy 并要支持 扩展 API 服务器 时,才需要front-proxy
证书
etcd 还实现了双向 TLS 来对客户端和对其他对等节点进行身份验证。
证书存放的位置
如果你是通过 kubeadm 安装的 Kubernetes,所有证书都存放在 /etc/kubernetes/pki
目录下。本文所有相关的路径都是基于该路径的相对路径。
手动配置证书
如果你不想通过 kubeadm 生成这些必需的证书,你可以通过下面两种方式之一来手动创建他们。
单根 CA
你可以创建一个单根 CA,由管理员控制器它。该根 CA 可以创建多个中间 CA,并将所有进一步的创建委托给 Kubernetes。
需要这些 CA:
路径 | 默认 CN | 描述 |
---|---|---|
ca.crt,key | kubernetes-ca | Kubernetes 通用 CA |
etcd/ca.crt,key | etcd-ca | 与 etcd 相关的所有功能 |
front-proxy-ca.crt,key | kubernetes-front-proxy-ca | 用于 前端代理 |
上面的 CA 之外,还需要获取用于服务账户管理的密钥对,也就是 sa.key
和 sa.pub
。
所有的证书
如果你不想将 CA 的私钥拷贝至你的集群中,你也可以自己生成全部的证书。
需要这些证书:
默认 CN | 父级 CA | O (位于 Subject 中) | 类型 | 主机 (SAN) |
---|---|---|---|---|
kube-etcd | etcd-ca | server, client | localhost , 127.0.0.1 |
|
kube-etcd-peer | etcd-ca | server, client | <hostname> , <Host_IP> , localhost , 127.0.0.1 |
|
kube-etcd-healthcheck-client | etcd-ca | client | ||
kube-apiserver-etcd-client | etcd-ca | system:masters | client | |
kube-apiserver | kubernetes-ca | server | <hostname> , <Host_IP> , <advertise_IP> , [1] |
|
kube-apiserver-kubelet-client | kubernetes-ca | system:masters | client | |
front-proxy-client | kubernetes-front-proxy-ca | client |
[1]: 用来连接到集群的不同 IP 或 DNS 名
(就像 kubeadm 为负载均衡所使用的固定
IP 或 DNS 名,kubernetes
、kubernetes.default
、kubernetes.default.svc
、
kubernetes.default.svc.cluster
、kubernetes.default.svc.cluster.local
)。
其中,kind
对应一种或多种类型的 x509 密钥用途:
kind | 密钥用途 |
---|---|
server | 数字签名、密钥加密、服务端认证 |
client | 数字签名、密钥加密、客户端认证 |
说明:上面列出的 Hosts/SAN 是推荐的配置方式;如果需要特殊安装,则可以在所有服务器证书上添加其他 SAN。
说明:对于 kubeadm 用户:
- 不使用私钥,将证书复制到集群 CA 的方案,在 kubeadm 文档中将这种方案称为外部 CA。
- 如果将以上列表与 kubeadm 生成的 PKI 进行比较,你会注意到,如果使用外部 etcd,则不会生成
kube-etcd
、kube-etcd-peer
和kube-etcd-healthcheck-client
证书。
证书路径
证书应放置在建议的路径中(以便 kubeadm使用)。无论使用什么位置,都应使用给定的参数指定路径。
默认 CN | 建议的密钥路径 | 建议的证书路径 | 命令 | 密钥参数 | 证书参数 |
---|---|---|---|---|---|
etcd-ca | etcd/ca.key | etcd/ca.crt | kube-apiserver | --etcd-cafile | |
kube-apiserver-etcd-client | apiserver-etcd-client.key | apiserver-etcd-client.crt | kube-apiserver | --etcd-keyfile | --etcd-certfile |
kubernetes-ca | ca.key | ca.crt | kube-apiserver | --client-ca-file | |
kubernetes-ca | ca.key | ca.crt | kube-controller-manager | --cluster-signing-key-file | --client-ca-file, --root-ca-file, --cluster-signing-cert-file |
kube-apiserver | apiserver.key | apiserver.crt | kube-apiserver | --tls-private-key-file | --tls-cert-file |
kube-apiserver-kubelet-client | apiserver-kubelet-client.key | apiserver-kubelet-client.crt | kube-apiserver | --kubelet-client-key | --kubelet-client-certificate |
front-proxy-ca | front-proxy-ca.key | front-proxy-ca.crt | kube-apiserver | --requestheader-client-ca-file | |
front-proxy-ca | front-proxy-ca.key | front-proxy-ca.crt | kube-controller-manager | --requestheader-client-ca-file | |
front-proxy-client | front-proxy-client.key | front-proxy-client.crt | kube-apiserver | --proxy-client-key-file | --proxy-client-cert-file |
etcd-ca | etcd/ca.key | etcd/ca.crt | etcd | --trusted-ca-file, --peer-trusted-ca-file | |
kube-etcd | etcd/server.key | etcd/server.crt | etcd | --key-file | --cert-file |
kube-etcd-peer | etcd/peer.key | etcd/peer.crt | etcd | --peer-key-file | --peer-cert-file |
etcd-ca | etcd/ca.crt | etcdctl | --cacert | ||
kube-etcd-healthcheck-client | etcd/healthcheck-client.key | etcd/healthcheck-client.crt | etcdctl | --key | --cert |
注意事项同样适用于服务帐户密钥对:
私钥路径 | 公钥路径 | 命令 | 参数 |
---|---|---|---|
sa.key | kube-controller-manager | --service-account-private-key-file | |
sa.pub | kube-apiserver | --service-account-key-file |
为用户帐户配置证书
你必须手动配置以下管理员帐户和服务帐户:
文件名 | 凭据名称 | 默认 CN | O (位于 Subject 中) |
---|---|---|---|
admin.conf | default-admin | kubernetes-admin | system:masters |
kubelet.conf | default-auth | system:node:<nodeName> (参阅注释) |
system:nodes |
controller-manager.conf | default-controller-manager | system:kube-controller-manager | |
scheduler.conf | default-scheduler | system:kube-scheduler |
-
对于每个配置,请都使用给定的 CN 和 O 生成 x509 证书/密钥偶对。
-
为每个配置运行下面的
kubectl
命令:
KUBECONFIG=<filename> kubectl config set-cluster default-cluster --server=https://<host ip>:6443 --certificate-authority <path-to-kubernetes-ca> --embed-certs
KUBECONFIG=<filename> kubectl config set-credentials <credential-name> --client-key <path-to-key>.pem --client-certificate <path-to-cert>.pem --embed-certs
KUBECONFIG=<filename> kubectl config set-context default-system --cluster default-cluster --user <credential-name>
KUBECONFIG=<filename> kubectl config use-context default-system
这些文件用途如下:
文件名 | 命令 | 说明 |
---|---|---|
admin.conf | kubectl | 配置集群的管理员 |
kubelet.conf | kubelet | 集群中的每个节点都需要一份 |
controller-manager.conf | kube-controller-manager | 必需添加到 manifests/kube-controller-manager.yaml 清单中 |
scheduler.conf | kube-scheduler | 必需添加到 manifests/kube-scheduler.yaml 清单中 |