kubeadm實現k8s高可用叢集環境部署與配置

遇見你我看到光發表於2020-06-02

高可用架構

k8s叢集的高可用實際是k8s各核心元件高可用,這裡使用主備模式,架構如下:
在這裡插入圖片描述
主備模式高可用架構說明:

核心元件 高可用模式 高可用實現方式
apiserver 主備 keepalived
controller-manager 主備 leader election
scheduler 主備 leader election
etcd 叢集 kubeadm
  • apiserver 通過keepalived實現高可用,當某個節點故障時觸發keepalived vip 轉移;
  • controller-manager k8s內部通過選舉方式產生領導者(由--leader-elect 選型控制,預設為true),同一時刻叢集內只有一個controller-manager元件執行;
  • scheduler k8s內部通過選舉方式產生領導者(由--leader-elect 選型控制,預設為true),同一時刻叢集內只有一個scheduler元件執行;
  • etcd 通過執行kubeadm方式自動建立叢集來實現高可用,部署的節點數為奇數,3節點方式最多容忍一臺機器當機。

部署環境

k8s版本

kubelet version kubeadm version kubectl version
v1.15.1 v1.15.1 v1.15.1

主機配置

Centos版本 系統核心 docker version flannel version Keepalived version
7.8.2003 4.4.223 19.03.9 v0.11.0 v1.3.5

主機列表

主機名 ip 主機配置 備註
master01 192.168.213.181 4U4G control plane
master02 192.168.213.182 4U4G control plane
master03 192.168.213.183 4U4G control plane
node01 192.168.213.192 2U2G node
node02 192.168.213.192 2U2G node
VIP 192.168.213.200 4U4G 在control plane上浮動

私有倉庫

主機名 ip 主機配置 備註
docker-registry 192.168.213.129 2U1G reg.zhao.com

其他準備

系統初始化,docker安裝,k8s(kubelet、kubeadm和kubectl)安裝省略

  • kubelet 執行在叢集所有節點上,用於啟動Pod和容器
  • kubeadm 用於初始化叢集,啟動叢集
  • kubectl 用於和叢集通訊,部署和管理應用,檢視各種資源,建立、刪除和更新各種元件

啟動kubelet並設定開機啟動 systemctl enable kubelet && systemctl start kubelet

keepalived安裝

在所有master節點上安裝

安裝keepalived

[root@master01 ~]# yum -y install keepalived

keepalived配置

master01

[root@master01 ~]# cat /etc/keepalived/keepalived.conf 
! Configuration File for keepalived
global_defs {
   router_id master01
}
vrrp_instance VI_1 {
    state MASTER 
    interface ens160
    virtual_router_id 50
    priority 150
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        172.27.34.130
    }
}

master02

[root@master02 ~]# cat /etc/keepalived/keepalived.conf 
! Configuration File for keepalived
global_defs {
   router_id master02
}
vrrp_instance VI_1 {
    state BACKUP 
    interface ens160
    virtual_router_id 50
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        172.27.34.130
    }
}

master03

[root@master03 ~]# cat /etc/keepalived/keepalived.conf 
! Configuration File for keepalived
global_defs {
   router_id master03
}
vrrp_instance VI_1 {
    state BACKUP 
    interface ens160
    virtual_router_id 50
    priority 80
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        172.27.34.130
    }
}

啟動keepalived並設定開機啟動

[root@master01 ~]# systemctl start keepalived
[root@master01 ~]# systemctl enable keepalived

VIP檢視

在這裡插入圖片描述

配置master節點

初始化master01節點

master01初始化

#初始化的配置檔案
[root@master01 ~]# cat kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.15.1
apiServer:
  certSANs:		##填寫所有kube-apiserver節點的hostname、IP、VIP
  - master01
  - master02
  - master03
  - node01
  - node02
  - 192.168.213.181
  - 192.168.213.182
  - 192.168.213.183
  - 192.168.213.191
  - 192.168.213.192
  - 192.168.213.200
controlPlaneEndpoint: "192.168.213.200:6443"
networking:
  podSubnet: "10.244.0.0/16"
[root@master01 ~]# kubeadm init --config=kubeadm-config.yaml|tee kubeadim-init.log

記錄kubeadm join的輸出,後面需要這個命令將備master節點和node節點加入叢集中

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.213.200:6443 --token ebx4uz.9y3twsnoj9yoscoo \
    --discovery-token-ca-cert-hash sha256:1bc280548259dd8f1ac53d75e918a8ec99c234b13f4fe18a71435bbbe8cb26f3

載入環境變數

[root@master01 ~]# echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
[root@master01 ~]# source .bash_profile

安裝flannel網路

[root@master01 ~]# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/2140ac876ef134e0ed5af15c65e414cf26827915/Documentation/kube-flannel.yml

備master節點加入叢集

配置免密登入

配置master01到master02、master03免密登入

#建立祕鑰
[root@master01 ~]# ssh-keygen -t rsa
#將祕鑰同步至master02,master03
[root@master01 ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.213.182
[root@master01 ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.213.183
#免密登陸測試
[root@master01 ~]# ssh master02
[root@master01 ~]# ssh 192.168.213.183

master01分發證書

在master01上執行指令碼cert-main-master.sh,將證書分發至master02和master03

[root@master01 ~]# cat cert-main-master.sh
USER=root # customizable
CONTROL_PLANE_IPS="192.168.213.182 192.168.213.183"
for host in ${CONTROL_PLANE_IPS}; do
    scp /etc/kubernetes/pki/ca.crt "${USER}"@$host:
    scp /etc/kubernetes/pki/ca.key "${USER}"@$host:
    scp /etc/kubernetes/pki/sa.key "${USER}"@$host:
    scp /etc/kubernetes/pki/sa.pub "${USER}"@$host:
    scp /etc/kubernetes/pki/front-proxy-ca.crt "${USER}"@$host:
    scp /etc/kubernetes/pki/front-proxy-ca.key "${USER}"@$host:
    scp /etc/kubernetes/pki/etcd/ca.crt "${USER}"@$host:etcd-ca.crt
    # Quote this line if you are using external etcd
    scp /etc/kubernetes/pki/etcd/ca.key "${USER}"@$host:etcd-ca.key
done
[root@master01 ~]# ./cert-main-master.sh

備master節點移動證書至指定目錄

在master02,master03上執行指令碼cert-other-master.sh,將證書移至指定目錄

[root@master02 ~]# cat cert-other-master.sh
USER=root # customizable
mkdir -p /etc/kubernetes/pki/etcd
mv /${USER}/ca.crt /etc/kubernetes/pki/
mv /${USER}/ca.key /etc/kubernetes/pki/
mv /${USER}/sa.pub /etc/kubernetes/pki/
mv /${USER}/sa.key /etc/kubernetes/pki/
mv /${USER}/front-proxy-ca.crt /etc/kubernetes/pki/
mv /${USER}/front-proxy-ca.key /etc/kubernetes/pki/
mv /${USER}/etcd-ca.crt /etc/kubernetes/pki/etcd/ca.crt
# Quote this line if you are using external etcd
mv /${USER}/etcd-ca.key /etc/kubernetes/pki/etcd/ca.key
[root@master02 ~]# ./cert-other-master.sh 

備master節點加入叢集

在master02和master03節點上執行加入叢集的命令

kubeadm join 192.168.213.200:6443 --token ebx4uz.9y3twsnoj9yoscoo \
    --discovery-token-ca-cert-hash sha256:1bc280548259dd8f1ac53d75e918a8ec99c234b13f4fe18a71435bbbe8cb26f3

備master節點載入環境變數

此步驟是為了在備master節點上也能執行kubectl命令

scp master01:/etc/kubernetes/admin.conf /etc/kubernetes/
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
source .bash_profile

node節點加入叢集

加入

在node節點執行初始化master生成的加入叢集的命令

kubeadm join 192.168.213.200:6443 --token ebx4uz.9y3twsnoj9yoscoo \
    --discovery-token-ca-cert-hash sha256:1bc280548259dd8f1ac53d75e918a8ec99c234b13f4fe18a71435bbbe8cb26f3

叢集節點檢視

[root@master01 ~]# kubectl get nodes
[root@master01 ~]# kubectl get pod -o wide -n kube-system 

所有control plane節點處於ready狀態,所有的系統元件也正常
在這裡插入圖片描述

對接私有倉庫

私有倉庫配置省略,在所有節點上執行以下步驟

修改daemon.json

[root@master01 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.213.181 master01
192.168.213.182 master02
192.168.213.183 master03
192.168.213.191 node01
192.168.213.192 node02
192.168.213.129 reg.zhao.com
[root@master01 ~]# cat /etc/docker/daemon.json
{
    "registry-mirrors": ["https://sopn42m9.mirror.aliyuncs.com"],
    "exec-opts": ["native.cgroupdriver=systemd"],
    "log-driver": "json-file",
        "log-opts": {
            "max-size": "100m"
        },
    "insecure-registries": ["https://reg.zhao.com"]
}
[root@master01 ~]# systemctl daemon-reload
[root@master01 ~]# systemctl restart docker

建立認證secret

使用Kuberctl建立docker register認證secret

[root@master01 ~]# kubectl create secret docker-registry myregistrykey --docker-server=https://reg.zhao.com --docker-username=admin --docker-password=Harbor12345 --docker-email=""
secret/myregistrykey created
[root@master02 ~]# kubectl get secrets
NAME                  TYPE                                  DATA   AGE
default-token-6mrjd   kubernetes.io/service-account-token   3      18h
myregistrykey         kubernetes.io/dockerconfigjson        1      19s

在建立Pod的時通過imagePullSecret引用myregistrykey

imagePullSecrets:
  - name: myregistrykey

叢集功能測試

測試私有倉庫

[root@master02 ~]# cat test_sc.yaml
apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
    - name: foo
      image: reg.zhao.com/zhao/myapp:v1.0
#  imagePullSecrets:
#    - name: myregistrykey

在這裡插入圖片描述在這裡插入圖片描述開啟註釋,應用金鑰,可以拉取到映象
在這裡插入圖片描述

測試叢集高可用

測試master節點高可用

通過ip檢視apiserver所在節點,通過leader-elect檢視scheduler和controller-manager所在節點

[root@master01 ~]# ip a|grep ens33
[root@master01 ~]# kubectl get endpoints kube-scheduler -n kube-system -o yaml |grep holderIdentity
[root@master01 ~]# kubectl get endpoints kube-controller-manager -n kube-system -o yaml |grep holderIdentity

在這裡插入圖片描述

元件名 所在節點
apiserver master01
controller-manager master01
scheduler master01

關閉master01,模擬當機,master01狀態為NotReady

[root@master01 ~]# init 0

VIP飄到了master02,controller-manager和scheduler也發生了遷移
在這裡插入圖片描述

元件名 所在節點
apiserver master02
controller-manager master03
scheduler master02

測試node節點高可用

K8S 的pod-eviction在某些場景下如節點 NotReady,資源不足時,會把 pod 驅逐至其它節點

Kube-controller-manager 週期性檢查節點狀態,每當節點狀態為 NotReady,並且超出 pod-eviction-timeout 時間後,就把該節點上的 pod 全部驅逐到其它節點,其中具體驅逐速度還受驅逐速度引數,叢集大小等的影響。最常用的 2 個引數如下:
pod-eviction-timeout:NotReady 狀態節點超過該時間後,執行驅逐,預設 5 min
node-eviction-rate:驅逐速度,預設為 0.1 pod/秒

建立pod,維持副本數3

[root@master02 ~]# cat myapp_deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      release: stabel
  template:
    metadata:
      labels:
        app: myapp
        release: stabel
        env: test
    spec:
      containers:
      - name: myapp
        image: library/nginx
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80

可以看到pod分佈在node01和node02節點上
在這裡插入圖片描述關閉node02,模擬當機,node02狀態為NotReady
在這裡插入圖片描述可以看到 NotReady 狀態節點超過指定時間後,pod被驅逐到 Ready 的節點上,deployment維持執行3個副本

問題

初始化master節點失敗

如果初始化失敗,可執行kubeadm reset後重新初始化

[root@master01 ~]# kubeadm reset
#非root使用者還須執行rm -rf $HOME/.kube/config

flanne檔案下載失敗

方法一:可以直接下載kube-flannel.yml檔案,然後再執行apply
方法二:配置域名解析
在https://site.ip138.com查詢伺服器IP
在這裡插入圖片描述echo "151.101.76.133 raw.Githubusercontent.com" >>/etc/hosts

節點狀態NotReady

在節點機器上執行journalctl -f -u kubelet檢視kubelet的輸出日誌資訊如下:

Container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized

出現這個錯誤的原因是網路外掛沒有準備好,在節點上執行命令 docker images|grep flannel 檢視flannel映象是否已經成功拉取,這個花費的時間可能會很長

如果很長時間仍然沒有拉下來flannel映象,可以使用如下方法解決

docker save把主節點上的flannel映象儲存為壓縮檔案(或在官方倉庫https://github.com/coreos/flannel/releases下載映象傳到主機上,要注意版本對應),在節點機器上執行docker load載入映象

[root@master02 ~]# docker save -o my_flannel.tar quay.io/coreos/flannel:v0.11.0-amd64
[root@master02 ~]# scp my_flannel.tar node01:/root
[root@node01 ~]# docker load < my_flannel.tar

unexpected token `$’do\r”

shell,執行出錯:syntax error near unexpected token `$’do\r”

原因:Linux和windows下的回車換行符不相容

解決方法:將windows下面的CR LF,轉換為Linux下面的LF
用notepad++開啟檔案,編輯->檔案格式轉換->轉換為UNIX格式->儲存即可

相關文章