etcd 集群运维实践

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

内容简介: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


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

查看所有标签

猜你喜欢:

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

断点:互联网进化启示录

断点:互联网进化启示录

[美]杰夫·斯蒂贝尔 / 师蓉 / 中国人民大学出版社有限公司 / 2014-11-1 / CNY 49.00

一部神经学、生物学与互联网技术大融合的互联网进化史诗巨著。 我们正置身网络革命中。互联网的每一丝变化都与你我息息相关。当科技变得无处不在时,它就会改变你我。在《断点》一书中,大脑科学家和企业家杰夫·斯蒂贝尔将带领读者来到大脑、生物与技术的交汇处,向读者展示生物学和神经学是如何与互联网技术发生联系的;我们是如何通过生物学上的前车之鉴,来预测互联网的发展的;互联网在经历增长、断点和平衡后又会发生......一起来看看 《断点:互联网进化启示录》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码