1. 程式人生 > >Kubernetes探祕-etcd節點和例項擴容

Kubernetes探祕-etcd節點和例項擴容

Kubernetes使用kubeadm安裝預設只有一個etcd例項,存在單點故障的風險。提升Kubernetes叢集可用性的方法包括:1、備份(Kubernetes探祕—etcd狀態資料及其備份 );2、etcd節點和例項擴容;3、apiserver的多節點服務和負載均衡。這裡主要實驗etcd節點和例項的擴容。

一、etcd擴容,主要思路

etcd是一個獨立的服務,在kubernetes中使用時將配置引數和資料目錄分別對映到了宿主機目錄,而且使用hostnetwork網路(本主機網路)。其中,/etc/kubernetes/manifest/etcd.yaml 為啟動引數檔案,/etc/kubernetes/pki/etcd

為 https使用的證書,/var/lib/etcd 為該節點的etcd資料檔案。

對於已用kubeadm安裝的單Master節點Kubernetes叢集,其etcd執行例項只有一個。我們希望將其etcd例項擴充套件到多個,以降低單點失效風險。Kubernetes中etcd的擴容的思路如下:

  • 所有節點安裝kubeadm/kubectl/kubelet,按照獨立master節點安裝。
  • 建立etcd叢集的證書,並複製到各個節點。
  • 在各節點修改etcd啟動配置檔案,啟動etcd例項。有多種方式(執行結果一樣、管理方式不同):
    • 通過 kubectl 部署,讓kubernetes控制啟動。通過nodeSelector指定執行的節點。
    • 通過 kubelet 服務來啟動,作業系統通過systemd啟動kubelet服務。這是k8s的標準過程。
    • 通過docker的--restart引數讓容器自行啟動,由容器服務來進行管理。
    • 把etcd作為宿主機服務來直接啟動,不使用Docker或者k8s管理。
  • 將所有節點kube-apiserver.yaml的etcd服務指向本地的etcd服務例項。
    • etcd是分散式的儲存,所有節點的資料將會自動同步,從任何節點訪問都是一樣的。

二、etcd擴容,實驗步驟

第一步:安裝多個節點

準備好安裝etcd的節點。我使用ubuntu 18.04LTS,然後安裝Docker CE 18.06和kubernetes 1.12.3。

我這裡的三個節點分別為:

  • podc01, 10.1.1.201
  • podc02, 10.1.1.202
  • podc03, 10.1.1.203

需要提前把k8s用到的容器映象拉取下來到每一個節點。參考:

第二步:建立etcd證書

本想嘗試複製主節點的/etc/kubernetes/kpi和/etc/kubernetes/manifest目錄到所有副(mate)節點,啟動後出現各種問題無法正常訪問,提示是ca證書問題。最後,準備從頭開始建立自己的證書和部署yaml檔案。

建立證書使用cfssl來建立,需要下載模版檔案和修改定義檔案,包括ca機構、ca-config配置、ca-key私鑰、csr請求、server/peer/client等證書的配置模版檔案等。需要將裡面的資訊按照自己的環境進行修改。

  • 最後生成cert-file證書檔案、key-file公鑰檔案和trusted-ca-file證書機構檔案(因為我們這裡用的是自簽名,所以建立自己的證書機構檔案)。
  • 這三個檔案在etcd例項啟動時配置進去(注意:API2和API3的引數名稱有些不同),需要放到每一個節點的相應目錄,並對映到etcd容器卷中。
  • 使用etcdctl作為服務客戶端訪問時也需要指定相應的引數,其它對端(Peer)etcd例項也需要使用這些引數來相互訪問、組成叢集、同步資料。

下面說明具體過程(更多資訊參考 https://segmentfault.com/a/1190000016010980)。

1、準備cfssl證書工具

mkdir ~/cfssl && cd ~/cfssl
mkdir bin && cd bin

wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -O cfssl
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -O cfssljson 

chmod +x {cfssl,cfssljson}
export PATH=$PATH:~/cfssl/bin
  • 可選:為了方便,可以將path新增到~/.profile檔案中,或者複製到/usr/local/bin目錄。

2、建立證書配置檔案

建立證書配置檔案目錄:

mkdir -p ~/cfssl/etcd-certs && cd ~/cfssl/etcd-certs

生成證書配置檔案放到~/cfssl/etcd-certs目錄中,檔案模版如下:

# ==============================================
# ca-config.json
{
    "signing": {
        "default": {
            "expiry": "43800h"
        },
        "profiles": {
            "server": {
                "expiry": "43800h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth"
                ]
            },
            "client": {
                "expiry": "43800h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "client auth"
                ]
            },
            "peer": {
                "expiry": "43800h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth",
                    "client auth"
                ]
            }
        }
    }
}

# ==============================================
# ca-csr.json
{
    "CN": "My own CA",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "US",
            "L": "CA",
            "O": "My Company Name",
            "ST": "San Francisco",
            "OU": "Org Unit 1",
            "OU": "Org Unit 2"
        }
    ]
}

# ==============================================
# server.json
{
    "CN": "etcd0",
    "hosts": [
        "127.0.0.1",
        "0.0.0.0",
        "10.1.1.201",
        "10.1.1.202",
        "10.1.1.203"
    ],
    "key": {
        "algo": "ecdsa",
        "size": 256
    },
    "names": [
        {
            "C": "US",
            "L": "CA",
            "ST": "San Francisco"
        }
    ]
}

# ==============================================
# peer1.json  # 填本機IP
{
    "CN": "etcd0",
    "hosts": [
        "10.1.1.201"
    ],
    "key": {
        "algo": "ecdsa",
        "size": 256
    },
    "names": [
        {
            "C": "US",
            "L": "CA",
            "ST": "San Francisco"
        }
    ]
}

# ==============================================
# client.json
{
    "CN": "client",
    "hosts": [
       ""
    ],
    "key": {
        "algo": "ecdsa",
        "size": 256
    },
    "names": [
        {
            "C": "US",
            "L": "CA",
            "ST": "San Francisco"
        }
    ]
}

3、建立etcd叢集的證書

操作如下:

cd ~/cfssl/etcd-certs
 
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server server.json | cfssljson -bare server
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=peer peer1.json | cfssljson -bare peer1
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client client.json | cfssljson -bare client

檢視所產生的證書檔案:

ls -l ~/cfssl/etcd-certs

檔案包括:

...

第三步:啟動etcd多例項

啟動etcd例項之前,務必將/var/lib/etcd目錄清空,否則一些設定的引數將不會起作用,仍然保留原來的狀態。

注意,etcd的下面幾個引數只在第一次啟動(初始化)時起作用,包括:

  •    - --initial-advertise-peer-urls=http://10.1.1.202:2380
  •    - --initial-cluster=podc02=http://10.1.1.202:2380,podc03=http://10.1.1.203:2380
  •    - --initial-cluster-token=etcd-cluster
  •    - --initial-cluster-state=new

1、上傳證書檔案

將cfssl/etcd-certs目錄拷貝到/etc/kubernetes/pki/etcd-certs 目錄,可以使用scp或sftp上傳。

2、編輯啟動檔案

編輯/etc/kubernetes/manifests/etcd.yaml檔案,這是kubelet啟動etcd例項的配置檔案。

# /etc/kubernetes/manifests/etcd.yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ""
  creationTimestamp: null
  labels:
    component: etcd
    tier: control-plane
  name: etcd
  namespace: kube-system
spec:
  containers:
  - command:
    - etcd
    - --advertise-client-urls=https://10.1.1.201:2379
    - --cert-file=/etc/kubernetes/pki/etcd-certs/server.pem
    - --client-cert-auth=true
    - --data-dir=/var/lib/etcd
    - --initial-advertise-peer-urls=https://10.1.1.201:2380
    - --initial-cluster=etcd0=https://10.1.1.201:2380
    - --key-file=/etc/kubernetes/pki/etcd-certs/server-key.pem
    - --listen-client-urls=https://10.1.1.201:2379
    - --listen-peer-urls=https://10.1.1.201:2380
    - --name=etcd1
    - --peer-cert-file=/etc/kubernetes/pki/etcd-certs/peer1.pem
    - --peer-client-cert-auth=true
    - --peer-key-file=/etc/kubernetes/pki/etcd-certs/peer1-key.pem
    - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd-certs/ca.pem
    - --snapshot-count=10000
    - --trusted-ca-file=/etc/kubernetes/pki/etcd-certs/ca.pem
    image: k8s.gcr.io/etcd-amd64:3.2.18
    imagePullPolicy: IfNotPresent
   #livenessProbe:
   #  exec:
   #    command:
   #    - /bin/sh
   #    - -ec
   #    - ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.1.201]:2379 --cacert=/etc/kubernetes/pki/etcd-certs/ca.pem
   #      --cert=/etc/kubernetes/pki/etcd-certs/client.pem --key=/etc/kubernetes/pki/etcd-certs/client-key.pem
   #      get foo
   #  failureThreshold: 8
   #  initialDelaySeconds: 15
   #  timeoutSeconds: 15
    name: etcd
    resources: {}
    volumeMounts:
    - mountPath: /var/lib/etcd
      name: etcd-data
    - mountPath: /etc/kubernetes/pki/etcd
      name: etcd-certs
  hostNetwork: true
  priorityClassName: system-cluster-critical
  volumes:
  - hostPath:
      path: /var/lib/etcd
      type: DirectoryOrCreate
    name: etcd-data
  - hostPath:
      path: /etc/kubernetes/pki/etcd-certs
      type: DirectoryOrCreate
    name: etcd-certs
status: {}

參照上面的模式,在各個副節點修改etcd啟動引數/etc/kubernetes/manifest/etcd.yaml檔案內容。

  • 注意:IP地址需要修改多個地方,不要遺漏、錯誤
  • 重啟kubelet服務。
    • sudo systemctl restart kubelet。
  • 檢查etcd服務。
    • ectdctl 連線到例項,etcdctl member list。
    • 最終,多節點的etcd例項連結為一個叢集。

3、驗證執行狀態

進入etcd容器執行:

alias etcdv3="ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.1.201]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.pem --cert=/etc/kubernetes/pki/etcd/client.pem --key=/etc/kubernetes/pki/etcd/client-key.pem"
etcdv3 member add etcd1 --peer-urls="https://10.1.1.202:2380"

4、增加etcd節點

拷貝etcd1(10.1.1.201)節點上的證書到etcd1(10.1.1.202)節點上,複製peer1.json到etcd2的peer2.json,修改peer2.json。

# peer2.json
{
    "CN": "etcd1",
    "hosts": [
        "10.1.86.202"
    ],
    "key": {
        "algo": "ecdsa",
        "size": 256
    },
    "names": [
        {
            "C": "US",
            "L": "CA",
            "ST": "San Francisco"
        }
    ]
}

重新生成在etcd1上生成peer1證書:

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=peer peer1.json | cfssljson -bare peer1

啟動etcd1,配置檔案如下:

# etcd02 etcd.yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ""
  creationTimestamp: null
  labels:
    component: etcd
    tier: control-plane
  name: etcd
  namespace: kube-system
spec:
  containers:
  - command:
    - etcd
    - --advertise-client-urls=https://10.1.1.202:2379
    - --cert-file=/etc/kubernetes/pki/etcd-certs/server.pem
    - --data-dir=/var/lib/etcd
    - --initial-advertise-peer-urls=https://10.1.1.202:2380
    - --initial-cluster=etcd01=https://10.1.1.201:2380,etcd02=https://10.1.1.202:2380
    - --key-file=/etc/kubernetes/pki/etcd-certs/server-key.pem
    - --listen-client-urls=https://10.1.1.202:2379
    - --listen-peer-urls=https://10.1.1.202:2380
    - --name=etcd02
    - --peer-cert-file=/etc/kubernetes/pki/etcd-certs/peer2.pem
    - --peer-client-cert-auth=true
    - --peer-key-file=/etc/kubernetes/pki/etcd-certs/peer2-key.pem
    - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd-certs/ca.pem
    - --snapshot-count=10000
    - --trusted-ca-file=/etc/kubernetes/pki/etcd-certs/ca.pem
    - --initial-cluster-state=existing  # 千萬別加雙引號,被坑死
    image: k8s.gcr.io/etcd-amd64:3.2.18
    imagePullPolicy: IfNotPresent
  # livenessProbe:
  #   exec:
  #     command:
  #     - /bin/sh
  #     - -ec
  #     - ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.1.202]:2379 --cacert=/etc/kubernetes/pki/etcd-certs/ca.crt
  #       --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd-certs/healthcheck-client.key
  #       get foo
  #   failureThreshold: 8
  #   initialDelaySeconds: 15
  #   timeoutSeconds: 15
    name: etcd
    resources: {}
    volumeMounts:
    - mountPath: /var/lib/etcd
      name: etcd-data
    - mountPath: /etc/kubernetes/pki/etcd
      name: etcd-certs
  hostNetwork: true
  priorityClassName: system-cluster-critical
  volumes:
  - hostPath:
      path: /var/lib/etcd
      type: DirectoryOrCreate
    name: etcd-data
  - hostPath:
      path: /etc/kubernetes/pki/etcd-certs
      type: DirectoryOrCreate
    name: etcd-certs
status: {}

進入etcd容器執行:

alias etcdv3="ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.86.201]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.pem --cert=/etc/kubernetes/pki/etcd/client.pem --key=/etc/kubernetes/pki/etcd/client-key.pem"
etcdv3 member add etcd1 --peer-urls="https://10.1.1.203:2380"

按照以上步驟,增加etcd03。

5、etcd叢集健康檢查

# etcdctl --endpoints=https://[10.1.1.201]:2379 --ca-file=/etc/kubernetes/pki/etcd-certs/ca.pem --cert-file=/etc/kubernetes/pki/etcd-certs/client.pem --key-file=/etc/kubernetes/pki/etcd-certs/client-key.pem cluster-health

member 5856099674401300 is healthy: got healthy result from https://10.1.86.201:2379
member df99f445ac908d15 is healthy: got healthy result from https://10.1.86.202:2379
cluster is healthy

第四步:修改apiserver服務指向

- --etcd-cafile=/etc/kubernetes/pki/etcd-certs/ca.pem
- --etcd-certfile=/etc/kubernetes/pki/etcd-certs/client.pem
- --etcd-keyfile=/etc/kubernetes/pki/etcd-certs/client-key.pem

至此,etcd已經擴充套件成多節點的分散式叢集,而且各個節點的kubernetes都是可以訪問的。

注意:

  • 上面的流程適合剛建立的k8s叢集。
  • 如果已經有kubeadm的多節點叢集,可以先建立node2/node3的etcd叢集,然後將node1的資料同步過來,再新增node1叢集,就能保留原來的資料。

上面所部署的工作節點還只能連線到一個apiserver,其它副節點的apiserver雖然可用但是無法被工作節點連線到。

下一步需要實現多master節點的容錯,遇主節點故障時可以轉移訪問其它的副節點。

更多參考