一、系统环境
- 操作系统: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 |
三、基础环境配置(所有节点)
1. 主机名设置
设置集群中各个节点的主机名
Master01 节点
hostnamectl set-hostname k8s-master01
Master02 节点
hostnamectl set-hostname k8s-master02
Master03 节点
hostnamectl set-hostname k8s-master03
Node01 节点
hostnamectl set-hostname k8s-node01
Node02 节点
hostnamectl set-hostname k8s-node02
2. 配置静态IP
集群内的每个几点都需要配置唯一的IP地址,这里同时配置了 IPV4地址 和 IPV6地址。
Master01 节点
[root@k8s-master01 ~]# cat /etc/NetworkManager/system-connections/ens34.nmconnection
[ipv4]
method=manual
address1=10.20.1.101/24;10.20.1.1
dns=61.132.163.68;114.114.114.114
[ipv6]
method=manual
addresses=2400:3200::101/64
gateway=2400:3200::1
dns=2400:3200::1;2400:3200:baba::1;2001:4860:4860::8888;2001:4860:4860::8844
Master02 节点
[root@k8s-master02 ~]# cat /etc/NetworkManager/system-connections/ens34.nmconnection
[ipv4]
method=manual
address1=10.20.1.102/24;10.20.1.1
dns=61.132.163.68;114.114.114.114
[ipv6]
method=manual
addresses=2400:3200::102/64
gateway=2400:3200::1
dns=2400:3200::1;2400:3200:baba::1;2001:4860:4860::8888;2001:4860:4860::8844
Master03 节点
[root@k8s-master03 ~]# cat /etc/NetworkManager/system-connections/ens34.nmconnection
[ipv4]
method=manual
address1=10.20.1.103/24;10.20.1.1
dns=61.132.163.68;114.114.114.114
[ipv6]
method=manual
addresses=2400:3200::103/64
gateway=2400:3200::1
dns=2400:3200::1;2400:3200:baba::1;2001:4860:4860::8888;2001:4860:4860::8844
Node01 节点
[root@k8s-node01 ~]# cat /etc/NetworkManager/system-connections/ens34.nmconnection
[ipv4]
method=manual
address1=10.20.1.104/24;10.20.1.1
dns=61.132.163.68;114.114.114.114
[ipv6]
method=manual
addresses=2400:3200::104/64
gateway=2400:3200::1
dns=2400:3200::1;2400:3200:baba::1;2001:4860:4860::8888;2001:4860:4860::8844
Node02 节点
[root@k8s-node02 ~]# cat /etc/NetworkManager/system-connections/ens34.nmconnection
[ipv4]
method=manual
address1=10.20.1.105/24;10.20.1.1
dns=61.132.163.68;114.114.114.114
[ipv6]
method=manual
addresses=2400:3200::105/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
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
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 network-scripts
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. 集群时间同步设置
在3主2从的集群环境中,配置3台 master 节点向使用 chony 通过外部网络同步时间校正自身的时间,并作为时间主服务器给集群中的其它 node 节点校正时间。
主节点时间权重不同
Master01 节点
yum install chrony -y
cat > /etc/chrony.conf << EOF
pool ntp1.aliyun.com iburst
pool ntp2.aliyun.com iburst
pool ntp3.aliyun.com iburst
pool ntp4.aliyun.com iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
allow 10.20.1.0/24
local stratum 10
keyfile /etc/chrony.keys
leapsectz right/UTC
logdir /var/log/chrony
EOF
systemctl restart chronyd ; systemctl enable chronyd
命令解析:
pool ntp.aliyun.com iburst 指定使用ntp.aliyun.com作为时间服务器池,iburst选项表示在初始同步时会发送多个请求以加快同步速度。 driftfile /var/lib/chrony/drift 指定用于保存时钟漂移信息的文件路径。 makestep 1.0 3 设置当系统时间与服务器时间偏差大于1秒时,会以1秒的步长进行调整。如果偏差超过3秒,则立即进行时间调整。 rtcsync 启用硬件时钟同步功能,可以提高时钟的准确性。 allow 10.20.1.0/24 允许10.20.1.0/24网段范围内的主机与chrony进行时间同步。 local stratum 10 将本地时钟设为stratum 10,stratum值表示时钟的准确度,值越小表示准确度越高。 keyfile /etc/chrony.keys 指定使用的密钥文件路径,用于对时间同步进行身份验证。 leapsectz right/UTC 指定时区为UTC。 logdir /var/log/chrony 指定日志文件存放目录。
Master02 节点
yum install chrony -y
cat > /etc/chrony.conf << EOF
pool ntp1.aliyun.com iburst
pool ntp2.aliyun.com iburst
pool ntp3.aliyun.com iburst
pool ntp4.aliyun.com iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
allow 10.20.1.0/24
local stratum 12
keyfile /etc/chrony.keys
leapsectz right/UTC
logdir /var/log/chrony
EOF
systemctl restart chronyd ; systemctl enable chronyd
Master03 节点
yum install chrony -y
cat > /etc/chrony.conf << EOF
pool ntp1.aliyun.com iburst
pool ntp2.aliyun.com iburst
pool ntp3.aliyun.com iburst
pool ntp4.aliyun.com iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
allow 10.20.1.0/24
local stratum 15
keyfile /etc/chrony.keys
leapsectz right/UTC
logdir /var/log/chrony
EOF
systemctl restart chronyd ; systemctl enable chronyd
Node01节点 和 Node02节点
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 m1 m2 m3 n1 n2)
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-master01
# 二进制包下载地址:https://download.docker.com/linux/static/stable/x86_64/
# 创建目录,后续下载的文件都放在这里
mkdir -p /opt/software/ /opt/module/ && chmod 777 -R /opt/software/ /opt/module/
# 更新 openssh-server
dnf -y install openssh-server
# 下载 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 复制到其它服务器中
hots='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
user=root
for i in $hots; do
echo $i;
rsync --rsync-path="sudo rsync" docker/* $user@$i:/usr/bin/;
done
# 验证
$ 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
# 将 containerd.service 复制到其它服务器中
hots='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
user=root
for i in $hots; do
echo $i;
rsync --rsync-path="sudo rsync" /etc/systemd/system/containerd.service $user@$i:/etc/systemd/system/;
done
# 配置设置每一台服务器 containerd 开机自启
hosts='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
for host in $hosts; do
ssh root@$host "systemctl enable --now containerd.service"
done
# 验证
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
# 将 docker.service 复制到其它服务器中
hots='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
user=root
for i in $hots; do
echo $i;
rsync --rsync-path="sudo rsync" /etc/systemd/system/docker.service $user@$i:/etc/systemd/system/;
done
命令解析:
[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.socket 复制到其它服务器中
hots='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
user=root
for i in $hots; do
echo $i;
rsync --rsync-path="sudo rsync" /etc/systemd/system/docker.socket $user@$i:/etc/systemd/system/;
done
命令解析:
这是一个用于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
# 配置设置每一台服务器都创建docker的配置目录和数据目录
hosts='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
for host in $hosts; do
ssh root@$host "mkdir /etc/docker/ /data/docker -pv"
done
# 将 daemon.json 复制到其它服务器中
hots='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
user=root
for i in $hots; do
echo $i;
rsync --rsync-path="sudo rsync" /etc/docker/daemon.json $user@$i:/etc/docker/;
done
命令解析:
该参数文件中包含以下参数: 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 服务状态
systemctl status docker.service
# 验证:查看docker信息
docker info
# 集群中的其他服务器也启动 Docker
hosts='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
for host in $hosts; do
ssh root@$host "groupadd docker"
ssh root@$host "systemctl daemon-reload"
ssh root@$host "systemctl enable --now docker.socket"
ssh root@$host "systemctl enable --now docker.service"
done
19. 安装 cri-docker
19.1 安装 cri-docker 二进制包
cri-docker 与 docker的版本匹配关系:https://github.com/Mirantis/cri-dockerd/releases/tag/v0.4.0
# 下载 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 复制到其它服务器中
hots='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
user=root
for i in $hots; do
echo $i;
rsync --rsync-path="sudo rsync" /usr/bin/cri-dockerd $user@$i:/usr/bin/;
done
# 验证
$ 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
# 将 cri-docker.service 复制到其它服务器中
hots='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
user=root
for i in $hots; do
echo $i;
rsync --rsync-path="sudo rsync" /usr/lib/systemd/system/cri-docker.service $user@$i:/usr/lib/systemd/system/;
done
命令解析:
[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
# 将 cri-docker.socket 复制到其它服务器中
hots='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
user=root
for i in $hots; do
echo $i;
rsync --rsync-path="sudo rsync" /usr/lib/systemd/system/cri-docker.socket $user@$i:/usr/lib/systemd/system/;
done
命令解析:
该配置文件是用于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 status cri-docker.service
# 集群中的其他服务器也启动 Docker
hosts='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
for host in $hosts; do
ssh root@$host "systemctl daemon-reload"
ssh root@$host "systemctl enable --now cri-docker.service"
done
四、K8S 与 ETCD 下载及安装(在 master01 节点上操作)
当前选择安装 K8S 版本:1.29.2,ETCD 版本:3.5.16
查看 K8S 与 ETCD 的版本匹配关系以及二进制包下载地址
https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.29.md
https://github.com/kubernetes/kubernetes/blob/release-1.29/cluster/images/etcd/Makefile
需要下载的镜像
https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.29.md#container-images-13

1. 安装 K8S 二进制包
下载地址:https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.29.md#v1292
# 下载 K8S 二进制包
wget https://dl.k8s.io/v1.29.2/kubernetes-server-linux-amd64.tar.gz
# 解压文件到指定目录
tar -xf kubernetes-server-linux-amd64.tar.gz --strip-components=3 -C /usr/local/bin kubernetes/server/bin/kube{let,ctl,-apiserver,-controller-manager,-scheduler,-proxy}
# 查看解压的文件
$ ls /usr/local/bin/
kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubectl kubelet
# 将解压后的 K8S 二进制包复制到其它服务器中
# 拷贝 master 组件
hots='k8s-master02 k8s-master03'
user=root
for i in $hots; do
echo $i;
rsync --rsync-path="sudo rsync" /usr/local/bin/kube* $user@$i:/usr/local/bin/;
done
# 拷贝 worker 组件
hots='k8s-node01 k8s-node02'
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
# 验证
$ kubelet --version
Kubernetes v1.29.2
命令解析:
这是一个 tar 命令,用于解压指定的 kubernetes-server-linux-amd64.tar.gz 文件,并将其中的特定文件提取到 /usr/local/bin 目录下。 命令的解释如下: tar:用于处理 tar 压缩文件的命令。 -xf:表示解压操作。 kubernetes-server-linux-amd64.tar.gz:要解压的文件名。 --strip-components=3:表示解压时忽略压缩文件中的前3级目录结构,提取文件时直接放到目标目录中。 -C /usr/local/bin:指定提取文件的目标目录为 /usr/local/bin。 kubernetes/server/bin/kube{let,ctl,-apiserver,-controller-manager,-scheduler,-proxy}:要解压和提取的文件名模式,用花括号括起来表示模式中的多个可能的文件名。 总的来说,这个命令的作用是将 kubernetes-server-linux-amd64.tar.gz 文件中的 kubelet、kubectl、kube-apiserver、kube-controller-manager、kube-scheduler和kube-proxy 六个文件提取到 /usr/local/bin 目录下,同时忽略文件路径中的前三级目录结构。
2. 安装 ETCD 二进制包
下载地址:https://github.com/etcd-io/etcd/releases/tag/v3.5.16
# 下载 ETCD 二进制安装包
wget https://github.com/etcd-io/etcd/releases/download/v3.5.16/etcd-v3.5.16-linux-amd64.tar.gz
# 解压etcd安装文件
tar -xf etcd*.tar.gz && mv etcd-*/etcd /usr/local/bin/ && mv etcd-*/etcdctl /usr/local/bin/
# 将解压后的 K8S 二进制包复制到其它服务器中
hots='k8s-master02 k8s-master03'
user=root
for i in $hots; do
echo $i;
rsync --rsync-path="sudo rsync" /usr/local/bin/etcd* $user@$i:/usr/local/bin/;
done
# 验证:查看/usr/local/bin下内容
$ etcdctl version
etcdctl version: 3.5.16
API version: 3.5
3. 生成相关证书
3.1 安装证书工具
k8s-master01
# master01 节点下载证书生成工具
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssl_1.6.4_linux_amd64 -O /usr/local/bin/cfssl
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssljson_1.6.4_linux_amd64 -O /usr/local/bin/cfssljson
chmod +x /usr/local/bin/cfssl /usr/local/bin/cfssljson
3.2 生成 ETCD 证书
3.2.1 ca-config.json
k8s-master01
# 创建目录,存放生成的证书
mkdir /etc/etcd/ssl -p
# 写入生成证书所需的配置文件,master01 节点生成 etcd 证书
cat > /etc/etcd/ssl/ca-config.json << EOF
{
"signing": {
"default": {
"expiry": "876000h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "876000h"
}
}
}
}
EOF
命令解析:
ca-config.json文件是使用CFSSL(CloudFlare’s PKI/TLS toolkit)工具生成证书的核心配置文件。它主要用于定义证书签名的全局策略和配置文件(profiles),确保生成的证书具有一致的安全属性、用途和有效期。在这里,有两个部分:signing 和 profiles。 signing 包含了默认签名配置和配置文件。 默认签名配置 default 指定了证书的过期时间为 876000h 。876000h 表示证书有效期为 100 年。 profiles 部分定义了不同的证书配置文件。 在这里,只有一个配置文件 kubernetes 。它包含了以下 usages 和过期时间 expiry: signing:用于对其他证书进行签名 key encipherment:用于加密和解密传输数据 server auth:用于服务器身份验证 client auth:用于客户端身份验证 对于 kubernetes 配置文件,证书的过期时间也是 876000h,即100年。
3.2.2 etcd-ca-csr.json
k8s-master01
cat > /etc/etcd/ssl/etcd-ca-csr.json << EOF
{
"CN": "etcd",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "etcd",
"OU": "Etcd Security"
}
],
"ca": {
"expiry": "876000h"
}
}
EOF
命令解析:
etcd-ca-csr.json 是 Certificate Signing Request (CSR) 文件,用于生成 ETCD 的根 CA 证书(etcd-ca.pem 和 etcd-ca-key.pem)。根 CA 证书是 ETCD 集群的安全基石,用于签署 ETCD 节点证书(etcd.pem 和 etcd-key.pem)和其他相关证书,确保集群内部通信的加密和身份验证。
JSON 配置文件指定了生成证书签名请求所需的数据。 "CN": "etcd" 指定了希望生成的证书的 CN 字段(Common Name),即证书的主题,通常是该证书标识的实体的名称。 "key": {} 指定了生成证书所使用的密钥的配置信息。"algo": "rsa" 指定了密钥的算法为 RSA,"size": 2048 指定了密钥的长度为 2048 位。 "names": [] 包含了生成证书时所需的实体信息。在这个例子中,只包含了一个实体,其相关信息如下: "C": "CN" 指定了实体的国家/地区代码,这里是中国。 "ST": "Beijing" 指定了实体所在的省/州。 "L": "Beijing" 指定了实体所在的城市。 "O": "etcd" 指定了实体的组织名称。 "OU": "Etcd Security" 指定了实体所属的组织单位。 "ca": {} 指定了生成证书时所需的CA(Certificate Authority)配置信息。 "expiry": "876000h" 指定了证书的有效期,这里是876000小时。 生成证书签名请求时,可以使用这个 JSON 配置文件作为输入,根据配置文件中的信息生成相应的 CSR 文件。然后,可以将 CSR 文件发送给 CA 进行签名,以获得有效的证书。 生成 etcd 证书和 etcd 证书的 key(如果你觉得以后可能会扩容,可以在 ip 那多写几个预留出来) 若没有IPv6 可删除可保留
3.2.3 生成 ETCD 的根 CA 证书
k8s-master01
# 生成 ETCD 的根 CA 证书
cfssl gencert -initca /etc/etcd/ssl/etcd-ca-csr.json | cfssljson -bare /etc/etcd/ssl/etcd-ca
# 查看生成的 ETCD 的根 CA 证书
$ ll /etc/etcd/ssl/
total 20
-rw-r--r--. 1 root root 294 Oct 11 19:03 ca-config.json
-rw-r--r--. 1 root root 249 Oct 11 19:20 etcd-ca-csr.json
-rw-------. 1 root root 1679 Oct 11 19:21 etcd-ca-key.pem
-rw-r--r--. 1 root root 1050 Oct 11 19:21 etcd-ca.csr
-rw-r--r--. 1 root root 1318 Oct 11 19:21 etcd-ca.pem
具体的解释如下: cfssl 是一个用于生成 TLS/SSL 证书的工具,它支持 PKI、JSON 格式配置文件以及与许多其他集成工具的配合使用。 gencert 参数表示生成证书的操作。-initca 参数表示初始化一个CA(证书颁发机构)。CA 是用于签发其他证书的根证书。etcd-ca-csr.json 是一个 JSON 格式的配置文件,其中包含了CA的详细信息,如私钥、公钥、有效期等。这个文件提供了生成 CA 证书所需的信息。 | 符号表示将上一个命令的输出作为下一个命令的输入。 cfssljson 是 cfssl 工具的一个子命令,用于格式化 cfssl 生成的 JSON 数据。 -bare 参数表示直接输出裸证书,即只生成证书文件,不包含其他格式的文件。/etc/etcd/ssl/etcd-ca 是指定生成的证书文件的路径和名称。 所以,这条命令的含义是使用 cfssl 工具根据配置文件 etcd-ca-csr.json 生成一个 CA 证书,并将证书文件保存在 /etc/etcd/ssl/etcd-ca 路径下。
3.2.4 etcd-csr.json
k8s-master01
cat > /etc/etcd/ssl/etcd-csr.json << EOF
{
"CN": "etcd",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "etcd",
"OU": "Etcd Security"
}
]
}
EOF
命令解析:
etcd-csr.json 用于生成 ETCD 节点的 TLS 证书(etcd.pem 和 etcd-key.pem),这些证书由 ETCD 的根 CA(通过 etcd-ca-csr.json 生成的 etcd-ca.pem)签署。
这段代码是一个 JSON 格式的配置文件,用于生成一个证书签名请求(Certificate Signing Request,CSR)。 首先,"CN"字段指定了该证书的通用名称(Common Name),这里设为"etcd"。 接下来,"key"字段指定了密钥的算法("algo"字段)和长度("size"字段),此处使用的是RSA算法,密钥长度为2048位。 最后,"names"字段是一个数组,其中包含了一个名字对象,用于指定证书中的一些其他信息。这个名字对象包含了以下字段: "C"字段指定了国家代码(Country),这里设置为"CN"。 "ST"字段指定了省份(State)或地区,这里设置为"Beijing"。 "L"字段指定了城市(Locality),这里设置为"Beijing"。 "O"字段指定了组织(Organization),这里设置为"etcd"。 "OU"字段指定了组织单元(Organizational Unit),这里设置为"Etcd Security"。 这些字段将作为证书的一部分,用于标识和验证证书的使用范围和颁发者等信息。
3.2.5 生成 ETCD 节点证书
k8s-master01
# 生成 ETCD 节点证书
cfssl gencert \
-ca=/etc/etcd/ssl/etcd-ca.pem \
-ca-key=/etc/etcd/ssl/etcd-ca-key.pem \
-config=/etc/etcd/ssl/ca-config.json \
-hostname=127.0.0.1,k8s-master01,k8s-master02,k8s-master03,10.20.1.101,10.20.1.102,10.20.1.103,2400:3200::101,2400:3200::102,2400:3200::103,::1 \
-profile=kubernetes \
/etc/etcd/ssl/etcd-csr.json | cfssljson -bare /etc/etcd/ssl/etcd
命令解析:
这是一条使用cfssl生成etcd节点证书的命令,下面是各个参数的解释: -ca=/etc/etcd/ssl/etcd-ca.pem:指定用于签名etcd证书的CA文件的路径。 -ca-key=/etc/etcd/ssl/etcd-ca-key.pem:指定用于签名etcd证书的CA私钥文件的路径。 -config=ca-config.json:指定CA配置文件的路径,该文件定义了证书的有效期、加密算法等设置。 -hostname=xxxx:指定要为etcd生成证书的主机名和IP地址列表。 -profile=kubernetes:指定使用的证书配置文件,该文件定义了证书的用途和扩展属性。 etcd-csr.json:指定etcd证书请求的JSON文件的路径,该文件包含了证书请求的详细信息。 | cfssljson -bare /etc/etcd/ssl/etcd:通过管道将cfssl命令的输出传递给cfssljson命令,并使用-bare参数指定输出文件的前缀路径,这里将生成etcd证书的.pem和-key.pem文件。 这条命令的作用是使用指定的CA证书和私钥,根据证书请求的JSON文件和配置文件生成etcd的证书文件。
3.2.6 将证书复制到其他节点
k8s-master01
# 将生成的 ETCD 证书复制到其他节点
hosts='k8s-master02 k8s-master03'
for host in $hosts; do
echo $host;
ssh root@$host "mkdir /etc/etcd/ssl -p"
rsync --rsync-path="sudo rsync" /etc/etcd/ssl/* $user@$host:/etc/etcd/ssl/;
done
3.3 生成 K8S 相关证书
3.3.1 ca-config.json
k8s-master01
# 创建目录,用于存放 K8S 相关证书
mkdir -p /etc/kubernetes/pki
cat > /etc/kubernetes/pki/ca-config.json << EOF
{
"signing": {
"default": {
"expiry": "876000h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "876000h"
}
}
}
}
EOF
命令解析:
ca-config.json文件是使用CFSSL(CloudFlare’s PKI/TLS toolkit)工具生成证书的核心配置文件。它主要用于定义证书签名的全局策略和配置文件(profiles),确保生成的证书具有一致的安全属性、用途和有效期。在这里,有两个部分:signing 和 profiles。 signing 包含了默认签名配置和配置文件。 默认签名配置 default 指定了证书的过期时间为 876000h 。876000h 表示证书有效期为 100 年。 profiles 部分定义了不同的证书配置文件。 在这里,只有一个配置文件 kubernetes 。它包含了以下 usages 和过期时间 expiry: signing:用于对其他证书进行签名 key encipherment:用于加密和解密传输数据 server auth:用于服务器身份验证 client auth:用于客户端身份验证 对于 kubernetes 配置文件,证书的过期时间也是 876000h,即100年。
3.3.2 ca-csr.json
cat > /etc/kubernetes/pki/ca-csr.json << EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Guangdong",
"L": "Guangzhou",
"O": "Kubernetes",
"OU": "System"
}
],
"ca": {
"expiry": "876000h"
}
}
EOF
命令解析:
ca-csr.json 用于生成 Kubernetes 集群的根 CA 证书(ca.pem 和 ca-key.pem)。根 CA 证书是 Kubernetes 安全体系的核心,用于签署集群内所有组件的证书(如 API Server、kubelet、admin 用户等),支持 TLS 加密和 Mutual TLS 认证。
这是一个用于生成 Kubernetes 相关证书的配置文件。该配置文件中包含以下信息: CN:CommonName,即用于标识证书的通用名称。在此配置中,CN 设置为 "kubernetes",表示该证书是用于 Kubernetes。 key:用于生成证书的算法和大小。在此配置中,使用的算法是 RSA,大小是 2048 位。 names:用于证书中的名称字段的详细信息。在此配置中,有以下字段信息: C:Country,即国家。在此配置中,设置为 "CN"。 ST:State,即省/州。在此配置中,设置为 "Beijing"。 L:Locality,即城市。在此配置中,设置为 "Beijing"。 O:Organization,即组织。在此配置中,设置为 "Kubernetes"。 OU:Organization Unit,即组织单位。在此配置中,设置为 "Kubernetes-manual"。 ca:用于证书签名的证书颁发机构(CA)的配置信息。在此配置中,设置了证书的有效期为 876000 小时。 这个配置文件可以用于生成 Kubernetes 相关的证书,以确保集群中的通信安全性。
3.3.3 生成 Kubernetes 集群的根 CA 证书
cfssl gencert -initca /etc/kubernetes/pki/ca-csr.json | cfssljson -bare /etc/kubernetes/pki/ca
命令解析:
具体的解释如下: cfssl是一个用于生成TLS/SSL证书的工具,它支持PKI、JSON格式配置文件以及与许多其他集成工具的配合使用。 gencert参数表示生成证书的操作。-initca参数表示初始化一个CA(证书颁发机构)。CA是用于签发其他证书的根证书。ca-csr.json是一个JSON格式的配置文件,其中包含了CA的详细信息,如私钥、公钥、有效期等。这个文件提供了生成CA证书所需的信息。 | 符号表示将上一个命令的输出作为下一个命令的输入。 cfssljson是cfssl工具的一个子命令,用于格式化cfssl生成的JSON数据。 -bare参数表示直接输出裸证书,即只生成证书文件,不包含其他格式的文件。/etc/kubernetes/pki/ca是指定生成的证书文件的路径和名称。 所以,这条命令的含义是使用cfssl工具根据配置文件ca-csr.json生成一个CA证书,并将证书文件保存在/etc/kubernetes/pki/ca路径下。
3.3.4 apiserver-csr.json
cat > /etc/kubernetes/pki/apiserver-csr.json << EOF
{
"CN": "kube-apiserver",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "Kubernetes",
"OU": "Kubernetes-manual"
}
]
}
EOF
命令解析:
apiserver-csr.json 用于生成 Kubernetes API Server 的 TLS 证书(apiserver.pem 和 apiserver-key.pem),这些证书由 Kubernetes 的根 CA(通过 ca-csr.json 生成的 ca.pem)签署。
证书用于:
- 服务器端认证:确保 API Server 的身份可信,客户端(如 kubectl、kubelet)可以通过 CA 证书(ca.pem)验证 API Server。
- 客户端认证:支持 Mutual TLS,API Server 验证客户端证书(如 admin、kubelet)的合法性。
- 加密通信:通过 TLS 加密 API Server 与客户端之间的通信,防止数据泄露或篡改。
3.3.5 生成 apiserver 证书
cfssl gencert \
-ca=/etc/kubernetes/pki/ca.pem \
-ca-key=/etc/kubernetes/pki/ca-key.pem \
-config=/etc/kubernetes/pki/ca-config.json \
-hostname=10.96.0.1,127.0.0.1,kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster,kubernetes.default.svc.cluster.local,10.20.1.101,10.20.1.102,10.20.1.103,10.20.1.104,10.20.1.105,10.20.1.106,10.20.1.107,10.20.1.108,10.20.1.109,2400:3200::101,2400:3200::102,2400:3200::103,2400:3200::104,2400:3200::105,2400:3200::106,2400:3200::107,2400:3200::108,2400:3200::109 \
-profile=kubernetes \
/etc/kubernetes/pki/apiserver-csr.json | cfssljson -bare /etc/kubernetes/pki/apiserver
3.3.6 apiserver 聚合证书
访问 kube-apiserver 的另一种方式就是使用 kube-proxy 来代理访问, 而该证书就是用来支持 SSL 代理访问的。在该种访问模式下,我们是以http的方式发起请求到代理服务的, 此时, 代理服务会将该请求发送给 kube-apiserver , 在此之前, 代理会将发送给 kube-apiserver 的请求头里加入证书信息。
客户端 -- 发起请求 ---> 代理 -- Add Header信息:发起请求 --> kube-apiserve
如果apiserver所在的主机上没有运行kube-proxy,既无法通过服务的ClusterIP进行访问,需要 --enable-aggregator-routing=true
3.3.6.1 front-proxy-ca-csr.json
cat > /etc/kubernetes/pki/front-proxy-ca-csr.json << EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"ca": {
"expiry": "876000h"
}
}
EOF
命令解析:
front-proxy-ca-csr.json 用于生成 Kubernetes 的 Front Proxy CA 证书(front-proxy-ca.pem 和 front-proxy-ca-key.pem)。Front Proxy CA 是 Kubernetes 集群中用于 前端代理认证 的独立 CA,专门用于签署前端代理客户端证书(如 front-proxy-client.pem),以支持 API Server 的请求头认证机制。
3.3.6.2 生成 Kubernetes Front Proxy 根 CA 证书
包括证书文件(front-proxy-ca.pem)、私钥文件(front-proxy-ca-key.pem)和 CSR 文件(front-proxy-ca.csr)
# 指示 CFSSL 生成根 CA 证书(而非普通证书)
cfssl gencert -initca /etc/kubernetes/pki/front-proxy-ca-csr.json | cfssljson -bare /etc/kubernetes/pki/front-proxy-ca
# 生成 前端代理客户端证书 的 CSR 配置文件
cat > /etc/kubernetes/pki/front-proxy-client-csr.json << EOF
{
"CN": "front-proxy-client",
"key": {
"algo": "rsa",
"size": 2048
}
}
EOF
# 生成前端代理客户端证书
cfssl gencert \
-ca=/etc/kubernetes/pki/front-proxy-ca.pem \
-ca-key=/etc/kubernetes/pki/front-proxy-ca-key.pem \
-config=/etc/kubernetes/pki/ca-config.json \
-profile=kubernetes /etc/kubernetes/pki/front-proxy-client-csr.json | cfssljson -bare /etc/kubernetes/pki/front-proxy-client
命令解析1:
cfssl gencert -initca front-proxy-ca-csr.json | cfssljson -bare /etc/kubernetes/pki/front-proxy-ca
这个命令使用 CFSSL 工具生成 Kubernetes Front Proxy CA 证书(根 CA 证书),包括证书文件(front-proxy-ca.pem)、私钥文件(front-proxy-ca-key.pem)和 CSR 文件(front-proxy-ca.csr)。
Front Proxy CA 的背景:在 Kubernetes 高可用集群中,Front Proxy CA 是用于 请求头认证(RequestHeader Authentication) 的独立 CA。它专门用于签署前端代理客户端证书(如 front-proxy-client.pem),以支持 API Server 的聚合层(Aggregation Layer)。这对于扩展组件(如 Metrics Server)至关重要,确保客户端(如 Metrics Server)可以通过 HTTP 请求头提供身份信息,并由 API Server 验证。
上下文:博客中,此证书用于 Metrics Server 的部署(components.yaml 中引用 –requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.pem),确保高可用集群(3 Master 节点 + 2 Node 节点)的扩展 API 安全。
命令解析2:
cat > front-proxy-client-csr.json << EOF … EOF
生成 前端代理客户端证书 的 CSR 配置文件
前端代理客户端证书的作用:用于 Metrics Server 或其他聚合 API 客户端的身份认证。客户端证书(front-proxy-client.pem 和 front-proxy-client-key.pem)由 Front Proxy CA 签署,API Server 使用它验证请求头中的客户端身份,确保只有可信客户端可以访问聚合 API
为什么需要?Kubernetes 的聚合层要求客户端提供证书以通过 RequestHeader 认证。Metrics Server 配置中引用了这些证书,确保安全访问 API Server。
上下文:博客中,此证书用于 Metrics Server 的 TLS 通信,支持高可用集群的扩展功能。
命令解析3:
cfssl gencert
-ca=/etc/kubernetes/pki/front-proxy-ca.pem
-ca-key=/etc/kubernetes/pki/front-proxy-ca-key.pem
-config=/etc/kubernetes/pki/ca-config.json
-profile=kubernetes /etc/kubernetes/pki/front-proxy-client-csr.json | cfssljson -bare /etc/kubernetes/pki/front-proxy-client
- 使用 CFSSL 生成 前端代理客户端证书(front-proxy-client.pem 和 front-proxy-client-key.pem),由 Front Proxy CA 签署。
- 客户端证书的作用:Metrics Server 等聚合客户端使用此证书在请求头中证明身份,API Server 通过 Front Proxy CA 验证,确保安全访问聚合 API(如 /apis/metrics.k8s.io/)
- Metrics Server 的配置(–requestheader-username-headers 等)依赖此证书,支持 RequestHeader 认证。
- 在高可用集群中,此证书分发到所有 Master 节点,供 kube-apiserver 使用
3.3.7 生成 controller-manage 的证书
# 生成 Kubernetes Controller Manager 客户端证书 的 Certificate Signing Request (CSR) 配置文件
cat > /etc/kubernetes/pki/manager-csr.json << EOF
{
"CN": "system:kube-controller-manager",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "system:kube-controller-manager",
"OU": "Kubernetes-manual"
}
]
}
EOF
# 使用 CFSSL 生成 Controller Manager 客户端证书(controller-manager.pem 和 controller-manager-key.pem),由 Kubernetes 根 CA(ca.pem)签署
cfssl gencert \
-ca=/etc/kubernetes/pki/ca.pem \
-ca-key=/etc/kubernetes/pki/ca-key.pem \
-config=/etc/kubernetes/pki/ca-config.json \
-profile=kubernetes \
/etc/kubernetes/pki/manager-csr.json | cfssljson -bare /etc/kubernetes/pki/controller-manager
# 配置 Controller Manager 的 kubeconfig 文件(/etc/kubernetes/controller-manager.kubeconfig),定义集群信息,指定 API Server 的地址和 CA 证书。
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.pem \
--embed-certs=true \
--server=https://127.0.0.1:8443 \
--kubeconfig=/etc/kubernetes/controller-manager.kubeconfig
# 设置 kubeconfig 的上下文,将集群、用户和命名空间绑定,定义 Controller Manager 的访问环境
kubectl config set-context system:kube-controller-manager@kubernetes \
--cluster=kubernetes \
--user=system:kube-controller-manager \
--kubeconfig=/etc/kubernetes/controller-manager.kubeconfig
# 设置 Controller Manager 的用户凭据,指定其客户端证书和私钥,用于与 API Server 的身份认证
kubectl config set-credentials system:kube-controller-manager \
--client-certificate=/etc/kubernetes/pki/controller-manager.pem \
--client-key=/etc/kubernetes/pki/controller-manager-key.pem \
--embed-certs=true \
--kubeconfig=/etc/kubernetes/controller-manager.kubeconfig
# 设置 kubeconfig 文件的默认上下文,确保 Controller Manager 使用 system:kube-controller-manager@kubernetes 上下文访问 API Server
kubectl config use-context system:kube-controller-manager@kubernetes \
--kubeconfig=/etc/kubernetes/controller-manager.kubeconfig
3.3.8 生成 kube-scheduler 的证书
# 生成 Kubernetes Scheduler 客户端证书 的 Certificate Signing Request (CSR) 配置文件
cat > /etc/kubernetes/pki/scheduler-csr.json << EOF
{
"CN": "system:kube-scheduler",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "system:kube-scheduler",
"OU": "Kubernetes-manual"
}
]
}
EOF
# 使用 CFSSL 生成 Scheduler 客户端证书(scheduler.pem 和 scheduler-key.pem),由 Kubernetes 根 CA(ca.pem)签署
cfssl gencert \
-ca=/etc/kubernetes/pki/ca.pem \
-ca-key=/etc/kubernetes/pki/ca-key.pem \
-config=/etc/kubernetes/pki/ca-config.json \
-profile=kubernetes \
/etc/kubernetes/pki/scheduler-csr.json | cfssljson -bare /etc/kubernetes/pki/scheduler
# 配置 Scheduler 的 kubeconfig 文件(/etc/kubernetes/scheduler.kubeconfig),定义集群信息,指定 API Server 的地址和 CA 证书。
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.pem \
--embed-certs=true \
--server=https://127.0.0.1:8443 \
--kubeconfig=/etc/kubernetes/scheduler.kubeconfig
# 设置 Scheduler 的用户凭据,指定其客户端证书和私钥,用于与 API Server 的身份认证。
kubectl config set-credentials system:kube-scheduler \
--client-certificate=/etc/kubernetes/pki/scheduler.pem \
--client-key=/etc/kubernetes/pki/scheduler-key.pem \
--embed-certs=true \
--kubeconfig=/etc/kubernetes/scheduler.kubeconfig
# 设置 kubeconfig 的上下文,将集群、用户和命名空间绑定,定义 Scheduler 的访问环境。
kubectl config set-context system:kube-scheduler@kubernetes \
--cluster=kubernetes \
--user=system:kube-scheduler \
--kubeconfig=/etc/kubernetes/scheduler.kubeconfig
# 设置 kubeconfig 文件的默认上下文,确保 Scheduler 使用 system:kube-scheduler@kubernetes 上下文访问 API Server
kubectl config use-context system:kube-scheduler@kubernetes \
--kubeconfig=/etc/kubernetes/scheduler.kubeconfig
3.3.9 生成 admin 的证书配置
# 生成一个 证书签名请求(Certificate Signing Request) 的配置文件,供 cfssl 工具使用
cat > /etc/kubernetes/pki/admin-csr.json << EOF
{
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "system:masters",
"OU": "Kubernetes-manual"
}
]
}
EOF
# 生成了管理员证书和密钥,用于 kubectl 访问 API Server 时进行身份认证
cfssl gencert \
-ca=/etc/kubernetes/pki/ca.pem \
-ca-key=/etc/kubernetes/pki/ca-key.pem \
-config=/etc/kubernetes/pki/ca-config.json \
-profile=kubernetes \
/etc/kubernetes/pki/admin-csr.json | cfssljson -bare /etc/kubernetes/pki/admin
# 设置集群信息
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.pem \
--embed-certs=true \
--server=https://127.0.0.1:8443 \
--kubeconfig=/etc/kubernetes/admin.kubeconfig
# 设置用户凭证
kubectl config set-credentials kubernetes-admin \
--client-certificate=/etc/kubernetes/pki/admin.pem \
--client-key=/etc/kubernetes/pki/admin-key.pem \
--embed-certs=true \
--kubeconfig=/etc/kubernetes/admin.kubeconfig
# 绑定上下文
kubectl config set-context kubernetes-admin@kubernetes \
--cluster=kubernetes \
--user=kubernetes-admin \
--kubeconfig=/etc/kubernetes/admin.kubeconfig
# 启用当前上下文
kubectl config use-context kubernetes-admin@kubernetes --kubeconfig=/etc/kubernetes/admin.kubeconfig
3.3.10 创建 kube-proxy 证书
# 生成 kube-proxy 证书签名请求文件 (CSR),这个文件会被用来生成证书请求
cat > /etc/kubernetes/pki/kube-proxy-csr.json << EOF
{
"CN": "system:kube-proxy",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "system:kube-proxy",
"OU": "Kubernetes-manual"
}
]
}
EOF
# 使用前面创建好的集群 CA 根证书来签发 kube-proxy 的客户端证书
cfssl gencert \
-ca=/etc/kubernetes/pki/ca.pem \
-ca-key=/etc/kubernetes/pki/ca-key.pem \
-config=/etc/kubernetes/pki/ca-config.json \
-profile=kubernetes \
/etc/kubernetes/pki/kube-proxy-csr.json | cfssljson -bare /etc/kubernetes/pki/kube-proxy
# 生成 kube-proxy 的 kubeconfig 文件, kube-proxy 在启动时需要使用一个 kubeconfig 文件来连接 API Server
# 设置集群信息
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.pem \
--embed-certs=true \
--server=https://127.0.0.1:8443 \
--kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig
# 设置用户凭证
kubectl config set-credentials kube-proxy \
--client-certificate=/etc/kubernetes/pki/kube-proxy.pem \
--client-key=/etc/kubernetes/pki/kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig
# 绑定上下文(Context)
kubectl config set-context kube-proxy@kubernetes \
--cluster=kubernetes \
--user=kube-proxy \
--kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig
# 启用当前上下文
kubectl config use-context kube-proxy@kubernetes --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig
3.3.11 生成 ServiceAccount(简称 SA)签名密钥对
# 生成文件 /etc/kubernetes/pki/sa.key —— ServiceAccount 私钥文件
openssl genrsa -out /etc/kubernetes/pki/sa.key 2048
# 生成文件 /etc/kubernetes/pki/sa.pub —— ServiceAccount 公钥文件
openssl rsa -in /etc/kubernetes/pki/sa.key -pubout -out /etc/kubernetes/pki/sa.pub
4. 分发证书到其它节点
4.1 分发到 master 节点
k8s-master01
# 将生成的 ETCD 证书复制到其他节点
hosts='k8s-master02 k8s-master03'
user=root
for host in $hosts; do
echo $host;
ssh root@$host "mkdir -p /etc/kubernetes/pki/"
rsync --rsync-path="sudo rsync" /etc/kubernetes/pki/* $user@$host:/etc/kubernetes/pki/;
rsync --rsync-path="sudo rsync" /etc/kubernetes/admin.kubeconfig $user@$host:/etc/kubernetes/
rsync --rsync-path="sudo rsync" /etc/kubernetes/controller-manager.kubeconfig $user@$host:/etc/kubernetes/
rsync --rsync-path="sudo rsync" /etc/kubernetes/scheduler.kubeconfig $user@$host:/etc/kubernetes/
rsync --rsync-path="sudo rsync" /etc/kubernetes/kube-proxy.kubeconfig $user@$host:/etc/kubernetes/
done
4.2 分发到 node 节点
k8s-master01
hosts='k8s-node01 k8s-node02'
user=root
for host in $hosts; do
echo $host;
ssh root@$host "mkdir -p /etc/kubernetes/pki/"
rsync --rsync-path="sudo rsync" /etc/kubernetes/pki/kube-proxy* $user@$host:/etc/kubernetes/pki/;
rsync --rsync-path="sudo rsync" /etc/kubernetes/kube-proxy.kubeconfig $user@$host:/etc/kubernetes/
done
5. 查看证书
5.1 master 节点
$ ll /etc/kubernetes/pki/
total 140
-rw-r--r--. 1 root root 225 Oct 16 23:22 admin-csr.json
-rw-------. 1 root root 1679 Oct 16 23:25 admin-key.pem
-rw-r--r--. 1 root root 1025 Oct 16 23:25 admin.csr
-rw-r--r--. 1 root root 1432 Oct 16 23:25 admin.pem
-rw-r--r--. 1 root root 230 Oct 11 20:11 apiserver-csr.json
-rw-------. 1 root root 1675 Oct 11 20:17 apiserver-key.pem
-rw-r--r--. 1 root root 1565 Oct 11 20:17 apiserver.csr
-rw-r--r--. 1 root root 1948 Oct 11 20:17 apiserver.pem
-rw-r--r--. 1 root root 294 Oct 11 19:58 ca-config.json
-rw-r--r--. 1 root root 258 Oct 11 20:04 ca-csr.json
-rw-------. 1 root root 1679 Oct 11 20:04 ca-key.pem
-rw-r--r--. 1 root root 1062 Oct 11 20:04 ca.csr
-rw-r--r--. 1 root root 1342 Oct 11 20:04 ca.pem
-rw-------. 1 root root 1675 Oct 16 22:19 controller-manager-key.pem
-rw-r--r--. 1 root root 1082 Oct 16 22:19 controller-manager.csr
-rw-r--r--. 1 root root 1489 Oct 16 22:19 controller-manager.pem
-rw-r--r--. 1 root root 118 Oct 11 20:23 front-proxy-ca-csr.json
-rw-------. 1 root root 1679 Oct 16 21:19 front-proxy-ca-key.pem
-rw-r--r--. 1 root root 940 Oct 16 21:19 front-proxy-ca.csr
-rw-r--r--. 1 root root 1094 Oct 16 21:19 front-proxy-ca.pem
-rw-r--r--. 1 root root 87 Oct 16 21:22 front-proxy-client-csr.json
-rw-------. 1 root root 1679 Oct 16 21:25 front-proxy-client-key.pem
-rw-r--r--. 1 root root 903 Oct 16 21:25 front-proxy-client.csr
-rw-r--r--. 1 root root 1188 Oct 16 21:25 front-proxy-client.pem
-rw-r--r--. 1 root root 240 Oct 16 23:31 kube-proxy-csr.json
-rw-------. 1 root root 1675 Oct 16 23:31 kube-proxy-key.pem
-rw-r--r--. 1 root root 1045 Oct 16 23:31 kube-proxy.csr
-rw-r--r--. 1 root root 1456 Oct 16 23:31 kube-proxy.pem
-rw-r--r--. 1 root root 266 Oct 16 22:11 manager-csr.json
-rw-------. 1 root root 1704 Oct 16 23:34 sa.key
-rw-r--r--. 1 root root 451 Oct 16 23:34 sa.pub
-rw-r--r--. 1 root root 248 Oct 16 23:07 scheduler-csr.json
-rw-------. 1 root root 1679 Oct 16 23:08 scheduler-key.pem
-rw-r--r--. 1 root root 1058 Oct 16 23:08 scheduler.csr
-rw-r--r--. 1 root root 1464 Oct 16 23:08 scheduler.pem
$ ll /etc/kubernetes/
total 36
-rw-------. 1 root root 6341 Oct 16 23:26 admin.kubeconfig
-rw-------. 1 root root 6469 Oct 16 22:30 controller-manager.kubeconfig
-rw-------. 1 root root 6345 Oct 16 23:32 kube-proxy.kubeconfig
drwxr-xr-x. 2 root root 4096 Oct 16 23:34 pki
-rw-------. 1 root root 6401 Oct 16 23:14 scheduler.kubeconfig
5.2 node 节点
$ ll /etc/kubernetes/pki/
total 16
-rw-r--r--. 1 root root 240 Oct 16 23:52 kube-proxy-csr.json
-rw-------. 1 root root 1675 Oct 16 23:52 kube-proxy-key.pem
-rw-r--r--. 1 root root 1045 Oct 16 23:52 kube-proxy.csr
-rw-r--r--. 1 root root 1456 Oct 16 23:52 kube-proxy.pem
$ ll /etc/kubernetes/
total 8
-rw-------. 1 root root 6345 Oct 16 23:52 kube-proxy.kubeconfig
drwxr-xr-x. 2 root root 103 Oct 16 23:52 pki
五、K8S 系统组件配置
1. ETCD 配置
etcd 配置大致相同,注意修改每个 Master 节点的 etcd 配置的主机名和IP地址
官方文档:https://etcd.io/docs/v3.5/op-guide/configuration/
从 Github 获取配置文件示例 :https://github.com/etcd-io/etcd/blob/main/etcd.conf.yml.sample
配置项解读:
- name:指定了当前节点的名称,用于集群中区分不同的节点。
- data-dir:指定了 etcd 数据的存储目录。
- wal-dir:指定了 etcd 数据写入磁盘的目录。
- snapshot-count:指定了触发快照的事务数量。
- heartbeat-interval:指定了 etcd 集群中节点之间的心跳间隔。
- election-timeout:指定了选举超时时间。
- quota-backend-bytes:指定了存储的限额,0 表示无限制。
- listen-peer-urls:指定了节点之间通信的 URL,使用 HTTPS 协议。
- listen-client-urls:指定了客户端访问 etcd 集群的 URL,同时提供了本地访问的 URL。
- max-snapshots:指定了快照保留的数量。
- max-wals:指定了日志保留的数量。
- initial-advertise-peer-urls:指定了节点之间通信的初始 URL。
- advertise-client-urls:指定了客户端访问 etcd 集群的初始 URL。
- discovery:定义了 etcd 集群发现相关的选项。
- initial-cluster:指定了 etcd 集群的初始成员。
- initial-cluster-token:指定了集群的 token。
- initial-cluster-state:指定了集群的初始状态。
- strict-reconfig-check:指定了严格的重新配置检查选项。
- enable-v2:启用了 v2 API。
- enable-pprof:启用了性能分析。
- proxy:设置了代理模式。
- client-transport-security:客户端的传输安全配置。
- peer-transport-security:节点之间的传输安全配置。
- debug:是否启用调试模式。
- log-package-levels:日志的输出级别。
- log-outputs:指定了日志的输出类型。
- force-new-cluster:是否强制创建一个新的集群。
1.1 Master01 节点
如果要用 IPv6 那么把 IPv4 地址修改为 IPv6 即可
cat > /etc/etcd/etcd.config.yml << EOF
name: 'k8s-master01'
data-dir: /data/etcd
wal-dir: /data/etcd/wal
snapshot-count: 5000
heartbeat-interval: 100
election-timeout: 1000
quota-backend-bytes: 0
listen-peer-urls: 'https://10.20.1.101:2380'
listen-client-urls: 'https://10.20.1.101:2379,http://127.0.0.1:2379'
max-snapshots: 3
max-wals: 5
cors:
initial-advertise-peer-urls: 'https://10.20.1.101:2380'
advertise-client-urls: 'https://10.20.1.101:2379'
discovery:
discovery-fallback: 'proxy'
discovery-proxy:
discovery-srv:
initial-cluster: 'k8s-master01=https://10.20.1.101:2380,k8s-master02=https://10.20.1.102:2380,k8s-master03=https://10.20.1.103:2380'
initial-cluster-token: 'etcd-k8s-cluster'
initial-cluster-state: 'new'
strict-reconfig-check: false
enable-v2: true
enable-pprof: true
proxy: 'off'
proxy-failure-wait: 5000
proxy-refresh-interval: 30000
proxy-dial-timeout: 1000
proxy-write-timeout: 5000
proxy-read-timeout: 0
client-transport-security:
cert-file: '/etc/kubernetes/pki/etcd/etcd.pem'
key-file: '/etc/kubernetes/pki/etcd/etcd-key.pem'
client-cert-auth: true
trusted-ca-file: '/etc/kubernetes/pki/etcd/etcd-ca.pem'
auto-tls: true
peer-transport-security:
cert-file: '/etc/kubernetes/pki/etcd/etcd.pem'
key-file: '/etc/kubernetes/pki/etcd/etcd-key.pem'
peer-client-cert-auth: true
trusted-ca-file: '/etc/kubernetes/pki/etcd/etcd-ca.pem'
auto-tls: true
debug: false
log-package-levels:
log-outputs: [default]
force-new-cluster: false
EOF
1.2 Master02 节点
cat > /etc/etcd/etcd.config.yml << EOF
name: 'k8s-master02'
data-dir: /data/etcd
wal-dir: /data/etcd/wal
snapshot-count: 5000
heartbeat-interval: 100
election-timeout: 1000
quota-backend-bytes: 0
listen-peer-urls: 'https://10.20.1.102:2380'
listen-client-urls: 'https://10.20.1.102:2379,http://127.0.0.1:2379'
max-snapshots: 3
max-wals: 5
cors:
initial-advertise-peer-urls: 'https://10.20.1.102:2380'
advertise-client-urls: 'https://10.20.1.102:2379'
discovery:
discovery-fallback: 'proxy'
discovery-proxy:
discovery-srv:
initial-cluster: 'k8s-master01=https://10.20.1.101:2380,k8s-master02=https://10.20.1.102:2380,k8s-master03=https://10.20.1.103:2380'
initial-cluster-token: 'etcd-k8s-cluster'
initial-cluster-state: 'new'
strict-reconfig-check: false
enable-v2: true
enable-pprof: true
proxy: 'off'
proxy-failure-wait: 5000
proxy-refresh-interval: 30000
proxy-dial-timeout: 1000
proxy-write-timeout: 5000
proxy-read-timeout: 0
client-transport-security:
cert-file: '/etc/kubernetes/pki/etcd/etcd.pem'
key-file: '/etc/kubernetes/pki/etcd/etcd-key.pem'
client-cert-auth: true
trusted-ca-file: '/etc/kubernetes/pki/etcd/etcd-ca.pem'
auto-tls: true
peer-transport-security:
cert-file: '/etc/kubernetes/pki/etcd/etcd.pem'
key-file: '/etc/kubernetes/pki/etcd/etcd-key.pem'
peer-client-cert-auth: true
trusted-ca-file: '/etc/kubernetes/pki/etcd/etcd-ca.pem'
auto-tls: true
debug: false
log-package-levels:
log-outputs: [default]
force-new-cluster: false
EOF
1.3 Master03 节点
cat > /etc/etcd/etcd.config.yml << EOF
name: 'k8s-master03'
data-dir: /data/etcd
wal-dir: /data/etcd/wal
snapshot-count: 5000
heartbeat-interval: 100
election-timeout: 1000
quota-backend-bytes: 0
listen-peer-urls: 'https://10.20.1.103:2380'
listen-client-urls: 'https://10.20.1.103:2379,http://127.0.0.1:2379'
max-snapshots: 3
max-wals: 5
cors:
initial-advertise-peer-urls: 'https://10.20.1.103:2380'
advertise-client-urls: 'https://10.20.1.103:2379'
discovery:
discovery-fallback: 'proxy'
discovery-proxy:
discovery-srv:
initial-cluster: 'k8s-master01=https://10.20.1.101:2380,k8s-master02=https://10.20.1.102:2380,k8s-master03=https://10.20.1.103:2380'
initial-cluster-token: 'etcd-k8s-cluster'
initial-cluster-state: 'new'
strict-reconfig-check: false
enable-v2: true
enable-pprof: true
proxy: 'off'
proxy-failure-wait: 5000
proxy-refresh-interval: 30000
proxy-dial-timeout: 1000
proxy-write-timeout: 5000
proxy-read-timeout: 0
client-transport-security:
cert-file: '/etc/kubernetes/pki/etcd/etcd.pem'
key-file: '/etc/kubernetes/pki/etcd/etcd-key.pem'
client-cert-auth: true
trusted-ca-file: '/etc/kubernetes/pki/etcd/etcd-ca.pem'
auto-tls: true
peer-transport-security:
cert-file: '/etc/kubernetes/pki/etcd/etcd.pem'
key-file: '/etc/kubernetes/pki/etcd/etcd-key.pem'
peer-client-cert-auth: true
trusted-ca-file: '/etc/kubernetes/pki/etcd/etcd-ca.pem'
auto-tls: true
debug: false
log-package-levels:
log-outputs: [default]
force-new-cluster: false
EOF
1.4 创建 ETCD Service
master 01
cat > /usr/lib/systemd/system/etcd.service << EOF
[Unit]
Description=Etcd Service
Documentation=https://coreos.com/etcd/docs/latest/
After=network.target
[Service]
Type=notify
ExecStart=/usr/local/bin/etcd --config-file=/etc/etcd/etcd.config.yml
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Alias=etcd3.service
EOF
命令解析:
该文件定义了 etcd 服务在 Linux 系统上的运行方式,使用 systemd 管理 etcd 进程的启动、停止、自动重启等行为。此配置是为 Kubernetes 高可用集群中的 etcd 节点(例如 k8s-master03)设计的,结合了 /etc/etcd/etcd.config.yml 配置文件运行 etcd。
After=network.target:定义服务在哪些 systemd 目标或单元启动后启动。network.target 表示网络服务可用。 影响:确保 etcd 在网络初始化后启动,因为 etcd 需要监听网络端口(2379/2380)进行客户端和节点间通信。如果网络不可用,etcd 可能启动失败
Type=notify:默认值:simple 描述:定义服务进程的类型。notify 表示主进程通过 sd_notify(3) 向 systemd 发送启动完成信号(etcd 支持此机制)。 影响:notify 允许 systemd 等待 etcd 完成初始化(如绑定端口、加入集群)后再标记服务为“运行”。
ExecStart=/usr/local/bin/etcd –config-file=/etc/etcd/etcd.config.yml
服务启动时执行的命令及其参数。运行 etcd 二进制,指定配置文件路径
Restart=on-failure:控制服务失败时的重启行为。on-failure 表示在进程异常退出(非零退出码)、超时或被信号终止时自动重启。
RestartSec=10:重启前的等待时间(秒)
LimitNOFILE=65536:设置进程的最大文件描述符数量(软限制和硬限制)。 影响:etcd 需处理大量网络连接(如 Kubernetes API 请求),默认值可能不足导致 “too many open files” 错误。65536 适合高负载集群,需确保系统级限制
WantedBy=multi-user.target:指定服务在哪个 systemd 目标启用。multi-user.target 表示多用户模式(非图形界面,通常为服务器默认运行级别)
Alias=etcd3.service:为服务创建别名,允许通过别名(如 systemctl start etcd3.service)操作服务
同步到其它Master节点
# 将生成的 ETCD Service复制到其他节点
hosts='k8s-master02 k8s-master03'
user=root
for host in $hosts; do
echo $host;
rsync --rsync-path="sudo rsync" /usr/lib/systemd/system/etcd.service $user@$host:/usr/lib/systemd/system/;
done
1.5 启动 ETCD Service
hosts='k8s-master01 k8s-master02 k8s-master03'
user=root
for host in $hosts; do
echo $host;
echo "创建 etcd 证书目录"
ssh root@$host "mkdir -p /etc/kubernetes/pki/etcd"
echo "创建软连接"
ssh root@$host "ln -s /etc/etcd/ssl/* /etc/kubernetes/pki/etcd/"
ssh root@$host "systemctl daemon-reload"
ssh root@$host "systemctl enable --now etcd.service"
ssh root@$host "systemctl status etcd.service"
done

1.6 检查 ETCD 集群的健康状态
master01 、master02、master03
export ETCDCTL_API=3
etcdctl --endpoints="10.20.1.101:2379,10.20.1.102:2379,10.20.1.103:2379" \
--cacert=/etc/kubernetes/pki/etcd/etcd-ca.pem \
--cert=/etc/kubernetes/pki/etcd/etcd.pem \
--key=/etc/kubernetes/pki/etcd/etcd-key.pem \
endpoint status --write-out=table

命令解析:
该命令用于检查 etcd 集群的健康状态,是 Kubernetes 高可用部署中验证 etcd 集群运行情况的关键步骤
export ETCDCTL_API=3
明确设置 ETCDCTL_API=3 确保 etcdctl 使用 v3 协议,避免与 v2 兼容性问题
etcdctl:是 etcd 提供的命令行工具,用于与 etcd 集群交互(如查询状态、管理成员、执行操作)
–endpoints:指定 etcd 集群的客户端访问端点,包含三个节点的 IP 和端口(2379)
–cacert:指定 CA 证书路径 /etc/kubernetes/pki/etcd/etcd-ca.pem
–cert:客户端证书路径 /etc/kubernetes/pki/etcd/etcd.pem
–key:客户端私钥路径 /etc/kubernetes/pki/etcd/etcd-key.pem
2. Nginx 配置
2.1 编译安装
master 01
# 安装编译环境
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 二进制包,拷贝到其它节点
hosts='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
user=root
for host in $hosts; do
echo $host;
rsync -a --rsync-path="sudo rsync" /usr/local/nginx $user@$host:/usr/local/;
rsync --rsync-path="sudo rsync" /bin/nginx* $user@$host:/bin/;
done
# 验证
$ nginx -v
nginx version: nginx/1.25.3
2.2 nginx 配置文件
Master 01
# 写入配置文件(在所有主机上执行)
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
# 将kube-nginx.conf,拷贝到其它 Master 节点
hosts='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
user=root
for host in $hosts; do
echo $host;
rsync -a --rsync-path="sudo rsync" /usr/local/nginx/conf/kube-nginx.conf $user@$host:/usr/local/nginx/conf/;
done
命令解析:
该命令用于创建 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 端口
2.3 配置 Nginx Service
Master 01
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 随系统启动。
2.4 设置 Nginx 开机自启
# 刷新系统服务
systemctl daemon-reload
# 设置 kube-nginx 开机自启
systemctl enable --now kube-nginx.service
# 查看 nginx 启动状态
systemctl status kube-nginx.service
将 kube-nginx.service 同步到其它服务器
# 将kube-nginx.service,拷贝到其它 Master 节点,并让Nginx开机自启
hosts='k8s-master02 k8s-master03 k8s-node01 k8s-node02'
user=root
for host in $hosts; do
echo $host;
rsync -a --rsync-path="sudo rsync" /etc/systemd/system/kube-nginx.service $user@$host:/etc/systemd/system/;
ssh root@$host "systemctl daemon-reload"
ssh root@$host "systemctl enable --now kube-nginx.service"
ssh root@$host "systemctl status kube-nginx.service"
done
3. kube-apiserver 配置
3.1 创建必要的目录
master01
# 所有 k8s 节点创建以下目录
hosts='k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02'
user=root
for host in $hosts; do
echo $host;
ssh root@$host "mkdir -p /etc/kubernetes/manifests/ /etc/systemd/system/kubelet.service.d /var/lib/kubelet /var/log/kubernetes"
done
3.2 配置 kube-apiserver.service
官方文档:https://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kube-apiserver/
master01
cat > /usr/lib/systemd/system/kube-apiserver.service << EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
After=network.target
[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
--v=2 \\
--allow-privileged=true \\
--bind-address=0.0.0.0 \\
--secure-port=6443 \\
--advertise-address=10.20.1.101 \\
--service-cluster-ip-range=10.96.0.0/12,fd00:1111::/112 \\
--service-node-port-range=30000-32767 \\
--etcd-servers=https://10.20.1.101:2379,https://10.20.1.102:2379,https://10.20.1.103:2379 \\
--etcd-cafile=/etc/etcd/ssl/etcd-ca.pem \\
--etcd-certfile=/etc/etcd/ssl/etcd.pem \\
--etcd-keyfile=/etc/etcd/ssl/etcd-key.pem \\
--client-ca-file=/etc/kubernetes/pki/ca.pem \\
--tls-cert-file=/etc/kubernetes/pki/apiserver.pem \\
--tls-private-key-file=/etc/kubernetes/pki/apiserver-key.pem \\
--kubelet-client-certificate=/etc/kubernetes/pki/apiserver.pem \\
--kubelet-client-key=/etc/kubernetes/pki/apiserver-key.pem \\
--service-account-key-file=/etc/kubernetes/pki/sa.pub \\
--service-account-signing-key-file=/etc/kubernetes/pki/sa.key \\
--service-account-issuer=https://kubernetes.default.svc.cluster.local \\
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota \
--authorization-mode=Node,RBAC \\
--enable-bootstrap-token-auth=true \\
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.pem \\
--proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.pem \\
--proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client-key.pem \\
--requestheader-allowed-names=aggregator \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-extra-headers-prefix=X-Remote-Extra- \\
--requestheader-username-headers=X-Remote-User \\
--enable-aggregator-routing=true
Restart=on-failure
RestartSec=10s
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOF
master02
cat > /usr/lib/systemd/system/kube-apiserver.service << EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
After=network.target
[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
--v=2 \\
--allow-privileged=true \\
--bind-address=0.0.0.0 \\
--secure-port=6443 \\
--advertise-address=10.20.1.102 \\
--service-cluster-ip-range=10.96.0.0/12,fd00:1111::/112 \\
--service-node-port-range=30000-32767 \\
--etcd-servers=https://10.20.1.101:2379,https://10.20.1.102:2379,https://10.20.1.103:2379 \\
--etcd-cafile=/etc/etcd/ssl/etcd-ca.pem \\
--etcd-certfile=/etc/etcd/ssl/etcd.pem \\
--etcd-keyfile=/etc/etcd/ssl/etcd-key.pem \\
--client-ca-file=/etc/kubernetes/pki/ca.pem \\
--tls-cert-file=/etc/kubernetes/pki/apiserver.pem \\
--tls-private-key-file=/etc/kubernetes/pki/apiserver-key.pem \\
--kubelet-client-certificate=/etc/kubernetes/pki/apiserver.pem \\
--kubelet-client-key=/etc/kubernetes/pki/apiserver-key.pem \\
--service-account-key-file=/etc/kubernetes/pki/sa.pub \\
--service-account-signing-key-file=/etc/kubernetes/pki/sa.key \\
--service-account-issuer=https://kubernetes.default.svc.cluster.local \\
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota \
--authorization-mode=Node,RBAC \\
--enable-bootstrap-token-auth=true \\
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.pem \\
--proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.pem \\
--proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client-key.pem \\
--requestheader-allowed-names=aggregator \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-extra-headers-prefix=X-Remote-Extra- \\
--requestheader-username-headers=X-Remote-User \\
--enable-aggregator-routing=true
Restart=on-failure
RestartSec=10s
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOF
master03
cat > /usr/lib/systemd/system/kube-apiserver.service << EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
After=network.target
[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
--v=2 \\
--allow-privileged=true \\
--bind-address=0.0.0.0 \\
--secure-port=6443 \\
--advertise-address=10.20.1.103 \\
--service-cluster-ip-range=10.96.0.0/12,fd00:1111::/112 \\
--service-node-port-range=30000-32767 \\
--etcd-servers=https://10.20.1.101:2379,https://10.20.1.102:2379,https://10.20.1.103:2379 \\
--etcd-cafile=/etc/etcd/ssl/etcd-ca.pem \\
--etcd-certfile=/etc/etcd/ssl/etcd.pem \\
--etcd-keyfile=/etc/etcd/ssl/etcd-key.pem \\
--client-ca-file=/etc/kubernetes/pki/ca.pem \\
--tls-cert-file=/etc/kubernetes/pki/apiserver.pem \\
--tls-private-key-file=/etc/kubernetes/pki/apiserver-key.pem \\
--kubelet-client-certificate=/etc/kubernetes/pki/apiserver.pem \\
--kubelet-client-key=/etc/kubernetes/pki/apiserver-key.pem \\
--service-account-key-file=/etc/kubernetes/pki/sa.pub \\
--service-account-signing-key-file=/etc/kubernetes/pki/sa.key \\
--service-account-issuer=https://kubernetes.default.svc.cluster.local \\
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota \
--authorization-mode=Node,RBAC \\
--enable-bootstrap-token-auth=true \\
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.pem \\
--proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.pem \\
--proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client-key.pem \\
--requestheader-allowed-names=aggregator \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-extra-headers-prefix=X-Remote-Extra- \\
--requestheader-username-headers=X-Remote-User \\
--enable-aggregator-routing=true
Restart=on-failure
RestartSec=10s
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOF
3.3 启动 kube-apiserver
hosts='k8s-master01 k8s-master02 k8s-master03'
user=root
for host in $hosts; do
echo $host;
ssh root@$host "systemctl daemon-reload"
ssh root@$host "systemctl enable --now kube-apiserver.service"
ssh root@$host "systemctl status kube-apiserver.service"
done
kube-apiserver.service 文件解析:
该配置文件创建 systemd 服务文件,运行 kube-apiserver(Kubernetes 控制平面的核心组件),监听 6443 端口,处理集群 API 请求
–v=2
设置日志级别为 2(中等详细,调试用)
生产环境可降为 –v=1 减少日志,或增至 –v=4 排查问题
–allow-privileged=true
API 服务器监听所有网络接口(0.0.0.0)上的 6443 端口
允许外部和内部客户端(如 kubectl、Nginx 负载均衡器)访问
若仅限本地访问,可设为 –bind-address=127.0.0.1,但高可用集群通常需要 0.0.0.0
–secure-port=6443
API 服务器监听的 HTTPS 端口(6443)
提供安全的 API 访问,配合 TLS 证书
6443 是 Kubernetes 默认端口,Nginx 负载均衡器代理到此端口。
–advertise-address=
API 服务器向集群其他组件通告的 IP 地址。
指定当前节点的 IP(k8s-master01),用于节点间通信和客户端连接。
–service-cluster-ip-range=10.96.0.0/12,fd00:1111::/112 \
定义 Service 的 Cluster IP 地址范围,支持双栈(IPv4 和 IPv6)。
- 10.96.0.0/12:IPv4 地址池(10.96.0.0 - 10.111.255.255,约 104 万个地址)。
- fd00:1111::/112:IPv6 唯一本地地址(ULA),提供 65,536 个地址。
作用:为 Service(ClusterIP 类型)分配虚拟 IP,供服务发现和负载均衡。
–service-node-port-range=30000-32767 \
NodePort 类型 Service 的端口范围。
限制 NodePort 分配的端口(默认 30000-32767),用于外部访问。
–etcd-servers=
指定 etcd 集群的 HTTPS 端点(三个主节点,2379 端口)。
–service-account-issuer=https://kubernetes.default.svc.cluster.local \
ServiceAccount token 的发行者标识
–kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \
API 服务器连接 kubelet 时优先使用的地址类型。
按顺序尝试 InternalIP、ExternalIP、Hostname。
适合 Calico 网络,优先内部 IP(10.20.1.x)。
–enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota \
启用准入控制插件
- NamespaceLifecycle:管理命名空间生命周期。
- LimitRanger:限制资源使用。
- ServiceAccount:自动注入 ServiceAccount token。
- DefaultStorageClass:为 PVC 设置默认存储类。
- DefaultTolerationSeconds:设置默认容忍时间。
- NodeRestriction:限制 kubelet 权限。
- ResourceQuota:强制资源配额。
–authorization-mode=Node,RBAC \
启用 Node 和 RBAC 授权模式。Node 授权 kubelet 请求,RBAC 管理用户和角色权限。
–enable-bootstrap-token-auth=true \
启用引导令牌认证,允许新节点通过 token 加入集群。
–requestheader-allowed-names=aggregator \
允许的聚合器客户端名称。
–requestheader-group-headers=X-Remote-Group \
HTTP 头中传递组信息的字段。
–requestheader-extra-headers-prefix=X-Remote-Extra- \
额外信息的 HTTP 头前缀。
–requestheader-username-headers=X-Remote-User \
HTTP 头中传递用户名的字段。
–enable-aggregator-routing=true
启用 API 聚合器路由
Restart=on-failure
服务失败时重启
RestartSec=10s
重启前等待 10 秒
LimitNOFILE=65535
最大文件描述符数,支持高并发连接,匹配 Nginx 的 65536
4. kube-controller-manager 配置
4.1 配置 kube-controller-manager.service
官方文档:https://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kube-controller-manager/
- 所有master节点配置,且配置相同
- 172.16.0.0/12 为 pod 网段,按需求设置你自己的网段
master01
cat > /usr/lib/systemd/system/kube-controller-manager.service << EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes
After=network.target
[Service]
ExecStart=/usr/local/bin/kube-controller-manager \\
--v=2 \\
--bind-address=0.0.0.0 \\
--root-ca-file=/etc/kubernetes/pki/ca.pem \\
--cluster-signing-cert-file=/etc/kubernetes/pki/ca.pem \\
--cluster-signing-key-file=/etc/kubernetes/pki/ca-key.pem \\
--service-account-private-key-file=/etc/kubernetes/pki/sa.key \\
--kubeconfig=/etc/kubernetes/controller-manager.kubeconfig \\
--leader-elect=true \\
--use-service-account-credentials=true \\
--node-monitor-grace-period=40s \\
--node-monitor-period=5s \\
--controllers=*,bootstrapsigner,tokencleaner \\
--allocate-node-cidrs=true \\
--service-cluster-ip-range=10.96.0.0/12,fd00:1111::/112 \\
--cluster-cidr=172.16.0.0/12,fc00:2222::/112 \\
--node-cidr-mask-size-ipv4=24 \\
--node-cidr-mask-size-ipv6=120 \\
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.pem
Restart=always
RestartSec=10s
[Install]
WantedBy=multi-user.target
EOF
配置解析:
kube-controller-manager 是 Kubernetes 控制平面的核心组件之一,负责运行控制器以维护集群状态(如 ReplicaSet、Deployment 控制器)。
ExecStart=/usr/local/bin/kube-controller-manager \
指定启动命令,运行 kube-controller-manager 可执行文件(位于 /usr/local/bin/),后续参数以 \ 分行。
–v=2 \
设置日志级别为 2(中等详细,适合调试)
生产环境可设为 –v=1 减少日志,或增至 –v=4 排查复杂问题。
–bind-address=0.0.0.0 \
Controller Manager 监听所有网络接口(0.0.0.0)上的端口(默认 10257,HTTPS)。允许外部访问健康检查或指标端点(如 /healthz、/metrics)。
–root-ca-file=/etc/kubernetes/pki/ca.pem \
Kubernetes CA 证书路径,用于验证客户端和服务端证书。
–cluster-signing-cert-file=/etc/kubernetes/pki/ca.pem \
用于签署集群内证书的 CA 证书。Controller Manager 使用该 CA 为 CSR(证书签名请求)签名(如 kubelet 证书)。
–cluster-signing-key-file=/etc/kubernetes/pki/ca-key.pem \
CA 证书的私钥。与 –cluster-signing-cert-file 配对,用于签署证书。
–service-account-private-key-file=/etc/kubernetes/pki/sa.key \
服务账户(ServiceAccount)token 的签名私钥。生成 ServiceAccount token,供 Pod 认证。
–kubeconfig=/etc/kubernetes/controller-manager.kubeconfig \
Controller Manager 的 kubeconfig 文件路径,定义 API 服务器连接信息和认证凭据。
允许 Controller Manager 通过 kubeconfig 访问 API 服务器(6443 端口)。
–leader-elect=true \
启用领导者选举,在高可用集群中,确保多个主节点的 Controller Manager 实例中只有一个活跃(其他为热备),避免冲突。
–use-service-account-credentials=true \
为每个控制器使用独立的 ServiceAccount 凭据。增强安全性,限制控制器权限(而非使用默认高权限凭据)。
–node-monitor-grace-period=40s \
节点控制器标记节点为 NotReady 前的宽限时间。若节点 40 秒未响应(无心跳),标记为不可用。
–node-monitor-period=5s \
节点控制器检查节点状态的周期。每 5 秒检查节点健康状态。
–controllers=*,bootstrapsigner,tokencleaner \
指定启用的控制器列表。
*:启用所有默认控制器(如 ReplicaSet、Deployment、Node 控制器)。
bootstrapsigner:签署引导令牌的 CSR。
tokencleaner:清理过期引导令牌。
–allocate-node-cidrs=true \
启用节点 CIDR 分配。Controller Manager 为每个节点分配 Pod CIDR(由 –cluster-cidr 定义)
–service-cluster-ip-range=10.96.0.0/12,fd00:1111::/112 \
Service 的 Cluster IP 地址范围(IPv4 和 IPv6)。
定义 Service 的虚拟 IP 池,与 kube-apiserver 的 –service-cluster-ip-range 一致。
–node-cidr-mask-size-ipv4=24 \
每个节点的 IPv4 Pod CIDR 子网掩码大小,每个节点分配 /24 子网(256 个 IP),从 172.16.0.0/12 中划分。
–node-cidr-mask-size-ipv6=120 \
每个节点的 IPv6 Pod CIDR 子网掩码大小。
每个节点分配 /120 子网(256 个 IP),从 fc00:2222::/112 中划分。
–requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.pem \
API 聚合器的 CA 证书。验证聚合器客户端(如扩展 API 服务器),与 kube-apiserver 一致。
Restart=always
服务无论何种原因退出都重启。确保 Controller Manager 高可用。
RestartSec=10s
重启前等待 10 秒。
配置分发到其它Master节点
hosts='k8s-master02 k8s-master03'
user=root
for host in $hosts; do
echo $host;
rsync -a --rsync-path="sudo rsync" /usr/lib/systemd/system/kube-controller-manager.service $user@$host:/usr/lib/systemd/system/;
done
4.2 启动 kube-controller-manager
hosts='k8s-master01 k8s-master02 k8s-master03'
user=root
for host in $hosts; do
echo $host;
ssh root@$host "systemctl daemon-reload"
ssh root@$host "systemctl enable --now kube-controller-manager.service"
ssh root@$host "systemctl status kube-controller-manager.service"
done
5. kube-scheduler 配置
所有 master 节点配置,且配置相同
5.1 kube-scheduler.service
cat > /usr/lib/systemd/system/kube-scheduler.service << EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes
After=network.target
[Service]
ExecStart=/usr/local/bin/kube-scheduler \\
--v=2 \\
--bind-address=0.0.0.0 \\
--leader-elect=true \\
--kubeconfig=/etc/kubernetes/scheduler.kubeconfig
Restart=always
RestartSec=10s
[Install]
WantedBy=multi-user.target
EOF
配置解析:
kube-scheduler 与 API 服务器(6443 端口)交互,通过 kubeconfig 文件访问集群状态,决定 Pod 分配。
ExecStart=/usr/local/bin/kube-scheduler \
指定启动命令,运行 kube-scheduler 可执行文件(位于 /usr/local/bin/),后续参数以 \ 分行。
启动 Scheduler,负责根据节点资源、策略和约束(如亲和性、污点)将 Pod 调度到节点。
–v=2 \
设置日志级别为 2(中等详细,适合调试)。
生产环境可设为 –v=1 减少日志,或增至 –v=4 排查复杂问题。
–bind-address=0.0.0.0 \
Scheduler 监听所有网络接口(0.0.0.0)上的端口(默认 10259,HTTPS)。
允许外部访问健康检查或指标端点(如 /healthz、/metrics),常用于监控(如 Prometheus)。
–leader-elect=true \
启用领导者选举。
在高可用集群中,确保多个主节点的 Scheduler 实例中只有一个活跃(其他为热备),避免调度冲突。
–kubeconfig=/etc/kubernetes/scheduler.kubeconfig \
Scheduler 的 kubeconfig 文件路径,定义 API 服务器连接信息和认证凭据。
Restart=always
服务无论何种原因退出都重启。
RestartSec=10s
重启前等待 10 秒。
配置同步到其它 master 节点
hosts='k8s-master02 k8s-master03'
user=root
for host in $hosts; do
echo $host;
rsync -a --rsync-path="sudo rsync" /usr/lib/systemd/system/kube-scheduler.service $user@$host:/usr/lib/systemd/system/;
done
5.2 启动 kube-scheduler
hosts='k8s-master01 k8s-master02 k8s-master03'
user=root
for host in $hosts; do
echo $host;
ssh root@$host "systemctl daemon-reload"
ssh root@$host "systemctl enable --now kube-scheduler.service"
ssh root@$host "systemctl status kube-scheduler.service"
done
六、TLS Bootstrapping 配置
官方文档:https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/kubelet-tls-bootstrapping/
1. 生成 bootstrap 的 token
master01
TOKEN_ID=$(openssl rand -hex 3)
TOKEN_SECRET=$(openssl rand -hex 8)
BOOTSTRAP_TOKEN=${TOKEN_ID}.${TOKEN_SECRET}
$ echo $BOOTSTRAP_TOKEN
25062c.208e46b2a427f63a
命令解析:
生成一个 Kubernetes 引导令牌(Bootstrap Token),格式为 .,用于节点(主节点或工作节点)通过 kubeadm join 加入集群时进行身份验证
2. 配置 bootstrap-kubelet.kubeconfig
master01
# 在指定的 kubeconfig 文件(/etc/kubernetes/bootstrap-kubelet.kubeconfig)中配置一个名为 kubernetes 的集群条目,定义如何连接到 Kubernetes API 服务器,包括 CA 证书和服务器地址
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.pem \
--embed-certs=true --server=https://127.0.0.1:8443 \
--kubeconfig=/etc/kubernetes/bootstrap-kubelet.kubeconfig
# 在指定的 kubeconfig 文件中创建或更新一个名为 tls-bootstrap-token-user 的用户凭据条目,配置引导令牌(25062c.208e46b2a427f63a),用于 kubelet 在节点引导过程中通过 Nginx 负载均衡器(127.0.0.1:8443)访问 API 服务器
kubectl config set-credentials tls-bootstrap-token-user \
--token=25062c.208e46b2a427f63a \
--kubeconfig=/etc/kubernetes/bootstrap-kubelet.kubeconfig
# 在 kubeconfig 文件中配置上下文(context),将集群和用户凭据关联起来,供 kubelet 在节点引导过程中使用以访问 Kubernetes API 服务器
kubectl config set-context tls-bootstrap-token-user@kubernetes \
--cluster=kubernetes \
--user=tls-bootstrap-token-user \
--kubeconfig=/etc/kubernetes/bootstrap-kubelet.kubeconfig
# 在 kubeconfig 文件中设置默认上下文,指定 kubelet 使用特定的上下文(tls-bootstrap-token-user@kubernetes)来访问 Kubernetes API 服务器,从而完成节点引导和注册。
kubectl config use-context tls-bootstrap-token-user@kubernetes \
--kubeconfig=/etc/kubernetes/bootstrap-kubelet.kubeconfig
# token的位置在 bootstrap.secret.yaml,如果修改的话到这个文件修改
# 创建 /root/.kube 目录,用于存储 Kubernetes 管理用户的 kubeconfig 文件
mkdir -p /root/.kube
# 将管理员的 kubeconfig 文件(/etc/kubernetes/admin.kubeconfig)复制到 /root/.kube/config,作为 kubectl 的默认配置文件
cp /etc/kubernetes/admin.kubeconfig /root/.kube/config
# 分发 kubelet 配置文件
host=(k8s-master02 k8s-master03)
user=root
for i in ${host[@]}; do
ssh $user@$i "mkdir -p /root/.kube"
rsync --rsync-path="sudo rsync" /root/.kube/config $user@$i:/root/.kube/;
done
3. 创建 bootstrap-secret.yaml
注意:bootstrap.secret.yaml的token-id、token-secret,需与上命令token保持一致(即 25062c.208e46b2a427f63a )
# 创建目录
mkdir -p /etc/kubernetes/yaml
# 编辑文件
cat > /etc/kubernetes/yaml/bootstrap-secret.yaml << EOF
apiVersion: v1
kind: Secret
metadata:
name: bootstrap-token-${TOKEN_ID}
namespace: kube-system
type: bootstrap.kubernetes.io/token
stringData:
description: "The default bootstrap token generated by 'kubelet '."
token-id: ${TOKEN_ID}
token-secret: ${TOKEN_SECRET}
usage-bootstrap-authentication: "true"
usage-bootstrap-signing: "true"
auth-extra-groups: system:bootstrappers:default-node-token,system:bootstrappers:worker,system:bootstrappers:ingress
EOF
# 执行资源清单
$ kubectl create -f /etc/kubernetes/yaml/bootstrap-secret.yaml
secret/bootstrap-token-25062c created
# 查看结果
$ kubectl get secret -n kube-system
NAME TYPE DATA AGE
bootstrap-token-25062c bootstrap.kubernetes.io/token 6 10s
4. 创建 kubelet-bootstrap-rbac.yaml
cat > /etc/kubernetes/yaml/kubelet-bootstrap-rbac.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubelet-bootstrap
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:node-bootstrapper
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:bootstrappers:default-node-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: node-autoapprove-bootstrap
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:bootstrappers:default-node-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: node-autoapprove-certificate-rotation
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:nodes
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:kube-apiserver-to-kubelet
rules:
- apiGroups:
- ""
resources:
- nodes/proxy
- nodes/stats
- nodes/log
- nodes/spec
- nodes/metrics
verbs:
- "*"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:kube-apiserver
namespace: ""
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kube-apiserver-to-kubelet
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kube-apiserver
EOF
# 执行清单
kubectl create -f /etc/kubernetes/yaml/kubelet-bootstrap-rbac.yaml
5. 分发配置文件
host=(k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02)
user=root
for i in ${host[@]}; do
rsync --rsync-path="sudo rsync" /etc/kubernetes/{bootstrap-kubelet,kube-proxy}.kubeconfig $user@$i:/etc/kubernetes/;
done
注:若kubectl get node 为空,那应该就是 bootstrap-kubelet.kubeconfig 中的 token 对不上, 修改后重启kubelet
6. 查看集群状态
[root@k8s-master01 ~]$ kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
etcd-0 Healthy ok
controller-manager Healthy ok
七、Node 配置
1. 复制相关证书至 node 节点
user=root
host=(k8s-master02 k8s-master03 k8s-node01 k8s-node02)
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} $user@$i:/etc/kubernetes/pki/;
done
2. 配置 kubelet(所有节点)
2.1 编辑 kubelet.service
Master01
# 当使用 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=:节点标签。为空值(可以自定义标签,如用于节点分组)。这里的 = 后无内容,表示一个空标签
2.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 表示每分钟收集一次卷使用数据。
2.3 同步文件到其它节点
user=root
host=(k8s-master02 k8s-master03 k8s-node01 k8s-node02)
for i in ${host[@]}; do
echo $i
rsync --rsync-path="sudo rsync" /usr/lib/systemd/system/kubelet.service $user@$i:/usr/lib/systemd/system/;
rsync --rsync-path="sudo rsync" /etc/kubernetes/kubelet-conf.yml $user@$i:/etc/kubernetes/;
done
2.4 所有节点启动 kubelet
user=root
host=(k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02)
for i in ${host[@]}; do
ssh $user@$i "systemctl daemon-reload";
ssh $user@$i "systemctl enable --now kubelet";
ssh $user@$i "systemctl status kubelet";
done
2.5 测试
[root@k8s-master01 ~]$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master01 NotReady <none> 20m v1.29.2
k8s-master02 NotReady <none> 13m v1.29.2
k8s-master03 NotReady <none> 13m v1.29.2
k8s-node01 NotReady <none> 7m53s v1.29.2
k8s-node02 NotReady <none> 7m52s v1.29.2
3. kube-proxy 配置(所有节点)
3.1 同步 kube-proxy.kubeconfig
master01
将 kube-proxy.kube.config 文件同步到其它所有节点
user=root
host=(k8s-master02 k8s-master03 k8s-node01 k8s-node02)
for i in ${host[@]}; do
echo $i
rsync --rsync-path="sudo rsync" /etc/kubernetes/kube-proxy.kubeconfig $user@$i:/etc/kubernetes/;
done
3.2 编辑 kube-proxy.service
Master01
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私有地址,支持双栈网络)。
3.3 编辑 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 连接,释放资源。
3.4 启动 kube-proxy
systemctl daemon-reload
systemctl enable --now kube-proxy.service
systemctl status kube-proxy.service
3.5 同步 kube-proxy 到其它节点
user=root
host=(k8s-master02 k8s-master03 k8s-node01 k8s-node02)
for i in ${host[@]}; do
echo $i
rsync --rsync-path="sudo rsync" /usr/lib/systemd/system/kube-proxy.service $user@$i:/usr/lib/systemd/system/;
rsync --rsync-path="sudo rsync" /etc/kubernetes/kube-proxy.yaml $user@$i:/etc/kubernetes/;
ssh $user@$i "systemctl daemon-reload";
ssh $user@$i "systemctl enable --now kube-proxy.service";
ssh $user@$i "systemctl status kube-proxy.service";
done
八、安装 calico 网络插件
1. 下载 calico 资源清单
Master01
# 创建calico目录,进入目录
$ mkdir -p /etc/calico/
$ cd /etc/calico/
# 下载calico资源清单
wget https://raw.githubusercontent.com/projectcalico/calico/refs/tags/v3.28.0/manifests/calico-typha.yaml
2. 编辑 calico 资源清单-IPV4
Master01
# 复制资源清单,用于IPV4网络
$ cp /etc/calico/calico-typha.yaml /etc/calico/calico.yaml
# IPV4环境
vim calico.yaml
# calico-config ConfigMap处
"ipam": {
"type": "calico-ipam",
},
- name: IP
value: "autodetect"
- name: CALICO_IPV4POOL_CIDR
value: "172.16.0.0/12"
3. 编辑 calico 资源清单-IPV6
Master01
# 复制资源清单,用于IPV4网络
$ cp /etc/calico/calico-typha.yaml /etc/calico/calico-ipv6.yaml
# IPV6环境
vim calico-ipv6.yaml
# calico-config ConfigMap处
"ipam": {
"type": "calico-ipam",
"assign_ipv4": "true",
"assign_ipv6": "true"
},
- name: IP
value: "autodetect"
- name: IP6
value: "autodetect"
- name: CALICO_IPV4POOL_CIDR
value: "172.16.0.0/12"
- name: CALICO_IPV6POOL_CIDR
value: "fc00:2222::/112"
- name: FELIX_IPV6SUPPORT
value: "true"
4. 执行 calico 资源清单
# 本地没有公网 IPv6 使用 calico.yaml(在master01节点执行即可)
kubectl apply -f calico.yaml
# 本地有公网 IPv6 使用 calico-ipv6.yaml
# kubectl apply -f calico-ipv6.yaml
# 查看结果:
[root@k8s-master01 ~]$ kubectl get pods -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
calico-kube-controllers-8d76c5f9b-485zp 1/1 Running 2 (3m35s ago) 5m31s 172.27.14.192 k8s-node02 <none> <none>
calico-node-d6plz 1/1 Running 1 (3m52s ago) 5m31s 10.20.1.104 k8s-node01 <none> <none>
calico-node-w6fvl 1/1 Running 0 5m32s 10.20.1.103 k8s-master03 <none> <none>
calico-node-z7zs2 1/1 Running 0 5m32s 10.20.1.101 k8s-master01 <none> <none>
calico-node-z8v77 1/1 Running 1 (3m43s ago) 5m32s 10.20.1.102 k8s-master02 <none> <none>
calico-node-zb9bv 1/1 Running 1 (4m14s ago) 5m31s 10.20.1.105 k8s-node02 <none> <none>
calico-typha-7cdb5b98f7-d47gx 1/1 Running 0 5m31s 10.20.1.104 k8s-node01 <none> <none>
注意:执行资源清单会自动下载 calico 需要的镜像,这些镜像基本都在国外,下载会很慢,甚至下载不下来。
解决办法1:使用国内仓库
# 若docker镜像拉不下来,可以使用国内的仓库
sed -i "s#docker.io/calico/#m.daocloud.io/docker.io/calico/#g" calico.yaml
sed -i "s#docker.io/calico/#m.daocloud.io/docker.io/calico/#g" calico-ipv6.yaml
sed -i "s#m.daocloud.io/docker.io/calico/#docker.io/calico/#g" calico.yaml
sed -i "s#m.daocloud.io/docker.io/calico/#docker.io/calico/#g" calico-ipv6.yaml
解决方法2:使用代理下载
参考:https://georgechan95.github.io/blog/b01d5c62.html
# 下载镜像
docker pull docker.io/calico/cni:v3.28.0
docker pull docker.io/calico/node:v3.28.0
docker pull docker.io/calico/kube-controllers:v3.28.0
docker pull docker.io/calico/typha:v3.28.0
# 打包
docker save docker.io/calico/cni:v3.28.0 -o cni-v3.28.0.tar
docker save docker.io/calico/node:v3.28.0 -o node-v3.28.0.tar
docker save docker.io/calico/kube-controllers:v3.28.0 -o kube-controllers-v3.28.0.tar
docker save docker.io/calico/typha:v3.28.0 -o typha-v3.28.0.tar
# 同步到其它节点
user=root
host=(k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02)
for i in ${host[@]}; do
echo $i
rsync -av /opt/software/hak8s/images root@$i:/opt/software/
ssh $user@$i "docker load -i /opt/software/images/calico/cni-v3.28.0.tar";
ssh $user@$i "docker load -i /opt/software/images/calico/node-v3.28.0.tar";
ssh $user@$i "docker load -i /opt/software/images/calico/kube-controllers-v3.28.0.tar";
ssh $user@$i "docker load -i /opt/software/images/calico/typha-v3.28.0.tar";
done
九、安装 Core DNS
Helm安装脚本: https://github.com/helm/helm/blob/main/scripts/get-helm-3
1. 安装Helm(仅master01)
参考:https://georgechan95.github.io/blog/d8e3c7b3.html
# 下载 helm 二进制包
$ wget https://get.helm.sh/helm-v3.14.3-linux-amd64.tar.gz
# 解压
$ tar -zxvf helm-v3.14.3-linux-amd64.tar.gz
# 安装到bin目录
$ mv linux-amd64/helm /usr/local/bin/helm
# 查看helm版本
$ helm version
version.BuildInfo{Version:"v3.14.3", GitCommit:"f03cc04caaa8f6d7c3e67cf918929150cf6f3f12", GitTreeState:"clean", GoVersion:"go1.21.7"}
2. 安装 CoreDns
2.1 下载 CoreDns 安装包
# 添加 coredns 仓库
helm repo add coredns https://coredns.github.io/helm
# 查看仓库 coredns 版本
helm search repo coredns --versions
# 拉取指定版本的 coredns
helm pull coredns/coredns --version 1.45.0
# 解压
tar -zxvf /opt/software/coredns-1.45.0.tgz -C /opt/module/
2.2 编辑配置文件
# 修改IP
$ cat values.yaml | grep clusterIP: -A 13
clusterIP: "10.96.0.10"
# clusterIPs: []
# loadBalancerIP: ""
# loadBalancerClass: ""
# externalIPs: []
# externalTrafficPolicy: ""
# ipFamilyPolicy: ""
# trafficDistribution: PreferClose
# The name of the Service
# If not set, a name is generated using the fullname template
name: ""
annotations: {}
# Pod selector
selector: {}
2.3 安装 CoreDns
master01
$ helm install coredns /opt/module/coredns/ -n kube-system
NAME: coredns
LAST DEPLOYED: Fri Oct 24 13:47:48 2025
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CoreDNS is now running in the cluster as a cluster-service.
It can be tested with the following:
1. Launch a Pod with DNS tools:
kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools
2. Query the DNS server:
/ # host kubernetes
注意事项:
安装 coredns 会自动从外网下载镜像,这里可能会失败。
方式一:
# 修改为国内源 docker源可选 sed -i "s#coredns/#m.daocloud.io/docker.io/coredns/#g" values.yaml sed -i "s#registry.k8s.io/#m.daocloud.io/registry.k8s.io/#g" values.yaml方式二:代理服务器下载
# 下载 docker pull coredns/coredns:1.13.1 docker pull registry.k8s.io/cpa/cluster-proportional-autoscaler:v1.9.0 # 打包 docker save coredns/coredns:1.13.1 -o coredns-1.13.1.tar docker save registry.k8s.io/cpa/cluster-proportional-autoscaler:v1.9.0 -o cluster-proportional-autoscaler-v1.9.0.tar # 发送到集群解压 user=root host=(k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02) for i in ${host[@]}; do echo $i rsync -av /opt/software/hak8s/images root@$i:/opt/software/ ssh $user@$i "docker load -i /opt/software/images/coredns/coredns-1.13.1.tar"; ssh $user@$i "docker load -i /opt/software/images/coredns/cluster-proportional-autoscaler-v1.9.0.tar"; done
验证 CoreDns
$ kubectl get pods -n kube-system -o wide | grep coredns
coredns-68746bb699-4mrxl 1/1 Running 0 11m 172.25.244.193 k8s-master01 <none> <none>
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready <none> 41h v1.29.2
k8s-master02 Ready <none> 41h v1.29.2
k8s-master03 Ready <none> 41h v1.29.2
k8s-node01 Ready <none> 41h v1.29.2
k8s-node02 Ready <none> 41h v1.29.2
十、安装 Metrics Server
官方文档:https://github.com/kubernetes-sigs/metrics-server/releases/tag/v0.7.1
1. 下载 metrics-server 资源清单
master01
# 创建文件夹
mkdir -p /opt/module/metrics-server
cd /opt/module/metrics-server
# 下载资源清单
wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.1/components.yaml
2. 编辑 components.yaml
# 修改配置
vim components.yaml
---
# 1
- args:
- --cert-dir=/tmp
- --secure-port=10250
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
- --kubelet-insecure-tls
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.pem
- --requestheader-username-headers=X-Remote-User
- --requestheader-group-headers=X-Remote-Group
- --requestheader-extra-headers-prefix=X-Remote-Extra-
# 2
volumeMounts:
- mountPath: /tmp
name: tmp-dir
- name: ca-ssl
mountPath: /etc/kubernetes/pki
# 3
volumes:
- emptyDir: {}
name: tmp-dir
- name: ca-ssl
hostPath:
path: /etc/kubernetes/pki
---
3. 部署 metrics-server
$ kubectl apply -f /opt/module/metrics-server/components.yaml
注意事项:
安装 metrics-server 会自动从外网下载镜像,这里可能会失败。
方式一:
# 修改为国内源 docker源可选 sed -i "s#registry.k8s.io/#m.daocloud.io/registry.k8s.io/#g" *.yaml方式二:代理服务器下载
# 下载 docker pull registry.k8s.io/metrics-server/metrics-server:v0.7.1 # 打包 docker save registry.k8s.io/metrics-server/metrics-server:v0.7.1 -o metrics-server-v0.7.1.tar # 发送到集群解压 user=root host=(k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02) for i in ${host[@]}; do echo $i rsync -av /opt/software/hak8s/images root@$i:/opt/software/ ssh $user@$i "docker load -i /opt/software/images/metrics-server/metrics-server-v0.7.1.tar"; done
验证部署
$ kubectl get pods -n kube-system | grep metrics-server
metrics-server-6d4cb7955c-688pj 1/1 Running 0 2m10s
$ kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
k8s-master01 77m 3% 2168Mi 61%
k8s-master02 101m 5% 1499Mi 42%
k8s-master03 114m 5% 1594Mi 44%
k8s-node01 46m 2% 960Mi 27%
k8s-node02 48m 2% 924Mi 26%
十一、安装Dashboard
仅在 master01 操作
1. 下载并执行 dashboard 资源清单
# 下载资源清单
wget https://raw.githubusercontent.com/kubernetes/dashboard/refs/tags/v2.7.0/aio/deploy/recommended.yaml
# 修改镜像拉取策略
$ vim /opt/module/dashboard/recommended.yaml
imagePullPolicy: IfNotPresent
# 执行资源清单
$ kubectl apply -f /opt/module/dashboard/recommended.yaml
# 查看 Pod
$ kubectl get pod -n kubernetes-dashboard -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
dashboard-metrics-scraper-5657497c4c-v5jlt 1/1 Running 0 36s 172.18.195.2 k8s-master03 <none> <none>
kubernetes-dashboard-5b749d9495-ns6q2 1/1 Running 0 43s 172.25.92.71 k8s-master02 <none> <none>
命令解析:
需提前下载好镜像文件
docker pull kubernetesui/dashboard:v2.7.0 docker pull kubernetesui/metrics-scraper:v1.0.8 docker save kubernetesui/dashboard:v2.7.0 -o dashboard-v2.7.0.tar docker save kubernetesui/metrics-scraper:v1.0.8 -o metrics-scraper-v1.0.8.tar user=root host=(k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02) for i in ${host[@]}; do echo $i rsync -av /opt/software/hak8s/images root@$i:/opt/software/ ssh $user@$i "docker load -i /opt/software/images/dashboard/dashboard-v2.7.0.tar"; ssh $user@$i "docker load -i /opt/software/images/dashboard/metrics-scraper-v1.0.8.tar"; done
2. 创建 ServiceAccount
mkdir -p /opt/module/dashboard/
# 创建 ServiceAccount
cat > /opt/module/dashboard/dashboard-user.yaml << EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
EOF
# 执行资源清单,创建SA
kubectl apply -f /opt/module/dashboard/dashboard-user.yaml
# 验证
$ kubectl get serviceaccount -A | grep admin-user
kubernetes-dashboard admin-user 0 57s
命令解析:
在 Kubernetes 集群中为 Dashboard 创建一个具有管理员权限的 ServiceAccount(服务账户),并通过 ClusterRoleBinding(集群角色绑定)授予其全集群管理权限(cluster-admin)。这是为了方便通过 Token 方式登录 Dashboard 进行集群管理,而非使用默认的有限权限账户。整个过程是标准的 Kubernetes RBAC(基于角色的访问控制)配置,适用于二进制部署的集群。
3. 更改 dashboard 的 svc 为 NodePort
$ kubectl edit svc kubernetes-dashboard -n kubernetes-dashboard
...
sessionAffinity: None
type: NodePort # 将Cluster为NodePort
status:
loadBalancer: {}
# 保存后,验证
$ kubectl get svc kubernetes-dashboard -n kubernetes-dashboard -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes-dashboard NodePort 10.101.243.82 <none> 443:30892/TCP 91s k8s-app=kubernetes-dashboard
4. 创建 token 访问
$ kubectl -n kubernetes-dashboard create token admin-user
eyJhbGciOiJSUzI1NiIsImtpZCI6IjVRcWNxMUt1ZzZsN3RoeTBHUzd4VzFGbktIZDBIZUNJazllQVFqdy1aSTgifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzYxNjU5MTM1LCJpYXQiOjE3NjE2NTU1MzUsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJhZG1pbi11c2VyIiwidWlkIjoiY2ZiNTA5MmYtMGY0My00OTllLTg1MzItOTM0YTljMDY0YTJmIn19LCJuYmYiOjE3NjE2NTU1MzUsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlcm5ldGVzLWRhc2hib2FyZDphZG1pbi11c2VyIn0.oHvY4JRIRoNXr_DK2wnIWEo-yQ6KLAXL4kuAxVfY-BfU6o_kI90MzG1N9t8t4HAplzXQcg_v-m4RsMyu63dy96h49WVj6Zp6WbmI2bUmeg7VgBmm43BReO-lKPdWfqUxEJ2Yt2fLSl4CbNuLyKgNxOUtJT_RDz1l_OBgFx23uNs7QrJ42miuJnkgDSXnS0_2VCyLbGYALSgWSZKXeWdjQUL-k40GghOj5I2-HEGld0j9fcl0ASiFEOuNWstP0PKZoO1qPJNrsVtqHM5PiNbhHzU6b60-sJO9keJY8K0ORdNjbTt857I3NIiAklBXsJY4dT8BOaesefa7TvBMHSFgNQ
复制生成的token: eyJhbGciOiJSU…..
浏览器访问宿主机地址:https://10.20.1.101:30892/#/login


十二、安装命令补全
所有节点
yum install bash-completion -y
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc
十三、高可用验证
1. 组件状态验证
验证ETCD状态
# 确认 etcd 高可用
$ etcdctl --endpoints="10.20.1.101:2379,10.20.1.102:2379,10.20.1.103:2379" --cacert=/etc/kubernetes/pki/etcd/etcd-ca.pem --cert=/etc/kubernetes/pki/etcd/etcd.pem --key=/etc/kubernetes/pki/etcd/etcd-key.pem endpoint status --write-out=table
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| 10.20.1.101:2379 | adb2616df23a8bc4 | 3.5.16 | 7.0 MB | false | false | 39 | 1893807 | 1893807 | |
| 10.20.1.102:2379 | 4039909ce7f85a53 | 3.5.16 | 7.0 MB | false | false | 39 | 1893807 | 1893807 | |
| 10.20.1.103:2379 | eee0233fd4f83d74 | 3.5.16 | 6.7 MB | true | false | 39 | 1893807 | 1893807 | |
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
集群健康状态
[root@k8s-master01 ~]$ kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-0 Healthy ok
[root@k8s-master01 ~]$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready <none> 6d v1.29.2
k8s-master02 Ready <none> 6d v1.29.2
k8s-master03 Ready <none> 6d v1.29.2
k8s-node01 Ready <none> 6d v1.29.2
k8s-node02 Ready <none> 6d v1.29.2
2. 使用 dnstools 测试
$ kubectl run -it --rm --restart=Never --image=infoblox/dnstools:v3 dnstools
dnstools# host kubernetes
kubernetes.default.svc.cluster.local has address 10.96.0.1
dnstools# dig kubernetes.default.svc.cluster.local
; <<>> DiG 9.11.3 <<>> kubernetes.default.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45690
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 39b672283592d58b (echoed)
;; QUESTION SECTION:
;kubernetes.default.svc.cluster.local. IN A
;; ANSWER SECTION:
kubernetes.default.svc.cluster.local. 20 IN A 10.96.0.1
;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Thu Oct 30 06:56:34 UTC 2025
;; MSG SIZE rcvd: 129
3. Nginx 部署测试
资源清单: nginx-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
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 3/3 3 3 3h21m nginx nginx:1.29.3 app=myapp
# 查看Pod
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
busybox 1/1 Running 3 (17m ago) 3h18m 172.25.92.67 k8s-master02 <none> <none>
nginx-6594975dd-fds78 1/1 Running 0 3h21m 172.18.195.2 k8s-master03 <none> <none>
nginx-6594975dd-pvkt8 1/1 Running 0 3h21m 172.27.14.193 k8s-node02 <none> <none>
nginx-6594975dd-v96mx 1/1 Running 0 3h21m 172.25.244.199 k8s-master01 <none> <none>
ubuntu-test 1/1 Running 0 8m54s 172.25.244.204 k8s-master01 <none> <none>
网络测试
$ kubectl exec -it nginx-6594975dd-fds78 -- /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),这是正常的,如果只是测试网络,不需要担心。
4. Ubuntu 镜像部署测试
3.1 部署 NetworkPolicy
默认 Kubernates 集群 Pod 不能直连外网,需要网络策略允许,这里部署一个 NetworkPolicy 让Pod 可以访问外网
网络策略资源清单: NetworkPolicy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-coredns-egress
namespace: kube-system
spec:
podSelector:
matchLabels:
k8s-app: coredns
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0 # 外部DNS
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- to:
- ipBlock:
cidr: 10.96.0.0/12 # 服务CIDR (API ClusterIP)
ports:
- protocol: TCP
port: 443
- to:
- ipBlock:
cidr: 10.20.1.0/24 # Master节点IP范围 (API后端端口)
ports:
- protocol: TCP
port: 8443
执行资源清单
$ kubectl apply -f NetworkPolicy.yaml
3.2 部署 Ubuntu Pod
# 运行 Ubuntu Pod
$ kubectl run -it --rm --restart=Never --image=ubuntu:22.04 ubuntu-test -- bash
# 替换阿里云源
cat > /etc/apt/sources.list << "EOF"
deb http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse
EOF
# 下载工具
apt update -y
apt install -y iputils-ping dnsutils curl netcat
测试网络1
root@ubuntu-test:/# nslookup kubernetes.default.svc.cluster.local
;; Got recursion not available from 10.96.0.10
;; Got recursion not available from 10.96.0.10
;; Got recursion not available from 10.96.0.10
;; Got recursion not available from 10.96.0.10
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: kubernetes.default.svc.cluster.local
Address: 10.96.0.1
;; Got recursion not available from 10.96.0.10
结论:DNS 解析成功
测试网络2
root@ubuntu-test:/# dig kubernetes.default.svc.cluster.local
; <<>> DiG 9.18.39-0ubuntu0.22.04.2-Ubuntu <<>> kubernetes.default.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31061
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 3bdf10d9d00e32a3 (echoed)
;; QUESTION SECTION:
;kubernetes.default.svc.cluster.local. IN A
;; ANSWER SECTION:
kubernetes.default.svc.cluster.local. 30 IN A 10.96.0.1
;; Query time: 1 msec
;; SERVER: 10.96.0.10#53(10.96.0.10) (UDP)
;; WHEN: Thu Oct 30 06:37:24 UTC 2025
;; MSG SIZE rcvd: 129
结论:DNS 解析成功
其它测试
# TCP 连接 443# # TCP 连接 443
root@ubuntu-test:/# nc -zv 10.96.0.1 443
Connection to 10.96.0.1 443 port [tcp/*] succeeded!
# 或 curl
root@ubuntu-test:/# 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
}
参考链接
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 george_95@126.com
