026-K8S-二进制安装Node新节点到集群中

一、系统环境

  • 操作系统:Rocky Linux 9.3
  • 内核版本:5.14.0-284.11.1.el9_2.x86_64
  • 容器运行时:Docker + CRI-Docker
  • Kubernetes 版本:1.29.2
  • 网络插件:Calico

二、集群规划

基于二进制安装包,部署三主两从的高可用集群。

主机名称 IPV4地址 CPU/内存/磁盘 说明 软件
10.20.1.203 2C/4G/200G 外网节点(可翻墙) 下载各种所需安装包
Master01 10.20.1.101 2C/4G/200G master节点(已有) apiserver、controller-manager、scheduler、etcd、 kubelet、kube-proxy、nginx
Master02 10.20.1.102 2C/4G/200G master节点(已有) apiserver、controller-manager、scheduler、etcd、 kubelet、kube-proxy、nginx
Master03 10.20.1.103 2C/4G/200G master节点(已有) apiserver、controller-manager、scheduler、etcd、 kubelet、kube-proxy、nginx
Node01 10.20.1.104 2C/4G/200G node节点(已有) kubelet、kube-proxy、nginx
Node02 10.20.1.105 2C/4G/200G node节点(已有) kubelet、kube-proxy、nginx
Node03 10.20.1.106 2C/4G/200G node节点(新节点) kubelet、kube-proxy、nginx
Node04 10.20.1.107 2C/4G/200G node节点(新节点) kubelet、kube-proxy、nginx
Node05 10.20.1.108 2C/4G/200G node节点(新节点) kubelet、kube-proxy、nginx

三、基础环境配置(所有节点)

1. 主机名设置

设置集群中各个节点的主机名

Node03 节点

hostnamectl set-hostname k8s-node03

Node04 节点

hostnamectl set-hostname k8s-node04

Node05 节点

hostnamectl set-hostname k8s-node05

2. 配置静态IP

集群内的每个几点都需要配置唯一的IP地址,这里同时配置了 IPV4地址 和 IPV6地址。

Node 节点

[root@k8s-master01 ~]# cat /etc/NetworkManager/system-connections/ens34.nmconnection
[ipv4]
method=manual
address1=10.20.1.106/24;10.20.1.1
dns=61.132.163.68;114.114.114.114

[ipv6]
method=manual
addresses=2400:3200::106/64
gateway=2400:3200::1
dns=2400:3200::1;2400:3200:baba::1;2001:4860:4860::8888;2001:4860:4860::8844

3. 修改hosts文件

配置集群各节点 hostname 和 ip 的映射

cat >> /etc/hosts << "EOF"
10.20.1.101 k8s-master01 m1
10.20.1.102 k8s-master02 m2
10.20.1.103 k8s-master03 m3
10.20.1.104 k8s-node01 n1
10.20.1.105 k8s-node02 n2
10.20.1.106 k8s-node03 n3
10.20.1.107 k8s-node04 n4
10.20.1.108 k8s-node05 n5
2400:3200::101 k8s-master01 m1
2400:3200::102 k8s-master02 m2
2400:3200::103 k8s-master03 m3
2400:3200::104 k8s-node01 n1
2400:3200::105 k8s-node02 n2
2400:3200::106 k8s-node03 n3
2400:3200::107 k8s-node04 n4
2400:3200::108 k8s-node05 n5
EOF

验证 hosts 文件配置

cat /etc/hosts
ping k8s-master01 -c 4  # 默认使用 IPv4
ping6 k8s-master01 -c 4  # 使用 IPv6

4. 修改终端颜色

这里只是修改shell终端显示文本的颜色,非必要步骤。

cat << EOF >> ~/.bashrc
PS1="\[\e[37;47m\][\[\e[32;47m\]\u\[\e[34;47m\]@\h \[\e[36;47m\]\w\[\e[0m\]]\\$ "
EOF

# 让修改立即见效
source ~/.bashrc

命令解析:

这段命令用于修改当前用户的 Bash Shell 提示符PS1),并将其设置写入到 ~/.bashrc 文件中,以便在每次登录或启动 Shell 时自动加载该配置。

PS1="..."
定义 Shell 的主提示符格式(Prompt String 1),即你在终端中输入命令时显示的提示符。

最终效果如下:

终端颜色修改

5. 更换系统软件源

将 Rocky 默认源替换成阿里源,提升软件安装速度。

# 更新源
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
    -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
    -i.bak /etc/yum.repos.d/[Rr]ocky*.repo
    

# 刷新dnf缓存
dnf makecache

# 验证源更新
dnf repolist

命令解析:

# 使用 sed 命令修改 Rocky Linux 的 YUM/DNF 源配置文件,切换到阿里云的镜像源。
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
 -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
 -i.bak /etc/yum.repos.d/[Rr]ocky*.repo

# 将以 mirrorlist= 开头的行注释掉(在前面加 #)
-e 's|^mirrorlist=|#mirrorlist=|g'

# 将以 #baseurl= 开头并指向默认 Rocky Linux 源的行取消注释,并替换为阿里云镜像源 URL。
's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g'

# -i.bak:直接修改文件,并为原文件创建备份(扩展名为 .bak)。
# 修改 /etc/yum.repos.d/ 目录下所有以 rocky 或 Rocky 开头的 .repo 文件。
# 修改完成后,原始文件会被备份为 .bak 文件。
-i.bak /etc/yum.repos.d/[Rr]ocky*.repo



# 更新本地缓存,确保系统可以快速查询软件包信息。
dnf makecache

6. 修改防火墙

关闭默认防火墙firewalld,配置 iptables 防火墙

systemctl stop firewalld
systemctl disable firewalld
yum -y install iptables-services
systemctl start iptables
iptables -F
systemctl enable iptables
service iptables save

命令解析:

# 停止运行 firewalld
systemctl stop firewalld

# 禁止 firewalld 开机自启
systemctl disable firewalld

# 安装 iptables 服务,用于管理 Linux 的防火墙规则
yum -y install iptables-services

# 使防火墙规则立即生效,并开始运行 iptables 防火墙服务。
systemctl start iptables

# 删除当前的防火墙规则,通常用于重置或清理防火墙规则。
iptables -F

# 设置 iptables 服务开机自启动,确保服务器重启后,iptables 服务会自动加载防火墙规则。
systemctl enable iptables

# 将当前 iptables 的规则配置保存到文件中(通常是 /etc/sysconfig/iptables),以便在系统重启或 iptables 服务重新启动后,能够自动加载保存的规则。
service iptables save

7. 禁用 Selinux

setenforce 0
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
grubby --update-kernel ALL --args selinux=0

命令解析:

# 将 SELinux 的模式设置为 Permissive(宽容模式)。
# 0:表示设置为 Permissive 模式,此模式下 SELinux 不会强制执行安全策略,而是记录违规日志。
# 1:表示 Enforcing 模式,此模式下 SELinux 会强制执行安全策略。
setenforce 0

# 修改 SELinux 配置文件 /etc/selinux/config,将 SELINUX 设置为 disabled。永久禁用 SELinux,即使系统重启也不会再启用。
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

# 通过 grubby 工具将 selinux=0 参数添加到所有内核启动配置中。
grubby --update-kernel ALL --args selinux=0
grubby --info DEFAULT

# 查看是否禁用,
grubby --info DEFAULT
# 回滚内核层禁用操作,、
grubby --update-kernel ALL --remove-args selinux

8. 设置时区

timedatectl set-timezone Asia/Shanghai

9. 关闭 swap 分区

swapoff -a
sed -i 's:/dev/mapper/rl-swap:#/dev/mapper/rl-swap:g' /etc/fstab

命令解析:

#  立即关闭系统中所有的交换分区
swapoff -a

# 注释掉 /etc/fstab 文件中定义的交换分区挂载条目,防止系统在重启后重新启用交换分区。
sed -i 's:/dev/mapper/rl-swap:#/dev/mapper/rl-swap:g' /etc/fstab

# 验证交换分区是否关系
free -h
输出中 Swap 一栏的值会变为 0。

10. 安装基本工具

dnf -y install openssh-server wget tree bash-completion psmisc vim net-tools lrzsz nfs-utils epel-release telnet rsync yum-utils device-mapper-persistent-data lvm2 git tar curl

11. 修改系统最大打开文件数

cat >> /etc/security/limits.conf <<EOF
* soft nofile 655360
* hard nofile 131072
* soft nproc 655350
* hard nproc 655350
* soft memlock unlimited
* hard memlock unlimited
EOF
 
echo "ulimit -SHn 65535" >> /etc/profile
source /etc/profile

命令解析:

soft nofile 655360
soft表示软限制,nofile 表示一个进程可打开的最大文件数,默认值为1024。这里的软限制设置为655360,即一个进程可打开的最大文件数为655360。

hard nofile 131072
hard表示硬限制,即系统设置的最大值。nofile表示一个进程可打开的最大文件数,默认值为4096。这里的硬限制设置为131072,即系统设置的最大文件数为131072。

soft nproc 655350
soft表示软限制,nproc表示一个用户可创建的最大进程数,默认值为30720。这里的软限制设置为655350,即一个用户可创建的最大进程数为655350。

hard nproc 655350
hard表示硬限制,即系统设置的最大值。nproc表示一个用户可创建的最大进程数,默认值为4096。这里的硬限制设置为655350,即系统设置的最大进程数为655350。

soft memlock unlimited
seft表示软限制,memlock表示一个进程可锁定在RAM中的最大内存,默认值为64 KB。这里的软限制设置为unlimited,即一个进程可锁定的最大内存为无限制。

hard memlock unlimited
hard表示硬限制,即系统设置的最大值。memlock表示一个进程可锁定在RAM中的最大内存,默认值为64 KB。这里的硬限制设置为unlimited,即系统设置的最大内存锁定为无限制。

12. 安装 ipvs

# 安装 ipvs
yum install ipvsadm ipset sysstat conntrack libseccomp -y

cat >> /etc/modules-load.d/ipvs.conf <<EOF 
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
ip_tables
ip_set
xt_set
ipt_set
ipt_rpfilter
ipt_REJECT
ipip
EOF

systemctl restart systemd-modules-load.service

lsmod | grep -e ip_vs -e nf_conntrack

命名解析:

  • ipvsadm 命令行工具,用于管理IPVS(IP Virtual Server)

  • ipset 内核级工具,用于高效管理IP地址、端口或MAC地址的集合(sets)

  • sysstat 系统性能监控工具包,包括sar、iostat、mpstat等命令,用于收集和报告CPU、内存、磁盘I/O、网络等系统统计数据

  • conntrack 命令行工具(conntrack-tools的一部分),用于管理Netfilter的连接跟踪表(connection tracking table)

  • libseccomp 这是一个库,用于支持seccomp(Secure Computing Mode),seccomp是Linux内核功能,用于限制进程的系统调用(syscall),从而增强安全性(如沙箱化)

cat >> ….. 显示的加载内核模块

  • ip_vs 核心IPVS模块,提供虚拟服务器功能,用于L4负载均衡
  • ip_vs_rr IPVS的 round-robin 调度算法模块(轮询)
  • ip_vs_wrr IPVS的 weighted round-robin 调度算法模块(加权轮询)
  • ip_vs_sh IPVS的 source hashing 调度算法模块(源地址哈希)
  • nf_conntrack Netfilter连接跟踪模块,跟踪网络连接状态(用于NAT和防火墙)
  • ip_tables iptables的核心模块,用于IPv4包过滤和NAT
  • ip_set IP集合管理模块,支持高效的IP列表处理
  • xt_set iptables的扩展模块,用于与ip_set集成
  • ipt_set iptables的set匹配模块(类似xt_set,但特定于IPv4)
  • ipt_rpfilter iptables的反向路径过滤模块,防止IP欺骗攻击
  • ipt_REJECT iptables的REJECT目标模块,用于拒绝包并发送拒绝消息
  • ipip 隧道模块,用于封装IP包(类似VPN隧道)

systemctl restart systemd-modules-load.service:立即加载这些模块(因为/etc/modules-load.d/目录下的.conf文件会被systemd-modules-load服务读取)

lsmod | grep -e ip_vs -e nf_conntrack :检查模块是否加载成功。

13. 开启路由转发

echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf
sysctl -p

14. 排除 calico 网卡被 NetworkManager 所管理

cat > /etc/NetworkManager/conf.d/calico.conf << EOF
[keyfile]
unmanaged-devices=interface-name:cali*;interface-name:tunl*;interface-name:vxlan.calico;interface-name:vxlan-v6.calico;interface-name:wireguard.cali;interface-name:wg-v6.cali
EOF

systemctl restart NetworkManager

命令解析:

这个参数用于指定不由 NetworkManager 管理的设备。它由以下两个部分组成

interface-name:cali*
表示以 "cali" 开头的接口名称被排除在 NetworkManager 管理之外。例如,"cali0", "cali1" 等接口不受 NetworkManager 管理

interface-name:tunl*
表示以 "tunl" 开头的接口名称被排除在 NetworkManager 管理之外。例如,"tunl0", "tunl1" 等接口不受 NetworkManager 管理

interface-name:vxlan.calico
匹配名为vxlan.calico的接口,Calico在VXLAN模式下可能使用该接口名进行跨节点通信(VXLAN是一种覆盖网络技术)

interface-name:vxlan-v6.calico
匹配名为vxlan-v6.calico的接口,这是Calico在支持IPv6的VXLAN模式下使用的接口名

interface-name:wireguard.cali
匹配名为wireguard.cali的接口,Calico支持使用WireGuard(一种高性能VPN协议)进行加密通信,这个接口用于WireGuard隧道。

interface-name:wg-v6.cali
匹配名为wg-v6.cali的接口,这是Calico在IPv6网络中使用的WireGuard接口

通过使用这个参数,可以将特定的接口排除在 NetworkManager 的管理范围之外,以便其他工具或进程可以独立地管理和配置这些接口

15. 修改内核参数

cat > /etc/sysctl.d/k8s.conf << EOF
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
fs.may_detach_mounts = 1
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.netfilter.nf_conntrack_max=2310720
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl =15
net.ipv4.tcp_max_tw_buckets = 36000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_orphans = 327680
net.ipv4.tcp_orphan_retries = 3
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.ip_conntrack_max = 65536
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_timestamps = 0
net.core.somaxconn = 16384
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.lo.disable_ipv6 = 0
net.ipv6.conf.all.forwarding = 1
EOF

sysctl --system

命令解析:

这些是Linux系统的一些参数设置,用于配置和优化网络、文件系统和虚拟内存等方面的功能。以下是每个参数的详细解释:

net.ipv4.ip_forward = 1
这个参数启用了IPv4的IP转发功能,允许服务器作为网络路由器转发数据包。

net.bridge.bridge-nf-call-iptables = 1
当使用网络桥接技术时,将数据包传递到iptables进行处理。

fs.may_detach_mounts = 1
允许在挂载文件系统时,允许被其他进程使用。

vm.overcommit_memory=1
该设置允许原始的内存过量分配策略,当系统的内存已经被完全使用时,系统仍然会分配额外的内存。

vm.panic_on_oom=0
当系统内存不足(OOM)时,禁用系统崩溃和重启。

fs.inotify.max_user_watches=89100
设置系统允许一个用户的inotify实例可以监控的文件数目的上限。

fs.file-max=52706963
设置系统同时打开的文件数的上限。

fs.nr_open=52706963
设置系统同时打开的文件描述符数的上限。

net.netfilter.nf_conntrack_max=2310720
设置系统可以创建的网络连接跟踪表项的最大数量。

net.ipv4.tcp_keepalive_time = 600
设置TCP套接字的空闲超时时间(秒),超过该时间没有活动数据时,内核会发送心跳包。

net.ipv4.tcp_keepalive_probes = 3
设置未收到响应的TCP心跳探测次数。

net.ipv4.tcp_keepalive_intvl = 15
设置TCP心跳探测的时间间隔(秒)。

net.ipv4.tcp_max_tw_buckets = 36000
设置系统可以使用的TIME_WAIT套接字的最大数量。

net.ipv4.tcp_tw_reuse = 1
启用TIME_WAIT套接字的重新利用,允许新的套接字使用旧的TIME_WAIT套接字。

net.ipv4.tcp_max_orphans = 327680
设置系统可以同时存在的TCP套接字垃圾回收包裹数的最大数量。

net.ipv4.tcp_orphan_retries = 3
设置系统对于孤立的TCP套接字的重试次数。

net.ipv4.tcp_syncookies = 1
启用TCP SYN cookies保护,用于防止SYN洪泛攻击。

net.ipv4.tcp_max_syn_backlog = 16384
设置新的TCP连接的半连接数(半连接队列)的最大长度。

net.ipv4.ip_conntrack_max = 65536
设置系统可以创建的网络连接跟踪表项的最大数量。

net.ipv4.tcp_timestamps = 0
关闭TCP时间戳功能,用于提供更好的安全性。

net.core.somaxconn = 16384
设置系统核心层的连接队列的最大值。

net.ipv6.conf.all.disable_ipv6 = 0
启用IPv6协议。

net.ipv6.conf.default.disable_ipv6 = 0
启用IPv6协议。

net.ipv6.conf.lo.disable_ipv6 = 0
启用IPv6协议。

net.ipv6.conf.all.forwarding = 1
允许IPv6数据包转发。

16. 集群时间同步设置

K8S-二进制高可用部署 中已经设置了以 Master01、Master02、Master03 作为时间同步的主节点,这里只需要设置 Node 节点从 Master 同步时间即可。

Node节点

yum install chrony -y

cat > /etc/chrony.conf << EOF 
pool 10.20.1.101 iburst
pool 10.20.1.102 iburst
pool 10.20.1.103 iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
keyfile /etc/chrony.keys
leapsectz right/UTC
logdir /var/log/chrony
EOF

systemctl restart chronyd ; systemctl enable chronyd

#使用客户端进行验证
chronyc sources -v

17. 配置免密登录

配置 k8s-master01 节点免密登录到其它节点,方便后续从 master01 节点往其它节点发送文件。

master-01

yum install -y expect
ssh-keygen -t rsa -P "" -f /root/.ssh/id_rsa
export user=root
export pass=123456
host=(k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02 k8s-node03 k8s-node04 k8s-node05 m1 m2 m3 n1 n2 n3 n4 n5)
 
for host in ${host[@]};do expect -c "
spawn ssh-copy-id -i /root/.ssh/id_rsa.pub $user@$host
    expect {
        \"*yes/no*\" {send \"yes\r\"; exp_continue}
        \"*password*\" {send \"$pass\r\"; exp_continue}
        \"*Password*\" {send \"$pass\r\";}
    }";
done

命令解析:

# 一个自动化交互工具,用于处理需要用户输入的命令行交互
yum install -y expect

# 生成RSA类型的SSH密钥对(公钥和私钥),并存储在指定路径。-P "":设置空密码(无口令保护),便于自动化使用
ssh-keygen -t rsa -P "" -f /root/.ssh/id_rsa
export user=root
export pass=123456

# 定义一个Bash数组host,包含集群中所有节点的主机名和别名
host=(k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02)

# 遍历host数组,对每个节点执行expect脚本
for host in ${host[@]};do expect -c "

# 启动ssh-copy-id命令,将公钥文件/root/.ssh/id_rsa.pub分发到目标节点
spawn ssh-copy-id -i /root/.ssh/id_rsa.pub $user@$host
 expect {
 	# 匹配:当ssh-copy-id提示是否信任目标主机
 	# 动作:发送yes并换行(\r),确认连接
 	# exp_continue:继续匹配后续模式(不退出expect)
     \"*yes/no*\" {send \"yes\r\"; exp_continue}

     # 匹配:当提示输入密码(大写Password)
     # 动作:发送变量$pass(即123456)并换行
     # exp_continue:继续匹配后续模式。
     \"*password*\" {send \"$pass\r\"; exp_continue}
     \"*Password*\" {send \"$pass\r\";}
 }";
done

18. 安装 Docker

18.1 安装 Docker 二进制包

k8s-node节点

# 二进制包下载地址:https://download.docker.com/linux/static/stable/x86_64/

# 创建目录,后续下载的文件都放在这里
mkdir -p /opt/software/ /opt/module/ && chmod 777 -R /opt/software/ /opt/module/

# 下载 Docker
wget https://download.docker.com/linux/static/stable/x86_64/docker-28.4.0.tgz

# 解压二进制包
tar xf docker-*.tgz

# 拷贝解压后的二进制包到 /usr/bin 目录下
cp docker/* /usr/bin/

# 验证
$ docker --version
Docker version 28.4.0, build d8eb465

# 查看 containerd 版本
$ containerd --version
containerd github.com/containerd/containerd v1.7.28 b98a3aace656320842a23f4a392a33f46af97866

18.2 配置 containerd.service

  • containerd 的作用:它是一个独立的守护进程(daemon),处理低级任务,如镜像拉取、容器启动/停止、快照管理、网络/存储挂载等。它基于 OCI(Open Container Initiative)标准,与 runC(Docker 的另一个组件,用于实际执行容器)协作。

  • dockerd 的作用:Docker Daemon (dockerd) 不再直接管理容器,而是作为一个高层管理器,通过 gRPC 接口与 containerd 通信。dockerd 处理用户命令(如 docker run)、镜像构建、网络/卷管理等,并将容器相关操作委托给 containerd。

Docker底层依赖 containerd ,如果不安装 containerd ,Docker 会启动失败,因为 dockerd 需要连接到 containerd.sock(由 containerd 服务生成)。这会导致整个链条崩溃:cri-dockerd → dockerd → containerd。

即使 Kubernetes 通过 cri-dockerd 使用 Docker,Docker 本身还是依赖 containerd 来实际执行容器操作。没有 containerd,cri-dockerd 和 Docker 都无法工作。

# 下载 containerd.service, 版本需要与 docker 二进制包中的 containerd 一致
# https://github.com/containerd/containerd/blob/main/containerd.service
wget https://raw.githubusercontent.com/containerd/containerd/refs/tags/v1.7.28/containerd.service

# containerd 路径修改后,内容如下:
cat >/etc/systemd/system/containerd.service <<EOF
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target dbus.service

[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/bin/containerd

Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=infinity
TasksMax=infinity
OOMScoreAdjust=-999

[Install]
WantedBy=multi-user.target
EOF


# 设置 containerd 开机自启
systemctl enable --now containerd.service

# 验证
systemctl is-enabled containerd.service

命令解析:

[Unit]

Description=containerd container runtime:指定服务的描述信息。
Documentation=https://containerd.io:指定服务的文档链接。
After=network.target local-fs.target:指定服务的启动顺序,在网络和本地文件系统启动之后再启动该服务。
[Service]

ExecStartPre=-/sbin/modprobe overlay:在启动服务之前执行的命令,使用-表示忽略错误。
ExecStart=/usr/bin/containerd:指定服务的启动命令。
Type=notify:指定服务的类型,notify表示服务会在启动完成后向systemd发送通知。
Delegate=yes:允许服务代理其他服务的应答,例如收到关机命令后终止其他服务。
KillMode=process:指定服务终止时的行为,process表示终止服务进程。
Restart=always:指定服务终止后是否自动重启,always表示总是自动重启。
RestartSec=5:指定服务重启的时间间隔,单位为秒。
LimitNPROC=infinity:限制服务的最大进程数,infinity表示没有限制。
LimitCORE=infinity:限制服务的最大核心数,infinity表示没有限制。
LimitNOFILE=1048576:限制服务的最大文件数,指定为1048576。
TasksMax=infinity:限制服务的最大任务数,infinity表示没有限制。
OOMScoreAdjust=-999:指定服务的OOM(Out of Memory)得分,负数表示降低被终止的概率。
[Install]

WantedBy=multi-user.target:指定服务的安装方式,multi-user.target表示该服务在多用户模式下安装。

18.3 配置 docker.service

下载地址:https://github.com/moby/moby/blob/master/contrib/init/systemd/docker.service

# 下载 docker.service
wget https://raw.githubusercontent.com/moby/moby/refs/tags/v28.4.0/contrib/init/systemd/docker.service


# 修改后写入到指定目录中
cat > /etc/systemd/system/docker.service <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target nss-lookup.target docker.socket firewalld.service containerd.service time-set.target cri-docker.service
Wants=network-online.target containerd.service
Requires=docker.socket containerd.service
StartLimitBurst=3
StartLimitIntervalSec=60

[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500

[Install]
WantedBy=multi-user.target
EOF

命令解析:

[Unit]

Description: 描述服务的作用,这里是Docker Application Container Engine,即Docker应用容器引擎。
Documentation: 提供关于此服务的文档链接,这里是Docker官方文档链接。
After: 说明该服务在哪些其他服务之后启动,这里是在网络在线、firewalld服务和containerd服务后启动。
Wants: 说明该服务想要的其他服务,这里是网络在线服务。
Requires: 说明该服务需要的其他服务,这里是docker.socket和containerd.service。
[Service]

Type: 服务类型,这里是notify,表示服务在启动完成时发送通知。
ExecStart: 命令,启动该服务时会执行的命令,这里是/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock,即启动dockerd并指定一些参数,其中-H指定dockerd的监听地址为fd://,--containerd指定containerd的sock文件位置。
ExecReload: 重载命令,当接收到HUP信号时执行的命令,这里是/bin/kill -s HUP $MAINPID,即发送HUP信号给主进程ID。
TimeoutSec: 服务超时时间,这里是0,表示没有超时限制。
RestartSec: 重启间隔时间,这里是2秒,表示重启失败后等待2秒再重启。
Restart: 重启策略,这里是always,表示总是重启。
StartLimitBurst: 启动限制次数,这里是3,表示在启动失败后最多重试3次。
StartLimitInterval: 启动限制时间间隔,这里是60秒,表示两次启动之间最少间隔60秒。
LimitNOFILE: 文件描述符限制,这里是infinity,表示没有限制。
LimitNPROC: 进程数限制,这里是infinity,表示没有限制。
LimitCORE: 核心转储限制,这里是infinity,表示没有限制。
TasksMax: 最大任务数,这里是infinity,表示没有限制。
Delegate: 修改权限,这里是yes,表示启用权限修改。
KillMode: 杀死模式,这里是process,表示杀死整个进程组。
OOMScoreAdjust: 用于调整进程在系统内存紧张时的优先级调整,这里是-500,表示将OOM分数降低500。
[Install]

WantedBy: 安装目标,这里是multi-user.target,表示在多用户模式下安装。
在WantedBy参数中,我们可以使用以下参数:
multi-user.target:指定该服务应该在多用户模式下启动。
graphical.target:指定该服务应该在图形化界面模式下启动。
default.target:指定该服务应该在系统的默认目标(runlevel)下启动。
rescue.target:指定该服务应该在系统救援模式下启动。
poweroff.target:指定该服务应该在关机时启动。
reboot.target:指定该服务应该在重启时启动。
halt.target:指定该服务应该在停止时启动。
shutdown.target:指定该服务应该在系统关闭时启动。
这些参数可以根据需要选择一个或多个,以告知系统在何时启动该服务。

18.4 准备 docker 的 socket 文件

下载地址:https://github.com/moby/moby/blob/v28.4.0/contrib/init/systemd/docker.socket

# 下载 docker.socket
wget https://raw.githubusercontent.com/moby/moby/refs/tags/v28.4.0/contrib/init/systemd/docker.socket


# 修改后写入到指定路径
cat > /etc/systemd/system/docker.socket <<EOF
[Unit]
Description=Docker Socket for the API

[Socket]
# If /var/run is not implemented as a symlink to /run, you may need to
# specify ListenStream=/var/run/docker.sock instead.
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker

[Install]
WantedBy=sockets.target
EOF

命令解析:

这是一个用于Docker API的socket配置文件,包含了以下参数:

[Unit]

Description:描述了该socket的作用,即为Docker API的socket。
[Socket]

ListenStream:指定了 socket 的监听地址,该 socket 会监听在 /var/run/docker.sock 上,即 Docker 守护程序使用的默认 sock 文件。
SocketMode:指定了socket文件的权限模式,此处为0660,即用户和用户组有读写权限,其他用户无权限。
SocketUser:指定了socket文件的所有者,此处为root用户。
SocketGroup:指定了socket文件的所属用户组,此处为docker用户组。
[Install]

WantedBy:指定了该socket被启用时的目标,此处为sockets.target,表示当sockets.target启动时启用该socket。
该配置文件的作用是为 Docker 提供 API 访问的通道,它监听在 /var/run/docker.sock 上,具有 root 用户权限,但只接受 docker 用户组的成员的连接,并且其他用户无法访问。这样,只有 docker 用户组的成员可以通过该 socket 与 Docker 守护进程进行通信。

18.5 配置 Docker 加速器

# 创建 docker 配置目录 和 数据目录
mkdir /etc/docker/ /data/docker -pv

# 写入docker配置,这里也修改了docker默认的数据目录
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "registry-mirrors": [
    "https://kfp63jaj.mirror.aliyuncs.com",
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com"
  ],
  "max-concurrent-downloads": 10,
  "log-driver": "json-file",
  "log-level": "warn",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
    },
  "data-root": "/data/docker"
}
EOF

命令解析:

该参数文件中包含以下参数:

exec-opts: 用于设置Docker守护进程的选项,native.cgroupdriver=systemd表示使用systemd作为Cgroup驱动程序。
registry-mirrors: 用于指定Docker镜像的镜像注册服务器。在这里有三个镜像注册服务器:https://docker.m.daocloud.io、https://docker.mirrors.ustc.edu.cn和http://hub-mirror.c.163.com。
max-concurrent-downloads: 用于设置同时下载镜像的最大数量,默认值为3,这里设置为10。
log-driver: 用于设置Docker守护进程的日志驱动程序,这里设置为json-file。
log-level: 用于设置日志的级别,这里设置为warn。
log-opts: 用于设置日志驱动程序的选项,这里有两个选项:max-size和max-file。max-size表示每个日志文件的最大大小,这里设置为10m,max-file表示保存的最大日志文件数量,这里设置为3。
data-root: 用于设置Docker守护进程的数据存储根目录,默认为/var/lib/docker,这里设置为 /data/docker。

18.6 启动 Docker

# 创建一个名为 docker 的组
groupadd docker
# 通知systemd重新加载所有单元配置文件(unit files),以识别新创建或修改的配置文件
systemctl daemon-reload
# 启用并立即启动Docker的socket单元(docker.socket),使其在系统启动时自动运行,并现在开始监听。
systemctl enable --now docker.socket
# 启用并立即启动Docker守护进程服务(docker.service),使其在系统启动时自动运行,并现在开始运行。
systemctl enable --now docker.service
# 重启docker.socket单元
systemctl restart --now docker.socket
# 重启docker.service单元,即重新启动Docker守护进程。
systemctl restart docker.service
# 验证:查看 docker 服务状态
systemctl status docker.service
# 验证:查看docker信息
docker info

19. 安装 cri-docker

19.1 安装 cri-docker 二进制包

cri-docker 与 docker的版本匹配关系:https://github.com/Mirantis/cri-dockerd/releases/tag/v0.4.0

  • Bump github.com/docker/docker to 27.0.2+incompatible by @cncal in #381
# 下载 cri-docker 二进制包
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.4.0/cri-dockerd-0.4.0.amd64.tgz
# 解压
tar xvf cri-dockerd-*.amd64.tgz 
# 复制到 /usr/bin/
cp cri-dockerd/cri-dockerd /usr/bin/
# 授权
chmod +x /usr/bin/cri-dockerd

# 验证
$ cri-dockerd --version
cri-dockerd 0.4.0 (b9b8893)

19.2 配置 cri-docker.service

从 github 获取文件:https://github.com/Mirantis/cri-dockerd/tree/master/packaging/systemd

# 下载 cri-docker.service 文件
wget https://raw.githubusercontent.com/Mirantis/cri-dockerd/refs/tags/v0.4.0/packaging/systemd/cri-docker.service

# 修改 ExecStart 启动命令后,写入到指定目录
cat > /usr/lib/systemd/system/cri-docker.service <<EOF
[Unit]
Description=CRI Interface for Docker Application Container Engine
Documentation=https://docs.mirantis.com
After=network-online.target firewalld.service docker.service
Wants=network-online.target
Requires=cri-docker.socket

[Service]
Type=notify
# 修啊该启动命令
ExecStart=/usr/bin/cri-dockerd --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9 --container-runtime-endpoint=unix:///var/run/cri-dockerd.sock --cri-dockerd-root-directory=/data/dockershim --cri-dockerd-root-directory=/data/docker

ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target
EOF

命令解析:

[Unit]

Description:该参数用于描述该单元的功能,这里描述的是CRI与Docker应用容器引擎的接口。
Documentation:该参数指定了相关文档的网址,供用户参考。
After:该参数指定了此单元应该在哪些其他单元之后启动,确保在网络在线、防火墙和Docker服务启动之后再启动此单元。
Wants:该参数指定了此单元希望也启动的所有单元,此处是希望在网络在线之后启动。
Requires:该参数指定了此单元需要依赖的单元,此处是cri-docker.socket单元。
[Service]

Type:该参数指定了服务的类型,这里是notify,表示当服务启动完成时向系统发送通知。
ExecStart:该参数指定了将要运行的命令和参数,此处是执行/usr/bin/cri-dockerd 命令,并指定了网络插件为cni和Pod基础设施容器的镜像为registry.aliyuncs.com/google_containers/pause:3.9。
  - --container-runtime-endpoint=unix:///var/run/cri-dockerd.sock 
  	- 定义 CRI 的监听端点。
  - --cri-dockerd-root-directory=/data/dockershim
  	- 定义 cri-dockerd 的根目录,用于存储临时文件或配置数据。
  - --cri-dockerd-root-directory=/data/docker
  	- 定义 Docker 的根目录。
ExecReload:该参数指定在服务重载时运行的命令,此处是发送HUP信号给主进程。
TimeoutSec:该参数指定了服务启动的超时时间,此处为0,表示无限制。
RestartSec:该参数指定了自动重启服务的时间间隔,此处为2秒。
Restart:该参数指定了在服务发生错误时自动重启,此处是始终重启。
StartLimitBurst:该参数指定了在给定时间间隔内允许的启动失败次数,此处为3次。
StartLimitInterval:该参数指定启动失败的时间间隔,此处为60秒。
LimitNOFILE:该参数指定了允许打开文件的最大数量,此处为无限制。
LimitNPROC:该参数指定了允许同时运行的最大进程数,此处为无限制。
LimitCORE:该参数指定了允许生成的core文件的最大大小,此处为无限制。
TasksMax:该参数指定了此服务的最大任务数,此处为无限制。
Delegate:该参数指定了是否将控制权委托给指定服务,此处为是。
KillMode:该参数指定了在终止服务时如何处理进程,此处是通过终止进程来终止服务。
[Install]

WantedBy:该参数指定了希望这个单元启动的多用户目标。在这里,这个单元希望在multi-user.target启动。

19.3 配置 cri-docker.socket

从 github 获取文件:https://github.com/Mirantis/cri-dockerd/tree/master/packaging/systemd

# 下载
wget https://raw.githubusercontent.com/Mirantis/cri-dockerd/refs/tags/v0.4.0/packaging/systemd/cri-docker.socket


# 修改 ListenStream,并写入到指令目录
cat > /usr/lib/systemd/system/cri-docker.socket <<EOF
[Unit]
Description=CRI Docker Socket for the API
PartOf=cri-docker.service

[Socket]
ListenStream=/var/run/cri-dockerd.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker

[Install]
WantedBy=sockets.target
EOF

命令解析:

该配置文件是用于systemd的单元配置文件(unit file),用于定义一个socket单元。

[Unit]

Description:表示该单元的描述信息。
PartOf:表示该单元是cri-docker.service的一部分。
[Socket]

ListenStream:指定了该socket要监听的地址和端口,这里要与 cri-docker.service 配置的 ExecStart 指定的套接字一致,都为 /var/run/cri-dockerd.sock。Unix域套接字用于在同一台主机上的进程之间通信。
SocketMode:指定了socket文件的权限模式,此处为0660,即用户和用户组有读写权限,其他用户无权限。
SocketUser:指定了socket文件的所有者,此处为root用户。
SocketGroup:指定了socket文件的所属用户组,此处为docker用户组。
[Install]

WantedBy:部分定义了该单元的安装配置信息。WantedBy=sockets.target表示当sockets.target单元启动时,自动启动该socket单元。sockets.target是一个系统服务,用于管理所有的socket单元。

19.4 启动 cri-docker

# 通知systemd重新加载所有单元配置文件(unit files),以识别新创建或修改的配置文件
systemctl daemon-reload
# 设置开机自启
systemctl enable --now cri-docker.service
systemctl enable --now cri-docker.socket
# 重启cri-docker.service单元,即重新启动cri-docker守护进程。
systemctl restart cri-docker.service
# 验证,查看状态
systemctl status cri-docker.service

四、导入镜像

# calico 镜像必须导入,每个Node节点都需要运行Calico网络
docker load -i /opt/software/images/calico/cni-v3.28.0.tar
docker load -i /opt/software/images/calico/node-v3.28.0.tar
docker load -i /opt/software/images/calico/kube-controllers-v3.28.0.tar
docker load -i /opt/software/images/calico/typha-v3.28.0.tar

五、Node 配置

1. Nginx 配置

1.1 编译安装

node节点

# 安装编译环境
yum install -y openssl-devel pcre-devel gcc

# 下载解压 nginx 二进制文件
wget http://nginx.org/download/nginx-1.25.3.tar.gz
tar xvf nginx-*.tar.gz
cd nginx-1.25.3

# 进行编译
./configure --prefix=/usr/local/nginx --sbin-path=/bin/ --user=nginx --group=nginx --with-stream --with-http_ssl_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --without-http --without-http_uwsgi_module --without-http_scgi_module --without-http_fastcgi_module
make && make install

# 验证 
$ nginx -v
nginx version: nginx/1.25.3

1.2 nginx 配置文件

node节点

# 写入配置文件(在所有主机上执行)
cat > /usr/local/nginx/conf/kube-nginx.conf <<EOF
worker_processes 1;
user nobody;
events {
    worker_connections  1024;
}
stream {
    upstream backend {
    	least_conn;
        hash $remote_addr consistent;
        server 10.20.1.101:6443        max_fails=3 fail_timeout=30s;
        server 10.20.1.102:6443        max_fails=3 fail_timeout=30s;
        server 10.20.1.103:6443        max_fails=3 fail_timeout=30s;
    }
    server {
        listen 127.0.0.1:8443;
        proxy_connect_timeout 1s;
        proxy_pass backend;
    }
}
EOF

命令解析:

该命令用于创建 Nginx 配置文件 /usr/local/nginx/conf/kube-nginx.conf,配置 Nginx 作为 Kubernetes API 服务器的负载均衡器,处理 TCP 流量(端口 6443)

  • upstream backend

    将本地 8443 端口的请求分发到三个 master 节点的 API 服务器的 6443 端口

  • least_conn;

    选择当前活跃连接数最少的后端服务器进行负载均衡

  • hash $remote_addr consistent;

    基于客户端 IP($remote_addr)进行一致性哈希,确保同一客户端始终连接到同一后端服务器

  • max_fails=3 fail_timeout=30s;

    max_fails=3(失败 3 次后标记为不可用),fail_timeout=30s(标记不可用后 30 秒内不尝试)

  • 6443 端口是 Kubernetes API 服务器(kube-apiserver)的默认端口,接受来自客户端(如 kubectl、kubelet、控制器等)的 HTTPS 请求。

  • 8443 端口是 kube-apiserver 的代理端口,用于接收请求,并将请求转发到真正的 6443 端口

1.3 配置 Nginx Service

node节点

cat > /etc/systemd/system/kube-nginx.service <<EOF
[Unit]
Description=kube-apiserver nginx proxy
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=forking
ExecStartPre=/bin/nginx -c /usr/local/nginx/conf/kube-nginx.conf -p /usr/local/nginx -t
ExecStart=/bin/nginx -c /usr/local/nginx/conf/kube-nginx.conf -p /usr/local/nginx
ExecReload=/bin/nginx -c /usr/local/nginx/conf/kube-nginx.conf -p /usr/local/nginx -s reload
PrivateTmp=true
Restart=always
RestartSec=5
StartLimitInterval=0
LimitNOFILE=65536
 
[Install]
WantedBy=multi-user.target
EOF

命令解析:

创建一个 systemd 单元文件,用于管理系统服务。这个文件定义了一个名为 kube-nginx 的服务,负责运行 Nginx 作为 Kubernetes API 服务器的负载均衡代理

Nginx 在这里被配置为 TCP 负载均衡器(非 HTTP),运行在每个 master 节点(k8s-master01、k8s-master02、k8s-master03,IP 分别为 192.168.10.11、12、13),监听本地 127.0.0.1:8443 端口,并将请求分发到三个 master 节点的 API 服务器端口 6443。

  • After=network.target :基本网络接口配置完成

  • After=network-online.target :网络完全在线(可路由外部)

  • Wants=network-online.target :声明弱依赖,建议(但不强制)在 network-online.target 启动后运行服务

  • Type=forking:

    forking 表示主进程派生子进程(如 Nginx master 进程派生 worker),systemd 跟踪子进程 PID(从 PID 文件读取)

  • ExecStartPre=/bin/nginx -c /usr/local/nginx/conf/kube-nginx.conf -p /usr/local/nginx -t

    启动前执行的预命令。-t 测试配置文件语法

  • ExecStart=/bin/nginx -c /usr/local/nginx/conf/kube-nginx.conf -p /usr/local/nginx

    启动服务的核心命令,运行 Nginx。 博客上下文:启动 Nginx,加载 kube-nginx.conf,启用 TCP 负载均衡(8443 到 6443)

  • ExecReload=/bin/nginx -c /usr/local/nginx/conf/kube-nginx.conf -p /usr/local/nginx -s reload

    重新加载配置的命令(systemctl reload kube-nginx)。-s reload 发送信号平滑重载

  • PrivateTmp=true :为服务分配私有 /tmp 和 /var/tmp 目录,隔离系统临时文件

  • Restart=always :失败或退出时自动重启。always 表示无论原因都重启

  • RestartSec=5 :重启前等待时间(秒)

  • StartLimitInterval=0 :重启时间窗口(秒),0 表示无限制。

  • LimitNOFILE=65536 :最大文件描述符数,防止 “too many open files” 错误

  • WantedBy=multi-user.target : 服务在多用户模式下启用, 确保 Nginx 随系统启动。

1.4 设置 Nginx 开机自启

# 刷新系统服务
systemctl daemon-reload

# 设置 kube-nginx 开机自启
systemctl enable --now kube-nginx.service

# 查看 nginx 启动状态
systemctl status kube-nginx.service

2. 复制文件至 node 节点

在 master01 节点操作

2.1 复制证书

user=root
host=(k8s-node03 k8s-node04 k8s-node05)

for i in ${host[@]}; do
  ssh $user@$i "sudo mkdir -p /etc/kubernetes/pki/";
  rsync --rsync-path="sudo rsync" /etc/kubernetes/pki/{ca.pem,ca-key.pem,front-proxy-ca.pem} $user@$i:/etc/kubernetes/pki/;
  rsync --rsync-path="sudo rsync" /etc/kubernetes/{bootstrap-kubelet.kubeconfig,kube-proxy.kubeconfig,kubelet.kubeconfig} $user@$i:/etc/kubernetes/;
done

2.2 复制二进制安装包

# 拷贝 worker 组件
hots='k8s-node03 k8s-node04 k8s-node05'
user=root
for i in $hots; do 
  echo $i; 
  rsync --rsync-path="sudo rsync" /usr/local/bin/kube{let,-proxy} $user@$i:/usr/local/bin/; 
done

3. 配置 kubelet(所有节点)

3.1 编辑 kubelet.service

Node节点

# 当使用 docker 作为 Runtime
# IPv4示例
cat > /usr/lib/systemd/system/kubelet.service << EOF

[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=network-online.target firewalld.service cri-docker.service docker.socket containerd.service
Wants=network-online.target
Requires=docker.socket containerd.service

[Service]
ExecStart=/usr/local/bin/kubelet \\
    --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.kubeconfig  \\
    --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\
    --config=/etc/kubernetes/kubelet-conf.yml \\
    --container-runtime-endpoint=unix:///run/cri-dockerd.sock  \\
    --node-labels=node.kubernetes.io/node= 

[Install]
WantedBy=multi-user.target
EOF

# IPv6示例
# 若不使用IPv6那么忽略此项即可
# 下方 --node-ip 更换为每个节点的IP即可
# cat > /usr/lib/systemd/system/kubelet.service << EOF
# [Unit]
# Description=Kubernetes Kubelet
# Documentation=https://github.com/kubernetes/kubernetes
# After=network-online.target firewalld.service cri-docker.service docker.socket # containerd.service
# Wants=network-online.target
# Requires=docker.socket containerd.service

# [Service]
# ExecStart=/usr/local/bin/kubelet \\
#     --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.kubeconfig  \\
#     --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\
#     --config=/etc/kubernetes/kubelet-conf.yml \\
#     --container-runtime-endpoint=unix:///run/cri-dockerd.sock  \\
#     --node-labels=node.kubernetes.io/node=   \\
#     --node-ip=192.168.1.31,2408:822a:245:8c01::fab
# [Install]
# WantedBy=multi-user.target
# EOF
  • 注意node-labels=node.kubernetes.io/node='' ubuntu为'' centos为空

命令解析:

  • –bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.kubeconfig:引导 kubeconfig 文件路径。用于 TLS Bootstrapping(节点自动加入集群的机制)。kubelet 使用此文件向 API Server 请求证书,首次启动时使用
  • –kubeconfig=/etc/kubernetes/kubelet.kubeconfig:最终的 kubeconfig 文件路径。引导成功后,kubelet 会切换到这个文件,用于与 Kubernetes API Server 通信。
  • –config=/etc/kubernetes/kubelet-conf.yml:kubelet 的 YAML 配置文件路径(包含详细配置,如 cgroup 驱动、Pod 限制等)。这个文件在稍后定义。
  • –container-runtime-endpoint=unix:///run/cri-dockerd.sock:容器运行时端点。指定使用 cri-dockerd 的 Unix socket(因为使用 Docker + cri-dockerd 作为 CRI 兼容运行时,而不是直接用 containerd 或 CRI-O)。
  • –node-labels=node.kubernetes.io/node=:节点标签。为空值(可以自定义标签,如用于节点分组)。这里的 = 后无内容,表示一个空标签

3.2 编辑 kubelet-conf.yml

官方文档:https://kubernetes.io/zh-cn/docs/reference/config-api/kubelet-config.v1beta1/

Master01

cat > /etc/kubernetes/kubelet-conf.yml <<EOF
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
address: 0.0.0.0
port: 10250
readOnlyPort: 10255
authentication:
  anonymous:
    enabled: false
  webhook:
    cacheTTL: 2m0s
    enabled: true
  x509:
    clientCAFile: /etc/kubernetes/pki/ca.pem
authorization:
  mode: Webhook
  webhook:
    cacheAuthorizedTTL: 5m0s
    cacheUnauthorizedTTL: 30s
cgroupDriver: systemd
cgroupsPerQOS: true
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
containerLogMaxFiles: 5
containerLogMaxSize: 10Mi
contentType: application/vnd.kubernetes.protobuf
cpuCFSQuota: true
cpuManagerPolicy: none
cpuManagerReconcilePeriod: 10s
enableControllerAttachDetach: true
enableDebuggingHandlers: true
enforceNodeAllocatable:
- pods
eventBurst: 10
eventRecordQPS: 5
evictionHard:
  imagefs.available: 15%
  memory.available: 100Mi
  nodefs.available: 10%
  nodefs.inodesFree: 5%
evictionPressureTransitionPeriod: 5m0s
failSwapOn: true
fileCheckFrequency: 20s
hairpinMode: promiscuous-bridge
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 20s
imageGCHighThresholdPercent: 85
imageGCLowThresholdPercent: 80
imageMinimumGCAge: 2m0s
iptablesDropBit: 15
iptablesMasqueradeBit: 14
kubeAPIBurst: 10
kubeAPIQPS: 5
makeIPTablesUtilChains: true
maxOpenFiles: 1000000
maxPods: 110
nodeStatusUpdateFrequency: 10s
oomScoreAdj: -999
podPidsLimit: -1
registryBurst: 10
registryPullQPS: 5
resolvConf: /etc/resolv.conf
rotateCertificates: true
runtimeRequestTimeout: 2m0s
serializeImagePulls: true
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 4h0m0s
syncFrequency: 1m0s
volumeStatsAggPeriod: 1m0s
EOF

命令解析:

创建 Kubernetes 的 kubelet 配置文件 /etc/kubernetes/kubelet-conf.yml。该文件是 kubelet 的主要配置文件,定义了 kubelet 的运行行为、资源管理、网络配置等关键参数。kubelet 是 Kubernetes 节点上的核心组件,负责管理 Pod、容器生命周期、节点资源等。

apiVersion: 指定配置文件使用的 Kubernetes API 版本。这里是 kubelet.config.k8s.io/v1beta1,表示 kubelet 配置的 v1beta1 版本。

kind: 指定配置类型为 KubeletConfiguration,这是 kubelet 的专用配置类型。

address: kubelet 的监听地址。0.0.0.0 表示监听所有网络接口,允许外部访问(如 API Server 或 kubectl)。

port: kubelet 的主端口,用于处理 HTTPS 请求(如状态查询、命令执行)。默认值为 10250。

readOnlyPort: 只读端口,提供无认证的只读访问(如健康检查或状态查询)。默认值为 10255。注意:在高安全性环境中,建议禁用只读端口(设置为 0)以防止未经授权的访问。

authentication: 定义 kubelet 的认证机制。

  • anonymous.enabled: 是否允许匿名访问。false 表示禁用匿名访问,增强安全性。
  • webhook.enabled: 是否启用 Webhook 认证。true 表示 kubelet 通过向 API Server 发送 Webhook 请求验证客户端身份。
  • webhook.cacheTTL: Webhook 认证结果的缓存时间,设置为 2m0s(2 分钟),减少重复验证开销。
  • x509.clientCAFile: 指定用于验证客户端证书的 CA 文件路径(/etc/kubernetes/pki/ca.pem)。客户端(如 API Server)必须提供由该 CA 签发的证书。

authorization: 定义 kubelet 的授权机制。

  • mode: Webhook: 使用 Webhook 模式向 API Server 请求授权决定(基于 RBAC 或其他授权策略)。
  • webhook.cacheAuthorizedTTL: 已授权请求的缓存时间,5m0s(5 分钟)。
  • webhook.cacheUnauthorizedTTL: 未授权请求的缓存时间,30s(30 秒)。较短的未授权缓存时间确保快速更新拒绝策略。

cgroupDriver: 指定 kubelet 使用的 cgroup 驱动程序。systemd 表示使用 systemd 管理 cgroup,与 Docker 的 systemd cgroup 驱动一致(配置了 Docker 的 daemon.json 使用 native.cgroupdriver=systemd)。

cgroupsPerQOS: 是否为不同 QoS(服务质量)级别的 Pod 创建单独的 cgroup。true 启用此功能,确保 Guaranteed、Burstable 和 BestEffort Pod 的资源隔离。

clusterDNS: 指定集群内 DNS 服务的 IP 地址。10.96.0.10 是 CoreDNS 的服务 IP(与安装 CoreDNS 时配置的 clusterIP 一致)。

clusterDomain: 指定集群的 DNS 域名后缀。cluster.local 是默认值,用于解析服务名称(如 my-service.default.svc.cluster.local)。

containerLogMaxFiles: 每个容器的最大日志文件数(轮转日志)。5 表示保留最多 5 个日志文件。

containerLogMaxSize: 每个日志文件的最大大小。10Mi 表示 10MB,超过后会触发日志轮转。

contentType: 指定 kubelet 与 API Server 通信时使用的内容类型。application/vnd.kubernetes.protobuf 表示使用 Protobuf 格式(比 JSON 更高效)。

cpuCFSQuota: 是否为容器启用 CPU CFS(Completely Fair Scheduler)配额。true 表示限制容器 CPU 使用量,基于 Pod 的 QoS 设置。

cpuManagerPolicy: CPU 分配策略。none 表示不使用 CPU 管理器(不分配专用 CPU 核心,Pod 共享 CPU 资源)。

cpuManagerReconcilePeriod: CPU 管理器的协调周期。10s 表示每 10 秒检查并调整 CPU 分配(尽管策略为 none,此参数仍需设置)。

enableControllerAttachDetach: 是否允许控制器管理卷的挂载和卸载。true 表示由 kubelet 和控制器协同处理卷操作。

enableDebuggingHandlers: 是否启用调试端点(如 /debug/pprof)。true 允许访问调试信息,便于性能分析。

enforceNodeAllocatable: 指定强制限制的资源类型。pods 表示对 Pod 分配的资源进行限制,确保节点保留系统和 kubelet 所需的资源(如内存、CPU)。

eventBurst: 事件处理的突发容量。10 表示允许短时间内处理最多 10 个事件。

eventRecordQPS: 每秒记录的事件数。5 表示平均每秒记录 5 个事件,控制事件报告频率以避免 API Server 过载。

evictionHard: 定义硬性驱逐阈值,当资源低于以下值时,kubelet 会驱逐 Pod 以回收资源:

  • imagefs.available: 镜像文件系统可用空间低于 15% 时触发驱逐。
  • memory.available: 可用内存低于 100Mi(100MB)时触发驱逐。
  • nodefs.available: 节点文件系统可用空间低于 10% 时触发驱逐。
  • nodefs.inodesFree: 节点文件系统可用 inode 低于 5% 时触发驱逐。

evictionPressureTransitionPeriod: 驱逐压力过渡期。5m0s 表示在资源压力缓解后,等待 5 分钟才停止驱逐。

failSwapOn: 是否允许在启用 swap 分区时启动 kubelet。true 表示如果 swap 启用,kubelet 将启动失败(当前已禁用 swap)。

fileCheckFrequency: 检查文件变更的频率。20s 表示每 20 秒检查一次(如 Pod 配置文件)。

hairpinMode: 指定 hairpin 流量(Pod 访问自身服务 IP)的处理方式。promiscuous-bridge 表示使用网桥的混杂模式,适用于 Calico 等 CNI 插件。

healthzBindAddress: 健康检查监听地址。127.0.0.1 表示仅本地可访问,增强安全性。

healthzPort: 健康检查端口。10248 是默认值,用于 /healthz 端点。

httpCheckFrequency: HTTP 健康检查频率。20s 表示每 20 秒检查一次。

imageGCHighThresholdPercent: 镜像垃圾回收的上限阈值。磁盘使用率达到 85% 时触发回收。

imageGCLowThresholdPercent: 镜像垃圾回收的下限阈值。回收后磁盘使用率低于 80% 时停止。

imageMinimumGCAge: 镜像的最小保留时间。2m0s 表示镜像至少保留 2 分钟,防止频繁回收。

iptablesDropBit: 用于标记丢弃数据包的 iptables 位。15 是默认值。

iptablesMasqueradeBit: 用于 SNAT(源地址转换)的 iptables 位。14 是默认值。

makeIPTablesUtilChains: 是否创建 iptables 工具链。true 表示 kubelet 自动管理 iptables 规则。

kubeAPIBurst: 与 API Server 通信的突发请求数。10 表示短时间内最多发送 10 个请求。

kubeAPIQPS: 与 API Server 通信的每秒请求数。5 表示平均每秒 5 个请求,控制负载。

maxOpenFiles: 最大打开文件数。1000000 允许 kubelet 处理大量文件描述符。

maxPods: 节点上最大 Pod 数。110 是默认值,限制节点负载。

podPidsLimit: 每个 Pod 的最大 PID 数。-1 表示无限制。

nodeStatusUpdateFrequency: 节点状态更新频率。10s 表示每 10 秒向 API Server 报告节点状态。

oomScoreAdj: kubelet 进程的 OOM(内存不足)优先级。-999 表示低优先级,降低被杀死概率。

registryBurst: 从镜像仓库拉取镜像的突发请求数。10 表示最多 10 个并发请求。

registryPullQPS: 镜像拉取的每秒请求数。5 表示平均每秒 5 个请求。

resolvConf: DNS 解析配置文件路径。/etc/resolv.conf 是系统默认值。

rotateCertificates: 是否启用证书轮换。true 表示自动更新过期证书。

runtimeRequestTimeout: 容器运行时请求超时时间。2m0s 表示 2 分钟。

serializeImagePulls: 是否串行拉取镜像。true 表示一次拉取一个镜像,降低资源争用。

staticPodPath: 静态 Pod 的清单目录。/etc/kubernetes/manifests 用于存放静态 Pod 的 YAML 文件。

streamingConnectionIdleTimeout: 流式连接(如 kubectl exec)的空闲超时。4h0m0s 表示 4 小时。

syncFrequency: Pod 同步频率。1m0s 表示每分钟同步一次 Pod 状态。

volumeStatsAggPeriod: 卷统计聚合周期。1m0s 表示每分钟收集一次卷使用数据。

3.3 启动 kubelet

systemctl daemon-reload
systemctl enable --now kubelet
systemctl status kubelet

3.4 测试

[root@k8s-master01 ~]$ kubectl get nodes
NAME           STATUS     ROLES    AGE   VERSION
k8s-master01   Ready      <none>   9d    v1.29.2
k8s-master02   Ready      <none>   9d    v1.29.2
k8s-master03   Ready      <none>   9d    v1.29.2
k8s-node01     Ready      <none>   9d    v1.29.2
k8s-node02     Ready      <none>   9d    v1.29.2
k8s-node03     NotReady   <none>   53s   v1.29.2
k8s-node04     NotReady   <none>   25s   v1.29.2
k8s-node05     NotReady   <none>   20s   v1.29.2

4. kube-proxy 配置(所有Node节点)

4.1 编辑 kube-proxy.service

Node 节点

cat > /usr/lib/systemd/system/kube-proxy.service << EOF
[Unit]
Description=Kubernetes Kube Proxy
Documentation=https://github.com/kubernetes/kubernetes
After=network.target

[Service]
ExecStart=/usr/local/bin/kube-proxy \\
  --config=/etc/kubernetes/kube-proxy.yaml \\
  --cluster-cidr=172.16.0.0/12,fc00:2222::/112 \\
  --v=2
Restart=always
RestartSec=10s

[Install]
WantedBy=multi-user.target

EOF

命令解析:

kube-proxy是Kubernetes的核心组件之一,负责处理Service和Pod的网络代理(如负载均衡、NAT等),确保集群内的网络通信正常工作。

适用节点:所有Kubernetes节点(Master和Node),因为kube-proxy需要在每个节点上运行,以处理本地Pod的网络流量。

  • ExecStart=/usr/local/bin/kube-proxy

    执行命令:指定服务的启动命令,即运行/usr/local/bin/kube-proxy二进制文件

  • –config=/etc/kubernetes/kube-proxy.yaml

    配置参数:指定kube-proxy的配置文件路径。这个YAML文件(教程中稍后定义)包含详细配置,如代理模式(IPVS)、绑定地址、连接跟踪等。使用配置文件可以分离配置,便于维护和统一所有节点。

  • –cluster-cidr=172.16.0.0/12,fc00:2222::/112

    172.16.0.0/12:IPv4 Pod CIDR(私有地址段,范围从172.16.0.0到172.31.255.255,可容纳大量Pod)。

    fc00:2222::/112:IPv6 Pod CIDR(ULA私有地址,支持双栈网络)。

4.2 编辑 kube-proxy.yaml

官方文档:https://kubernetes.io/zh-cn/docs/reference/config-api/kube-proxy-config.v1alpha1/

cat > /etc/kubernetes/kube-proxy.yaml << EOF
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
clientConnection:
  acceptContentTypes: ""
  burst: 10
  contentType: application/vnd.kubernetes.protobuf
  kubeconfig: /etc/kubernetes/kube-proxy.kubeconfig
  qps: 5
clusterCIDR: 172.16.0.0/12,fc00:2222::/112
configSyncPeriod: 15m0s
conntrack:
  max: null
  maxPerCore: 32768
  min: 131072
  tcpCloseWaitTimeout: 1h0m0s
  tcpEstablishedTimeout: 24h0m0s
enableProfiling: false
healthzBindAddress: 0.0.0.0:10256
hostnameOverride: ""
iptables:
  masqueradeAll: false
  masqueradeBit: 14
  minSyncPeriod: 0s
  syncPeriod: 30s
ipvs:
  masqueradeAll: true
  minSyncPeriod: 5s
  scheduler: "rr"
  syncPeriod: 30s
kind: KubeProxyConfiguration
metricsBindAddress: 127.0.0.1:10249
mode: "ipvs"
nodePortAddresses: null
oomScoreAdj: -999
portRange: ""
udpIdleTimeout: 250ms
EOF

命令解析:

kube-proxy 的配置文件,定义了 Kubernetes 集群中 kube-proxy 组件的行为。kube-proxy 运行在每个节点上,负责处理 Service 和 Pod 的网络代理(如负载均衡、NAT),支持 Kubernetes 的网络功能。

  • apiVersion: kubeproxy.config.k8s.io/v1alpha1

    指定配置文件的 API 版本,告诉 Kubernetes 使用 kubeproxy.config.k8s.io/v1alpha1 版本的 KubeProxyConfiguration 资源格式来解析此文件

  • bindAddress: 0.0.0.0

    监听所有网络接口(IPv4 和 IPv6),允许 kube-proxy 接受来自任何网络接口的请求。0.0.0.0 确保 kube-proxy 能处理两种协议的流量

  • clientConnection: 定义 kube-proxy 与 Kubernetes API 服务器的通信参数

    • acceptContentTypes: “” :指定 kube-proxy 接受的 API 响应内容类型,空字符串表示接受默认类型(通常由 contentType 定义)
    • burst: 10 允许的突发请求数(QPS 的上限),控制 kube-proxy 向 API 服务器发送请求的速率
    • contentType: application/vnd.kubernetes.protobuf 与 API 服务器通信时使用的内容类型,比 JSON(application/json)更高效,减少网络带宽
    • kubeconfig: /etc/kubernetes/kube-proxy.kubeconfig 访问 API 服务器的 kubeconfig 文件路径
    • qps: 5 每秒向 API 服务器发送的请求数,限制 kube-proxy 的 API 请求速率,qps: 5 表示每秒最多 5 个请求,配合 burst 控制突发
  • clusterCIDR: 172.16.0.0/12,fc00:2222::/112 定义集群的 Pod IP 地址范围(Pod CIDR),与 Calico 的 CALICO_IPV4POOL_CIDR 和 CALICO_IPV6POOL_CIDR 一致(calico.yaml 或 calico-ipv6.yaml)

  • configSyncPeriod: 15m0s kube-proxy 同步配置的间隔时间,每 15 分钟,kube-proxy 从 API 服务器重新获取 Service 和 Endpoint 配置,更新本地代理规则

  • conntrack: 配置连接跟踪(Connection Tracking),用于 NAT 和负载均衡

    • max: null 系统中连接跟踪表的最大条目数,null 表示使用系统默认值(通常由内核参数 net.nf_conntrack_max 决定)
    • maxPerCore: 32768 每个 CPU 核心的连接跟踪条目上限
    • min: 131072 连接跟踪表的最小条目数
    • tcpCloseWaitTimeout: 1h0m0s TCP 连接在 CLOSE_WAIT 状态的超时时间,连接关闭后,等待 1 小时释放资源,防止短时间内频繁释放导致性能问题
    • tcpEstablishedTimeout: 24h0m0s 已建立的 TCP 连接的超时时间, 保持长连接(如数据库连接)24 小时,减少重新建立开销
  • enableProfiling: false 是否启用 kube-proxy 的性能分析(profiling),false 禁用 profiling,降低资源消耗

  • healthzBindAddress: 0.0.0.0:10256 健康检查监听地址和端口,kube-proxy 在 0.0.0.0:10256 提供 /healthz 端点,供 kubelet 或外部工具检查状态

  • hostnameOverride: “” 覆盖 kube-proxy 报告的节点主机名,空字符串表示使用节点默认主机名(由 uname -n 或 kubelet 提供)

  • iptables: 配置 iptables 代理模式(尽管当前使用 IPVS,此配置仍保留)

    • masqueradeAll: false 是否对所有出站流量执行 NAT 伪装(SNAT),false 表示仅对 Service 相关的流量执行 NAT,减少开销
    • masqueradeBit: 14 iptables 伪装时使用的标记位,默认值 14 用于标记 NAT 流量,防止冲突
    • minSyncPeriod: 0s iptables 规则同步的最小间隔,0s 表示无最小间隔,允许快速同步
    • syncPeriod: 30s iptables 规则同步的周期,每 30 秒同步 iptables 规则,确保与 API 服务器一致
  • ipvs: 配置 IPVS 代理模式(本文明确使用 mode: “ipvs”)

    • masqueradeAll: true 是否对所有出站流量执行 NAT 伪装。true 表示对所有 Pod 流量执行 SNAT,适合 IPVS 模式,确保外部访问(如 NodePort)正确。
    • minSyncPeriod: 5s IPVS 规则同步的最小间隔。确保至少 5 秒同步一次,防止频繁更新导致性能问题。
    • scheduler: “rr” IPVS 负载均衡调度算法。rr(Round Robin,轮询)平均分配 Service 流量到后端 Pod
    • syncPeriod: 30s IPVS 规则同步周期。每 30 秒同步 IPVS 规则,确保与 API 服务器一致。
  • kind: KubeProxyConfiguration 指定资源的类型,声明这是 kube-proxy 的配置文件

  • metricsBindAddress: 127.0.0.1:10249 指标(metrics)监听地址和端口,kube-proxy 在 127.0.0.1:10249 提供 Prometheus 格式的指标,供监控系统(如 Prometheus)采集

  • mode: “ipvs” kube-proxy 的代理模式, ipvs 模式使用 Linux IPVS(IP Virtual Server)实现高效负载均衡。

  • nodePortAddresses: null NodePort 服务的监听地址。null 表示监听所有接口(0.0.0.0)

  • oomScoreAdj: -999 调整 kube-proxy 进程的 OOM(Out of Memory)优先级,-999 降低被 OOM Killer 杀死的概率,优先级接近系统关键进程。

  • portRange: “” 分配 NodePort 的端口范围。空字符串使用默认范围(30000-32767)。

  • udpIdleTimeout: 250ms UDP 连接的空闲超时时间。250 毫秒后关闭空闲 UDP 连接,释放资源。

4.3 启动 kube-proxy

systemctl daemon-reload

systemctl enable --now kube-proxy.service

systemctl status kube-proxy.service

4.4 查看集群状态

$ kubectl get nodes
NAME           STATUS   ROLES    AGE   VERSION
k8s-master01   Ready    <none>   9d    v1.29.2
k8s-master02   Ready    <none>   9d    v1.29.2
k8s-master03   Ready    <none>   9d    v1.29.2
k8s-node01     Ready    <none>   9d    v1.29.2
k8s-node02     Ready    <none>   9d    v1.29.2
k8s-node03     Ready    <none>   15m   v1.29.2
k8s-node04     Ready    <none>   14m   v1.29.2
k8s-node05     Ready    <none>   14m   v1.29.2

提示:当 Nginx、kubelet、kube-proxy 都安装好后,新建的 Node 节点会自动开始运行 calico Pod

$ kubectl get pods -A
NAMESPACE              NAME                                         READY   STATUS    RESTARTS       AGE
kube-system            calico-kube-controllers-8d76c5f9b-vtnc9      1/1     Running   1 (121m ago)   126m
kube-system            calico-node-6vj7z                            1/1     Running   0              126m
kube-system            calico-node-bm9t6                            1/1     Running   0              16m
kube-system            calico-node-jxq4g                            1/1     Running   0              16m
kube-system            calico-node-s7k6p                            1/1     Running   3 (124m ago)   126m
kube-system            calico-node-t9vgb                            1/1     Running   2 (120m ago)   126m
kube-system            calico-node-tlz9j                            1/1     Running   0              16m
kube-system            calico-node-w2vrb                            1/1     Running   1 (121m ago)   125m
kube-system            calico-node-xc5x5                            1/1     Running   1 (121m ago)   126m
kube-system            calico-typha-7cdb5b98f7-b9rvd                1/1     Running   0              125m
kube-system            coredns-68746bb699-tr8qb                     1/1     Running   0              125m
kube-system            metrics-server-6d4cb7955c-w2wnd              1/1     Running   4 (120m ago)   125m
kubernetes-dashboard   dashboard-metrics-scraper-5657497c4c-8kzbs   1/1     Running   0              125m
kubernetes-dashboard   kubernetes-dashboard-5b749d9495-kb6b4        1/1     Running   2 (120m ago)   125m

因此,需要保证新建的 Node 节点上有 calico 镜像,如果镜像拉取失败,Node 节点将处于 NotReady 状态

六、安装命令补全

所有节点

yum install bash-completion -y
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc

七、测试

3. Nginx 部署测试

资源清单: nginx-test.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 30
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: nginx
          image: nginx:1.29.3
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: default
spec:
  ports:
    - port: 80
      targetPort: 80    # 修正:必须是 Pod 实际监听的端口号
      protocol: TCP
      nodePort: 30339
  selector:
    app: myapp

执行资源清单:

# 执行资源清单
$ kubectl apply -f nginx-test.yaml

# 查看 Service
$ kubectl get svc 
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP        8d
nginx-svc    NodePort    10.98.200.91   <none>        80:30339/TCP   3h21m

# 查看 Deployment
$ kubectl get deploy -o wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES         SELECTOR
nginx   30/30   30           30          3m29s   nginx        nginx:1.29.3   app=myapp

# 查看Pod
$ kubectl get pods -o wide -w
NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE           NOMINATED NODE   READINESS GATES
nginx-6444df9cd5-2cx9t   1/1     Running   0          3m6s    172.17.54.136    k8s-node05     <none>           <none>
nginx-6444df9cd5-5llx5   1/1     Running   0          2m54s   172.18.195.10    k8s-master03   <none>           <none>
nginx-6444df9cd5-628p6   1/1     Running   0          3m1s    172.17.54.139    k8s-node05     <none>           <none>
nginx-6444df9cd5-65gnq   1/1     Running   0          2m54s   172.18.195.11    k8s-master03   <none>           <none>
nginx-6444df9cd5-6gkl6   1/1     Running   0          2m54s   172.25.244.212   k8s-master01   <none>           <none>
nginx-6444df9cd5-8m2nv   1/1     Running   0          3m1s    172.27.14.201    k8s-node02     <none>           <none>
nginx-6444df9cd5-8xl7q   1/1     Running   0          3m1s    172.25.92.76     k8s-master02   <none>           <none>
nginx-6444df9cd5-b4tjh   1/1     Running   0          2m54s   172.25.214.200   k8s-node03     <none>           <none>
nginx-6444df9cd5-bxq95   1/1     Running   0          2m54s   172.27.14.202    k8s-node02     <none>           <none>
nginx-6444df9cd5-c8r9w   1/1     Running   0          2m54s   172.17.125.20    k8s-node01     <none>           <none>
nginx-6444df9cd5-cq5xz   1/1     Running   0          3m1s    172.29.115.134   k8s-node04     <none>           <none>
nginx-6444df9cd5-dcss9   1/1     Running   0          3m6s    172.25.214.199   k8s-node03     <none>           <none>
nginx-6444df9cd5-fmzpc   1/1     Running   0          3m1s    172.27.14.200    k8s-node02     <none>           <none>
nginx-6444df9cd5-ggfkn   1/1     Running   0          3m4s    172.25.244.211   k8s-master01   <none>           <none>
nginx-6444df9cd5-j9pfn   1/1     Running   0          2m54s   172.29.115.136   k8s-node04     <none>           <none>
nginx-6444df9cd5-kbhxv   1/1     Running   0          3m8s    172.29.115.135   k8s-node04     <none>           <none>
nginx-6444df9cd5-kt7qw   1/1     Running   0          3m4s    172.17.125.18    k8s-node01     <none>           <none>
nginx-6444df9cd5-l62jc   1/1     Running   0          2m54s   172.17.54.138    k8s-node05     <none>           <none>
nginx-6444df9cd5-lmcnf   1/1     Running   0          2m54s   172.17.54.137    k8s-node05     <none>           <none>
nginx-6444df9cd5-lztdb   1/1     Running   0          2m54s   172.25.92.77     k8s-master02   <none>           <none>
nginx-6444df9cd5-m9xfv   1/1     Running   0          2m54s   172.29.115.137   k8s-node04     <none>           <none>
nginx-6444df9cd5-ms4xg   1/1     Running   0          3m1s    172.25.214.201   k8s-node03     <none>           <none>
nginx-6444df9cd5-ms7g7   1/1     Running   0          3m1s    172.25.244.213   k8s-master01   <none>           <none>
nginx-6444df9cd5-nnh47   1/1     Running   0          2m54s   172.25.214.202   k8s-node03     <none>           <none>
nginx-6444df9cd5-pbtf4   1/1     Running   0          2m54s   172.18.195.12    k8s-master03   <none>           <none>
nginx-6444df9cd5-pcgqz   1/1     Running   0          2m54s   172.17.125.19    k8s-node01     <none>           <none>
nginx-6444df9cd5-pfx5n   1/1     Running   0          3m4s    172.25.92.75     k8s-master02   <none>           <none>
nginx-6444df9cd5-shqtn   1/1     Running   0          3m4s    172.18.195.9     k8s-master03   <none>           <none>
nginx-6444df9cd5-sjbp7   1/1     Running   0          2m54s   172.25.92.74     k8s-master02   <none>           <none>
nginx-6444df9cd5-t4hnx   1/1     Running   0          3m1s    172.17.125.17    k8s-node01     <none>           <none>

新建的各个node节点, 都正常运行Pod

网络测试

$ kubectl exec -it nginx-6444df9cd5-2cx9t -- /bin/bash
root@nginx-6594975dd-fds78:/# curl -k https://10.96.0.1:443
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
  "reason": "Forbidden",
  "details": {},
  "code": 403
}

说明:

  • Pod 网络到 Kubernetes API Server 是通的。
  • 返回 403 而不是超时或连接失败,说明请求已经到达 API Server。
  • 403 的原因是你没有提供认证信息(anonymous user),这是正常的,如果只是测试网络,不需要担心。

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 george_95@126.com