架构设计

OS: AlmaLinux 9.1

节点名 IP 地址
zqf-Master01 10.101.5.110
zqf-Master02 10.101.5.111
zqf-Master03 10.101.5.112
zqf-Worker01 10.101.5.113
zqf-Worker02 10.101.5.114
zqf-Worker03 10.101.5.115
zqf-Worker04 10.101.5.116

1. 所有节点操作

1.1 基础配置

1.1.1 配置镜像源

1sed -e 's|^mirrorlist=|#mirrorlist=|g' \
2    -e 's|^#\s*baseurl=https://repo.almalinux.org/almalinux|baseurl=https://mirrors.zju.edu.cn/almalinux|g' \
3    -i.bak \
4    /etc/yum.repos.d/almalinux-*.repo
1dnf makecache

1.1.2 配置主机名

1hostnamectl set-hostname <主机名>

添加解析记录,使节点直接使用主机名访问通信

1cat << EOF >> /etc/hosts
210.101.5.110 zqf-Master01
310.101.5.111 zqf-Master02
410.101.5.112 zqf-Master03
510.101.5.113 zqf-Worker01
610.101.5.114 zqf-Worker02
710.101.5.115 zqf-Worker03
810.101.5.116 zqf-Worker04
9EOF

1.1.3 免密登录配置(新增/可选)

1ssh-keygen -t rsa -b 2048
1ssh-copy-id root@目标节点IP

1.1.4 禁用防火墙

1systemctl stop firewalld && systemctl disable firewalld
2systemctl disable --now dnsmasq

1.1.5 禁用 SELINUX

  1. 修改配置文件,使 SELINUX=disabled

注意,是 disabled ,不是 disable

1vim /etc/selinux/config
  1. 或者,直接执行下列命令
1sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/sysconfig/selinux
2sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
  1. 查看系统 SELinux 运行状态
1sestatus

1.1.6 禁用 Swap 分区

Swap 是交换分区,如果机器内存不够,会使用swap分区。

但是,swap分区性能较低,k8s 默认不允许使用交换分区。

kubeadm 初始化的时候会检测 swap 状态,未关闭 swap 会导致初始化失败。

1swapoff -a && sysctl -w vm.swappiness=0
2sed -ri '/^[^#]*swap/s@^@#@' /etc/fstab

若 swap 为 0, 说明 swap 关闭成功

1free -mh

1.1.7 时间同步(新增)

  1. 所有节点安装 chrony
1dnf -y install chrony
  1. 挑一个节点 (10.101.5.110) 修改配置
1# 配置chrony服务
2vim /etc/chrony.conf
3
4# 指定使用的上游时间服务器地址
5pool ntp.aliyun.com iburst
6
7# 允许访问的服务器
8allow 192.168.10.0/24
  1. 其他节点修改上游服务器即可
1# 配置chrony服务
2vim /etc/chrony.conf
3
4# 指定 10.101.5.110 为上游服务器
5pool 10.101.5.110 iburst
  1. 启用服务
1systemctl restart chronyd
2systemctl enable chronyd


5. 查看同步状态

1chronyc sources

1.1.8 配置系统资源限制

1vim /etc/security/limits.conf

添加以下配置,包括最大文件描述符数量、最大进程数量和内存锁定限制

1* soft nofile 65536
2* hard nofile 131072
3* soft nproc 65535
4* hard nproc 655350
5* soft memlock unlimited
6* hard memlock unlimited

1.1.9 配置内核参数

1sysctl net.core.bpf_jit_limit=452534528

配置 K8S 所需内核参数。

 1cat <<EOF >  /etc/sysctl.d/k8s.conf 
 2net.ipv4.ip_forward = 1
 3net.bridge.bridge-nf-call-iptables = 1
 4net.bridge.bridge-nf-call-ip6tables = 1
 5fs.may_detach_mounts = 1
 6vm.overcommit_memory=1
 7vm.panic_on_oom=0
 8fs.inotify.max_user_watches=89100
 9fs.file-max=52706963
10fs.nr_open=52706963
11net.netfilter.nf_conntrack_max=2310720
12net.ipv4.tcp_keepalive_time = 600
13net.ipv4.tcp_keepalive_probes = 3
14net.ipv4.tcp_keepalive_intvl =15
15net.ipv4.tcp_max_tw_buckets = 36000
16net.ipv4.tcp_tw_reuse = 1
17net.ipv4.tcp_max_orphans = 327680
18net.ipv4.tcp_orphan_retries = 3
19net.ipv4.tcp_syncookies = 1
20net.ipv4.tcp_max_syn_backlog = 16384
21net.ipv4.ip_conntrack_max = 65536
22net.ipv4.tcp_max_syn_backlog = 16384
23net.ipv4.tcp_timestamps = 0
24net.core.somaxconn = 16384
25vm.swappiness=0
26EOF

其中,

1net.ipv4.ip_forward = 1
2net.bridge.bridge-nf-call-iptables = 1
3net.bridge.bridge-nf-call-ip6tables = 1

也是 Containerd CRI 所需的内核参数。

加载上述内核参数生效所需要的模块,并加载生效

1modprobe -- overlay
2modprobe -- br_netfilter
3sysctl --system

1.3 配置 IPVS

K8S 集群将使用 ipvs 模式,因此这里事先安装 ipvs 相关组件。

  1. 安装 ipvs 相关软件包
1dnf install -y ipvsadm ipset sysstat conntrack libseccomp
  1. 载入模块
1modprobe -- ip_vs
2modprobe -- ip_vs_rr
3modprobe -- ip_vs_wrr
4modprobe -- ip_vs_sh
5modprobe -- nf_conntrack
  1. 创建ipvs.conf,设置内核模块的自动载入
 1cat <<EOF > /etc/modules-load.d/ipvs.conf 
 2ip_vs
 3ip_vs_lc
 4ip_vs_wlc
 5ip_vs_rr
 6ip_vs_wrr
 7ip_vs_lblc
 8ip_vs_lblcr
 9ip_vs_dh
10ip_vs_sh
11ip_vs_fo
12ip_vs_nq
13ip_vs_sed
14ip_vs_ftp
15ip_vs_sh
16nf_conntrack
17ip_tables
18ip_set
19xt_set
20ipt_set
21ipt_rpfilter
22ipt_REJECT
23ipip
24EOF
1systemctl enable --now systemd-modules-load.service

1.4 安装 Containerd

  1. 安装 Containerd
1dnf install containerd -y 
1ctr -v
2ctr containerd.io 1.7.18
  1. 生成 containerd 配置文件
1mkdir -p /etc/containerd
2containerd config default | sudo tee /etc/containerd/config.toml
  1. 修改 Containerd 使用的 cgroup 为 systemd cgroup driver
1[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]  
2  ...  
3  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]  
4    SystemdCgroup = true
  1. 修改 Containerd 使用的 sandbox_image

修改 sandbox 的镜像地址

1sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9"
  1. 配置 Containerd 私服地址跳过 https 验证
1[plugins."io.containerd.grpc.v1.cri".registry.configs]
2    [plugins."io.containerd.grpc.v1.cri".registry.configs."10.101.7.108".tls]
3                insecure_skip_verify = true
4        [plugins."io.containerd.grpc.v1.cri".registry.configs."szharbor.hithium.cn".tls]
5                insecure_skip_verify = true
6
7[plugins."io.containerd.grpc.v1.cri".registry.configs."docker.io".tls]
8                insecure_skip_verify = true
  1. 配置 docker.io 镜像
1      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
2        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
3                endpoint = ["https://docker.1panel.live"][plugins."io.containerd.grpc.v1.cri".registry.mirrors."10.101.7.108:80"]
4                endpoint = ["http://10.101.7.108"]
  1. 使配置生效
1systemctl daemon-reload
2systemctl restart containerd.service
3systemctl enable containerd.service

1.5 安装 K8S 相关组件

https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.29/rpm/

1cat <<EOF > /etc/yum.repos.d/kubernetes.repo
2[kubernetes]
3name=Kubernetes
4baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.29/rpm/
5enabled=1
6gpgcheck=1
7gpgkey=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.29/rpm/repodata/repomd.xml.key
8EOF
1dnf -y install kubectl kubelet kubeadm

2. 主节点配置

2.1 高可用配置

2.1.1 安装相关组件

安装keepalived, haproxy

1dnf -y install keepalived haproxy

2.1.2 配置检测脚本文件

该脚本检测本地 8443 端口(haproxy服务)是否正常,若不正常,则停止本地的 Keepalived 服务,VIP飘逸到其它 haproxy 可用的节点,继续提供服务。

1vim /etc/keepalived/check_apiserver.sh
1#!/bin/sh
2curl -sfk --max-time 2 https://localhost:8443/healthz -o /dev/null  
3if [ $? -nq 0]  
4then  
5        echo "*** Error GET https://localhost:8443/healthz" 1>&2  
6        systemctl stop keepalived  
7fi

给脚本文件执行权限

1chmod +x /etc/keepalived/check_apiserver.sh

2.1.3 配置 keepalived.conf

VIP 记得使用节点所在网段,但不使用的 IP 地址

1vim /etc/keepalived/keepalived.conf
 1! Configuration File for keepalived
 2global_defs {
 3    router_id LVS_DEVEL
 4}
 5
 6# 指定检测脚本:
 7# script: 脚本路径;
 8# interval: 脚本执行时间;
 9# weight: 权重;
10# fall: 连续检测失败多少次之后认定节点不可用;
11# rise: 连续检测成功多少次认为节点恢复正常。
12vrrp_script check_apiserver {
13  script "/etc/keepalived/check_apiserver.sh"
14  interval 3
15  weight -2
16  fall 10
17  rise 2
18}
19
20# state: 指定MASTER身份, 另外两台Keepalived设置成BACKUP
21# interface: 指定网卡;
22# virtual_router_id: VRRP虚拟路由id, 同一集群的Keepalived节点要相同, 用来识别彼此
23# priority: 优先级, 另外两台Keepalived分别设置成90 70
24# auth_type: VRRP组节点之间认证方式为PASS铭文
25# auth_pass: VRRP组节点之间用来认证通信的密码
26# virtual_ipaddress: VIP
27# track_script: 指定使用的检测脚本名称
28
29vrrp_instance VI_1 {
30    state MASTER
31    interface ens192
32    virtual_router_id 51
33    priority 100
34    authentication {
35        auth_type PASS
36        auth_pass 1111
37    }
38    virtual_ipaddress {
39        10.101.5.2
40    }
41    track_script {
42        check_apiserver
43    }
44}

2.1.4 配置 haproxy.cfg

1vim /etc/haproxy/haproxy.cfg
 1#---------------------------------------------------------------------  
 2# Global settings  
 3#---------------------------------------------------------------------  
 4global
 5  log	stdout	format	raw	local0
 6  chroot	/var/lib/haproxy
 7  pidfile	/var/run/haproxy.pid
 8  maxconn	4000
 9  user		haproxy
10  group		haproxy
11
12
13#---------------------------------------------------------------------  
14# common defaults that all the 'listen' and 'backend' sections will  
15# use if not designated in their block  
16#---------------------------------------------------------------------  
17defaults
18  log		global
19  option	httplog
20  option	dontlognull
21  timeout	connect		5s
22  timeout	client		35s
23  timeout	server		35s
24
25
26#---------------------------------------------------------------------  
27# apiserver frontend which proxys to the control plane nodes  
28#---------------------------------------------------------------------  
29# 主要是这里的bind: 定义haproxy的代理端口为8443。也可以是其它。  
30frontend	apiserver
31	bind	*:8443
32	mode	tcp
33	option	tcplog
34	default_backend	apiserverbackend
35
36
37#---------------------------------------------------------------------  
38# round robin balancing for apiserver  
39#---------------------------------------------------------------------  
40# 以下是后端相关配置, 关键参数解释如下  
41# mode tcp: 设置与后端服务通信的模式为TCP  
42# balance roundrobin: 轮询方式  
43# inter 10s: 检查间隔为10秒。  
44# downinter 5s: 当服务被标记为不可用后,每5秒检查一次是否恢复。  
45# rise 2: 在将服务器标记为上线之前,服务器必须连续2次成功响应检查。  
46# fall 2: 在将服务器标记为下线之前,服务器必须连续2次失败响应检查。  
47# slowstart 60s: 慢启动时间为60秒,用于控制新服务器上线后逐渐增加其权重。  
48# maxconn 250: 每个服务器的最大并发连接数为250。  
49# maxqueue 256: 后端队列的最大长度为256。  
50# weight 100: 服务器的默认权重为100。  
51# server 定义后端的服务器列表。  
52
53
54backend		apiserverbackend
55	option	tcplog
56	option	tcp-check
57	mode		tcp
58	balance	roundrobin
59	default-server inter 10s downinter 5s rise 2 fall 2 slowstart 60s maxconn 250 maxqueue 256 weight 100
60	server	zqf-Master01	10.101.5.110:6443	check
61	server	zqf-Master02	10.101.5.111:6443	check
62	server	zqf-Master03	10.101.5.112:6443	check

2.1.5 启动服务并验证

  1. 启动服务
1systemctl enable --now keepalived
2systemctl enable --now haproxy
  1. 验证

停止 master01 上的 keepalived 服务后, 虚拟 IP 192.168.10.240/32 会移动到 moster02。 恢复 master01 上的 keepalived 服务后, 虚拟 IP 192.168.10.240/32 会移动回 moster01。

1[root@zqf-Master01 ~]# ip a | grep ens
22: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
3    inet 10.101.5.110/24 brd 10.101.5.255 scope global noprefixroute ens192
4    inet 192.168.10.240/32 scope global ens192
5
6[root@zqf-Master02 keepalived]# ip a | grep ens
72: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
8    inet 10.101.5.111/24 brd 10.101.5.255 scope global noprefixroute ens192

2.2 基于 kubeadm 安装集群

2.2.1 提前拉取镜像

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

2.2.2 修改 kubeadm 配置文件

1kubeadm config print init-defaults >  kubeadm-init.yaml
配置项 描述
advertiseAddress 指定本机地址
name 指定本机的主机名
controlPlaneEndpoint 指定控制面的通信地址,这里写 VIP 地址
imageRepository 指定下载 Kubernetes 组件的镜像仓库地址, 默认访问国外的仓库, 这里需要修改为国内的镜像仓库源
kubernetesVersion 指定安装的 kubernetes 版本
serviceSubnet 指定 Kubernetes 的 Service 资源分配的网段, 网段不能与真实机和 Pod 的网段冲突。
podSubnet 指定 Kubernetes 的 Pod 资源分配的网段, 网段不能与真实机和 Service 的网段冲突。

需要修改的部分包括:

  • localAPIEndpoint.advertiseAddress:主节点 IP 地址
  • nodeRegistration.name:主节点 hostname
  • imageRepository:镜像仓库地址
  • networking.podSubnet: pod 子网范围
 1apiVersion: kubeadm.k8s.io/v1beta3
 2bootstrapTokens:
 3- groups:
 4  - system:bootstrappers:kubeadm:default-node-token
 5  token: abcdef.0123456789abcdef
 6  ttl: 24h0m0s
 7  usages:
 8  - signing
 9  - authentication
10kind: InitConfiguration
11localAPIEndpoint:
12  advertiseAddress: 10.101.5.110
13  bindPort: 6443
14nodeRegistration:
15  criSocket: unix:///var/run/containerd/containerd.sock
16  imagePullPolicy: IfNotPresent
17  name: zqf-Master01
18  taints: null
19---
20apiServer:
21  timeoutForControlPlane: 4m0s
22apiVersion: kubeadm.k8s.io/v1beta3
23certificatesDir: /etc/kubernetes/pki
24clusterName: kubernetes
25controllerManager: {}
26dns: {}
27controlPlaneEndpoint: "10.101.5.2:8443"
28etcd:
29  local:
30    dataDir: /var/lib/etcd
31imageRepository: registry.aliyuncs.com/google_containers
32kind: ClusterConfiguration
33kubernetesVersion: 1.29.6
34networking:
35  dnsDomain: cluster.local
36  serviceSubnet: 10.96.0.0/12
37  podSubnet: 192.168.0.0/16
38scheduler: {}
39
40# 补充
41---
42apiVersion: kubeproxy.config.k8s.io/v1alpha1
43kind: KubeProxyConfiguration
44mode: ipvs
45---
46apiVersion: kubelet.config.k8s.io/v1beta1
47kind: KubeletConfiguration
48cgroupDriver: systemd

2.2.3 初始化 K8S 集群

1kubeadm init --config=kubeadm-init.yaml  --upload-certs

其中, --upload-certs 会自动将证书从主控制平面节点复制到将要加入的控制平面节点上。

然后,根据提示将各个节点加入集群。

1# 添加master节点的命令
2kubeadm token create --print-join-command --certificate-key
3
4# 添加worker节点的命令获取方式
5kubeadm token create --print-join-command

kubeadm token create –print-join-command –ttl 0

2.2.4 配置 kubectl

1mkdir -p $HOME/.kube
2sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
3sudo chown $(id -u):$(id -g) $HOME/.kube/config
4# 将以下命令加到.bashrc
5export KUBECONFIG=/etc/kubernetes/admin.conf

其中,admin.conf 是连接 Kubernetes 的认证文件,通过此文件才能连接到 kubernetes,kubectl 也需要这个文件;在 Linux 中,使用 KUBECONFIG 环境变量知道认证文件的所在。

Linux 中每个用户的环境变量是不同的,如果切换了用户,则也需要设置 KUBECONFIG 环境变量;如果要在别的节点上连接集群,则可以把这个文件复制过去。

此时,在 master01 上执行 kubectl get no 应有

1[root@zqf-Master01 ~]# kubectl get no
2NAME           STATUS     ROLES           AGE     VERSION
3zqf-master01   NotReady   control-plane   2m23s   v1.29.6
4zqf-master02   NotReady   control-plane   101s    v1.29.6
5zqf-master03   NotReady   control-plane   101s    v1.29.6
6zqf-worker01   NotReady   <none>          67s     v1.29.6
7zqf-worker02   NotReady   <none>          65s     v1.29.6
8zqf-worker03   NotReady   <none>          63s     v1.29.6
9zqf-worker04   NotReady   <none>          60s     v1.29.6

2.3 安装 Calico

Calico3.28 版本支持: Kubernetesv1.27-v1.30。

Calico 的安装方式目前有两种:

  • 基于 Operator 方式安装,能够管理 Calico 集群的安装,升级,生命周期管理等,但不方便管理镜像地址。(优先)
  • 基于静态资源清单安装,方便,简单,但无法像 Opertaor 一样能够自动管理 Calico 的生命周期。

基于静态资源清单的部署常见的也分为两种:

  • calico.yaml:当 Calico 使用 Kubernetes API 作为数据存储,且集群节点少于 50 个。
  • calico-typha.yaml: 当 Calico 使用 Kubernetes API 作为数据存储,且集群节点大于 50 个。

https://github.com/projectcalico/calico/blob/master/manifests/calico-typha.yaml

replicas: 副本数 , 建议每200个节点1个副本, 生产的话建议3个副本。

其中,镜像推荐提前拉取到私服,然后修改 imageurl

安装成功后,如下所示

 1[root@zqf-Master01 ~]# kubectl get po -n kube-system
 2NAME                                       READY   STATUS    RESTARTS   AGE
 3calico-kube-controllers-7884dfffd6-pdj8v   1/1     Running   0          61s
 4calico-node-7q2dp                          1/1     Running   0          46s
 5calico-node-gdtc4                          1/1     Running   0          46s
 6calico-node-hndr8                          1/1     Running   0          46s
 7calico-node-jd9zm                          1/1     Running   0          46s
 8calico-node-n8z5j                          1/1     Running   0          46s
 9calico-node-pn4l2                          1/1     Running   0          46s
10calico-node-wtqtn                          1/1     Running   0          46s
11calico-typha-866db88dc4-8njgj              1/1     Running   0          61s
12calico-typha-866db88dc4-8wd57              1/1     Running   0          61s
13calico-typha-866db88dc4-wnjzh              1/1     Running   0          61s
14coredns-66db75cf8c-96t2p                   1/1     Running   0          61s
15coredns-66db75cf8c-xgdf9                   1/1     Running   0          61s
16etcd-zqf-master01                          1/1     Running   1          53m
17etcd-zqf-master02                          1/1     Running   0          52m
18etcd-zqf-master03                          1/1     Running   0          52m
19kube-apiserver-zqf-master01                1/1     Running   1          53m
20kube-apiserver-zqf-master02                1/1     Running   0          52m
21kube-apiserver-zqf-master03                1/1     Running   0          52m
22kube-controller-manager-zqf-master01       1/1     Running   1          53m
23kube-controller-manager-zqf-master02       1/1     Running   0          52m
24kube-controller-manager-zqf-master03       1/1     Running   0          52m
25kube-proxy-75sbq                           1/1     Running   0          37s
26kube-proxy-g2nqd                           1/1     Running   0          45s
27kube-proxy-jqd92                           1/1     Running   0          40s
28kube-proxy-kwxcb                           1/1     Running   0          44s
29kube-proxy-lhtvl                           1/1     Running   0          38s
30kube-proxy-vkv5v                           1/1     Running   0          43s
31kube-proxy-ws2fl                           1/1     Running   0          41s
32kube-scheduler-zqf-master01                1/1     Running   1          53m
33kube-scheduler-zqf-master02                1/1     Running   0          52m
34kube-scheduler-zqf-master03                1/1     Running   0          52m
1[root@zqf-Master01 ~]# kubectl get node
2NAME           STATUS   ROLES           AGE   VERSION
3zqf-master01   Ready    control-plane   54m   v1.29.6
4zqf-master02   Ready    control-plane   53m   v1.29.6
5zqf-master03   Ready    control-plane   53m   v1.29.6
6zqf-worker01   Ready    <none>          52m   v1.29.6
7zqf-worker02   Ready    <none>          52m   v1.29.6
8zqf-worker03   Ready    <none>          52m   v1.29.6
9zqf-worker04   Ready    <none>          52m   v1.29.6

2.4 配置 kubectl 命令补全

1dnf install -y bash-completion 
2source /usr/share/bash-completion/bash_completion
3source <(kubectl completion bash)
4echo "source <(kubectl completion bash)" >> ~/.bashrc

3. 清除 kubeadm 环境

1kubeadm reset cleanup-node
2y
3kubeadm reset
4y
5rm -rf /etc/cni/net.d
6ipvsadm --clear
7rm -rf $HOME/.kube/config