第19章: kubeadm方式部署K8S1.20高可用集群
kubeadm方式部署K8S1.20高可用集群
作者 |
刘畅 |
时间 |
2021-08-19 |
目录
1.1 生产环境可部署Kubernetes集群的两种方式 1
2 部署Nginx+Keepalived高可用负载均衡器 4
2.3 keepalived配置文件(NginxMaster) 6
2.4 keepalived配置文件(NginxBackup) 8
4 安装kubeadm/kubelet/kubectl 19
1 架构说明
1.1 生产环境可部署Kubernetes集群的两种方式
1 kubeadm部署
(1) Kubeadm是一个K8s部署工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。这里采用kubeadm搭建集群。
(2)
kubeadm工具功能
kubeadm
init # 初始化一个Master节点
kubeadm
join # 将工作节点加入集群
kubeadm
upgrade # 升级K8s版本
kubeadm
token # 管理 kubeadm join 使用的令牌
kubeadm
reset # 清空 kubeadm init 或者 kubeadm join 对主机所做的任何更改
kubeadm
version # 打印 kubeadm 版本
kubeadm
alpha # 预览可用的新功能
2 二进制包部署
从github下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群。
1.2 准备环境
1 服务器要求
建议最小硬件配置: 2核CPU、2G内存、30G硬盘
服务器最好可以访问外网,会有从网上拉取镜像需求,如果服务器不能上网,需要提前下载对应镜像并导入节点。
2 服务器规划
操作系统: CentOS7.5
主机名 |
IP |
软件 |
VIP |
k8s-master1 (2核4G) |
主网卡: 172.16.1.81 |
docker-ce-19.03.9、kubernetes-1.20、etcd(etcd-1)、nginx + keepalived(master) |
172.16.1.80
|
k8s-master2 (2核4G) |
主网卡: 172.16.1.82 |
docker-ce-19.03.9、kubernetes-1.20、etcd(etcd-2)、nginx + keepalived(backup) | |
k8s-node1 (4核8G) |
主网卡: 172.16.1.83 |
docker-ce-19.03.9、kubernetes-1.20、etcd(etcd-3) |
|
(1) 为了节省机器,etcd集群与K8s节点机器复用,也可以独立于k8s集群之外部署,只
要apiserver能连接到就行。
(2) 为了节省机器,nginx+keepalived与K8s master节点机器复用,也可以独立于k8s集
群之外部署,只要nginx与apiserver能通信就行。
3 架构图
1.3 操作系统初始化配置
在172.16.1.81-83节点上操作
(1) 关闭防火墙
#
systemctl stop firewalld
#
systemctl disable firewalld
(2)
关闭selinux
#
sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久
#
setenforce 0 #
临时
(3)
关闭swap
#
swapoff -a # 临时
#
sed -ri 's/.*swap.*/#&/' /etc/fstab # 永久
(4)
在master添加hosts
cat
>> /etc/hosts << EOF
172.16.1.81
k8s-master1
172.16.1.82
k8s-master2
172.16.1.83
k8s-node1
EOF
(5)
将桥接的IPv4流量传递到iptables的链
#
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables
= 1
net.bridge.bridge-nf-call-iptables
= 1
EOF
#
sysctl --system # 生效,手动加载所有的配置文件
(6)
时间同步
#
yum install ntpdate -y
#
ntpdate ntp.aliyun.com
# crontab
-e
#
crontab -l
*/5
* * * * /usr/sbin/ntpdate ntp.aliyun.com &>/dev/null
(7)
部署docker
这里使用Docker作为容器引擎,也可以换成别的,例如containerd。
1)
安装依赖包
#
yum install -y yum-utils device-mapper-persistent-data lvm2
2)
添加Docker软件包源
#
yum-config-manager \
--add-repo
\
https://download.docker.com/linux/centos/docker-ce.repo
3)
更新为阿里云的源
#
wget -O /etc/yum.repos.d/docker-ce.repo
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
4)
清理源缓存
#
yum clean all
5)
安装指定版本的Docker CE
#
yum list docker-ce --showduplicates
| sort -r
# yum
list docker-ce-cli --showduplicates | sort -r
#
yum install docker-ce-19.03.9-3.el7 docker-ce-cli-19.03.9-3.el7
-y
6)
启动Docker服务并设置开机启动
#
systemctl start docker
#
systemctl enable docker
# docker
version # 可以看到docker客户端和服务端都是同一个版本
# docker
info
7)
添加阿里云的镜像仓库
#
mkdir -p /etc/docker
#
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors":
["https://b1cx9cn7.mirror.aliyuncs.com"]
}
EOF
8)
重启docker
#
systemctl daemon-reload
#
systemctl restart docker
(8)
增加 iptables
conntrack
表大小,防止iptables性能不佳
参考网站: https://docs.projectcalico.org/maintenance/troubleshoot/troubleshooting#configure-networkmanager
# sysctl -w
net.netfilter.nf_conntrack_max=1000000
# echo "net.netfilter.nf_conntrack_max=1000000"
>> /etc/sysctl.conf
2 部署Nginx+Keepalived高可用负载均衡器
在172.16.1.81-82节点上操作
(1) Kubernetes作为容器集群系统,通过健康检查+重启策略实现了Pod故障自我修复能力,通过调度算法实现将Pod分布式部署,并保持预期副本数,根据Node失效状态自动在其他Node拉起Pod,实现了应用层的高可用性。
(2)
针对Kubernetes集群,高可用性还应包含以下两个层面的考虑:Etcd数据库的高可用性和Kubernetes Master组件的高可用性。而kubeadm搭建的K8s集群,Etcd只起了一个,存在单点,所以我们这里会独立搭建一个Etcd集群。
(3)
Master节点扮演着总控中心的角色,通过不断与工作节点上的Kubelet和kube-proxy进行通信来维护整个集群的健康工作状态。如果Master节点故障,将无法使用kubectl工具或者API做任何集群管理。
(4)
Master节点主要有三个服务kube-apiserver、kube-controller-manager和kube-scheduler,其中kube-controller-manager和kube-scheduler组件自身通过选择机制已经实现了高可用,所以Master高可用主要针对kube-apiserver组件,而该组件是以HTTP API提供服务,因此对他高可用与Web服务器类似,增加负载均衡器对其负载均衡即可,并且可水平扩容。
(5) kube-apiserver高可用架构图:
(6)
Nginx是一个主流Web服务和反向代理服务器,这里用四层实现对apiserver实现负载均衡。
Keepalived是一个主流高可用软件,基于VIP绑定实现服务器双机热备,在上述拓扑中,Keepalived主要根据Nginx运行状态判断是否需要故障转移(偏移VIP),例如当Nginx主节点挂掉,VIP会自动绑定在Nginx备节点,从而保证VIP一直可用,实现Nginx高可用。
2.1 安装软件包
# yum install epel-release -y
# yum install nginx keepalived -y
2.2 Nginx配置文件
# cat
> /etc/nginx/nginx.conf << "EOF"
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;
}
#
四层负载均衡,为两台Master
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
172.16.1.81:6443; #
Master1 APISERVER IP:PORT
server
172.16.1.82:6443; #
Master2 APISERVER IP:PORT
}
server
{
listen
16443; #
由于nginx与master节点复用,这个监听端口不能是6443,否则会冲突
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 _;
location
/ {
}
}
}
EOF
(1)
验证 nginx配置文件是否正确
# nginx -t
nginx: [emerg] unknown directive "stream" in /etc/nginx/nginx.conf:13
nginx: configuration file /etc/nginx/nginx.conf test
failed
# 报错提示找不到stream这个模块
(2)
解决办法
# yum
install nginx-mod-stream -y
# cat
/usr/share/nginx/modules/mod-stream.conf
load_module
"/usr/lib64/nginx/modules/ngx_stream_module.so";
# nginx 配置文件已经加载了stream模块,nginx -t
验证配置文件就不会报错了。
2.3 keepalived配置文件(NginxMaster)
在172.16.1.81节点上操作
# cat
> /etc/keepalived/keepalived.conf << EOF
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
}
vrrp_script
check_nginx {
script
"/etc/keepalived/check_nginx.sh"
}
vrrp_instance
VI_1 {
#state
MASTER
state
BACKUP #
指定实例初始状态,实际的MASTER和BACKUP是选举决定的
nopreempt # 设置master恢复后为不抢占VIP资源
interface
eth1 #
修改为实际网卡名
virtual_router_id
51 #
VRRP 路由 ID实例,每个实例是唯一的
priority
100 #
优先级,备服务器设置 90
advert_int
1 # 指定VRRP
心跳包通告间隔时间,默认1秒
authentication
{
auth_type
PASS
auth_pass
1111
}
#
虚拟IP
virtual_ipaddress
{
172.16.1.80/24
}
track_script
{
check_nginx
}
}
EOF
notification_email # 设置报警邮件地址即报警邮件接收者,可设置多个,每行一个;如果要开启邮件报警功能,需要开启本机的postfix或者sendmail服务;
notification_email_from # 用于设置邮件的发送地址,即报警邮件发送者;
smtp_server # 用于设置邮件的SMTP Server地址;
smtp_connect_timeout # 设置连接SMTP Server的超时时间;
router_id # 表示运行keepalived服务器的一个标识,是发邮件时显示在邮件主题中的信息;
vrrp_script # 指定检查nginx工作状态脚本(根据nginx状态判断是否故障转移)
virtual_ipaddress # 虚拟IP(VIP)
nopreempt # 通常如果master服务死掉后backup会变成master,但是当master服务又好了的时候master此时会抢占VIP,这样就会发生两次切换对业务繁忙的网站来说是不好的。所以我们要在Master节点配置文件加入nopreempt非抢占,但是这个参数只能用于state为backup,故我们在用HA的时候最好master和backup的state都设置成backup让其通过priority(优先级)来竞争。
检查nginx运行状态的脚本
# cat
> /etc/keepalived/check_nginx.sh << "EOF"
#!/bin/bash
count=$(ss
-antp |grep 16443 |egrep -cv "grep|$$")
if
[ "$count" -eq 0 ];then
exit
1
else
exit
0
fi
EOF
#
chmod +x /etc/keepalived/check_nginx.sh
注: keepalived根据脚本返回状态码(0为工作正常,非0不正常)判断是否故障转移。
2.4 keepalived配置文件(NginxBackup)
在172.16.1.82节点上操作
# cat
> /etc/keepalived/keepalived.conf << EOF
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
eth1
virtual_router_id
51 #
VRRP 路由 ID实例,每个实例是唯一的
priority
90
advert_int
1
authentication
{
auth_type
PASS
auth_pass
1111
}
virtual_ipaddress
{
172.16.1.80/24
}
track_script
{
check_nginx
}
}
EOF
配置检查nginx运行状态的脚本
# cat
> /etc/keepalived/check_nginx.sh << "EOF"
#!/bin/bash
count=$(ss
-antp |grep 16443 |egrep -cv "grep|$$")
if
[ "$count" -eq 0 ];then
exit
1
else
exit
0
fi
EOF
# chmod +x
/etc/keepalived/check_nginx.sh
2.5 启动并设置开机启动
# systemctl
start nginx
# systemctl
start keepalived
# systemctl
enable nginx
# systemctl
enable keepalived
注: 因为nginx为无状态应用,keepalived可以做开机自启动。如果做的是有状态应用的高可用,
keepalived不要设置开机自启动,防止主从切换问题。
2.6 查看keepalived工作状态
(1)
172.16.1.81 (NginxMaster)节点
[root@k8s-master1
~]# systemctl status keepalived.service
[root@k8s-master1
~]# ip addr
(2)
172.16.1.82(NginxBackup)节点
[root@k8s-master2
~]# systemctl status keepalived.service
[root@k8s-master2
~]# ip
addr
(3)
通过keepalived状态可以看到,172.16.1.81节点的eth1网卡绑定了虚拟IP 172.16.1.80,172.16.1.82节点的状态为BACKUP。说明Keepalived+Nginx高可用配置正常。
2.7 Nginx+Keepalived高可用测试
1 杀掉172.16.1.81(NginxMaster)节点上的nginx进程
[root@k8s-master1 ~]# systemctl stop
nginx
[root@k8s-master1
~]# systemctl status keepalived.service
# keepalived释放vip
[root@k8s-master1
~]# ip addr
2 在172.16.1.82(NginxBackup)上查看VIP已经成功绑定到eth1网卡
[root@k8s-master2 ~]# systemctl status
keepalived.service
# eth1成功绑定vip
[root@k8s-master2
~]# ip addr
3 启动172.16.1.81(NginxMaster)节点上的nginx,发现keepalived变为BACKUP状态
[root@k8s-master1 ~]# systemctl start
nginx
[root@k8s-master1
~]# systemctl status keepalived.service
[root@k8s-master1
~]# ip addr
4 同理,当172.16.1.82(NginxBackup)节点nginx进程停止后会释放VIP资源,同时172.16.1.81(NginxMaster)节点会重新接管VIP资源。当172.16.1.82(NginxBackup)节点nginx启动后其keepalived状态会变为BACKUP状态。
3 部署Etcd集群
Etcd是一个分布式键值存储系统,Kubernetes使用Etcd进行数据存储,kubeadm搭建默认情况下只启动一个Etcd Pod,存在单点故障,生产环境强烈不建议,所以我们这里使用3台服务器组建集群,可容忍1台机器故障,当然,你也可以使用5台组建集群,可容忍2台机器故障。
3.1 准备cfssl证书生成工具
在172.16.1.81节点上操作
cfssl是一个开源的证书管理工具,使用json文件生成证书,相比openssl更方便使用。
# wget
https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
#
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
#
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
#
chmod +x cfssl_linux-amd64 cfssljson_linux-amd64
cfssl-certinfo_linux-amd64
#
mv cfssl_linux-amd64 /usr/local/bin/cfssl
#
mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
# mv cfssl-certinfo_linux-amd64
/usr/bin/cfssl-certinfo
3.2 生成Etcd证书
在172.16.1.81节点上操做
1 创建工作目录
# mkdir -p /root/etcd_tls/
# cd /root/etcd_tls/
2 自签证书颁发机构(CA)
(1)
自签CA属性配置文件
# cat
> ca-config.json <<
EOF
{
"signing":
{
"default":
{
"expiry":
"876000h"
},
"profiles":
{
"server":
{
"expiry":
"876000h",
"usages":
[
"signing",
"key
encipherment",
"server
auth",
"client
auth"
]
}
}
}
}
EOF
(2)
自签CA生成配置文件
# cat
> ca-csr.json <<
EOF
{
"CN": "etcd
CA",
"key":
{
"algo":
"rsa",
"size":
2048
},
"names":
[
{
"C":
"CN",
"L":
"Beijing",
"ST":
"Beijing"
}
]
}
EOF
注: "CN":
"etcd CA" 表示证书颁发机构(CA)的名称。
(3)
生成CA
#
cfssl gencert -initca ca-csr.json |
cfssljson -bare ca –
生成以ca开头证书颁发机构(CA)的文件有ca.csr、ca-key.pem、ca.pem
2 使用自签CA签发Etcd HTTPS证书
(1)
创建证书申请文件(CSR)
cat
> etcd-csr.json <<
EOF
{
"CN":
"etcd",
"hosts":
[
"172.16.1.81",
"172.16.1.82",
"172.16.1.83"
],
"key":
{
"algo":
"rsa",
"size":
2048
},
"names":
[
{
"C":
"CN",
"L":
"BeiJing",
"ST":
"BeiJing"
}
]
}
EOF
注:
1) 上述文件hosts字段中IP为所有etcd节点的集群内部通信IP,一个都不能少,为了方便后
期扩容可以多写几个预留的IP。
2)
"CN": "etcd" 表示CA签发Etcd
HTTPS证书的域名。
(2)
生成证书
#
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server etcd-csr.json |
cfssljson -bare etcd
生成以etcd开头的文件etcd.csr、etcd-key.pem、etcd.pem。
3 验证CA签发的Etcd HTTPS证书etcd.pem
验证网站:
https://myssl.com/cert_decode.html
验证信息如下:
3.3 从Github下载Etcd二进制文件
# 下载地址
https://github.com/etcd-io/etcd/releases/download/v3.5.0/etcd-v3.5.0-linux-amd64.tar.gz
3.4 部署Etcd集群
1 创建工作目录并解压二进制包
# mkdir
-p /usr/local/etcd/{bin,cfg,ssl,default.etcd}
# tar
-xzf etcd-v3.5.0-linux-amd64.tar.gz
# cp
-a etcd-v3.5.0-linux-amd64/{etcd,etcdctl} /usr/local/etcd/bin/
#
useradd -M -s /sbin/nologin etcd
#
id etcd
uid=1000(etcd)
gid=1000(etcd) groups=1000(etcd)
# chown -R etcd.etcd
/usr/local/etcd/
2 创建etcd配置文件
cat > /usr/local/etcd/cfg/etcd.conf <<
EOF
#[Member]
ETCD_NAME="etcd-1"
# 节点名称,集群中唯一,172.16.1.81-83节点名分别为etcd-1、etcd-2、etcd-3
ETCD_DATA_DIR="/usr/local/etcd/default.etcd"
# 数据目录
ETCD_LISTEN_PEER_URLS="https://172.16.1.81:2380"
# 集群通信监听地址,172.16.1.81-83节点分别为各自的IP
ETCD_LISTEN_CLIENT_URLS="https://172.16.1.81:2379"
# 客户端访问监听地址,172.16.1.81-83节点分别为各自的IP
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://172.16.1.81:2380"
# 集群通告地址,172.16.1.81-83节点分别为各自的IP
ETCD_ADVERTISE_CLIENT_URLS="https://172.16.1.81:2379"
# 客户端通告地址,172.16.1.81-83节点分别为各自的IP
ETCD_INITIAL_CLUSTER="etcd-1=https://172.16.1.81:2380,etcd-2=https://172.16.1.82:2380,etcd-3=https://172.16.1.83:2380"
# 集群节点地址,172.16.1.81-83节点的IP
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
# 集群Token
ETCD_INITIAL_CLUSTER_STATE="new"
# 加入集群的当前状态,new是新集群,existing表示加入已有集群
EOF
3 systemd管理etcd
cat > /usr/lib/systemd/system/etcd.service <<
EOF
[Unit]
Description=Etcd
Server
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
EnvironmentFile=/usr/local/etcd/cfg/etcd.conf
ExecStart=/usr/local/etcd/bin/etcd
\
--cert-file=/usr/local/etcd/ssl/etcd.pem
\
--key-file=/usr/local/etcd/ssl/etcd-key.pem
\
--peer-cert-file=/usr/local/etcd/ssl/etcd.pem
\
--peer-key-file=/usr/local/etcd/ssl/etcd-key.pem
\
--trusted-ca-file=/usr/local/etcd/ssl/ca.pem
\
--peer-trusted-ca-file=/usr/local/etcd/ssl/ca.pem
\
--logger=zap
ExecReload=/bin/kill
-HUP "\$MAINPID"
KillMode=process
Restart=on-failure
LimitNOFILE=65536
User=etcd
Group=etcd
[Install]
WantedBy=multi-user.target
EOF
4 拷贝生成的证书
在172.16.1.81节点上操作
# cp
-a /root/etcd_tls/ca.pem /root/etcd_tls/etcd*pem
/usr/local/etcd/ssl/
#
scp
-p -P 22 /root/etcd_tls/ca.pem /root/etcd_tls/etcd*pem
root@172.16.1.82:/usr/local/etcd/ssl/
#
scp
-p -P 22 /root/etcd_tls/ca.pem /root/etcd_tls/etcd*pem
root@172.16.1.83:/usr/local/etcd/ssl/
5 启动并设置开机启动
# systemctl daemon-reload
#
systemctl start etcd
# systemctl enable etcd
6 查看集群状态
在172.16.1.81-83上任意一个节点上都可以查看
# ETCDCTL_API=3 /usr/local/etcd/bin/etcdctl
--cacert=/usr/local/etcd/ssl/ca.pem \
--cert=/usr/local/etcd/ssl/etcd.pem
\
--key=/usr/local/etcd/ssl/etcd-key.pem
\
--endpoints="https://172.16.1.81:2379,https://172.16.1.82:2379,https://172.16.1.83:2379"
\
endpoint
health --write-out=table
注: 如果输出上面信息,就说明集群部署成功。如果有问题第一步先看日志:"/var/log/message"或
"journalctl -u
etcd"
4 安装kubeadm/kubelet/kubectl
在172.16.1.81-83节点上操作
4.1 添加阿里云YUM软件源
# 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
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
#
yum clean
all
# yum makecache
4.2 安装
由于版本更新频繁,这里指定版本号部署
# yum install kubelet-1.20.0 kubeadm-1.20.0
kubectl-1.20.0 -y
# systemctl enable kubelet.service
5 部署Kubernetes Master
在172.16.1.81-82节点上操作
5.1 初始化Master1
在172.16.1.81节点上操作
1 生成初始化配置文件
[root@k8s-master1 ~]# cat > kubeadm-config.yaml
<< EOF
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
-
groups:
-
system:bootstrappers:kubeadm:default-node-token
token:
9037x2.tcaqnpaqkra9vsbw
ttl:
24h0m0s
usages:
-
signing
-
authentication
kind:
InitConfiguration
localAPIEndpoint:
advertiseAddress:
172.16.1.81
bindPort:
6443
nodeRegistration:
criSocket:
/var/run/dockershim.sock
name:
k8s-master1
taints:
-
effect: NoSchedule
key:
node-role.kubernetes.io/master
---
apiServer:
certSANs: #
包含所有Master/LB/VIP IP,一个都不能少,为了方便后期扩容可以多写几个预留的IP。
-
k8s-master1
-
k8s-master2
-
172.16.1.81
- 10.0.0.81
-
172.16.1.82
- 10.0.0.82
-
172.16.1.80
-
127.0.0.1
extraArgs:
authorization-mode:
Node,RBAC
timeoutForControlPlane:
4m0s
apiVersion:
kubeadm.k8s.io/v1beta2
certificatesDir:
/etc/kubernetes/pki
clusterName:
kubernetes
controlPlaneEndpoint:
172.16.1.80:16443 #
负载均衡虚拟IP(VIP)和端口
controllerManager:
{}
dns:
type:
CoreDNS
etcd:
external: # 使用外部etcd
endpoints:
-
https://172.16.1.81:2379 # etcd集群3个节点
-
https://172.16.1.82:2379
-
https://172.16.1.83:2379
caFile:
/usr/local/etcd/ssl/ca.pem
# 连接etcd所需证书
certFile:
/usr/local/etcd/ssl/etcd.pem
keyFile:
/usr/local/etcd/ssl/etcd-key.pem
imageRepository:
registry.aliyuncs.com/google_containers # 由于默认拉取镜像地址k8s.gcr.io国内无法访问,这里指定阿里云镜像仓库地址
kind:
ClusterConfiguration
kubernetesVersion:
v1.20.0 # K8s版本,与上面安装的一致
networking:
dnsDomain:
cluster.local
podSubnet:
10.244.0.0/16 # Pod网络,与下面部署的CNI网络组件yaml中保持一致
serviceSubnet:
10.96.0.0/12 # 集群内部虚拟网络,Pod统一访问入口
scheduler: {}
EOF
2 使用配置文件进行初始化
(1)
进行初始化
[root@k8s-master1
~]# kubeadm init --config kubeadm-config.yaml
(2)
初始化出现警告
1)
警告内容
[WARNING IsDockerSystemdCheck]: detected "cgroupfs" as
the Docker cgroup driver. The recommended driver is "systemd". Please follow the
guide at https://kubernetes.io/docs/setup/cri/
2) 原因
表示,更改设置,令容器运行时和kubelet使用systemd作为cgroup驱动,以此使系统更为稳定。 请注意在docker下设置native.cgroupdriver=systemd选项。
3) 解决办法
方法1:
编辑"/etc/docker/daemon.json"文件,追加"exec-opts"配置。
{
"exec-opts":
["native.cgroupdriver=systemd"]
}
方法2:
编辑"/usr/lib/systemd/system/docker.service"文件,在ExecStart后追加
"--exec-opt
native.cgroupdriver=systemd"配置。
4) 使配置生效
# systemctl daemon-reload.service
# systemctl restart docker.service
5) 验证
# docker info | grep Cgroup
Cgroup Driver: systemd
注: 验证成功,不要忘记在docker各个节点上都要做配置
(3)
清空kubeadm init
所做的更改
[root@k8s-master1
~]# kubeadm reset
(4)
重新进行初始化
[root@k8s-master1
~]# kubeadm init --config kubeadm-config.yaml
……(省略的日志)
Your Kubernetes control-plane has initialized
successfully!
To
start using your cluster, you need to run the following as a regular
user:
mkdir
-p $HOME/.kube
sudo
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo
chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively,
if you are the root user, you can run:
export
KUBECONFIG=/etc/kubernetes/admin.conf
You
should now deploy a pod network to the cluster.
Run
"kubectl apply -f [podnetwork].yaml" with one of the options listed
at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You
can now join any number of control-plane nodes by copying certificate
authorities
and
service account keys on each node and then running the following as
root:
kubeadm
join 172.16.1.80:16443 --token 9037x2.tcaqnpaqkra9vsbw \
--discovery-token-ca-cert-hash
sha256:a5669a292020ec7facec1584461ffe6c18791e721c4e1d135a11970897fbcfc7
\
--control-plane
Then
you can join any number of worker nodes by running the following on each as
root:
kubeadm
join 172.16.1.80:16443 --token 9037x2.tcaqnpaqkra9vsbw \
--discovery-token-ca-cert-hash
sha256:a5669a292020ec7facec1584461ffe6c18791e721c4e1d135a11970897fbcfc7
注: 初始化完成后,会有两个join的命令,带有"--control-plane"是用于加入组建多master集
群的,不带的是加入节点的。
3 拷贝kubectl使用的连接k8s认证文件到默认路径
[root@k8s-master1 ~]# mkdir -p
$HOME/.kube
[root@k8s-master1
~]# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master1
~]# chown $(id -u):$(id -g) $HOME/.kube/config
[root@k8s-master1 ~]# kubectl get
node
NAME STATUS ROLES AGE VERSION
k8s-master1 NotReady control-plane,master 45m v1.20.0
5.2 初始化Master2
在172.16.1.82节点上操作
1 将Master1节点生成的证书拷贝到Master2
[root@k8s-master2 ~]# scp -rp -P 22 root@172.16.1.81:/etc/kubernetes/pki /etc/kubernetes/
2 复制加入master1初始化时输出的join命令在master2执行
[root@k8s-master2 ~]# kubeadm
join 172.16.1.80:16443 --token 9037x2.tcaqnpaqkra9vsbw \
--discovery-token-ca-cert-hash
sha256:a5669a292020ec7facec1584461ffe6c18791e721c4e1d135a11970897fbcfc7
\
--control-plane
……(省略的日志)
This node has joined the cluster and a new control plane
instance was created:
*
Certificate signing request was sent to apiserver and approval was
received.
*
The Kubelet was informed of the new secure connection details.
*
Control plane (master) label and taint were applied to the new node.
*
The Kubernetes control plane instances scaled up.
To
start administering your cluster from this node, you need to run the following
as a regular user:
mkdir
-p $HOME/.kube
sudo
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo
chown $(id -u):$(id -g) $HOME/.kube/config
Run 'kubectl get nodes' to see this node join the
cluster.
3 拷贝kubectl使用的连接k8s认证文件到默认路径
[root@k8s-master2 ~]# mkdir
-p $HOME/.kube
[root@k8s-master2
~]# cp
-i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master2
~]# chown
$(id -u):$(id -g) $HOME/.kube/config
[root@k8s-master2
~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master1 NotReady control-plane,master 105m v1.20.0
k8s-master2 NotReady control-plane,master 101m v1.20.0
注:由于网络插件还没有部署,还没有准备就绪
NotReady
5.3 访问负载均衡器测试
找K8s集群中任意一个节点,使用curl查看K8s版本测试,使用VIP访问。
这里在172.16.1.83节点上测试
[root@k8s-node1 ~]# curl -k
https://172.16.1.80:16443/version
{
"major":
"1",
"minor":
"20",
"gitVersion":
"v1.20.0",
"gitCommit":
"af46c47ce925f4c4ad5cc8d1fca46c7b77d13b38",
"gitTreeState":
"clean",
"buildDate":
"2020-12-08T17:51:19Z",
"goVersion":
"go1.15.5",
"compiler":
"gc",
"platform":
"linux/amd64"
}
可以正确获取到K8s版本信息,说明负载均衡器搭建正常。
该请求数据流程为: curl->vip(nginx)->apiserver,通过
查看Nginx日志也可以看到转发apiserver IP。
通过"systemctl status
keepalived"命令得知VIP在master1(172.16.1.81)节点上。
[root@k8s-master1 ~]# tail
/var/log/nginx/k8s-access.log -f
172.16.1.83 172.16.1.81:6443 - [21/Aug/2021:16:48:49
+0800] 200 419
172.16.1.83
172.16.1.82:6443 - [21/Aug/2021:16:48:50 +0800] 200 419
172.16.1.83 172.16.1.81:6443 - [21/Aug/2021:16:48:50
+0800] 200 419
6 加入Kubernetes Node
在172.16.1.83(k8s-node1)节点上操作
向集群添加新节点,执行在kubeadm init输出的kubeadm join命令
[root@k8s-node1 ~]# kubeadm join 172.16.1.80:16443
--token 9037x2.tcaqnpaqkra9vsbw \
--discovery-token-ca-cert-hash
sha256:a5669a292020ec7facec1584461ffe6c18791e721c4e1d135a11970897fbcfc7
……(省略的日志)
This node has joined the cluster:
*
Certificate signing request was sent to apiserver and a response was
received.
*
The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this
node join the cluster.
后续其他节点也是这样加入。默认token有效期为24小时,当过期之后,该token就不可用了。
这时就需要重新创建token,可以直接使用命令快捷生成: kubeadm token create --print-join-command
7 部署网络组件
在master1或master2节点上操作都可,我这里在172.16.1.81节点上操作
7.1 网络通信机制
k8s中的网络主要涉及到pod的各种访问需求,如同一pod的内部(单容器或者多容器)通
信、pod A与pod
B的通信、从外部网络访问pod以及从pod访问外部网络。k8s的网络
基于第三方插件实现,该规范有CoreOS和Google联合定制,叫做CNI(Container
Network
Interface)。目前常用的的CNI网络插件有calico和flannel。
7.2 calico简介
1 calico是一个纯三层的网络解决方案,为容器提供多node间的访问通信,calico将每一个
node节点都当做为一个路由器(router),各节点通过BGP(Border Gateway Protocol)
边界
网关协议学习并在node节点生成路由规则,从而将不同node节点上的pod连接起来进
行通信,是目前Kubernetes主流的网络方案。
2
BGP是一个去中心化的协议,它通过自动学习和维护路由表实现网络的可用性,但是并不
是所有的网络都支持BGP,另外为了跨网络实现更大规模的网络管理,calico 还支持IP-in-IP
的叠加模型,简称IPIP,IPIP可以实现跨不同网段建立路由通信,但是会存在安全性问题,其
在内核内置,可以通过Calico的配置文件设置是否启用IPIP,在公司内部如果k8s的node节
点没有跨越网段建议关闭IPIP,默认IPIP为启用。
7.3 部署Calico
1 由于我采用了https来安装etcd,所以要下载支持https的yaml文件
(1) 官方文档
https://docs.projectcalico.org/getting-started/kubernetes/self-managed-onprem/onpremises
(2) 下载
# wget
https://docs.projectcalico.org/manifests/calico-etcd.yaml
# 我这里使用的版本为3.20.0
2修改calico-etcd.yaml文件
(1) 修改secret
(2) 修改etcd数据库地址及认证证书路径
(3) 修改集群网段
(4) 添加calico环境变量的配置
- name: KUBERNETES_SERVICE_HOST
value:
"172.16.1.80"
-
name: KUBERNETES_SERVICE_PORT
value:
"16443"
-
name: KUBERNETES_SERVICE_PORT_HTTPS
value: "16443"
3 部署
[root@k8s-master1 ~]# kubectl
apply -f calico.yaml
[root@k8s-master1
~]# kubectl get pods -n
kube-system
4 查看Calico Pod都为Running
[root@k8s-master1 ~]# kubectl get pod -A -o
wide
5 补充
(1) 后续如果发生异常时,可以用到的命令
1) 查看pod产生的日志
#
kubectl
logs -f <PodName> -n
kube-system
2)
查看pod的具体描述
#
kubectl
describe pod <PodName> -n
kube-system
3)
查看集群环境输出
#
kubectl
get ev -n kube-system
(2) coredns
pod起不来
1)
查看pod描述信息,报错如下
network for pod "coredns-7f89b7bc75-bspm8":
networkPlugin cni failed to set up pod "coredns-7f89b7bc75-bspm8_kube-system"
network: stat /var/lib/calico/nodename: no such file or directory: check that
the calico/node container is running and has mounted /var/lib/calico/
2) 报错原因
calico
pod正常运行时会在宿主机上生成路径为"/var/lib/calico/nodename"的文件,如果
calico pod没有正常运行,会导致coredns pod无法挂载宿主机上的"/var/lib/calico/"卷。
3)
解决办法
在calico pod 运行正常的情况下删除coredns pod,让coredns pod自动创建新的。
6 节点准备就绪
[root@k8s-master1 ~]# kubectl get
node
8 部署 Dashboard
在master1或master2节点上操作都可,我这里在172.16.1.81节点上操作
8.1 说明
Dashboard是官方提供的一个UI,可用于基本管理K8s资源。
1 官方文档
https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/
2 gitlab项目地址
https://github.com/kubernetes/dashboard
3 版本兼容
https://github.com/kubernetes/dashboard/releases/tag/v2.3.1
4 下载
# wget -O kubernetes-dashboard.yaml \
https://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml
8.2 部署
1 修改kubernetes-dashboard.yaml配置
由于默认kubernetes-dashboard只能集群内部访问,因此修改Service为NodePort类型,暴露
到k8s集群外部进行访问。
2 应用kubernetes-dashboard.yaml
[root@k8s-master1 ~]# kubectl apply -f
kubernetes-dashboard.yaml
#
查看pod状态
[root@k8s-master1
~]# kubectl get pod -n kubernetes-dashboard -o wide
注: kubernetes dashboard pod运行正常,访问地址: https://NodeIP:30001
3 创建访问dashboard的token
(1)
创建serviceaccount并赋权
1)
在kube-system命名空间中创建serviceaccount/dashboard-admin
#
kubectl create serviceaccount dashboard-admin -n kube-system
2)
绑定kube-system命名空间中serviceaccount/dashboard-admin到集群角色cluster-admin上
#
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin
\
--serviceaccount=kube-system:dashboard-admin
(2)
获取访问token
1) 获取kube-system命名空间中serviceaccount/dashboard-admin的secrets名称
#
kubectl describe serviceaccount dashboard-admin -n kube-system
2)
获取kube-system命名空间中secrets/dashboard-admin-token-ld7hk登录k8s集群的token
#
kubectl describe secrets
dashboard-admin-token-ld7hk -n kube-system
3)
补充: 一条命令获取token
# kubectl describe secrets -n kube-system $(kubectl
-n kube-system get secret | awk '/dashboard-admin/{print
$1}')
8.3 token登录Dashboard
https://kubernetes.io/docs/reference/access-authn-authz/authentication/
9 补充
自此使用kubeadm方式部署K8S1.20高可用集群就完成了。
9.1 在master1节点查看k8s集群中所有的pod
172.16.1.81节点
[root@k8s-master1 ~]# kubectl get pod -A -o wide
9.2 在master2节点查看k8s集群中所有的pod
172.16.1.82节点
[root@k8s-master2 ~]# kubectl get pod -A -o wide