Kubernetes的etcd多节点扩容实战技巧

在《Kubernetes探秘-多master节点容错部署》中介绍了经过部署多个主节点来提升Kubernetes的容错能力。其中,最为关键是存储集群控制数据的etcd服务必须在多个副节点间实时同步,而kube-apiserver经过keepalived进行IP主地址的切换。 在《Kubernetes探秘-etcd节点和实例扩容》中已经详细介绍了etcd多节点扩容的步骤,但在实际操做中发现,必须要遵循必定的操做顺序、注意细节,不然会致使扩容失败,并且很容易形成整个etcd集群没法访问。这里将etcd集群扩容的实际操做经验整理出来分享。git

  • 注意:
    • 由于扩容过程当中,须要将原来的etcd库删除,会致使kubernetes集群的master节点信息丢失
      • 所以在扩容以前,建议使用etcdctl snapshot命令进行备份。或者,另建etcd节点,将原来的数据传送过去。
    • 若是出现“ID mismatch”等错误,整个etcd集群将没法链接,后续的member remove等操做都没法进行,只能所有废弃。
    • 能够将/var/lib/etcd目录和etcd容器实例所有删除。重启动kubelet服务后能够恢复,可是里面存储的数据将会所有丢失。
  • 提示:

一、生成证书文件

所有使用https进行etcd集群的链接,须要生成和配置证书,能够参考《Kubernetes探秘-etcd节点和实例扩容》里的方法,这些证书文件须要复制到每个节点的/etc/kubernetes/pki目录下。须要所有使用固定IP地址,在Ubuntu 18.06中使用 Netplan进行配置(参考《Ubuntu 18.04设置静态IP》),使用 sudo netplan apply让其当即生效(须要稍等会儿配置完毕)。github

上传目录,示例:docker

sudo scp -r root@10.1.1.201:/etc/kubernetes/pki /etc/kubernetes

二、安装Kubernetes主节点

2.1 安装主节点

咱们首先安装一个Kubernetes主节点,其它节点配置参数将从其衍生出来。参考:数据库

准备工做完成后,使用下面的命令安装Kubernetes的单实例Master节点。api

sudo kubeadm init --kubernetes-version=v1.13.1 --apiserver-advertise-address=10.1.1.199

由于个人机器上有多块网卡,使用 --apiserver-advertise-address=10.1.1.199 指定apiserver的服务地址,这个地址也是keepalived的虚拟IP地址(须要提早安装,参考《Keepalived快速使用》),将会在遇故障时在多个节点间自动漂移该主地址,使其它节点能够访问到。app

输入 kubectl get pod --all-namespaces检查该单实例集群是否运行正常。工具

2.2 备份etcd数据库

主节点已经安装了一个etcd的实例,而且存放了集群运行的最基础参数。为了防止etcd集群扩容过程数据丢失,咱们将其备份。具体操做参见《Kubernetes的etcd数据查看和迁移》。须要注意的是,etcd api2和api3的备份和恢复方法不一样,由于从Kubernetes 1.13.0开始已经使用API3,下面介绍的都是API3的方法。url

  • 建立snapshot
ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.1.202]: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 \
snapshot save /home/supermap/openthings/etcd$(date +%Y%m%d_%H%M%S)_snapshot.db
  • 恢复snapshot restore:
ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.1.199]: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 \
--data-dir=/var/lib/etcd \
--initial-advertise-peer-urls=https://10.1.1.199:2380 \
--initial-cluster=podc01=https://10.1.1.199:2380 \
--initial-cluster-token=etcd-cluster \
--name=podc01 \
snapshot restore /home/supermap/etcd_snapshot.db

上面的备份文件名能够本身起,恢复时能对上就行。spa

2.3 更新主节点的etcd配置参数

  • 为何须要更新?
    • 集群apiserver使用地址为10.1.1.199须要在多节点漂移,本地的etcd实例使用10.1.1.201固定地址。
    • 主节点etcd实例初始使用199地址,与最终的201不一致,这将自动生成两个不一样的etcd peerID,出现“peerID mismatch”错误,引发整个etcd集群没法访问。
    • 10.1.1.199的PeerID已写入/var/lib/etcd数据库中,只能在etcd服务可用时经过服务接口member update修改。

包括:.net

  • /var/lib/etcd目录下的数据,使用etcdctl member update命令来进行。
  • 以及修改/etc/kubernetes/manifests/etcd.yaml配置参数,由kubelet来加载运行etcd的实例。

首先,检查etcd集群的运行状态:

ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.1.199]: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 \
endpoint status -w table

而后,更新etcd实例的peer-urls:

ETCDCTL_API=3 etcdctl --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 \
--endpoints=https://[10.1.1.199]:2379 \
member update podc01 --peer-urls=https://10.1.1.201:2380

第三,修改etcd实例的client-urls。

  • 此时,中止kubelet服务。
sudo systemctl stop kubelet
  • 编辑/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/server.pem
    - --client-cert-auth=true
    - --data-dir=/var/lib/etcd
    - --initial-advertise-peer-urls=https://10.1.1.201:2380
    - --initial-cluster=podc01=https://10.1.1.201:2380
    - --key-file=/etc/kubernetes/pki/etcd/server-key.pem
    - --listen-client-urls=https://127.0.0.1:2379,https://10.1.1.201:2379
    - --listen-peer-urls=https://10.1.1.201:2380
    - --name=podc01
    - --peer-cert-file=/etc/kubernetes/pki/etcd/peer1.pem
    - --peer-client-cert-auth=true
    - --peer-key-file=/etc/kubernetes/pki/etcd/peer1-key.pem
    - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem
    - --snapshot-count=10000
    - --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem
    image: k8s.gcr.io/etcd:3.2.24
    imagePullPolicy: IfNotPresent
    livenessProbe:
      exec:
        command:
        - /bin/sh
        - -ec
        - ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.pem
          --cert=/etc/kubernetes/pki/etcd/client.pem --key=/etc/kubernetes/pki/etcd/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: /etc/kubernetes/pki/etcd-certs
      type: DirectoryOrCreate
    name: etcd-certs
  - hostPath:
      path: /var/lib/etcd
      type: DirectoryOrCreate
    name: etcd-data
status: {}
  • 此时,重启kubelet服务。
sudo systemctl start kubelet

检查一下etcd的服务状态:

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 endpoint status -w table
  • 注意这里的变化:--endpoints=https://[10.1.1.201]:2379,已经完成了地址切换。

2.4 修改 api-server.yaml

修改/etc/kubernetes/manifests/api-server.yaml文件,以下:

#    - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
#    - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
#    - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
#    - --etcd-servers=https://127.0.0.1:2379

    - --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-servers=https://10.1.1.201:2379

将上面的新的etcd服务地址配置给kube-apiserver。

重启 kubelet,以下:

#从新启动kubelet服务。
sudo systemctl restart kubelet

#查看运行的容器实例。
docker ps

#查看全部运行的容器实例。
#包含已中止的,若是etcd启动失败退出,可经过该命令查看。
docker ps -a

#查看特定容器实例的日志。
docker logs idxxxx

再次检查etcd状态:

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 \
endpoint status -w table

检查kubernetes集群状态(kubectl get pod --all-namespaces)。

2.5 注意事项

  • Kubernetes的kubeadm工具安装的单节点etcd实例没法直接扩展到集群,须要修改配置参数。
  • 任什么时候候(如下同)修改etcd文件时,都应该中止kubelet集群,手工终止运行的etcd实例。
    • 不然,若是“脏”信息被写入etcd数据库,将致使etcd服务所有没法访问。
  • 在出现“ID mismatch”错误时:
    • 若是直接删除/var/lib/etcd的内容,将丢失Kubernetes集群的配置信息。
    • 即使etcd集群运行成功,后续也没法访问K8s服务。
    • 能够经过备份snapshot store来重置原始数据库。

三、扩展etcd实例到多个节点

下面将节点逐个加入(etcd节点的IP地址必须在前面的证书生成时加入)。

我使用Kubernetes的kubelet来托管etcd的运行(也能够部署为独立的系统服务,如使用systemd)。

3.1 添加为k8s工做节点

使用kubeadm join加入新的节点(将会建立kubelet基础服务,并且etcd节点和kubernetes节点同时可用)。在主节点获取添加命令,以下:

#在主节点上执行

kubeadm token create --print-join-command

3.2 复制pki证书

直接将master节点的/etc/kubernetes/pki目录复制到子节点。以下:

#在子节点上执行

sudo scp -r root@10.1.1.201:/etc/kubernetes/pki /etc/kubernetes/
  • 其中,etcd的证书放在/etc/kubernetes/pki/etc-certs中,在下面的etcd.yaml文件将按照此设置。

3.3 中止kubelet服务

命令为:

sudo systemctl stop kubelet
  • 若是不是第一次启动,使用docker ps查看etcd实例是否已经运行。
  • 若是已经有etcd实例运行,使用docker rm -f idxxx将该实例完全删除。

3.4 添加节点到etcd集群

使用etcdctl的member add命令添加节点:

#在子节点上执行,将子节点peer-urls添加到etcd集群中。

ETCDCTL_API=3 etcdctl \
--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 \
--endpoints=https://[10.1.1.201]:2379 \
member add podc02 --peer-urls=https://10.1.1.202:2380

此时,etcdctl member list查当作员为unstarted状态。命令以下:

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 \
member list -w table
  • 在编辑etcd.yaml过程当中,保持kubelet不要启动(不然触发etcd实例启动,若是写入错误数据到etcd集群,将可能致使集群没法访问)。

3.5 复制etcd.yaml

将etcd.yaml文件放入各个子节点的/etc/kubernetes/manifests目录下,跟master节点同样,而后sudo systemctl restart kubelet重启kubelet服务,kubelet启动时将会自动启动/etc/kubernetes/manifests下的全部*.yaml实例为静态pod(静态pod在Dashboard删除时会删除当前的运行实例,而后被kubelet自动重启,不会永久删除)。

  • 复制etcd.yaml文件,以下:
#在子节点上执行

sudo scp -r root@10.1.1.201:/etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/manifests/
  • 编辑 etcd.conf 文件,以下:
sudo nano /etc/kubernetes/manifest/etcd.yaml
  • 内容以下:
#子节点podc02上的/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.202:2379
    - --cert-file=/etc/kubernetes/pki/etcd/server.pem
    - --client-cert-auth=true
    - --data-dir=/var/lib/etcd

    - --initial-advertise-peer-urls=https://10.1.1.202:2380
    - --initial-cluster=podc01=https://10.1.1.201:2380,podc02=https://10.1.1.202:2380
    - --initial-cluster-token=etcd-cluster
    - --initial-cluster-state=existing

    - --key-file=/etc/kubernetes/pki/etcd/server-key.pem
    - --listen-client-urls=https://127.0.0.1:2379,https://10.1.1.202:2379
    - --listen-peer-urls=https://10.1.1.202:2380

    - --name=podc02
    - --peer-cert-file=/etc/kubernetes/pki/etcd/peer2.pem
    - --peer-client-cert-auth=true
    - --peer-key-file=/etc/kubernetes/pki/etcd/peer2-key.pem
    - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem
    - --snapshot-count=10000
    - --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem
    image: k8s.gcr.io/etcd:3.2.24
    imagePullPolicy: IfNotPresent
    livenessProbe:
      exec:
        command:
        - /bin/sh
        - -ec
        - ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.pem
          --cert=/etc/kubernetes/pki/etcd/client.pem --key=/etc/kubernetes/pki/etcd/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: /etc/kubernetes/pki/etcd-certs
      type: DirectoryOrCreate
    name: etcd-certs
  - hostPath:
      path: /var/lib/etcd
      type: DirectoryOrCreate
    name: etcd-data
status: {}
  • 提示:
    • 修改的地方:
      • 修改:本地IP地址所有设为10.1.1.202。
      • 修改:--name=podc02
      • 修改:--initial-cluster=podc01=https://10.1.1.201:2380,podc02=https://10.1.1.202:2380
      • 添加:initial-cluster-token=etcd-cluster、- --initial-cluster-state=existing两个参数。
      • 修改:证书格式为*.pem,cfssl生成的格式与kubernetes原始的有些不一样,用法同样。
      • 修改:host-path的证书目录指向到/etc/kubernetes/pki/etcd-certs。
    • 仔细检查设置参数是否有错。

3.6 重启kubelet服务

确认etcd参数正确,如今能够启动kubelet服务了。命令为:

sudo systemctl start kubelet
  • 使用docker ps查看etcd实例是否已经运行。
  • 若是etcd实例未运行,使用docker ps -a查看未运行的etcd实例ID。
  • 使用命令 docker logs idxxx 查看etcd实例的日志信息,根据信息修改etcd.yaml从新启动kubelet。
    • 命令为:sudo systemctl restart kubelet
  • ⚠️注意:该节点必须已有etcd的容器镜像。

! 参照上面的3.1-3.6方法将全部etcd集群子节点加入到集群中(注意严格按照顺序操做)。

3.7 查看etcd集群信息

能够在主机安装etcd-client,而后etcdctl能够直接链接到容器中的etcd服务。

查看etcd集群成员列表:

# etcd cluster member list

echo ""
echo "============================="
echo "+ etcd cluster member list..."

ETCDCTL_API=3 etcdctl \
--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 \
member list -w table --endpoints=https://[10.1.1.201]:2379

输出以下:

=============================
+ etcd cluster member list...
+------------------+---------+--------+-------------------------+-------------------------+
|        ID        | STATUS  |  NAME  |       PEER ADDRS        |      CLIENT ADDRS       |
+------------------+---------+--------+-------------------------+-------------------------+
|  741ead392743e35 | started | podc02 | https://10.1.1.202:2380 | https://10.1.1.202:2379 |
| 72077d56570df47f | started | podc01 | https://10.1.1.201:2380 | https://10.1.1.201:2379 |
| dfc70cacefa4fbbb | started | podc04 | https://10.1.1.204:2380 | https://10.1.1.204:2379 |
| e3ecb8f6d5866785 | started | podc03 | https://10.1.1.203:2380 | https://10.1.1.203:2379 |
+------------------+---------+--------+-------------------------+-------------------------+

查看etcd集群成员状态:

# member list, local

echo ""
echo "========================="
echo "+ etcd cluster status... "

ETCDCTL_API=3 etcdctl \
--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 \
--endpoints=https://[10.1.1.201]:2379,https://[10.1.1.202]:2379,https://[10.1.1.203]:2379,https://[10.1.1.204]:2379 \
endpoint status -w table

输出以下:

=========================
+ etcd cluster status... 
+---------------------------+------------------+---------+---------+-----------+-----------+------------+
|         ENDPOINT          |        ID        | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+---------------------------+------------------+---------+---------+-----------+-----------+------------+
| https://[10.1.1.201]:2379 | 72077d56570df47f |  3.2.24 |  4.2 MB |      true |      1875 |     253980 |
| https://[10.1.1.202]:2379 |  741ead392743e35 |  3.2.24 |  4.2 MB |     false |      1875 |     253980 |
| https://[10.1.1.203]:2379 | e3ecb8f6d5866785 |  3.2.24 |  4.2 MB |     false |      1875 |     253980 |
| https://[10.1.1.204]:2379 | dfc70cacefa4fbbb |  3.2.24 |  4.2 MB |     false |      1875 |     253980 |
+---------------------------+------------------+---------+---------+-----------+-----------+------------+

3.8 修改etcd节点的api-server.yaml

修改/etc/kubernetes/manifests/api-server.yaml文件,以下:

#    - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
#    - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
#    - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
#    - --etcd-servers=https://127.0.0.1:2379

    - --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-servers=https://10.1.1.201:2379

将上面的新的etcd服务地址配置给kube-apiserver。

⚠️提示:

  • etcd集群要么一个节点,要么至少三个节点,能够对一个节点失败提供容错。
  • etcd集群若是只有两个节点,一个节点失败时,整个集群将没法访问,即便还有一个节点可用。

下一步:

  • 再配合keepalived的虚拟IP漂移功能,节点故障时主IP转移到子节点上的apiserver服务,并使用本地的etcd实例访问存储。
  • 此时,主节点的状态控制和调度功能在子节点上尚未,所以没法使用。
  • 还须要对kube-control-manager和kube-scheduler进行多节点部署,实现状态控制和调度功能的多节点迁移,便可完整实现容错机制。

参考:

相关文章
相关标签/搜索