etcd 集群运维实践

栏目: 服务器 · 发布时间: 7年前

内容简介:etcd 是```shellIP=123.123.123.123

etcd 是 Kubernetes 集群的数据核心,最严重的情况是,当 etcd 出问题彻底无法恢复的时候,解决问题的办法可能只有重新搭建一个环境。因此围绕 etcd 相关的运维知识就比较重要。etcd 可以容器化部署,也可以在宿主机自行搭建,以下内容是通用的。

集群的备份和恢复

添加备份

```shell

!/bin/bash

IP=123.123.123.123

BACKUP_DIR=/alauda/etcd_bak/

mkdir -p $BACKUP_DIR

export ETCDCTL_API=3

etcdctl --endpoints=http://$IP:2379 snapshot save $BACKUP/snap-$(date +%Y%m%d%H%M).db

备份一个节点的数据就可以恢复,实践中,为了防止定时任务配置的节点异常没有生成备份,建议多加几个

```

恢复集群

```shell

!/bin/bash

使用 etcdctl snapshot restore 生成各个节点的数据

比较关键的变量是

--data-dir 需要是实际 etcd 运行时的数据目录

--name --initial-advertise-peer-urls 需要用各个节点的配置

--initial-cluster initial-cluster-token 需要和原集群一致

ETCD_1=10.1.0.5

ETCD_2=10.1.0.6

ETCD_3=10.1.0.7

for i in ETCD_1 ETCD_2 ETCD_3

do

export ETCDCTL_API=3

etcdctl snapshot restore snapshot.db \

--data-dir=/var/lib/etcd \

--name $i \

--initial-cluster ${ETCD_1}=http://${ETCD_1}:2380,${ETCD_2}=http://${ETCD_2}:2380,${ETCD_3}=http://${ETCD_3}:2380 \

--initial-cluster-token k8s_etcd_token \

--initial-advertise-peer-urls http://$i:2380 && \

mv /var/lib/etcd/ etcd_$i

done

把 etcd_10.1.0.5 复制到 10.1.0.5节点,覆盖/var/lib/etcd(同--data-dir路径)

其他节点依次类推

```

用etcd自动创建的snapdb恢复

```shell

!/bin/bash

export ETCDCTL_API=3

etcdctl snapshot restore snapshot.db \

--skip-hash-check \

--data-dir=/var/lib/etcd \

--name 10.1.0.5 \

--initial-cluster 10.1.0.5= http://10.1.0.5:2380 ,10.1.0.6= http://10.1.0.6:2380 ,10.1.0.7= http://10.1.0.7:2380 \

--initial-cluster-token k8s_etcd_token \

--initial-advertise-peer-urls http://10.1.0.5:2380

也是所有节点都需要生成自己的数据目录,参考上一条

和上一条命令唯一的差别是多了 --skip-hash-check (跳过完整性校验)

这种方式不能确保 100% 可恢复,建议还是自己加备份

通常恢复后需要做一下数据压缩和碎片整理,可参考相应章节

```

etcd运行期间,会自动的生成snapdb(数据目录里的 db)和上一条命令唯一的差别是多了 --skip-hash-check 需要跳过完整性校验,不过这种方式不能确保 100% 可恢复,虽然我拿它救了7 8 个环境回来,但还是强烈建议自己加。

通常恢复后需要做一下数据压缩和碎片整理,可参考后面相应的章节。

踩过的坑

[ 3.0.14版 etcd restore 功能不可用 ] https://github.com/etcd-io/etcd/issues/7533

使用更新的 etcd 即可。

总结:恢复就是要拿 db 去把 etcd 的数据生成一份,用同一个节点的,可以保证除了 restore 时候指定的参数外,所有数据都一样。这就是用一份 db,操作三次(或者5次)的原因。

集群的扩容

从1到3

  1. 执行添加
    ```shell

    !/bin/bash

    export ETCDCTL_API=2
    etcdctl --endpoints= http://10.1.0.6:2379 member add 10.1.0.6 http://10.1.0.6:2380
    etcdctl --endpoints= http://10.1.0.7:2379 member add 10.1.0.7 http://10.1.0.7:2380

    ETCD_NAME="etcd_10.1.0.6"

    ETCD_INITIAL_CLUSTER="10.1.0.6= http://10.1.0.6:2380 ,10.1.0.5= http://10.1.0.5:2380"

    ETCD_INITIAL_CLUSTER_STATE="existing"

    ```
    从 1 到 3 期间,会经过集群是两节点的状态,这时候可能集群的表现就像挂了,不能访问的endpoint status 这些命令都不能用,所以我们需要用member add先把集群扩到三节点,然后再依次启动etcd实例,这样做就能确保etcd 就是健康的。
  2. 准备添加的节点 etcd 参数配置
    ```shell

    !/bin/bash

    /usr/local/bin/etcd
    --data-dir=/data.etcd
    --name 10.1.0.6
    --initial-advertise-peer-urls http://10.1.0.6:2380
    --listen-peer-urls http://10.1.0.6:2380
    --advertise-client-urls http://10.1.0.6:2379
    --listen-client-urls http://10.1.0.6:2379
    --initial-cluster 10.1.0.6= http://10.1.0.6:2380 ,10.1.0.5= http://10.1.0.5:2380
    --initial-cluster-state exsiting
    --initial-cluster-token k8s_etcd_token

    --initial-cluster 集群所有节点的 name=ip:peer_url

    --initial-cluster-state exsiting 告诉 etcd 自己归属一个已存在的集群,不要自立门户

    ```
    从 1 到 3 期间,会经过集群是两节点的状态,这时候可能集群的表现就像挂了,endpoint status 这些命令都不能用,所以我们需要用member add先把集群扩到三节点,然后再依次启动etcd实例,这样做就能确保 etcd 就是健康的。从3到更多,其实还是member add。

集群加证书

生成证书

shell

curl -s -L -o /usr/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64

curl -s -L -o /usr/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64

chmod +x /usr/bin/{cfssl,cfssljson}

cd /etc/kubernetes/pki/etcd
json

cat ca-config.json

{

"signing": {

"default": {

"expiry": "100000h"

},

"profiles": {

"server": {

"usages": ["signing", "key encipherment", "server auth", "client auth"],

"expiry": "100000h"

},

"client": {

"usages": ["signing", "key encipherment", "server auth", "client auth"],

"expiry": "100000h"

}

}

}

}

json

cat ca-csr.json

{

"CN": "etcd",

"key": {

"algo": "rsa",

"size": 4096

},

"names": [

{

"C": "CN",

"L": "Beijing",

"O": "Alauda",

"OU": "PaaS",

"ST": "Beijing"

}

]

}

json

cat server-csr.json

{

"CN": "etcd-server",

"hosts": [

"localhost",

"0.0.0.0",

"127.0.0.1",

"所有master 节点ip ",

"所有master 节点ip ",

"所有master 节点ip "

],

"key": {

"algo": "rsa",

"size": 4096

},

"names": [

{

"C": "CN",

"L": "Beijing",

"O": "Alauda",

"OU": "PaaS",

"ST": "Beijing"

}

]

}

```json

cat client-csr.json

{

"CN": "etcd-client",

"hosts": [

""

],

"key": {

"algo": "rsa",

"size": 4096

},

"names": [

{

"C": "CN",

"L": "Beijing",

"O": "Alauda",

"OU": "PaaS",

"ST": "Beijing"

}

]

}

```

```bash

cd /etc/kubernetes/pki/etcd

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-csr.json | cfssljson -bare server

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client client-csr.json | cfssljson -bare client

```

参考链接: https://lihaoquan.me/2017/3/29 ... .html

首先更新节点的peer-urls

shell

export ETCDCTL_API=3

etcdctl --endpoints=http://x.x.x.x:2379 member list

   #  1111111111  ..........

   #  2222222222  ..........

   #  3333333333  ..........

etcdctl --endpoints=http://172.30.0.123:2379 member update 1111111111 --peer-urls=https://x.x.x.x:2380

   # 执行三次把三个节点的peer-urls都改成https

修改配置

```shell

vim /etc/kubernetes/main*/etcd.yaml

etcd启动命令部分修改 http 为 https,启动状态改成 existing

- --advertise-client-urls= https://x.x.x.x:2379

- --initial-advertise-peer-urls= https://x.x.x.x:2380

- --initial-cluster=xxx= https://x.x.x.x:2380 ,xxx= https://x.x.x.x:2380 ,xxx= https://x.x.x.x:2380

- --listen-client-urls= https://x.x.x.x:2379

- --listen-peer-urls= https://x.x.x.x:2380

- --initial-cluster-state=existing

etcd 启动命令部分插入

- --cert-file=/etc/kubernetes/pki/etcd/server.pem

- --key-file=/etc/kubernetes/pki/etcd/server-key.pem

- --peer-cert-file=/etc/kubernetes/pki/etcd/server.pem

- --peer-key-file=/etc/kubernetes/pki/etcd/server-key.pem

- --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem

- --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem

- --peer-client-cert-auth=true

- --client-cert-auth=true

检索hostPath在其后插入

- hostPath:

path: /etc/kubernetes/pki/etcd

type: DirectoryOrCreate

name: etcd-certs

检索mountPath在其后插入

- mountPath: /etc/kubernetes/pki/etcd

name: etcd-certs

```

shell

vim /etc/kubernetes/main*/kube-apiserver.yaml

apiserver 启动部分插入,修改 http 为https

- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.pem

- --etcd-certfile=/etc/kubernetes/pki/etcd/client.pem

- --etcd-keyfile=/etc/kubernetes/pki/etcd/client-key.pem

- --etcd-servers=https://x.x.x.x:2379,https://x.x.x.x:2379,https://x.x.x.x:2379

总结下就是,先准备一套证书。然后修改 etcd 内部通信地址为https,这时候etcd日志会报错(可以忽略),然后用etcd --带证书的参数启动,把所有链接etcd的地方都用上证书,即可。

遇到的坑

[ etcd加证书后,apiserver的健康检查还是http请求,etcd会一直刷日志 ]

https://github.com/etcd-io/etcd/issues/9285

verilog

2018-02-06 12:41:06.905234 I | embed: rejected connection from "127.0.0.1:35574" (error "EOF", ServerName "")

解决办法:直接去掉apiserver的健康检查,或者把默认的检查命令换成curl (apiserver的镜像里应该没有curl,如果是刚需的话自己重新build一下吧 )

集群升级

已经是 v3 的的集群不需要太多的配置,保留数据目录,替换镜像(或者二进制)即可;

v2到v3的升级需要一个merge的操作,我并没有实际的实践过,也不太推荐这样做。

集群状态检查

其实上述所有步骤都需要这些命令的辅助——

```shell

!/bin/bash

如果证书的话,去掉--cert --key --cacert 即可

--endpoints= 需要写了几个节点的url,endpoint status就输出几条信息

export ETCDCTL_API=3

etcdctl \

--endpoints= https://x.x.x.x:2379 \

--cert=/etc/kubernetes/pki/etcd/client.pem \

--key=/etc/kubernetes/pki/etcd/client-key.pem \

--cacert=/etc/kubernetes/pki/etcd/ca.pem \

endpoint status -w table

etcdctl --endpoints=xxxx endpoint health

etcdctl --endpoints=xxxx member list

kubectl get cs

```

数据操作(删除、压缩、碎片整理)

删除

```shell

ETCDCTL_API=2 etcdctl rm --recursive # v2 的 api 可以这样删除一个“目录”

ETCDCTL_API=3 etcdctl --endpoints=xxx del /xxxxx --prefix # v3 的版本

带证书的话,参考上一条添加 --cert --key --cacert 即可

```

遇到的坑:在一个客户环境里发现Kubernetes集群里的 “事件” 超级多,就是 kubectl describe xxx 看到的events部分信息,数据太大导致 etcd 跑的很累,我们就用这样的方式删掉没用的这些数据。

碎片整理

shell

ETCDCTL_API=3 etcdctl --endpoints=xx:xx,xx:xx,xx:xx defrag

ETCDCTL_API=3 etcdctl --endpoints=xx:xx,xx:xx,xx:xx endpoint status # 看数据量

压缩

```shell

ETCDCTL_API=3 etcdctl --endpoints=xx:xx,xx:xx,xx:xx compact

这个在只有 K8s 用的 etcd 集群里作用不太大,可能具体场景我没遇到

可参考这个文档

https://www.cnblogs.com/davygeek/p/8524477.html

不过跑一下不碍事

etcd --auto-compaction-retention=1

添加这个参数让 etcd 运行时自己去做压缩

```

常见问题

context deadline exceeded

日志收集

etcd 的日志暂时只支持 syslog 和 stdout 两种—— https://github.com/etcd-io/etcd/issues/7936

etcd 的日志在排查故障时很有用,如果我们用宿主机来部署 etcd,日志可以通过 systemd 检索到,但kubeadm 方式启动的 etcd 在容器重启后就会丢失所有历史。我们可以用以下的方案来做——

  1. shell 的重定向
    shell
    
    etcd --xxxx --xxxx   >  /var/log/etcd.log 
    
    

    配合 logratate 来做日志切割

    将日志通过 volume 挂载到宿主机

  2. supervisor
    supervisor 从容器刚开始流行时,就是保持服务持续运行很有效的工具
  3. sidecar 容器(后续我在github上补充一个例子,github.com/jing2uo)
    sidecar可以简单理解为一个pod里有多个容器(比如kubedns)他们彼此可以看到对方的进程,因此我们可以用传统的 strace 来捕捉 etcd进程的输出,然后在sidecar这个容器里和 shell 重定向一样操作。
    strace -e trace=write -s 200 -f -p 1

kubeadm 1.13部署的集群

最近我们测试kubernetes 1.13集群时发现了一些有趣的改变,诈一看我们上面的命令就没法用了——

https://kubernetes.io/docs/set ... logy/

区分了 Stacked etcd topologyExternal etcd topology ,官方的链接了这个图很形象——

etcd 集群运维实践

这种模式下的 etcd 集群,最明显的差别是容器内 etcd 的initial-cluster 启动参数只有自己的 ip,会有点懵挂了我这该怎么去恢复。其实基本原理没有变,kubeadm 藏了个 configmap,启动参数被放在了这里 ——

shell

kubectl get cm  etcdcfg -n kube-system -o yaml
yaml

    etcd:

      local:

        serverCertSANs:

        - "192.168.8.21"

        peerCertSANs:

        - "192.168.8.21"

        extraArgs:

          initial-cluster: 192.168.8.21=https://192.168.8.21:2380,192.168.8.22=https://192.168.8.22:2380,192.168.8.20=https://192.168.8.20:2380

          initial-cluster-state: new

          name: 192.168.8.21

          listen-peer-urls: https://192.168.8.21:2380

          listen-client-urls: https://192.168.8.21:2379

          advertise-client-urls: https://192.168.8.21:2379

          initial-advertise-peer-urls: https://192.168.8.21:2380

Q&A:

Q1:请问etcd监控和告警如何做的?告警项都有哪些?

A1:告警要看用的什么监控吧,和k8s配套比较常见的是普罗米修思和grafana咯。告警项我没有具体配过,可以关注的点是:endpoint status -w table 里可以看到数据量,endpoints health看到健康状态,还有内存使用这些,具体可以参考普罗米修思的exporter是怎么做的。

Q2:使用kubeadm部署高可用集群是不是相当于先部署三个独立的单点master,最后靠etcd添加节点操作把数据打通?

A2:不是,kubeadm部署会在最开始就先建一个etcd集群,apiserver启动之前就需要准备好etcd,否则apiserver起不了,集群之间就没法通信。可以尝试手动搭一下集群,不用kubeadm,一个个把组件开起来,之后对 k8s 的组件关系会理解更好的。

Q3:etcd跨机房高可用如何保证呢?管理etcd有好的ui工具推荐么?

A3:etcd对时间和网络要求很高,所以跨机房的网络不好的话性能很差,光在那边选 请输入链接描述 举去了。我分享忘了提一个etcd 的mirror,可以去参考下做法。跨机房的话,我觉得高速网络是个前提吧,不过还没做过。ui工具没找过,都是命令行操作来着。

Q4:kubeadm启动的集群内etcd节点,kubectl操作etcd的备份恢复有尝试过吗?

A4:没有用kubectl去处理过etcd的备份恢复。etcd的恢复依赖用snapdb生成数据目录,把etcd进程丢进容器里,类似的操作避免不了,还有启动的状态需要修改。kubeadm 启动的etcd 可以通过kubectl 查询和exec,但是数据操作应该不可以,比如恢复etcd ing时,无法连接etcd,kubectl还怎么工作?

Q5:kubeadm-ha启动3个master,有3个etcd节点,怎么跟集群外的3个etcd做集群,做成3master 6etcd

A5: 可以参考文档里的扩容部分,只要保证etcd的参数正确,即使一个集群一部分容器化,一部分宿主机,都是可以的(当然不建议这么做)。可以先用kubeadm搭一个集群,然后用扩容的方式把其他三个节点加进来,或者在kubeadm操作之前,先搭一个etcd集群。然后kubeadm调用它就可以。

Q6:有没有试过kubeadm的滚动升级,etcd版本变更,各master机分别重启,数据同步是否有异常等等?

A6:做过。kubeadm的滚动升级公司内部有从1.7一步步升级到1.11、1.12的文档,或多或少有一点小坑,不过今天主题是etcd所以没提这部分。各个master分别重启后数据的一致我们测试时没问题,还有比较极端的是直接把三master停机一天,再启动后也能恢复。

联系我

文档实践过程中 google 了大量文档和教程,整理时我尽量找了印象深刻的文档的历史补充进来,但时间过去了很久不可能搜集完整,如果发现某部分内容侵犯了版权,可以联系我删除内容或者补充参考链接。若文档表述或者知识点有问题,也请指出,我修正后避免误导更多人。

github: jing2uo

email: hipkomh@gmail.com

本文长期repo: https://github.com/jing2uo/etcd-wiki 欢迎来提 issue


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Machine Learning in Action

Machine Learning in Action

Peter Harrington / Manning Publications / 2012-4-19 / GBP 29.99

It's been said that data is the new "dirt"—the raw material from which and on which you build the structures of the modern world. And like dirt, data can seem like a limitless, undifferentiated mass. ......一起来看看 《Machine Learning in Action》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具