..

部署大型 Kubernetes 生产集群

本文将探讨如何部署一个较大规模的 Kubernetes 生产集群。

准备工作

硬件和软件推荐

对于不同规模的 Kubernetes 生产集群有着不同的硬件规则要求,以下将针对不同规模的集群给出相应的硬件要求

ETCD

etcd 通常在开发或测试目的下使用有限资源时运行良好;在笔记本电脑或廉价云计算机上开发 etcd 是很常见的。 然而,在生产中运行 etcd 集群时,一些硬件指南对于正确管理非常有用。 这些建议不是硬性规定;它们作为强大的生产部署的良好起点。

CPUs

很少的 etcd 部署需要大量的 CPU 容量。典型集群需要两到四个核心才能平稳运行。 负载较重的 etcd 部署,为数千个客户端或每秒数万个请求提供服务,往往会受到 CPU 限制, 因为 etcd 可以从内存中提供请求。这样高负载的部署通常需要 8 至 16 个专用核心。

内存

etcd 的内存占用相对较小,但其性能仍取决于具有足够内存。 etcd 服务器将积极缓存 key-value 数据,并花费大部分其余内存跟踪观察者,通常 8GB 就足够了; 对于拥有数千个观察者和数百万个 keys 的重型部署,请相应地分配 16GB 到 64GB 内存。

硬盘

快速磁盘是 etcd 部署性能和稳定性最关键的因素。对于大型集群建议使用 100MB/s 或者更高的硬盘速度;尽可能地使用 SSD 作为 etcd 的存储后端。

网络

多成员 etcd 部署受益于快速可靠的网络。为了使 etcd 既一致又分区容错,不可靠的网络和分区故障会导致可用性差。 低延迟可以确保 etcd 成员快速通信、高带宽可以减少恢复失败的 etcd 成员所需的时间。 1GbE 对于常见的 etcd 部署已足够。对于大型 etcd 群集,10GbE 网络将减少平均恢复时间。

硬件配置推荐

以下是针对 Kubernetes 规模做出的硬件配置推荐

集群规模节点数vCPUs内存(GB)硬盘Concurrent IOPS硬盘带宽 (MB/s)
502850G SSD150025
250416150G SSD450075
1000832250G SSD7500125
超大30001664500G SSD15,000250

初始化操作

关闭防火墙或开启所有流量

以下方式任选其一

关闭防火墙

systemctl stop firewalld

允许所有流量

systemctl start firewalld
firewall-cmd --set-default-zone=trusted
firewall-cmd --complete-reload
systemctl disable iptables && systemctl enable firewalld

开机加载 ipvs 内核模块

cat << EOF > /etc/modules-load.d/ipvs.conf
# Load IPVS at boot
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
EOF

修改/etc/sysctl.conf 文件

echo 'br_netfilter' >/etc/modules-load.d/br_netfilter.conf
modprobe br_netfilter
cat>>/etc/sysctl.conf <<EOF
net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
EOF
sysctl -p

modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4

禁用 swap

sed -i "/swap/d" /etc/fstab
swapoff -a #kube scheduler要求关闭swap

Kubernetes

  • 在集群中,确保所有计算机之间存在全网络连接(公网或私网)
  • 在所有机器上具有 sudo 权限
    • 可以使用其他工具;本教程以 sudo 举例

master 节点配置要求

节点数配置
1-51vCPU 4G 内存
6-102vCPU 8G 内存
11-1004vCPU 16G 内存
101-2508vCPU 32G 内存
251-50016vCPU 64G 内存
大于 50032vCPU 128G 内存

部署

⚠️ 注意 请给所有的节点关闭防火墙以及设置 hosts

配置清单

服务类型IP/主机名配置
ETCD10.20.0.1/etcd14C16G
ETCD10.20.0.2/etcd24C16G
ETCD10.20.0.3/etcd34C16G
ETCD10.20.0.4/etcd44C16G
ETCD10.20.0.5/etcd54C16G
ETCD10.20.0.6/etcd64C16G
Master10.20.0.10/master132C128G
Master10.20.0.11/master232C128G
Master10.20.0.12/master332C128G
Worker10.20.0.20/worker132C128G
Worker10.20.0.21/worker232C128G
Worker10.20.0.221/worker20032C128G

步骤 1:安装 kubelet 和 kubeadm

该步骤需要在所有机器上执行,建议使用 Ansible 等脚本批量执行

添加 kubernetes.repo

cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF

无法访问的话,可以切换成使用镜像源 https://developer.aliyun.com/mirror/kubernetes/

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF

设置 SELinux

# Set SELinux in permissive mode (effectively disabling it)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

安装 kubernetes 组件

这是会安装最新版本

# 这是会安装最新版本
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

或者安装指定版本

sudo yum install -y kubelet-1.25.8 kubeadm-1.25.8 kubectl-1.25.8 --disableexcludes=kubernetes
sudo systemctl enable --now kubelet

系统参数设置

modprobe overlay  # 打开overlay
modprobe br_netfilter  # 打开netfilter
cat > /etc/sysctl.d/99-kubernetes-cri.conf <<EOF #内核处理
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sysctl --system

步骤 2:安装 CRI-O

该步骤需要在所有机器上执行,建议使用 Ansible 等脚本批量执行

OS=CentOS_8
VERSION=1.25 # 安装 1.25 版本的 cri-o
curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/devel:kubic:libcontainers:stable.repo
curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo
yum install -y cri-o

安装 podman

cri-o 默认不提供前端 cli,需要额外安装 podman

dnf install -y podman

获取 kubernetes 镜像列表

kubeadm config images list
registry.k8s.io/kube-apiserver:v1.25.8
registry.k8s.io/kube-controller-manager:v1.25.8
registry.k8s.io/kube-scheduler:v1.25.8
registry.k8s.io/kube-proxy:v1.25.8
registry.k8s.io/pause:3.8
registry.k8s.io/etcd:3.5.6-0
registry.k8s.io/coredns/coredns:v1.9.3

修改 cri-o 配置

vim /etc/crio/crio.conf 讲 pause_image 修改成镜像列表一致

[crio.image]
pause_image="registry.k8s.io/pause:3.8"

# 或者使用镜像地址
# pause_image="registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.8"

# 这个可以设置非 https 的镜像仓库
# insecure_registries = ["your.insecure.registry:5000", "another.insecure.registry:5000"]

启动 CRI-O 并设置其开机自启动

sudo systemctl start crio
sudo systemctl enable crio

步骤 3:安装 ETCD

该步骤将基于 kubeadm 部署 etcd 高可用集群

服务类型IP/主机名配置
ETCD10.20.0.1/etcd14C16G
ETCD10.20.0.2/etcd24C16G
ETCD10.20.0.3/etcd34C16G
ETCD10.20.0.4/etcd44C16G
ETCD10.20.0.5/etcd54C16G
ETCD10.20.0.6/etcd64C16G

将 kubelet 配置为 etcd 的服务管理器


# /usr/lib/systemd/system/kubelet.service.d 如果不存在
# 可以执行 systectl status kubelet 获取正确路径
cat <<EOF > /usr/lib/systemd/system/kubelet.service.d/20-etcd-service-manager.conf
[Service]
ExecStart=
# 将下面的 "systemd" 替换为你的容器运行时所使用的 cgroup 驱动。
# kubelet 的默认值为 "cgroupfs"。
# cri-o 需要使用 --cgroup-driver="systemd"
# 如果需要的话,将 "--container-runtime-endpoint " 的值替换为一个不同的容器运行时。
ExecStart=/usr/bin/kubelet --address=127.0.0.1 --pod-manifest-path=/etc/kubernetes/manifests --cgroup-driver=systemd --container-runtime=remote --container-runtime-endpoint=unix:///run/crio/crio.sock
Restart=always
EOF

systemctl daemon-reload
systemctl restart kubelet

为 kubeadm 创建配置文件

# 使用你的主机 IP 替换 HOST0、HOST1 和 HOST2 的 IP 地址
export HOST0=10.20.0.1
export HOST1=10.20.0.2
export HOST2=10.20.0.3

# 使用你的主机名更新 NAME0、NAME1 和 NAME2
export NAME0="etcd1"
export NAME1="etcd2"
export NAME2="etcd3"

# 创建临时目录来存储将被分发到其它主机上的文件
mkdir -p /tmp/${HOST0}/ /tmp/${HOST1}/ /tmp/${HOST2}/

HOSTS=(${HOST0} ${HOST1} ${HOST2})
NAMES=(${NAME0} ${NAME1} ${NAME2})

for i in "${!HOSTS[@]}"; do
HOST=${HOSTS[$i]}
NAME=${NAMES[$i]}
cat << EOF > /tmp/${HOST}/kubeadmcfg.yaml
---
apiVersion: "kubeadm.k8s.io/v1beta3"
kind: InitConfiguration
nodeRegistration:
    name: ${NAME}
localAPIEndpoint:
    advertiseAddress: ${HOST}
---
apiVersion: "kubeadm.k8s.io/v1beta3"
kind: ClusterConfiguration
kubernetesVersion: v1.25.8 # 替换版本
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers
etcd:
    local:
        serverCertSANs:
        - "${HOST}"
        peerCertSANs:
        - "${HOST}"
        extraArgs:
            initial-cluster: ${NAMES[0]}=https://${HOSTS[0]}:2380,${NAMES[1]}=https://${HOSTS[1]}:2380,${NAMES[2]}=https://${HOSTS[2]}:2380
            initial-cluster-state: new
            name: ${NAME}
            listen-peer-urls: https://${HOST}:2380
            listen-client-urls: https://${HOST}:2379
            advertise-client-urls: https://${HOST}:2379
            initial-advertise-peer-urls: https://${HOST}:2380
EOF
done

生成证书颁发机构(CA 证书)

如果你已经拥有 CA,那么唯一的操作是复制 CA 的 crt 和 key 文件到 /etc/kubernetes/pki/etcd/ca.crt/etc/kubernetes/pki/etcd/ca.key。 复制完这些文件后继续下一步,“为每个成员创建证书”。

如果你还没有 CA,则在 $HOST0(你为 kubeadm 生成配置文件的位置)上运行此命令。

kubeadm init phase certs etcd-ca --kubernetes-version v1.25.8

这一操作创建如下两个文件:

  • /etc/kubernetes/pki/etcd/ca.crt
  • /etc/kubernetes/pki/etcd/ca.key

为每个成员创建证书

kubeadm init phase certs etcd-server --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
cp -R /etc/kubernetes/pki /tmp/${HOST2}/
# 清理不可重复使用的证书
find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete

kubeadm init phase certs etcd-server --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
cp -R /etc/kubernetes/pki /tmp/${HOST1}/
find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete

kubeadm init phase certs etcd-server --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
# 不需要移动 certs 因为它们是给 HOST0 使用的

# 清理不应从此主机复制的证书
find /tmp/${HOST2} -name ca.key -type f -delete
find /tmp/${HOST1} -name ca.key -type f -delete

将 ${HOST0} 的文件复制到主目录

mv /tmp/${HOST0}/* ~/

复制证书和 kubeadm 配置

证书已生成,现在必须将它们移动到对应的主机。

USER=root
HOST=${HOST1}
scp -r /tmp/${HOST}/* ${USER}@${HOST}:
ssh ${USER}@${HOST}
root@HOST $ mv pki /etc/kubernetes/

确保已经所有预期的文件都存在

创建静态 Pod 清单

既然证书和配置已经就绪,是时候去创建清单了。 在每台主机上运行 kubeadm 命令来生成 etcd 使用的静态清单。

root@HOST0 $ kubeadm init phase etcd local --config=$HOME/kubeadmcfg.yaml
root@HOST1 $ kubeadm init phase etcd local --config=$HOME/kubeadmcfg.yaml
root@HOST2 $ kubeadm init phase etcd local --config=$HOME/kubeadmcfg.yaml

注意:etcd-ca 证书只需要执行一次。 上面已经创建好了 etcd-cluster-1 的集群,接下来只需要重复以上操作,在 etcd4,etcd5,etcd6 创建一个 etcd-cluster-2 etcd 集群

步骤 4:初始化 Kubernetes 控制平面

从 etcd 所在的任意节点复制以下内容在所有 master 节点上

/etc/kubernetes/pki/etcd/ca.crt
/etc/kubernetes/pki/apiserver-etcd-client.crt
/etc/kubernetes/pki/apiserver-etcd-client.key

master(10.20.0.10) 节点上添加以下文件,

kubeadm-config.yaml

apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
# apiserver LOAD_BALANCER_ADDRESS
# 高可用的环境下,请务必设置该参数
controlPlaneEndpoint: "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT"
kubernetesVersion: v1.25.8 # 替换版本
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers # 改成镜像地址
networking:
  dnsDomain: cluster.local
  podSubnet: 10.244.0.0/16 # 按需修改
  serviceSubnet: 10.96.0.0/12 # 按需修改
etcd:
  external:
    endpoints:
      - https://10.20.0.1:2379
      - https://10.20.0.2:2379
      - https://10.20.0.3:2379
    caFile: /etc/kubernetes/pki/etcd/ca.crt
    certFile: /etc/kubernetes/pki/apiserver-etcd-client.crt
    keyFile: /etc/kubernetes/pki/apiserver-etcd-client.key
apiServer:
  extraArgs:
    etcd-servers-overrides: "/events#https://10.20.0.4:2379,https://10.20.0.5:2379,https://10.20.0.6:2379"
  # 该参数给签发的证书附加 IP 或者 域名
  #certSANs:
  #  -
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
# kubelet specific options here
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
# kube-proxy specific options here

执行以下命令进行初始化

sudo kubeadm init --config kubeadm.yaml --upload-certs

将会看到类似于以下的输出

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 10.20.0.10:6443 --token zjtxal.8au2tvz9sh1hgsmp \
  --discovery-token-ca-cert-hash sha256:13d1241a5b5454d8052ef84176df45d4e82ad5e3a26b6dab9a4c5d888badb818

如在这个过程发生了意外情况,导致无法部署,请检查一下由什么问题引起的。 解决问题后,快捷的方式是将这台 master 重置,然后重新复制 etcd 的证书,再重新初始化

kubeadm reset -f

完成这部操作后,请从 步骤 4:初始化 Kubernetes 控制平面 重新开始

完成这一步之后需要安装 Calico CNI

步骤 5:安装 CNI(Calico)

首先,在您的集群上安装 operator

kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/tigera-operator.yaml

下载必要的自定义资源以配置 Calico

curl https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/custom-resources.yaml -O

如果您希望自定义 Calico 安装,请在本地自定义下载的 custom-resources.yaml 清单。

# This section includes base Calico installation configuration.
# For more information, see: https://projectcalico.docs.tigera.io/master/reference/installation/api#operator.tigera.io/v1.Installation
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
  name: default
spec:
  # Configures Calico networking.
  calicoNetwork:
    # Note: The ipPools section cannot be modified post-install.
    ipPools:
      - blockSize: 26
        cidr: 192.168.0.0/16 # 不要和现有 IP 段发生重合
        encapsulation: VXLANCrossSubnet
        natOutgoing: Enabled
        nodeSelector: all()
---
# This section configures the Calico API server.
# For more information, see: https://projectcalico.docs.tigera.io/master/reference/installation/api#operator.tigera.io/v1.APIServer
apiVersion: operator.tigera.io/v1
kind: APIServer
metadata:
  name: default
spec: {}

创建清单以安装 Calico

kubectl create -f custom-resources.yaml

步骤 6:添加 Kubernetes master 节点

执行先前由第一个节点上的 kubeadm init 输出提供给你的 join 命令。 它看起来应该像这样:

kubeadm join 10.20.0.10:6443 --token zjtxal.8au2tvz9sh1hgsmp \
  --discovery-token-ca-cert-hash sha256:13d1241a5b5454d8052ef84176df45d4e82ad5e3a26b6dab9a4c5d888badb818 \
  --control-plane --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07

步骤 7:添加 Kubernetes worker 节点

kubeadm join 10.20.0.10:6443 --token zjtxal.8au2tvz9sh1hgsmp \
  --discovery-token-ca-cert-hash sha256:13d1241a5b5454d8052ef84176df45d4e82ad5e3a26b6dab9a4c5d888badb818

(可选) 将 ETCD 节点加入集群

将 ETCD 加入集群的好处是可以在集群内一起管理,需要加入集群的 ETCD 可以执行以下操作

rm -rf /usr/lib/systemd/system/kubelet.service.d/20-etcd-service-manager.conf

systemctl daemon-reload
systemctl stop kubelet

kubeadm join 10.20.0.10:6443 --token zjtxal.8au2tvz9sh1hgsmp \
  --discovery-token-ca-cert-hash sha256:13d1241a5b5454d8052ef84176df45d4e82ad5e3a26b6dab9a4c5d888badb818

加入集群后,需要将 etcd 所在节点设置禁止调度,避免其他应用抢占资源

kubectl cordon <NODENAME>

集群管理和优化

ETCD 优化

提高磁盘 IO 性能 ETCD

对磁盘写入延迟非常敏感,对于负载较重的集群建议磁盘使用 SSD 固态硬盘。可以使用 diskbench 或 fio 测量磁盘实际顺序 IOPS。

提高 ETCD 的磁盘 IO 优先级

由于 ETCD 必须将数据持久保存到磁盘日志文件中,因此来自其他进程的磁盘活动可能会导致增加写入时间,结果导致 ETCD 请求超时和临时 leader 丢失。当给定高磁盘优先级时,ETCD 服务可以稳定地与这些进程一起运行:

sudo ionice -c2 -n0 -p $(pgrep etcd)

添加节点

在运行一段时间后,可能存在添加新的节点的需求,通过 kubeadm 将可以很容易实现

执行以下命令将会创建一个新的 token 和一条命令

kubeadm token create --print-join-command

将类似于这样

kubeadm join 10.20.0.10:6443 --token zjtxal.8au2tvz9sh1hgsmp \
  --discovery-token-ca-cert-hash sha256:13d1241a5b5454d8052ef84176df45d4e82ad5e3a26b6dab9a4c5d888badb818

参考资料