🌻 05-kubeadm部署生产级多Master高可用K8s集群
一、集群整体规划
1. 网络网段规划
-
Pod网段(podSubnet):
10.244.0.0/16 -
Service网段(serviceSubnet):
10.96.0.0/16 -
高可用虚拟VIP:
192.168.40.199
2. 节点角色规划
| 角色 | 主机名 | IP地址 | 核心组件 |
|---|---|---|---|
| 控制节点Master1 | zhappymaster1 | 192.168.40.180 | apiserver、controller-manager、scheduler、kubelet、etcd、docker、kube-proxy、keepalived、nginx、calico |
| 控制节点Master2 | zhappymaster2 | 192.168.40.181 | apiserver、controller-manager、scheduler、kubelet、etcd、docker、kube-proxy、keepalived、nginx、calico |
| 工作节点Node1 | zhappynode1 | 192.168.40.182 | kubelet、kube-proxy、docker、calico、coredns |
3. 系统环境要求
-
操作系统:CentOS 7.6 / 7.9
-
硬件配置:4GiB内存 / 4vCPU / 60G硬盘
-
网络:NAT模式,虚拟机开启CPU虚拟化支持
4. kubeadm vs 二进制安装对比
| 部署方式 | 核心特点 | 适用场景 |
|---|---|---|
| kubeadm | 官方自动化工具,组件以Pod运行具备故障自愈能力;部署快捷,屏蔽底层细节,排障门槛稍高 | 高频部署、自动化要求高的生产环境 |
| 二进制 | 手动逐组件部署,对K8s架构理解更深入,排障清晰;部署流程繁琐 | 定制化需求高、希望深度掌握原理的场景 |
两种方式生产环境运行均稳定可靠,可根据团队技术栈与运维能力选择。
二、集群环境初始化(所有节点执行)
1. 配置静态IP
修改网卡配置(网卡名以实际为准,示例为ens33):
vim /etc/sysconfig/network-scripts/ifcfg-ens33
核心配置:
BOOTPROTO=static
IPADDR=192.168.40.180 # 替换为对应节点IP
NETMASK=255.255.255.0
GATEWAY=192.168.40.2
DNS1=192.168.40.2
ONBOOT=yes
NAME=ens33
DEVICE=ens33
重启网络生效:
service network restart
2. 关闭SELinux
# 临时关闭
setenforce 0
# 永久关闭,重启后生效
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
# 验证状态,输出 Disabled 即为成功
getenforce
3. 设置主机名
分别在对应节点执行:
# Master1执行
hostnamectl set-hostname zhappymaster1 && bash
# Master2执行
hostnamectl set-hostname zhappymaster2 && bash
# Node1执行
hostnamectl set-hostname zhappynode1 && bash
可选操作:执行
yum update -y将系统从CentOS7.6升级至7.9。
4. 配置主机名解析
所有节点的/etc/hosts添加节点映射:
cat >> /etc/hosts <<EOF
192.168.40.180 zhappymaster1
192.168.40.181 zhappymaster2
192.168.40.182 zhappynode1
EOF
5. 配置节点间SSH免密登录
分别在三个节点生成密钥并分发至所有节点:
# 生成密钥,一路回车即可
ssh-keygen
# 分发公钥,按提示输入yes与密码
ssh-copy-id zhappymaster1
ssh-copy-id zhappymaster2
ssh-copy-id zhappynode1
6. 关闭Swap交换分区
K8s默认禁用Swap以保证性能,未关闭会导致初始化失败。
# 临时关闭
swapoff -a
# 永久关闭:注释fstab中swap挂载行
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
说明:若必须保留Swap,可在kubeadm命令后追加
--ignore-preflight-errors=Swap跳过检测。
7. 配置内核网络参数
加载桥接模块,开启IP转发与网桥iptables支持:
# 加载br_netfilter内核模块
modprobe br_netfilter
echo "modprobe br_netfilter" >> /etc/profile
# 写入内核配置
cat > /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
# 生效配置
sysctl -p /etc/sysctl.d/k8s.conf
参数作用:
-
bridge-nf-call-iptables:让网桥流量经过iptables链,是容器网络插件的基础依赖 -
ip_forward:开启IP数据包转发,实现跨节点容器网络互通
8. 关闭firewalld防火墙
systemctl stop firewalld
systemctl disable firewalld
9. 配置软件源
-
备份原有YUM源,替换为阿里云CentOS基础源+epel源
-
添加Docker阿里云YUM源:
yum install yum-utils -y
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
10. 配置K8s阿里云YUM源
在Master1创建源文件,再分发到其他节点:
cat > /etc/yum.repos.d/kubernetes.repo <<EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
EOF
# 分发至另外两个节点
scp /etc/yum.repos.d/kubernetes.repo zhappymaster2:/etc/yum.repos.d/
scp /etc/yum.repos.d/kubernetes.repo zhappynode1:/etc/yum.repos.d/
11. 配置时间同步
# 安装同步工具
yum install ntpdate -y
# 立即同步时间
ntpdate cn.pool.ntp.org
# 添加定时任务,每小时同步一次
crontab -e
# 写入以下内容
* */1 * * * /usr/sbin/ntpdate cn.pool.ntp.org
# 重启定时任务
service crond restart
12. 安装基础依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2 wget net-tools nfs-utils lrzsz gcc gcc-c++ make cmake libxml2-devel openssl-devel curl curl-devel unzip sudo ntp libaio-devel vim ncurses-devel autoconf automake zlib-devel python-devel epel-release openssh-server socat ipvsadm conntrack ntpdate telnet
三、安装Docker服务(所有节点执行)
1. 安装指定版本Docker
yum install docker-ce-20.10.6 docker-ce-cli-20.10.6 containerd.io -y
2. 启动并设置开机自启
systemctl start docker
systemctl enable docker
systemctl status docker
3. 配置镜像加速器与Cgroup驱动
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors":["https://rsbud4vc.mirror.aliyuncs.com","https://registry.docker-cn.com","https://docker.mirrors.ustc.edu.cn","https://dockerhub.azk8s.cn","http://hub-mirror.c.163.com"],
"exec-opts": ["native.cgroupdriver=systemd"]
}
EOF
重要:Kubelet默认使用
systemd作为cgroup驱动,Docker默认为cgroupfs,两者必须一致,否则集群启动失败。
重启Docker生效:
systemctl daemon-reload
systemctl restart docker
四、安装K8s核心组件(所有节点执行)
1. 安装指定版本组件
yum install -y kubelet-1.20.6 kubeadm-1.20.6 kubectl-1.20.6
2. 设置kubelet开机自启
systemctl enable kubelet
组件说明:
-
kubeadm:K8s集群自动化初始化工具
-
kubelet:运行在所有节点,负责Pod生命周期管理、与APIServer通信
-
kubectl:K8s命令行客户端,用于集群资源管理与操作
五、Keepalived+Nginx实现APIServer高可用(两个Master节点执行)
方案原理
-
Nginx做四层负载均衡,将请求转发至两台Master的6443端口
-
Keepalived提供虚拟VIP,实现Nginx主备故障自动切换
-
Nginx监听16443端口,避免与宿主机APIServer的6443端口冲突
1. 安装依赖软件
yum install nginx keepalived nginx-mod-stream -y
2. 配置Nginx四层负载(两个Master配置一致)
vim /etc/nginx/nginx.conf
完整配置:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
# 四层负载:转发APIServer请求
stream {
log_format main '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent';
access_log /var/log/nginx/k8s-access.log main;
upstream k8s-apiserver {
server 192.168.40.180:6443 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.40.181:6443 weight=5 max_fails=3 fail_timeout=30s;
}
server {
listen 16443;
proxy_pass k8s-apiserver;
}
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80 default_server;
server_name _;
}
}
3. 配置Keepalived
(1)Master1(主节点)配置
vim /etc/keepalived/keepalived.conf
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id NGINX_MASTER
}
# Nginx健康检查脚本
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
}
vrrp_instance VI_1 {
state MASTER
interface ens33 # 修改为实际网卡名
virtual_router_id 51 # 主备节点必须一致
priority 100 # 优先级,主节点高于备节点
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
# 虚拟VIP地址
virtual_ipaddress {
192.168.40.199/24
}
track_script {
check_nginx
}
}
(2)Master2(备节点)配置
vim /etc/keepalived/keepalived.conf
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id NGINX_BACKUP
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.40.199/24
}
track_script {
check_nginx
}
}
4. 创建Nginx健康检查脚本(两个Master都配置)
vim /etc/keepalived/check_nginx.sh
#!/bin/bash
# 检测Nginx进程是否存活
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
if [ $counter -eq 0 ]; then
# 尝试启动Nginx
service nginx start
sleep 2
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
# 启动失败则停止Keepalived,触发VIP漂移
if [ $counter -eq 0 ]; then
service keepalived stop
fi
fi
授权可执行:
chmod +x /etc/keepalived/check_nginx.sh
5. 启动服务
systemctl daemon-reload
systemctl start nginx
systemctl start keepalived
systemctl enable nginx keepalived
6. 验证VIP与故障切换
- 查看VIP是否绑定在Master1:
ip addr
# ens33网卡下出现 192.168.40.199 即为成功
- 故障切换测试:停止Master1的keepalived,观察VIP漂移至Master2
# Master1执行
service keepalived stop
# Master2查看
ip addr
- 恢复Master1服务,VIP自动漂移回主节点
systemctl start keepalived
六、kubeadm初始化K8s集群(Master1执行)
1. 导入离线镜像(所有节点)
提前将k8simage-1-20-6.tar.gz上传至所有节点,导入镜像:
docker load -i k8simage-1-20-6.tar.gz
2. 编写初始化配置文件
cd /root/
vim kubeadm-config.yaml
配置内容:
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.20.6
controlPlaneEndpoint: 192.168.40.199:16443 # 高可用VIP入口
imageRepository: registry.aliyuncs.com/google_containers
apiServer:
certSANs:
- 192.168.40.180
- 192.168.40.181
- 192.168.40.182
- 192.168.40.199
networking:
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/16
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
说明:
-
controlPlaneEndpoint:所有节点统一通过VIP访问APIServer -
certSANs:APIServer证书信任的IP列表 -
mode: ipvs:kube-proxy采用IPVS模式,性能远高于默认iptables,生产环境推荐
3. 执行集群初始化
kubeadm init --config kubeadm-config.yaml --ignore-preflight-errors=SystemVerification
初始化成功后会输出Master节点加入命令和Worker节点加入命令,请务必保存好token和hash值。
4. 配置kubectl管理员权限
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
5. 查看节点初始状态
kubectl get nodes
此时节点状态为NotReady属于正常现象,原因是尚未安装网络插件。
七、扩容集群节点
1. 添加第二个Master控制节点
(1)拷贝集群证书到Master2
Master1执行,将证书分发至Master2:
# 先在Master2创建目录
ssh zhappymaster2 "mkdir -p /etc/kubernetes/pki/etcd && mkdir -p ~/.kube/"
# 批量拷贝证书
scp /etc/kubernetes/pki/ca.crt zhappymaster2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/ca.key zhappymaster2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/sa.key zhappymaster2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/sa.pub zhappymaster2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/front-proxy-ca.crt zhappymaster2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/front-proxy-ca.key zhappymaster2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/etcd/ca.crt zhappymaster2:/etc/kubernetes/pki/etcd/
scp /etc/kubernetes/pki/etcd/ca.key zhappymaster2:/etc/kubernetes/pki/etcd/
(2)生成节点加入命令(Master1执行)
kubeadm token create --print-join-command
(3)Master2执行加入命令
在join命令后追加--control-plane表示加入控制平面:
kubeadm join 192.168.40.199:16443 --token 你的token值 \
--discovery-token-ca-cert-hash sha256:你的hash值 \
--control-plane --ignore-preflight-errors=SystemVerification
2. 添加Worker工作节点
(1)生成加入命令(Master1执行)
kubeadm token create --print-join-command
(2)Node1执行加入
kubeadm join 192.168.40.199:16443 --token 你的token值 \
--discovery-token-ca-cert-hash sha256:你的hash值 \
--ignore-preflight-errors=SystemVerification
(3)给Worker节点打角色标签
kubectl label node zhappynode1 node-role.kubernetes.io/worker=worker
八、安装Calico网络插件(Master1执行)
1. 部署Calico
上传calico.yaml文件,或在线下载:
# 在线下载(可选)
# wget https://docs.projectcalico.org/manifests/calico.yaml
kubectl apply -f calico.yaml
2. 验证Pod状态
kubectl get pods -n kube-system
等待所有calico相关Pod变为Running,CoreDNS也会从Pending转为正常运行。
3. 验证节点状态
kubectl get nodes
所有节点STATUS变为Ready,说明集群网络正常。
九、集群功能验证
1. 验证Pod外网访问能力
导入busybox测试镜像(node节点):
docker load -i busybox-1-28.tar.gz
启动临时测试Pod(master节点):
kubectl run busybox --image busybox:1.28 --restart=Never --rm -it -- sh
容器内执行ping测试:
ping www.baidu.com
能正常通说明容器外网网络正常。
2. 验证CoreDNS域名解析
在busybox容器内执行:
nslookup kubernetes.default.svc.cluster.local
能正常解析出Service IP则集群DNS服务正常。
注意:必须使用busybox 1.28版本,高版本存在nslookup解析异常问题。
十、延长K8s证书有效期
kubeadm默认签发的APIServer组件证书有效期为1年,CA根证书为10年,可通过脚本将组件证书延长至10年。
1. 查看证书有效期
# 查看CA根证书有效期
openssl x509 -in /etc/kubernetes/pki/ca.crt -noout -text | grep Not
# 查看APIServer证书有效期
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text | grep Not
2. 执行续期脚本(两个Master节点都执行)
上传update-kubeadm-cert.sh脚本至两个Master节点:
# 授权可执行
chmod +x update-kubeadm-cert.sh
# 执行全量证书续期,延长至10年
./update-kubeadm-cert.sh all
3. 验证续期结果
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text | grep Not
有效期变为10年即为操作成功。