1、环境准备
1.1、配置主机名,ip,host,免密登录
# 设置主机名
hostnamectl set-hostname master01
hostnamectl set-hostname master02
hostnamectl set-hostname master03
hostnamectl set-hostname node01
hostnamectl set-hostname node02
hostnamectl set-hostname node03
#关闭DHCP,设置静态ip
vim /etc/sysconfig/network-scripts/ifcfg-ens18
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=eui64
NAME=ens18
UUID=9e635292-87e0-4a97-b5f7-ce2d5151fc97
DEVICE=ens18
ONBOOT=yes
IPADDR=192.168.8.70
PREFIX=24
GATEWAY=192.168.8.1
DNS1=114.114.114.114
# 重启网卡
systemctl restart NetworkManager
nmcli c reload
nmcli c up ens18
# 设置hosts
cat >> /etc/hosts << 'EOF'
192.168.8.70 master01
192.168.8.71 master02
192.168.8.72 master03
192.168.8.75 node01
192.168.8.76 node02
192.168.8.77 node03
EOF
# 在master01 设置ssh免密登录
ssh-keygen -t rsa # 三次回车
for i in master01 master02 master03 node01 node02 node03;do ssh-copy-id -i .ssh/id_rsa.pub $i;done1.2、关闭防火墙,swap分区和selinux
# 关闭firewalld
systemctl disable --now firewalld
firewall-cmd --state
not running
# selinux默认已关闭
sestatus
SELinux status: disabled
# 如果没有关闭,则修改配置文件
setenforce 0
sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/sysconfig/selinux
sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
#关闭swap分区
swapon --show
#无输出则关闭
# 关闭swap分区
swapoff -a && sysctl -w vm.swappiness=0
sed -ri '/^[^#]*swap/s@^@#@' /etc/fstab1.3、配置时间同步
# kylin默认已经开启时间同步
timedatectl
Local time: 一 2025-09-29 15:55:53 CST
Universal time: 一 2025-09-29 07:55:53 UTC
RTC time: 一 2025-09-29 07:55:53
Time zone: Asia/Shanghai (CST, +0800)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
systemctl status chronyd.service
Warning: The unit file, source configuration file or drop-ins of chronyd.service changed on disk. Run 'systemctl daemon-reload' to reload units.
● chronyd.service - NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; preset: enabled)
Active: active (running) since Mon 2025-09-29 12:02:24 CST; 3h 53min ago
Docs: man:chronyd(8)
man:chrony.conf(5)
Main PID: 923 (chronyd)
Tasks: 1 (limit: 21400)
Memory: 4.4M ()
CGroup: /system.slice/chronyd.service
└─923 /usr/sbin/chronyd
9月 29 12:02:22 master systemd[1]: Starting NTP client/server...
9月 29 12:02:24 master chronyd[923]: chronyd version 4.3 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +NTS +SECHASH +IPV6 +DEBUG)
9月 29 12:02:24 master chronyd[923]: Frequency -25.286 +/- 3.260 ppm read from /var/lib/chrony/drift
9月 29 12:02:24 master systemd[1]: Started NTP client/server.
9月 29 12:02:47 master chronyd[923]: Selected source 113.141.164.39 (ntp.ntsc.ac.cn)
9月 29 12:03:52 master chronyd[923]: Selected source 8.149.241.96 (ntp1.aliyun.com)
1.4、配置内核路由转发及网桥过滤
# 修改/etc/sysctl.conf
net.ipv4.ip_forward = 1
# 生效
sysctl -p
# 添加网桥过滤文件
cat > /etc/sysctl.d/k8s.conf << 'EOF'
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
# 加载br_netfilter模块
tee /etc/modules-load.d/k8s.conf << 'EOF'
overlay
br_netfilter
EOF
# 立刻生效,如果不执行此命令不会生效
modprobe overlay
modprobe br_netfilter
# 查看是否加载
lsmod |grep br_netfilter
br_netfilter 36864 0
bridge 425984 1 br_netfilter
# 重新加载生效
sysctl --system
1.5、修改系统上cgroup版本
查看当前系统版本
stat -fc %T /sys/fs/cgroup/对于1.35以后的版本可能不再支持cgroupv1,我们需要将其求改为cgroupv2
此外 cgroup v2 对内核版本要求 >= kernel 4.5
通过修改 GRUB 配置文件,让系统在启动时加载 cgroup v2。
# 打开 GRUB 配置文件
vim /etc/default/grub找到 GRUB_CMDLINE_LINUX 这一行,在双引号内的参数列表末尾,添加 systemd.unified_cgroup_hierarchy=1 。
修改了引导配置后,需要更新 GRUB 文件并重启系统使其生效
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
# 重启
reboot -h now1.6、安装ipset和ipvsadm
# 安装ipset和ipvsadm
dnf install -y ipset ipvsadm
#配置ipvs需要加载的模块
cat <<EOF > /etc/sysconfig/modules/ipvs.modules
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack
EOF
# 加载生效
chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod |grep -e ip_vs -e nf_conntrack
配置完参数后reboot重启服务器
2、组件准备
kylin11默认安装了docker-cli,moby,containerd,我们需要卸载这些组件,并重新安装containerd
dnf list |grep -E 'docker|moby|containerd|runc'
containerd.x86_64 1.7.23-1.p02.ky11 @anaconda
docker-cli.x86_64 1:24.0.9-1.ky11 @anaconda
moby.x86_64 24.0.9-1.p01.ky11 @anaconda
runc.x86_64 1.1.12-1.p03.ky11 @anaconda
# 移除组件
dnf remove -y docker* moby* containerd* runc*
Removed:
containerd-1.7.23-1.p02.ky11.x86_64 docker-cli-1:24.0.9-1.ky11.x86_64 libcgroup-3.1.0-6.ky11.x86_64 moby-24.0.9-1.p01.ky11.x86_64 runc-1.1.12-1.p03.ky11.x86_64 tini-static-0.19.0-1.p01.ky11.x86_64
# 安装需要用到的软件包
dnf install -y wget curl
# 会安装两个依赖包(libmetalink libcurl)2.1、安装containerd
GitHub仓库地址 https://github.com/containerd/containerd/blob/main/docs/getting-started.md
# 获取压缩包文件
wget https://github.com/containerd/containerd/releases/download/v2.1.4/containerd-2.1.4-linux-amd64.tar.gz
# 解压文件
tar Czxvf /usr/local containerd-2.1.4-linux-amd64.tar.gz
##输出信息
bin/
bin/containerd-stress
bin/ctr
bin/containerd
bin/containerd-shim-runc-v2配置systemd启动文件,此处存放路径与官网有差异,systemd优先扫描此路径 /etc/systemd/system/(管理员自定义服务),其次/usr/lib/systemd/system/(包管理器安装的软件存放路径)
curl -o /etc/systemd/system/containerd.service https://raw.githubusercontent.com/containerd/containerd/main/containerd.service
cat /etc/systemd/system/containerd.service
# Copyright The containerd Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target dbus.service
[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/containerd
Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity
# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
OOMScoreAdjust=-999
[Install]
WantedBy=multi-user.target
此处注意修改ExecStart= 为实际路径,并添加必要参数
可以输入systemctl show -p FragmentPath containerd
FragmentPath=/etc/systemd/system/containerd.service
查看实际存放路径
设置配置文件toml
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml修改 containerd 配置文件
# 修改沙箱镜像
49 [plugins.'io.containerd.cri.v1.images'.pinned_images]
50 sandbox = 'registry.k8s.io/pause:3.10'
sandbox = 'registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.10.1'
#修改镜像仓库的配置路径,此处在2.x默认为空即可,详见注意1
[plugins.'io.containerd.cri.v1.images'.registry]
config_path = '/etc/containerd/certs.d'
# 添加SystemdCgroup = true,此处在2.x已经废弃,默认无此参数,详见注意2
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc]
...
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
SystemdCgroup = true关于配置的pause:3.10.1的版本问题,取决于kubeadm config images pull 实际拉取的版本,通过kubeadm config images list 命令查看
注意1:配置镜像仓库,2.x版本修改了配置方法。
在 containerd 的 config.toml 中设置 config_path = "/etc/containerd/certs.d" 。在配置路径下创建一个目录树,其中包括 docker.io 作为表示要配置的主机命名空间的目录。然后在 docker.io 中添加一个 hosts.toml 文件来配置主机命名空间。
参见 docs/hosts.md 获取更多信息
$ tree /etc/containerd/certs.d
/etc/containerd/certs.d
└── docker.io
└── hosts.toml
$ cat /etc/containerd/certs.d/docker.io/hosts.toml
server = "https://docker.io"
[host."https://registry-1.docker.io"]
capabilities = ["pull", "resolve"]
$ cat /etc/containerd/certs.d/192.168.12.34:5000/hosts.toml
server = "https://192.168.12.34:5000"
[host."https://192.168.12.34:5000"]
ca = "/path/to/ca.crt"cat /etc/containerd/certs.d/docker.io/hosts.toml
server = "https://docker.io"
[host."https://docker.shaunyang.site"]
capabilities = ["pull", "resolve"]
[host."https://docker.m.daocloud.io"]
capabilities = ["pull", "resolve"]
[host."https://docker.1ms.run"]
capabilities = ["pull", "resolve"]
[host."https://docker.xuanyuan.me"]
capabilities = ["pull", "resolve"]
最后 更改完所有配置文件之后启动containerd
systemctl daemon-reload
systemctl enable --now containerd注意2:在 containerd 2.x(包括 2.1.4)中,config.toml 默认不包含 SystemdCgroup 参数,这是设计上的重大变更,而非配置缺失。
🔑 核心原因:containerd 2.x 的 Cgroup 驱动机制已重构
📌 containerd 2.x 的正确配置方式
✅ 方式一:依赖自动检测(推荐)
containerd 2.x 启动时会自动判断:
如果 PID 1 是 systemd → 自动使用 systemd cgroup driver
否则 → 回退到 cgroupfs
大多数现代 Linux 发行版(CentOS/RHEL/Ubuntu/Debian)无需任何配置即可正确工作。
查看 PID 1的进程名确定
ps -p 1 -o comm=
输出
systemd→ ✅ PID 1 是 systemd输出
init、runit、openrc-init等 → ❌ 不是 systemd
✅ 方式二:显式指定(仅在自动检测失败时)
如果确实需要强制指定,containerd 2.x 使用了新的配置结构:
# containerd 2.x 新格式
[plugins."io.containerd.cri.v1.runtime".runtimes.runc.options]
# 注意:不再是 SystemdCgroup = true/false
# 而是使用 string 类型的 CgroupDriver
CgroupDriver = "systemd" # 或 "cgroupfs"
⚠️ 旧版的
SystemdCgroup = true布尔字段在 2.x 中已被彻底移除,写入会被忽略或报错。
🔍 验证当前实际使用的 Cgroup Driver
# 方法1:通过 crictl 查看运行时信息
sudo crictl info | jq '.config.containerd.runtimes.runc.options'
# 方法2:检查 containerd 日志
journalctl -u containerd | grep -i "cgroup driver"
# 方法3:直接查看生成的完整配置
containerd config dump | grep -A3 'CgroupDriver'
💡 为什么做这个改动?
减少配置错误:1.x 时代大量 K8s 故障源于
SystemdCgroup与 kubelet 的--cgroup-driver不一致。2.x 通过自动检测消除这种人为失误。对齐 OCI Runtime Spec:新配置更贴近 runc/crun 的原生接口。
支持多运行时:不同 runtime(runc、crun、youki)可以独立配置 cgroup driver,不再全局绑定。
⚠️ 升级注意事项
如果你是从 1.x 升级到 2.x:
删除所有
SystemdCgroup = true/false配置行确保 kubelet 的
--cgroup-driver与宿主机 init 系统一致(systemd 主机用systemd)运行
containerd config migrate可自动转换旧配置到新格式:containerd config migrate /etc/containerd/config.toml > /etc/containerd/config-v2.toml
📚 参考
总结:
SystemdCgroup消失是 containerd 2.x 的正常行为。只要你的系统是 systemd 管理的,containerd 2.1.4 会自动使用 systemd cgroup driver,无需手动配置。如需确认,请用上述命令验证实际生效值。
2.2、安装runc
下载安装
wget https://github.com/opencontainers/runc/releases/download/v1.3.1/runc.amd64
install -m 755 runc.amd64 /usr/local/sbin/runc
runc --version
#有如下输出
runc version 1.3.1
commit: v1.3.1-0-ge6457afc
spec: 1.2.1
go: go1.23.12
libseccomp: 2.5.6
2.3、安装crictl
安装容器运行时接口CRI
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.34.0/crictl-v1.34.0-linux-amd64.tar.gz
tar Czxvf /usr/local/bin/ crictl-v1.34.0-linux-amd64.tar.gz配置运行时端点配置
cat > /etc/crictl.yaml << 'EOF'
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 2
debug: true
pull-image-on-create: false
EOF2.4、安装高可用组件
高可用组件只在master节点上面安装
2.4.1、安装haproxy
# dnf源包安装,默认版本 2.9.5
dnf install haproxy -y 三台master 配置相同的haproxy参数,注意backend的 主机名 ip和端口号
sudo tee /etc/haproxy/haproxy.cfg << 'EOF'
global
log /dev/log local0
log /dev/log local1 notice
stats timeout 30s
maxconn 2000
ulimit-n 16384
defaults
log global
mode tcp
option tcplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
frontend kube-apiserver
bind *:16443
mode tcp
option tcplog
default_backend kube-apiserver
backend kube-apiserver
mode tcp
option tcplog
option tcp-check
balance roundrobin
default-server inter 10s downinter 5s rise 2 fall 2 slowstart 60s maxconn 250 maxqueue 256 weight 100
server master01 192.168.8.70:6443 check
server master02 192.168.8.71:6443 check
server master03 192.168.8.72:6443 check
EOF
# 重启
sudo systemctl restart haproxy
sudo systemctl enable haproxy
# 验证(应该看到 LISTEN 在 16443 端口)
sudo ss -tlnp | grep 16443关键:HAProxy 监听 16443 端口,把请求轮询分发到 3 个 Master 的 6443 端口(6443 是 K8s API Server 默认端口)。所有客户端(kubectl、其他 Master、Worker)都通过 VIP:16443 访问 K8s,而不是直接连某个 Master 的 IP。
2.4.2、安装配置keepalived
# dnf源包安装 版本 2.2.8
dnf install keepalived -y 3 台 Master 都装,但要配成"互斥"——同一时间只有一台"持有" VIP。(192.168.8.79)
Master1(优先级 150,抢 VIP):
sudo tee /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
enable_script_security
script_user root
}
vrrp_script check_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2
weight -30
fall 3
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface ens18
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.8.70
unicast_peer {
192.168.8.71
192.168.8.72
}
virtual_ipaddress {
192.168.8.79/24
}
track_script {
check_haproxy
}
}
EOFMaster2(优先级 120):
sudo tee /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
enable_script_security
script_user root
}
vrrp_script check_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2
weight -30
fall 3
rise 2
}
vrrp_instance VI_1 {
state BACKUP
interface ens18
virtual_router_id 51
priority 120
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.8.71
unicast_peer {
192.168.8.70
192.168.8.72
}
virtual_ipaddress {
192.168.8.79/24
}
track_script {
check_haproxy
}
}
EOFMaster3(优先级 100):
sudo tee /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
enable_script_security
script_user root
}
vrrp_script check_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2
weight -30
fall 3
rise 2
}
vrrp_instance VI_1 {
state BACKUP
interface ens18
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.8.72
unicast_peer {
192.168.8.70
192.168.8.71
}
virtual_ipaddress {
192.168.8.79/24
}
track_script {
check_haproxy
}
}
EOF小白解释 VRRP: - VRRP = Virtual Router Redundancy Protocol(虚拟路由冗余协议) - 3 台 Master 之间会互相发"心跳",告诉对方"我还活着" - 优先级最高的 Master(150)持有 VIP 192.168.8.79 - 如果这台 Master 挂了(或 HAProxy 挂了),优先级次高的(120)会"抢"过来 - 整个切换过程大约 5-10 秒,对客户端几乎无感
关键参数说明: -
interface ens18:你的网卡名(不一定是 ens18,用ip a查) -virtual_router_id 51:3 台必须相同,相当于"同一个集群" -auth_pass 1111:3 台必须相同的密码 -unicast_src_ip:本机 IP(用单播通信,避免组播问题) -virtual_ipaddress:VIP 地址
启动keepalive
# 3 台 Master 都执行
sudo systemctl restart keepalived
sudo systemctl enable keepalived
# 验证:在 Master1 上能看到 VIP
ip a show ens18 | grep 192.168.8.79
# 应该看到 inet 192.168.8.79/24
# 其他 Master 上不应该有
# 如果都有,说明 VRRP 没正常工作如果 VIP 没出现在 Master1 上:检查网络、unicast_peer 配错没、网卡名是否对(不一定是 eth0)。
3、集群初始化
3.1、安装k8s组件
所有节点安装 kubeadm、kubelet 和 kubectl
kubeadm:用来初始化集群的指令。kubelet:在集群中的每个节点上用来启动 Pod 和容器等。kubectl:用来与集群通信的命令行工具
添加 Kubernetes 的 yum 仓库。
在仓库定义中的 exclude 参数确保了与 Kubernetes 相关的软件包在运行 yum update 时不会升级,因为升级 Kubernetes 需要遵循特定的过程。
# 此操作会覆盖 /etc/yum.repos.d/kubernetes.repo 中现存的所有配置
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.34/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.34/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOFcat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.34/rpm/
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes-new/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF安装并启动
# 清理缓存并重建数据
sudo yum clean all && yum makecache
# 查询可用版本
yum list available --showduplicates --disableexcludes=kubernetes | grep kubeadm
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
Installed:
conntrack-tools-1.4.8-2.ky11.x86_64 containernetworking-plugins-1.2.0-4.ky11.x86_64 cri-tools-1.34.0-150500.1.1.x86_64 kubeadm-1.34.1-150500.1.1.x86_64 kubectl-1.34.1-150500.1.1.x86_64 kubelet-1.34.1-150500.1.1.x86_64 libnetfilter_cthelper-1.0.1-1.ky11.x86_64
libnetfilter_cttimeout-1.0.1-1.ky11.x86_64 libnetfilter_queue-1.0.5-3.ky11.x86_64
kubelet设置cgroup驱动为systemd,在containerd 2.x作为容器运行时此步可省略不必配置,会自动检测
cat <<EOF > /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS="--cgroup-driver=systemd"
EOFkubelet设置开机自启动
sudo systemctl enable --now kubeletkubelet 现在每隔几秒就会重启,因为它陷入了一个等待 kubeadm 指令的死循环。
3.2、修改集群初始化文件
在主节点上生成配置文件 kubeadm config print init-defaults > kubeadm-config.yaml
1 apiVersion: kubeadm.k8s.io/v1beta4
2 bootstrapTokens:
3 - groups:
4 - system:bootstrappers:kubeadm:default-node-token
5 token: abcdef.0123456789abcdef
6 ttl: 24h0m0s
7 usages:
8 - signing
9 - authentication
10 kind: InitConfiguration
11 localAPIEndpoint:
######################################修改################################
12 advertiseAddress: 192.168.8.70
13 bindPort: 6443
14 nodeRegistration:
15 criSocket: unix:///var/run/containerd/containerd.sock
16 imagePullPolicy: IfNotPresent
17 imagePullSerial: true
##################################修改#####################################
18 name: master01
19 taints: null
20 timeouts:
21 controlPlaneComponentHealthCheck: 4m0s
22 discovery: 5m0s
23 etcdAPICall: 2m0s
24 kubeletHealthCheck: 4m0s
25 kubernetesAPICall: 1m0s
26 tlsBootstrap: 5m0s
27 upgradeManifests: 5m0s
28 ---
29 apiServer: {}
30 apiVersion: kubeadm.k8s.io/v1beta4
#############################修改百年令牌期限#########################
31 caCertificateValidityPeriod: 876000h0m0s
32 certificateValidityPeriod: 876000h0m0s
33 certificatesDir: /etc/kubernetes/pki
34 clusterName: kubernetes
35 controllerManager: {}
###############新增集群控制平面入口# VIP + HAProxy 端口####################################
35 controlPlaneEndpoint: "192.168.8.79:16443"
36 dns: {}
37 encryptionAlgorithm: RSA-2048
38 etcd:
39 local:
40 dataDir: /var/lib/etcd
################################修改###################################
41 imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers
42 kind: ClusterConfiguration
############################版本号与kubeadm一致#####################
43 kubernetesVersion: v1.34.11
44 networking:
45 dnsDomain: cluster.local
46 serviceSubnet: 10.96.0.0/12
##############################修改##################################
podSubnet: 172.33.0.0/16
47 proxy: {}
48 scheduler: {}
3.3、拉取k8s镜像
kubeadm config images pull \
--image-repository=registry.aliyuncs.com/google_containers \
--kubernetes-version=v1.34.113.4、初始化集群
kubeadm init --config kubeadm-config.yaml --upload-certs --v=9如果出现报错,建议 kubeadm reset -f 后重新初始化
# 1. 重置集群
kubeadm reset -f
# 2. 清理旧数据(可选但推荐)
rm -rf /etc/kubernetes/pki /var/lib/etcd ~/.kube/config
# 3. 使用修正后的配置重新初始化
kubeadm init --config kubeadm-config.yaml --upload-certs
3.5、配置kubectl权限
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 验证配置
kubectl config view
# 输出
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.8.79:16443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
users:
- name: kubernetes-admin
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
3.6、配置kube-proxy使用ipvs模式
# 编辑kube-proxy配置
kubectl edit configmap kube-proxy -n kube-system
# 在config.conf部分修改mode为ipvs
# mode: "ipvs"
# 重启kube-proxy
kubectl rollout restart daemonset kube-proxy -n kube-system3.7、安装calico网络插件
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.30.3/manifests/tigera-operator.yaml
wget https://raw.githubusercontent.com/projectcalico/calico/v3.30.3/manifests/custom-resources.yaml
vim custom-resources.yaml
# 需要修改成指定的podIP段
cidr: 172.33.0.0/16
kubectl create -f custom-resources.yaml
# 验证网络插件状态(所有pod状态为Running)
watch kubectl get pods -n calico-system3.8、加入其它节点
3.8.1、加入控制节点
初始化成功后,添加其他控制平面节点时使用:
kubeadm join 192.168.8.79:16443 \
--token abcdef.0123456789abcdef \
--control-plane \
--certificate-key <init输出的certificate-key>⚠️
--certificate-key的值来自kubeadm init --upload-certs的输出,有效期仅 2 小时。过期后可用kubeadm init phase upload-certs --upload-certs重新生成。
3.8.2、加入工作节点
获取token(在master节点执行)
kubeadm token create --print-join-command加入集群(在node节点执行)
# 依据实际环境改动
kubeadm join 192.168.8.79:16443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:6b028dd0c8d1390ea89ed32fa9cdd811accd253c436ccc8fca9642da716dccb8 4、集群验证
1. 检查节点状态
kubectl get nodes
# 预期输出:所有节点状态为Ready2. 检查系统组件状态
kubectl get pods -n kube-system
# 预期输出:所有pod状态为Running
kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy ok
kubectl get svc -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
calico-apiserver calico-api ClusterIP 10.98.217.92 <none> 443/TCP 24m
calico-system calico-kube-controllers-metrics ClusterIP None <none> 9094/TCP 9m10s
calico-system calico-typha ClusterIP 10.98.13.246 <none> 5473/TCP 24m
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 87m
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 87m
3. 验证 dns解析功能
dig -t a www.baidu.com @10.96.0.10
; <<>> DiG 9.18.21 <<>> -t a www.baidu.com @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50661
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: c595abdf33358469 (echoed)
;; QUESTION SECTION:
;www.baidu.com. IN A
;; ANSWER SECTION:
www.baidu.com. 30 IN CNAME www.a.shifen.com.
www.a.shifen.com. 30 IN A 220.181.111.1
www.a.shifen.com. 30 IN A 220.181.111.232
;; Query time: 33 msec
;; SERVER: 10.96.0.10#53(10.96.0.10) (UDP)
;; WHEN: Tue Sep 30 18:22:47 CST 2025
;; MSG SIZE rcvd: 161
4. 验证 IPVS 模式是否生效
# 查看kube-proxy日志确认IPVS模式
kubectl logs -n kube-system $(kubectl get pods -n kube-system -l k8s-app=kube-proxy -o jsonpath='{.items[0].metadata.name}') | grep "Using ipvs Proxier"
# 查看IPVS规则
ipvsadm -Ln
# 预期输出:包含K8s服务的IPVS规则
curl 127.0.0.1:10249/proxyMode
# 预期输出:ipvs5. 验证集群功能
# 创建测试部署
kubectl create deployment nginx --image=nginx:1.23
# 暴露服务
kubectl expose deployment nginx --port=80 --type=NodePort
# 查看服务
kubectl get svc nginx
# 访问测试(替换为实际NodePort)
curl http://192.168.8.70:3xxxx