首页
学习
活动
专区
圈层
工具
发布
50 篇文章
1
kubernetes与velero的第一次尝试
2
在Kubernetes中如何针对Namespace进行资源限制?
3
kubernetes之metrics-server安装与配置
4
kubernetes部署metrics-server
5
Kubernetes1.20.9摘掉一个master节点再重新加入(ETCD需要注意的)
6
Kubernetes 1.17.17升级到1.18.20
7
Kubernetes 1.18.20升级到1.19.12
8
Kubernetes 1.19.12升级到1.20.9(强调一下selfLink)
9
Kubernetes 1.16.15升级到1.17.17
10
使用 kainstall 工具一键部署 kubernetes 高可用集群
11
附034.Kubernetes_v1.21.0高可用部署架构二
12
附016.Kubernetes_v1.17.4高可用部署
13
附022.Kubernetes_v1.18.3高可用部署架构一
14
附024.Kubernetes_v1.18.3高可用部署架构二
15
使用 StatefulSet 部署 etcd 集群
16
Kubernetes 稳定性保障手册 -- 极简版
17
Linux(centos7)离现安装kubernetes1.19.2和docker——组件部分
18
docker register 私有仓库部署 - http模式
19
KubeSphere 开源 KubeEye:Kubernetes 集群自动巡检工具
20
K8S 中的 CPUThrottlingHigh 到底是个什么鬼?
21
全链路分布式跟踪系统 Apache SkyWalking 入门教程
22
pod Evicted的状态究竟是何人所为
23
使用 ezctl 工具部署和管理 Kubernetes 集群
24
Kubernetes部署策略详解
25
kubernetes容器探针检测
26
使用Spring Boot实现动态健康检查HealthChecks
27
真一文搞定 ingress-nginx 的使用
28
K8S备份、恢复、迁移神器 Velero
29
一次关于k8s kubectl top 和 contained ps 不一致的问题探究
30
kubernetes备份恢复之velero
31
使用 Velero 进行集群备份与迁移
32
TKE集群中nginx-ingress使用实践
33
使用velero进行kubernetes灾备
34
Kubernetes 映射外部服务
35
运维体系建设套路
36
k8s解决pod调度不均衡的问题
37
ingress中虚拟路径解决方案
38
容器下的两地三中心建设
39
k8s集群外的主机访问pod的解决方案
40
k8s基础-健康检查机制
41
k8s基础-标签使用
42
ingress-nginx请求改写
43
nginx ingress server alias 多域名多证书问题
44
JAVA | Java 解决跨域问题 花式解决跨域问题
45
如何通过ingress-nginx实现应用灰度发布?
46
在Kubernetes(k8s)中使用GPU
47
使用 Prometheus-Operator 监控 Calico
48
使用Kubespray部署Kubernetes集群
49
云原生下的CI/CD:Argo CD 详解,手把手教你入门
50
Pod的健康检查机制
清单首页k8s文章详情

使用 StatefulSet 部署 etcd 集群

上文我们简单介绍了 etcd 的基本概念和使用场景,本文就来介绍如何搭建 etcd 集群。在生产环境中,为了整个集群的高可用,etcd 正常都会以集群方式部署,避免单点故障。引导 etcd 集群的启动有以下三种机制:

  • 静态
  • etcd 动态发现
  • DNS 发现

静态启动 etcd 集群要求每个成员都知道集群中的另一个成员。在许多情况下,群集成员的 IP 可能未知,在这些情况下,可以在发现服务的帮助下引导 etcd 集群。

“可以使用官方提供的工具来生成 etcd 集群的配置:http://play.etcd.io/install ”

这里我们将主要介绍静态方式启动 etcd 集群。

安装

由于 etcd 是基于 raft 分布式协议的集群,所以如果要组成一个集群,集群的数量需要奇数台。如果只有一个节点的话我们也可以通过不同的端口来进行模拟,比如这里我们在一台机器上来安装一个3节点的 etcd 伪集群,对应的配置如下所示:

这里我们在一台 CentOS7 系统的节点上来进行演示,首先下载 etcd 二进制包,直接从 github release 页面下载对应的包即可:

代码语言:javascript
复制
$ wget https://github.com/etcd-io/etcd/releases/download/v3.4.13/etcd-v3.4.13-linux-amd64.tar.gz
$ tar -xvf etcd-v3.4.13-linux-amd64.tar.gz
$ mkdir /tmp/etcd 
$ mv etcd-v3.4.13-linux-amd64/etcd /tmp/etcd/
$ mv etcd-v3.4.13-linux-amd64/etcdctl /tmp/etcd

etcd 安装完成后,启动3个不同的终端分别执行下面的3个命令来启动 etcd 集群:

代码语言:javascript
复制
# 确保 etcd 进程对数据目录具有写访问权
# 如果集群是新集群,则删除该目录;如果重新启动则保留该目录

# 启动第一个节点
$ /tmp/etcd/etcd --name s1 \  # etcd 节点名称
  --data-dir /tmp/etcd/s1 \  # 数据存储目录 
  --listen-client-urls http://localhost:2379 \  # 本节点访问地址
  --advertise-client-urls http://localhost:2379 \  # 用于通知其他 ETCD 节点,客户端接入本节点的监听地址
  --listen-peer-urls http://localhost:2380 \  # 本节点与其他节点进行数据交换的监听地址
  --initial-advertise-peer-urls http://localhost:2380 \  # 通知其他节点与本节点进行数据交换的地址
  --initial-cluster s1=http://localhost:2380,s2=http://localhost:22380,s3=http://localhost:32380 \  # 集群所有节点配置
  --initial-cluster-token tkn \  # 集群唯一标识
  --initial-cluster-state new  # 节点初始化方式

# 启动第二个节点
$ /tmp/etcd/etcd --name s2 \
  --data-dir /tmp/etcd/s2 \
  --listen-client-urls http://localhost:22379 \
  --advertise-client-urls http://localhost:22379 \
  --listen-peer-urls http://localhost:22380 \
  --initial-advertise-peer-urls http://localhost:22380 \
  --initial-cluster s1=http://localhost:2380,s2=http://localhost:22380,s3=http://localhost:32380 \
  --initial-cluster-token tkn \
  --initial-cluster-state new

# 启动第三个节点
$ /tmp/etcd/etcd --name s3 \
  --data-dir /tmp/etcd/s3 \
  --listen-client-urls http://localhost:32379 \
  --advertise-client-urls http://localhost:32379 \
  --listen-peer-urls http://localhost:32380 \
  --initial-advertise-peer-urls http://localhost:32380 \
  --initial-cluster s1=http://localhost:2380,s2=http://localhost:22380,s3=http://localhost:32380 \
  --initial-cluster-token tkn \
  --initial-cluster-state new

正常启动完成后,我们可以使用 etcdctl 命令来查看集群的状态:

代码语言:javascript
复制
$ ETCDCTL_API=3 /tmp/etcd/etcdctl \
  --endpoints localhost:2379,localhost:22379,localhost:32379 \
  endpoint health
localhost:2379 is healthy: successfully committed proposal: took = 14.22105ms
localhost:22379 is healthy: successfully committed proposal: took = 13.058173ms
localhost:32379 is healthy: successfully committed proposal: took = 16.497453ms
$ ETCDCTL_API=3 /tmp/etcd/etcdctl \
  --endpoints localhost:2379,localhost:22379,localhost:32379 \ 
  endpoint status --write-out=table
+-----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|    ENDPOINT     |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|  localhost:2379 | 7339c4e5e833c029 |  3.4.13 |   20 kB |      true |      false |        43 |          9 |                  9 |        |
| localhost:22379 | 729934363faa4a24 |  3.4.13 |   20 kB |     false |      false |        43 |          9 |                  9 |        |
| localhost:32379 |  b548c2511513015 |  3.4.13 |   20 kB |     false |      false |        43 |          9 |                  9 |        |
+-----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

正常可以看到3个 etcd 节点都运行成功了,也可以查看当前集群的 LEADER 节点。如果这个时候我们把 2379 端口的进程杀掉,再来查看集群的状态:

代码语言:javascript
复制
$ ETCDCTL_API=3 /tmp/etcd/etcdctl   --endpoints localhost:2379,localhost:22379,localhost:32379  endpoint status --write-out=table
{"level":"warn","ts":"2020-11-16T14:39:25.024+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"passthrough:///localhost:2379","attempt":0,"error":"rpc error: code = DeadlineExceeded desc = latest balancer error: connection error: desc = \"transport: Error while dialing dial tcp [::1]:2379: connect: connection refused\""}
Failed to get the status of endpoint localhost:2379 (context deadline exceeded)
+-----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|    ENDPOINT     |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| localhost:22379 | 729934363faa4a24 |  3.4.13 |   20 kB |      true |      false |        44 |         10 |                 10 |        |
| localhost:32379 |  b548c2511513015 |  3.4.13 |   20 kB |     false |      false |        44 |         10 |                 10 |        |
+-----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

可以看到现在集群中只有两个节点,但是现在集群还是可以正常使用的,因为我们一共3个节点,现在还有超过一一半的节点正常,那么集群就是正常的,当然如果我们再关闭一个节点那么我们集群就将处于不健康的状态下了。

参数说明

上面我们成功搭建了 etcd 的集群,etcd 在启动过程中有很多参数可以配置,这里我们就先来对这些参数进行一个简单的说明。

  • --name :节点名称 默认值:default 环境变量:ETCD_NAME 说明:这个值和 --initial-cluster 参数中的 key 值一一对应,如果在集群环境中,name 必须是唯一的,建议用主机名称或者机器 ID。
  • --data-dir:数据存储目录 默认值:${name}.etcd 环境变量:ETCD_DATA_DIR
  • --wal-dir:存放预写日志目录 默认值:"" 环境变量:ETCD_WAL_DIR 说明:最大的作用是记录了整个数据变化的全部历程,如果未配置则共用 --data-dir 文件所在目录。
  • --snapshot-count:数据快照触发数量 默认值:100000 环境变量:ETCD_SNAPSHOT_COUNT 说明:etcd 处理指定次数的事务提交后,生产数据快照
  • --heartbeat-interval:客户端连接后的心跳间隔(毫秒) 默认值:100 环境变量:ETCD_HEARTBEAT_INTERVAL
  • --election-timeout**:**集群选举的超时时间 默认值:1000 环境变量:ETCD_ELECTION_TIMEOUT
  • --max-snapshots:最大快照数量,0表示不限制 默认值:5 环境变量:ETCD_MAX_SNAPSHOTS
  • --max-wals:最大预写日志数量,0表示不限制 默认值:5 环境变量:ETCD_MAX_WAL
  • --listen-peer-urls:本节点使用,用于监听其他节点发送信息的地址,地址写法是 scheme://IP:port 默认值:http://localhost:2380 环境变量:ETCD_LISTEN_PEER_URL 示例:http://10.0.0.1:2380 无效的示例:http://example.com:2380 (域名对绑定无效)
  • --listen-client-urls:本节点使用,用于 etcd 客户端通信的 url,写法是 scheme://IP:port,可以多个并用逗号隔开 默认值:http://localhost:2379 示例:http://10.0.0.1:2379 无效的示例:http://example.com:2379 (域名对绑定无效)
  • --initial-advertise-peer-urls:其他节点通过该地址与本节点进行数据交换(选举,同步)的地址,URL 可以使用域名地址 默认值:http://localhost:2380 环境变量:ETCD_INITIAL_ADVERTISE_PEER_URL 说明:与 --listener-peer-urls 不同在于 listener-peer-urls 用于请求客户端的接入控制,initial-advertise-peer-urls 是告知其他集群节点访问哪个 URL,一般来说,initial-advertise-peer-urlsl 将是 listene-peer-urls 的子集。静态配置方式下,该参数值一定要同时在 --initial-cluster 参数中存在
  • --advertise-client-urls :用于通知其他 ETCD 节点,客户端接入本节点的监听地址,一般来说 advertise-client-urls 是 listen-client-urls 子集 默认值:http://localhost:2379 环境变量:ETCD_ADVERTISE_CLIENT_URL
  • --initial-cluster :集群所有节点配置,多个用逗号隔开 默认值:http://localhost:2380 环境变量:ETCD_INITIAL_CLUSTER 说明:key 是所提供的每个节点的 --name 标志的值
  • --initial-cluster-state :节点初始化方式 默认值:new 环境变量:ETCD_INITIAL_CLUSTER_STATE 说明:new 表示如果没有集群不存在,创建新集群,existing 表示如果集群不存在,节点将处于加入集群失败状态。
  • --initial-cluster-token :集群唯一标识 默认值:etcd-cluster 环境变量:ETCD_INITIAL_CLUSTER_TOKEN 说明:相同标识的节点将视为在一个集群内

在 Kubernetes 集群中部署

我们现在了解了 etcd 集群的基本搭建方式,那么我们应该如何将其运行到 Kubernetes 集群中呢?毕竟我们是要来编写 Operator 的,所以我们肯定需要先知道怎么能够在 Kubernetes 集群中运行起来。

这里我们可以使用 StatefulSet 这个控制器来运行 etcd 集群,etcd 集群的编排的资源清单文件我们可以使用 Kubernetes 源码中提供的,位于目录:test/e2e/testing-manifests/statefulset/etcd 下面。

代码语言:javascript
复制
$ ls -la test/e2e/testing-manifests/statefulset/etcd  
total 40
drwxr-xr-x   6 ych  staff   192 Jun 18  2019 .
drwxr-xr-x  10 ych  staff   320 Oct 10  2018 ..
-rw-r--r--   1 ych  staff   173 Oct 10  2018 pdb.yaml
-rw-r--r--   1 ych  staff   242 Oct 10  2018 service.yaml
-rw-r--r--   1 ych  staff  6441 Jun 18  2019 statefulset.yaml
-rw-r--r--   1 ych  staff   550 Oct 10  2018 tester.yaml

其中 service.yaml 文件中就是一个用户 StatefulSet 使用的 headless service:

代码语言:javascript
复制
apiVersion: v1
kind: Service
metadata:
  name: etcd
  labels:
    app: etcd
spec:
  ports:
  - port: 2380
    name: etcd-server
  - port: 2379
    name: etcd-client
  clusterIP: None
  selector:
    app: etcd
  publishNotReadyAddresses: true

pdb.yaml 文件是用来保证 etcd 的高可用的一个 PodDisruptionBudget 资源对象:

代码语言:javascript
复制
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: etcd-pdb
  labels:
    pdb: etcd
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: etcd

最重要的当然是 statefulset.yaml 文件,但是这个文件有很多 bug,比如在上面参数配置的时候我们就提到过 --listen-peer-urls 和 --listen-client-urls 这两个参数的值是不支持域名的绑定形式的,而这里使用的 http://{HOSTNAME}.{SET_NAME} 这个 FQDN 形式的域名,所以启动失败了,我们需要将其修改为 IP 的形式,要获取 Pod 的 IP 地址也很简单,我们可以通过 Kubernetes 提供的 Downward API 来注入一个 POD_IP 的环境变量来获取,然后将这两个参数值改成 http://

代码语言:javascript
复制
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app: etcd
  name: etcd
spec:
  replicas: 3
  selector:
    matchLabels:
      app: etcd
  serviceName: etcd
  template:
    metadata:
      labels:
        app: etcd
    spec:
      containers:
        - name: etcd
          image: cnych/etcd:v3.4.13
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 2380
            name: peer
            protocol: TCP
          - containerPort: 2379
            name: client
            protocol: TCP
          env:
          - name: INITIAL_CLUSTER_SIZE
            value: "3"
          - name: MY_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          - name: POD_IP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
          - name: SET_NAME
            value: "etcd"
          command:
            - /bin/sh
            - -ec
            - |
              HOSTNAME=$(hostname)

              ETCDCTL_API=3

              eps() {
                  EPS=""
                  for i in $(seq 0 $((${INITIAL_CLUSTER_SIZE} - 1))); do
                      EPS="${EPS}${EPS:+,}http://${SET_NAME}-${i}.${SET_NAME}.${MY_NAMESPACE}.svc.cluster.local:2379"
                  done
                  echo ${EPS}
              }

              member_hash() {
                  etcdctl member list | grep -w "$HOSTNAME" | awk '{ print $1}' | awk -F "," '{ print $1}'
              }

              initial_peers() {
                  PEERS=""
                  for i in $(seq 0 $((${INITIAL_CLUSTER_SIZE} - 1))); do
                    PEERS="${PEERS}${PEERS:+,}${SET_NAME}-${i}=http://${SET_NAME}-${i}.${SET_NAME}.${MY_NAMESPACE}.svc.cluster.local:2380"
                  done
                  echo ${PEERS}
              }

              # etcd-SET_ID
              SET_ID=${HOSTNAME##*-}

              # adding a new member to existing cluster (assuming all initial pods are available)
              if [ "${SET_ID}" -ge ${INITIAL_CLUSTER_SIZE} ]; then
                  # export ETCDCTL_ENDPOINTS=$(eps)
                  # member already added?

                  MEMBER_HASH=$(member_hash)
                  if [ -n "${MEMBER_HASH}" ]; then
                      # the member hash exists but for some reason etcd failed
                      # as the datadir has not be created, we can remove the member
                      # and retrieve new hash
                      echo "Remove member ${MEMBER_HASH}"
                      etcdctl --endpoints=$(eps) member remove ${MEMBER_HASH}
                  fi

                  echo "Adding new member"

                  echo "etcdctl --endpoints=$(eps) member add ${HOSTNAME} --peer-urls=http://${HOSTNAME}.${SET_NAME}.${MY_NAMESPACE}.svc.cluster.local:2380"
                  etcdctl member --endpoints=$(eps) add ${HOSTNAME} --peer-urls=http://${HOSTNAME}.${SET_NAME}.${MY_NAMESPACE}.svc.cluster.local:2380 | grep "^ETCD_" > /var/run/etcd/new_member_envs

                  if [ $? -ne 0 ]; then
                      echo "member add ${HOSTNAME} error."
                      rm -f /var/run/etcd/new_member_envs
                      exit 1
                  fi

                  echo "==> Loading env vars of existing cluster..."
                  sed -ie "s/^/export /" /var/run/etcd/new_member_envs
                  cat /var/run/etcd/new_member_envs
                  . /var/run/etcd/new_member_envs

                  echo "etcd --name ${HOSTNAME} --initial-advertise-peer-urls ${ETCD_INITIAL_ADVERTISE_PEER_URLS} --listen-peer-urls http://${POD_IP}:2380 --listen-client-urls http://${POD_IP}:2379,http://127.0.0.1:2379 --advertise-client-urls http://${HOSTNAME}.${SET_NAME}.${MY_NAMESPACE}.svc.cluster.local:2379 --data-dir /var/run/etcd/default.etcd --initial-cluster ${ETCD_INITIAL_CLUSTER} --initial-cluster-state ${ETCD_INITIAL_CLUSTER_STATE}"

                  exec etcd --listen-peer-urls http://${POD_IP}:2380 \
                      --listen-client-urls http://${POD_IP}:2379,http://127.0.0.1:2379 \
                      --advertise-client-urls http://${HOSTNAME}.${SET_NAME}.${MY_NAMESPACE}.svc.cluster.local:2379 \
                      --data-dir /var/run/etcd/default.etcd
              fi

              for i in $(seq 0 $((${INITIAL_CLUSTER_SIZE} - 1))); do
                  while true; do
                      echo "Waiting for ${SET_NAME}-${i}.${SET_NAME}.${MY_NAMESPACE}.svc.cluster.local to come up"
                      ping -W 1 -c 1 ${SET_NAME}-${i}.${SET_NAME}.${MY_NAMESPACE}.svc.cluster.local > /dev/null && break
                      sleep 1s
                  done
              done

              echo "join member ${HOSTNAME}"
              # join member
              exec etcd --name ${HOSTNAME} \
                  --initial-advertise-peer-urls http://${HOSTNAME}.${SET_NAME}.${MY_NAMESPACE}.svc.cluster.local:2380 \
                  --listen-peer-urls http://${POD_IP}:2380 \
                  --listen-client-urls http://${POD_IP}:2379,http://127.0.0.1:2379 \
                  --advertise-client-urls http://${HOSTNAME}.${SET_NAME}.${MY_NAMESPACE}.svc.cluster.local:2379 \
                  --initial-cluster-token etcd-cluster-1 \
                  --data-dir /var/run/etcd/default.etcd \
                  --initial-cluster $(initial_peers) \
                  --initial-cluster-state new
          lifecycle:
            preStop:
              exec:
                command:
                  - /bin/sh
                  - -ec
                  - |
                    HOSTNAME=$(hostname)

                    member_hash() {
                        etcdctl member list | grep -w "$HOSTNAME" | awk '{ print $1}' | awk -F "," '{ print $1}'
                    }

                    eps() {
                        EPS=""
                        for i in $(seq 0 $((${INITIAL_CLUSTER_SIZE} - 1))); do
                            EPS="${EPS}${EPS:+,}http://${SET_NAME}-${i}.${SET_NAME}.${MY_NAMESPACE}.svc.cluster.local:2379"
                        done
                        echo ${EPS}
                    }

                    export ETCDCTL_ENDPOINTS=$(eps)
                    SET_ID=${HOSTNAME##*-}

                    # Removing member from cluster
                    if [ "${SET_ID}" -ge ${INITIAL_CLUSTER_SIZE} ]; then
                        echo "Removing ${HOSTNAME} from etcd cluster"
                        etcdctl member remove $(member_hash)
                        if [ $? -eq 0 ]; then
                            # Remove everything otherwise the cluster will no longer scale-up
                            rm -rf /var/run/etcd/*
                        fi
                    fi
          volumeMounts:
          - mountPath: /var/run/etcd
            name: datadir
  volumeClaimTemplates:
  - metadata:
      name: datadir
    spec:
      accessModes:
      - "ReadWriteOnce"
      resources:
        requests:
          # upstream recommended max is 700M
          storage: 1Gi

修改完成后,我们在 Kubernetes 集群中创建上面的几个资源对象:

代码语言:javascript
复制
➜  etcd git:(1e11e4a2108) ✗ kubectl apply -f pdb.yaml                             
poddisruptionbudget.policy/etcd-pdb created
➜  etcd git:(1e11e4a2108) ✗ kubectl apply -f service.yaml 
service/etcd created
➜  etcd git:(1e11e4a2108) ✗ kubectl apply -f statefulset.yaml 
statefulset.apps/etcd created
➜  etcd git:(1e11e4a2108) ✗ kubectl get pods -l app=etcd     
NAME     READY   STATUS    RESTARTS   AGE
etcd-0   1/1     Running   0          5m35s
etcd-1   1/1     Running   0          5m12s
etcd-2   1/1     Running   0          4m51s

“需要注意上面的 StatefulSet 需要3个可用的 1G 容量 ReadWriteOnce 模式的 PV ”

现在我们可以看到 etcd 集群就启动成功了,同样我们可以查看集群现在的状态:

代码语言:javascript
复制
➜  etcd git:(1e11e4a2108) ✗ kubectl exec -it etcd-0 /bin/sh                                                                          
# etcdctl --endpoints etcd-0.etcd:2379,etcd-1.etcd:2379,etcd-2.etcd:2379 endpoint status --write-out=table
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|     ENDPOINT     |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| etcd-0.etcd:2379 | 2e80f96756a54ca9 |  3.4.13 |   20 kB |      true |      false |         2 |          9 |                  9 |        |
| etcd-1.etcd:2379 | 7fd61f3f79d97779 |  3.4.13 |   20 kB |     false |      false |         2 |          9 |                  9 |        |
| etcd-2.etcd:2379 | b429c86e3cd4e077 |  3.4.13 |   20 kB |     false |      false |         2 |          9 |                  9 |        |
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

我们可以尝试去删除其中一个 Pod 来验证集群是否正常,Pod 重建后是否还可以加入到集群中去。比如我们执行下面的命令将集群扩容到5个副本:

代码语言:javascript
复制
➜  etcd git:(1e11e4a2108) ✗ kubectl scale --replicas=5 statefulset etcd
➜  etcd git:(1e11e4a2108) ✗ kubectl get pods -l app=etcd               
NAME     READY   STATUS    RESTARTS   AGE
etcd-0   1/1     Running   0          5m59s
etcd-1   1/1     Running   0          5m52s
etcd-2   1/1     Running   0          5m47s
etcd-3   1/1     Running   0          4m
etcd-4   1/1     Running   1          3m55s

此时我们再去查看集群的状态:

代码语言:javascript
复制
➜  etcd git:(1e11e4a2108) ✗ kubectl exec -it etcd-0 /bin/sh            
# etcdctl --endpoints etcd-0.etcd:2379,etcd-1.etcd:2379,etcd-2.etcd:2379,etcd-3.etcd:2379,etcd-4.etcd:2379 endpoint status --write-out=table
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|     ENDPOINT     |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| etcd-0.etcd:2379 | c799a6ef06bc8c14 |  3.4.13 |   20 kB |     false |      false |        16 |         13 |                 13 |        |
| etcd-1.etcd:2379 | 9869f0647883a00d |  3.4.13 |   20 kB |      true |      false |        16 |         13 |                 13 |        |
| etcd-2.etcd:2379 | 42c8b94265b9b79a |  3.4.13 |   20 kB |     false |      false |        16 |         13 |                 13 |        |
| etcd-3.etcd:2379 | 41eec5480dc0d9ec |  3.4.13 |   20 kB |     false |      false |        16 |         13 |                 13 |        |
| etcd-4.etcd:2379 | ebbc833cba01ecad |  3.4.13 |   20 kB |     false |      false |        16 |         13 |                 13 |        |
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

当然同样也可以去对其进行缩容操作:

代码语言:javascript
复制
➜  etcd git:(1e11e4a2108) ✗ kubectl scale --replicas=3 statefulset etcd
statefulset.apps/etcd scaled
➜  etcd git:(1e11e4a2108) ✗ kubectl get pods -l app=etcd               
NAME     READY   STATUS    RESTARTS   AGE
etcd-0   1/1     Running   0          11m
etcd-1   1/1     Running   0          28s
etcd-2   1/1     Running   0          23s
➜  etcd git:(1e11e4a2108) ✗ kubectl exec -it etcd-0 /bin/sh            
# etcdctl --endpoints etcd-0.etcd:2379,etcd-1.etcd:2379,etcd-2.etcd:2379 endpoint status --write-out=table
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|     ENDPOINT     |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| etcd-0.etcd:2379 | 2e80f96756a54ca9 |  3.4.13 |   20 kB |      true |      false |       139 |         23 |                 23 |        |
| etcd-1.etcd:2379 | 7fd61f3f79d97779 |  3.4.13 |   20 kB |     false |      false |       139 |         23 |                 23 |        |
| etcd-2.etcd:2379 | b429c86e3cd4e077 |  3.4.13 |   20 kB |     false |      false |       139 |         23 |                 23 |        |
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

现在又变回我们的集群模式了。

下一篇
举报
领券