本文基于 Kubernetes 1.2.9版本

集群类型

K8S 高可用集群拓扑类型分为两种:堆叠拓扑集群拓扑

  1. 这两种拓扑结构有各自的优缺点,综合成本和实际业务量来选型(均可应用与生产环境)。
  2. 开发测试环境部署这两种集群拓扑的单控制面板节点(有单点故障风险,勿在生产环境中使用)即可。

堆叠拓扑

堆叠拓扑的 K8S 高可用集群如下图所示, 其中etcd分布式数据存储集群堆叠在kubeadm管理的控制面板节点上,作为控制面板节点的一个组件运行。

kubeadm-ha-topology-stacked-etcd.svg

  1. 每个控制面板节点运行apiserverschedulercontroller-manager实例;apiserver使用load balancer暴露给工作节点。
  2. 每个控制平面节点创建一个本地etcd成员,该etcd成员只与该节点的apiserver通信;这同样适用于本地controller-managerscheduler实例。
  3. 这种拓扑将控制面板和etcd成员耦合在同一节点上;相对使用外部拓扑的etcd集群,设置起来更简单,而且更易于副本管理。
  4. 堆叠集群存在耦合失败的风险;如果一个节点发生故障,则etcd成员和控制面板实例都将丢失,并且冗余会受到影响;可以通过添加更多控制平面节点来降低此风险(若采用这种 HA 方式搭建 K8S 集群,官方推荐运行至少三个堆叠的控制面板节点)。

该集群拓扑结构是kubeadm安装 K8S 集群默认采用的集群拓扑,当使用kubeadm initkubeadm join --control-plane时, 在控制面板节点上会自动创建本地etcd成员。

外部拓扑

外部拓扑的 K8S 高可用集群etcd的 HA 集群如下图所示,其中etcd分布式数据存储集群在独立于控制面板节点的其他节点上运行。

kubeadm-ha-topology-external-etcd.svg

  1. 与堆叠拓扑一样,外部拓扑中的每个控制面板节点都会运行apiserverschedulercontroller-manager 实例; 同样,apiserver使用load balancer暴露给工作节点;但是etcd成员在不同的主机上运行,每个etcd主机与每个控制面板节点的apiserver通信。
  2. 该拓扑结构解耦了控制面板和etcd成员;因此它提供了一种高可用设置,其中失去控制面板实例或者etcd成员的影响较小,并且不会像堆叠拓扑那样影响集群冗余。
  3. 但此拓扑需要两倍于堆叠拓扑的主机数量。具有此拓扑的高可用集群至少需要三个用于控制平面节点的主机和三个用于etcd节点的主机。

部署工具

K8S 有多种部署方式:

  • kind:是一个使用 Docker 容器节点运行本地 K8S 集群的工具;主要用于测试 K8S 本身,但也可用于本地开发或 CI。
  • minikube:可快速搭建的单节点本地版 K8S,主要用于本地开发和学习 K8S。
  • kubeadm:创建和管理 K8S 集群,可应用于生产环境。

此外,无论哪种安装部署方式都会使用到kubectl命令行工具,该工具可以对 K8S 集群运行命令;使用它可以在 K8S 中部署应用、监测和管理集群资源以及查看日志。

主机配置

本文采用 K8S 单控制面板节点外部拓扑集群架构来部署 K8S;所需主机配置如下

职责角色 IP地址 操作系统 配置规格 主机名称
控制面板(control plane node) 10.0.0.110 AlmaLinux OS 9.3 4 vCPU 4GiB kube-alma-m-01
工作节点(worker node) 10.0.0.120 AlmaLinux OS 9.3 4 vCPU 4GiB kube-alma-n-01
工作节点(worker node) 10.0.0.121 AlmaLinux OS 9.3 4 vCPU 4GiB kube-alma-n-02

上述主机配置遵循官方文档中要求的最低配置,此外还需满足以下条件:

  1. 使用兼容 K8S 的 Linux 操作系统(K8S 项目为基于 Debian 和 Red Hat 的 Linux 发行版以及一些不提供包管理器的发行版提供通用的指令)。

  2. 每台机器至少2GiB RAM,2 vCPU。

  3. 集群中的所有机器的网络彼此均能相互连接。

  4. 每台机器的主机名、MAC、product_uuid 必须唯一。

  5. 开启 K8S 运行必须的端口(关闭防火墙即可,目前各大云平台的云主机默认也未开启防火墙,都是通过安全组来控制端口);需要放行的端口如下:

    • 控制面板:
      协议 方向 端口范围 目的 使用者
      TCP 入站 6443 Kubernetes API server 所有
      TCP 入站 2379-2380 etcd server client API kube-apiserver, etcd
      TCP 入站 10250 Kubelet API 自身, 控制面
      TCP 入站 10259 kube-scheduler 自身
      TCP 入站 10257 kube-controller-manager 自身
    • 工作节点:
      协议 方向 端口范围 目的 使用者
      TCP 入站 10250 Kubelet API 自身, 控制面
      TCP 入站 30000-32767 NodePort Services† 所有
  6. 配置交换区:建议关闭交换区,避免不必要的折腾

    • kubelet的默认行为是在节点上检测到交换内存时无法启动。
    • kubeletv1.22起已开始支持交换分区,自v1.28起,仅针对cgroup v2支持交换分区。
    • kubelet的 NodeSwap 特性门控处于 Beta 阶段,但默认被禁用。
    • kubelet若未被正确配置使用交换分区,则你必须禁用交换分区。
      • 临时禁用交换区:sudo swapoff -a
      • 永久禁用交换区:可能需要在如/etc/fstabsystemd.swap等配置文件中禁用交换分区,具体的配置因操作系统的发行版本不同而有差异。

sudo dnf config-manager –add-repo https://download.docker.com/linux/centos/docker-ce.repo

sudo dnf -y install containerd.io

sudo systemctl enable containerd.service

systemctl start containerd

systemctl status containerd

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# 设置所需的 sysctl 参数,参数在重新启动后保持不变
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

# 应用 sysctl 参数而不重新启动
sudo sysctl --system

通过运行以下指令确认 br_netfilter 和 overlay 模块被加载:

1
2
lsmod | grep br_netfilter
lsmod | grep overlay

通过运行以下指令确认 net.bridge.bridge-nf-call-iptables、net.bridge.bridge-nf-call-ip6tables 和 net.ipv4.ip_forward 系统变量在你的 sysctl 配置中被设置为 1:

1
sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward
1
2
3
4
5
cat <<EOF | sudo tee -a /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
EOF

你需要启用 CRI 支持才能在 Kubernetes 集群中使用 containerd。 要确保 cri 没有出现在 /etc/containerd/config.toml 文件中 disabled_plugins 列表内。如果你更改了这个文件,也请记得要重启 containerd

需要重启。

1
2
3
4
5

setenforce 0
yum install -y kubelet kubeadm kubectl
systemctl enable kubelet && systemctl start kubelet

Add the Kubernetes repo

exclude 参数确保了与 Kubernetes 相关的软件包在运行 yum update 时不会升级,因为升级 Kubernetes 需要遵循特定的过程。

1
2
3
4
5
6
7
8
9
cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.29/rpm/
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.29/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF
Add the CRI-O repo
1
2
3
4
5
6
7
8
cat <<EOF | tee /etc/yum.repos.d/cri-o.repo
[cri-o]
name=CRI-O
baseurl=https://pkgs.k8s.io/addons:/cri-o:/prerelease:/main/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/addons:/cri-o:/prerelease:/main/rpm/repodata/repomd.xml.key
EOF
Install official package dependencies
1
2
3
4
5
6
7
sudo dnf install -y \
conntrack \
container-selinux \
ebtables \
ethtool \
iptables \
socat
Install the packages from the added repos
1
2
3
4
5
6
sudo dnf install -y --repo cri-o --repo kubernetes \
cri-o \
kubeadm \
kubectl \
kubelet \
--disableexcludes=kubernetes

设置 kubelet 为开机自启动即可,由于没有生成配置文件,集群初始化后自动启动:​

1
systemctl enable --now kubelet

设置 cri-o 开机自启动:

1
sudo systemctl daemon-reload && sudo systemctl enable crio && sudo systemctl start crio

确认 cri-o 服务是否在运行中:

1
sudo crictl --runtime-endpoint unix:///var/run/crio/crio.sock version

输出如下:

1
2
3
4
Version:  0.1.0
RuntimeName: cri-o
RuntimeVersion: 1.30.0
RuntimeApiVersion: v1

前置准备

设置主机名:

1
sudo hostnamectl set-hostname kube-alma-m-01
1
sudo hostnamectl set-hostname kube-alma-n-01
1
sudo hostnamectl set-hostname kube-alma-n-02

配置内网DNS:这里使用ikuai网关实现,配置如下图

关闭防火墙:学习阶段可以关闭防火墙,并且公有云上也没有防火墙,只有安全组。

1
sudo systemctl stop firewalld && sudo systemctl disable firewalld && sudo reboot

时间同步(公有云跳过):Kubernetes 要求集群中的节点时间必须精确一致,所以在每个节点上添加时间同步:

1
sudo dnf -y install chrony && systemctl enable chronyd  --now

查看同步状态

1
chronyc sources

关闭 SELinux:

1
sudo sed -i 's/enforcing/disabled/' /etc/selinux/config && sudo reboot

关闭 swap 分区:容器虚拟化需要关闭 swap 分区

1
sudo sed -ri 's/.*swap.*/#&/' /etc/fstab && sudo reboot

下载 Kubernetes 安装所需镜像

1
sudo kubeadm config images pull --image-repository registry.aliyuncs.com/google_containers

输出如下:

1
2
3
4
5
6
7
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-apiserver:v1.29.3
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-controller-manager:v1.29.3
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-scheduler:v1.29.3
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-proxy:v1.29.3
[config/images] Pulled registry.aliyuncs.com/google_containers/coredns:v1.11.1
[config/images] Pulled registry.aliyuncs.com/google_containers/pause:3.9
[config/images] Pulled registry.aliyuncs.com/google_containers/etcd:3.5.12-0

查看下载的镜像:

1
crictl images

输出如下:

1
2
3
4
5
6
7
8
IMAGE                                                             TAG                 IMAGE ID            SIZE
registry.aliyuncs.com/google_containers/coredns v1.11.1 cbb01a7bd410d 61.2MB
registry.aliyuncs.com/google_containers/etcd 3.5.12-0 3861cfcd7c04c 151MB
registry.aliyuncs.com/google_containers/kube-apiserver v1.29.3 39f995c9f1996 129MB
registry.aliyuncs.com/google_containers/kube-controller-manager v1.29.3 6052a25da3f97 123MB
registry.aliyuncs.com/google_containers/kube-proxy v1.29.3 a1d263b5dc5b0 83.6MB
registry.aliyuncs.com/google_containers/kube-scheduler v1.29.3 8c390d98f50c0 60.7MB
registry.aliyuncs.com/google_containers/pause 3.9 e6f1816883972 750kB

注意:

  • containerd 的客户端工具有 ctr、crictl 和 nerdctl。
  • ctr 是由 containerd 提供的一个客户端工具。
  • crictl 是 CRI 兼容的容器运行时命令行接口,和 containerd 无关,由 Kubernetes 提供,可以使用它来检查和调试 Kubernetes 节点上的容器运行时和应用程序。
  • nerdctl 是和 Docker 兼容的 CLI 客户端,支持 Compose,默认没有安装,需要手动安装。