灵雀云:etcd 集群运维实践

【编者的话】etcd 是 Kubernetes 集群的数据核心,最严重的状况是,当 etcd 出问题完全没法恢复的时候,解决问题的办法可能只有从新搭建一个环境。所以围绕 etcd 相关的运维知识就比较重要,etcd 能够容器化部署,也能够在宿主机自行搭建,如下内容是通用的。html

集群的备份和恢复

添加备份

#!/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

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

  

 

恢复集群

#!/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 恢复

 1 #!/bin/bash 
 2 export ETCDCTL_API=3
 3 etcdctl snapshot restore snapshot.db \
 4 --skip-hash-check \
 5 --data-dir=/var/lib/etcd \
 6 --name 10.1.0.5 \
 7 --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 \
 8 --initial-cluster-token k8s_etcd_token \
 9 --initial-advertise-peer-urls http://10.1.0.5:2380
10 
11 # 也是全部节点都须要生成本身的数据目录,参考上一条
12 # 和上一条命令惟一的差异是多了  --skip-hash-check  (跳过完整性校验)
13 # 这种方式不能确保 100% 可恢复,建议仍是本身加备份
14 # 一般恢复后须要作一下数据压缩和碎片整理,可参考相应章节

 

 

踩过的坑

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

使用更新的 etcd 便可。

总结:恢复就是要拿 DB 去把 etcd 的数据生成一份,用同一个节点的,能够保证除了 restore 时候指定的参数外,全部数据都同样。这就是用一份 DB,操做三次(或者5次)的缘由。linux

集群的扩容——从 1 到 3

执行添加

1 #!/bin/bash
2 export ETCDCTL_API=2
3 etcdctl --endpoints=http://10.1.0.6:2379 member add 10.1.0.6 http://10.1.0.6:2380
4 etcdctl --endpoints=http://10.1.0.7:2379 member add 10.1.0.7 http://10.1.0.7:2380
5 
6 # ETCD_NAME="etcd_10.1.0.6" 
7 # ETCD_INITIAL_CLUSTER="10.1.0.6=http://10.1.0.6:2380,10.1.0.5=http://10.1.0.5:2380"
8 # ETCD_INITIAL_CLUSTER_STATE="existing"

 

 

准备添加的节点 etcd 参数配置

#!/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 啦,就放心搞吧。git

集群加证书

生成证书

  1 curl -s -L -o /usr/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
  2 curl -s -L -o /usr/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
  3 chmod +x /usr/bin/{cfssl,cfssljson}
  4 cd /etc/kubernetes/pki/etcd
  5 
  6 
  7 #  cat ca-config.json
  8 {
  9 "signing": {
 10 "default": {
 11   "expiry": "100000h"
 12 },
 13 "profiles": {
 14   "server": {
 15     "usages": ["signing", "key encipherment", "server auth", "client auth"],
 16     "expiry": "100000h"
 17   },
 18   "client": {
 19     "usages": ["signing", "key encipherment", "server auth", "client auth"],
 20     "expiry": "100000h"
 21   }
 22 }
 23 }
 24 } 
 25 
 26 
 27 #  cat ca-csr.json
 28 {
 29 "CN": "etcd",
 30 "key": {
 31 "algo": "rsa",
 32 "size": 4096
 33 },
 34 "names": [
 35 {
 36   "C": "CN",
 37   "L": "Beijing",
 38   "O": "Alauda",
 39   "OU": "PaaS",
 40   "ST": "Beijing"
 41 }
 42 ]
 43 } 
 44 
 45 
 46 #  cat server-csr.json
 47 {
 48 "CN": "etcd-server",
 49 "hosts": [
 50 "localhost",
 51 "0.0.0.0",
 52 "127.0.0.1",
 53 "全部master 节点ip ",
 54 "全部master 节点ip ",
 55 "全部master 节点ip "
 56 ],
 57 "key": {
 58 "algo": "rsa",
 59 "size": 4096
 60 },
 61 "names": [
 62 {
 63   "C": "CN",
 64   "L": "Beijing",
 65   "O": "Alauda",
 66   "OU": "PaaS",
 67   "ST": "Beijing"
 68 }
 69 ]
 70 } 
 71 
 72 
 73 # cat client-csr.json
 74 
 75 {
 76 "CN": "etcd-client",
 77 "hosts": [
 78 ""
 79 ],
 80 "key": {
 81 "algo": "rsa",
 82 "size": 4096
 83 },
 84 "names": [
 85 {
 86   "C": "CN",
 87   "L": "Beijing",
 88   "O": "Alauda",
 89   "OU": "PaaS",
 90   "ST": "Beijing"
 91 }
 92 ]
 93 } 
 94 
 95 
 96 cd /etc/kubernetes/pki/etcd
 97 
 98 cfssl gencert -initca ca-csr.json | cfssljson -bare ca
 99 
100 cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server server-csr.json | cfssljson -bare server
101 
102 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 ... .htmlgithub

首先更新节点的peer-urls

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

  

 

修改配置

#  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


#  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的地方都用上证书,便可。shell

遇到的坑

[ etcd 加证书后,apiserver 的健康检查仍是 http 请求,etcd 会一直刷日志 ] https://github.com/etcd-io/etcd/issues/9285json

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 一下吧)vim

集群升级

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

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

集群状态检查

其实上述全部步骤都须要这些命令的辅助——bash

#!/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

  

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

删除

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 跑的很累,咱们就用这样的方式删掉没用的这些数据。网络

碎片整理

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 # 看数据量

  

压缩

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 运行时本身去作压缩

  

 

常见问题

  1. etcd 对时间很依赖,因此集群里的节点时间必定要同步
  2. 磁盘空间不足,若是磁盘是被 etcd 本身吃完了,就须要考虑压缩和删数据啦
  3. 加证书后全部请求就都要带证书了,要不会提示 context deadline exceeded
  4. 作各个操做时 etcd 启动参数里标明节点状态的要当心,不然须要从新作一遍前面的步骤很麻烦

 

日志收集

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

etcd 的日志在排查故障时颇有用,若是咱们用宿主机来部署 etcd,日志能够经过 systemd 检索到,但 kubeadm 方式启动的 etcd 在容器重启后就会丢失全部历史。咱们能够用如下的方案来作——

shell 的重定向

etcd --xxxx --xxxx   >  /var/log/etcd.log 
# 配合 logratate 来作日志切割
# 将日志经过 volume 挂载到宿主机

  

supervisor

supervisor 从容器刚开始流行时,就是保持服务持续运行颇有效的工具。

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 topology 和 External etcd topology,官方的连接了这个图很形象——

B70D000C-83B2-4B9C-A612-53925238D0DA.png


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

kubectl get cm  etcdcfg -n kube-system -o 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

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

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

Q:使用 Kubeadm 部署高可用集群是否是至关于先部署三个独立的单点 Master,最后靠 etcd 添加节点操做把数据打通?

A:不是,Kubeadm 部署会在最开始就先建一个 etcd 集群,apiserver 启动以前就须要准备好 etcd,不然 apiserver 起不了,集群之间就无法通讯。能够尝试手动搭一下集群,不用 Kubeadm,一个个把组件开起来,以后对Kubernetes的组件关系会理解更好的。

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

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

Q:Kubeadm 启动的集群内 etcd节 点,kubectl 操做 etcd 的备份恢复有尝试过吗?

A:没有用 kubectl 去处理过 etcd 的备份恢复。etcd 的恢复依赖用 SnapDb 生成数据目录,把 etcd 进程丢进容器里,相似的操做避免不了,还有启动的状态须要修改。kubeadm 启动的 etcd 能够经过 kubectl 查询和 exec,可是数据操做应该不能够,好比恢复 etcd ing 时,没法链接 etcd,kubectl 还怎么工做?

Q:kubeadm-ha 启动 3 个 Master,有 3 个 etcd 节点,怎么跟集群外的 3 个 etcd 作集群,作成 3 Master 6 etcd?

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

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

A:作过。Kubeadm 的滚动升级公司内部有从 1.7 一步步升级到 1.十一、1.12 的文档,或多或少有一点小坑,不过今天主题是 etcd 因此没提这部分。各个 Master 分别重启后数据的一致咱们测试时没问题,还有比较极端的是直接把三 Master 停机一天,再启动后也能恢复。
相关文章
相关标签/搜索