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