はじめに
etcdはKubernetsの全ての構成情報が保存されるKey-Value Storeです。これが障害などで壊れてしまうと、PodやServiceなどの全ての情報が壊れてしまいます。よって、通常は複数台(3,5,7台などの奇数)で冗長構成を組むことが推奨されています。また、Masterノードとは別のサーバで稼働させることも可能です。
冗長構成を取っていたとしても、何らかの影響で壊れてしまうことがないとは言えませんので、バックアップは取っておいた方がよいでしょう。
ということで、今回はetcdのバックアップとリストアの手順を以下に沿って確認したいと思います。
今回の構成は、Masterノード1台にetcdが同居しています。
既存環境の確認
既存環境を確認します。Masterノード1台とWorkerノード2台のクラスタ構成にPodとServiceが以下のようにデプロイされています。
$ kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 138d v1.18.3
k8s-worker01 Ready <none> 138d v1.18.3
k8s-worker02 Ready <none> 138d v1.18.3
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-dep-5589d85476-nhc7q 1/1 Running 1 46h
nginx-dep-5589d85476-xdrhg 1/1 Running 1 46h
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd ClusterIP 10.97.210.85 <none> 80/TCP 8d
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 140d
load-balancer LoadBalancer 10.111.156.47 10.20.30.150 8080:30002/TCP 42d
nginx-svc ClusterIP 10.110.96.251 <none> 8080/TCP 8d
etcdctl ユーティリティの入手
etcdのバックアップリストアを行うには、etcdctlが必要になります。
以下の手順で入手します。
環境変数の設定
以降の手順を簡素化するために、以下の環境変数を設定します。
$ ETCD_VER = v3.4.9
$ GOOGLE_URL=https://storage.googleapis.com/etcd
$ DOWNLOAD_URL=${GOOGLE_URL}
アーカイブのダウンロードと展開
$ curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 16.5M 100 16.5M 0 0 3200k 0 0:00:05 0:00:05 --:--:-- 4616k
$ mkdir -p /tmp/etcd-download-test
$ tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1
$ rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
バージョンの確認
$ /tmp/etcd-download-test/etcd --version
etcd Version: 3.4.9
Git SHA: 54ba95891
Go Version: go1.12.17
Go OS/Arch: linux/amd64
$ ETCDCTL_API=3 /tmp/etcd-download-test/etcdctl version
etcdctl version: 3.4.9
API version: 3.4
/usr/binへの移動
etcdctlを/usr/binに移動します。
$ sudo mv /tmp/etcd-download-test/etcdctl /usr/bin
バックアップ
etcdctlを使用してバックアップします。
etcdの設定確認
デプロイされているetcdの設定情報を確認します。バックアップする際には、以下4つのオプションを指定する必要がありますので、確認しておきます。
- --cacert
- --cert
- --endpoints
- --key
以下の設定情報の中のそれぞれ該当する値にコメントで記載しています。見つけにくいですが。。。
デフォルトだったら同じかなと思います。
$ kubectl -n kube-system describe pod etcd-k8s-master
Name: etcd-k8s-master
Namespace: kube-system
Priority: 2000000000
Priority Class Name: system-cluster-critical
Node: k8s-master/10.20.30.10
Start Time: Wed, 15 Jul 2020 21:25:29 +0900
Labels: component=etcd
tier=control-plane
Annotations: kubernetes.io/config.hash: be47c66ed7fcacf39bb0343a2aa5e685
kubernetes.io/config.mirror: be47c66ed7fcacf39bb0343a2aa5e685
kubernetes.io/config.seen: 2020-07-13T22:12:51.453317107+09:00
kubernetes.io/config.source: file
Status: Running
IP: 10.20.30.10
IPs:
IP: 10.20.30.10
Controlled By: Node/k8s-master
Containers:
etcd:
Container ID: docker://f75768f70af8a1a936227090f43e341cac5292cce2826f9b15df4fc9432b1c27
Image: k8s.gcr.io/etcd:3.4.3-0
Image ID: docker-pullable://k8s.gcr.io/etcd@sha256:4afb99b4690b418ffc2ceb67e1a17376457e441c1f09ab55447f0aaf992fa646
Port: <none>
Host Port: <none>
Command:
etcd
--advertise-client-urls=https://10.20.30.10:2379
--cert-file=/etc/kubernetes/pki/etcd/server.crt #--cert
--client-cert-auth=true
--data-dir=/var/lib/etcd
--initial-advertise-peer-urls=https://10.20.30.10:2380
--initial-cluster=k8s-master=https://10.20.30.10:2380
--key-file=/etc/kubernetes/pki/etcd/server.key #--key
--listen-client-urls=https://127.0.0.1:2379,https://10.20.30.10:2379 #--endpoints
--listen-metrics-urls=http://127.0.0.1:2381
--listen-peer-urls=https://10.20.30.10:2380
--name=k8s-master
--peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
--peer-client-cert-auth=true
--peer-key-file=/etc/kubernetes/pki/etcd/peer.key
--peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
--snapshot-count=10000
--trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt #--cacert
State: Running
Started: Wed, 15 Jul 2020 21:25:57 +0900
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: Mon, 13 Jul 2020 22:12:55 +0900
Finished: Mon, 13 Jul 2020 23:28:30 +0900
Ready: True
Restart Count: 1
Liveness: http-get http://127.0.0.1:2381/health delay=15s timeout=15s period=10s #success=1 #failure=8
Environment: <none>
Mounts:
/etc/kubernetes/pki/etcd from etcd-certs (rw)
/var/lib/etcd from etcd-data (rw)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
etcd-certs:
Type: HostPath (bare host directory volume)
Path: /etc/kubernetes/pki/etcd
HostPathType: DirectoryOrCreate
etcd-data:
Type: HostPath (bare host directory volume)
Path: /var/lib/etcd
HostPathType: DirectoryOrCreate
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: :NoExecute
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SandboxChanged 15m kubelet, k8s-master Pod sandbox changed, it will be killed and re-created.
Normal Pulled 15m kubelet, k8s-master Container image "k8s.gcr.io/etcd:3.4.3-0" already present on machine
Normal Created 15m kubelet, k8s-master Created container etcd
Normal Started 14m kubelet, k8s-master Started container etcd
Warning Unhealthy 14m (x2 over 14m) kubelet, k8s-master Liveness probe failed: Get http://127.0.0.1:2381/health: dial tcp 127.0.0.1:2381: connect: connection refused
バックアップ
etcdctlを使用してバックアップします。
$ sudo ETCDCTL_API=3 etcdctl \
> --endpoints=https://127.0.0.1:2379 \
> --cacert=/etc/kubernetes/pki/etcd/ca.crt \
> --cert=/etc/kubernetes/pki/etcd/server.crt \
> --key=/etc/kubernetes/pki/etcd/server.key \
> snapshot save /tmp/snapshot-pre-boot.db
{"level":"info","ts":1594817675.7622454,"caller":"snapshot/v3_snapshot.go:119","msg":"created temporary db file","path":"/tmp/snapshot-pre-boot.db.part"}
{"level":"info","ts":"2020-07-15T21:54:35.773+0900","caller":"clientv3/maintenance.go:200","msg":"opened snapshot stream; downloading"}
{"level":"info","ts":1594817675.773231,"caller":"snapshot/v3_snapshot.go:127","msg":"fetching snapshot","endpoint":"https://127.0.0.1:2379"}
{"level":"info","ts":"2020-07-15T21:54:35.856+0900","caller":"clientv3/maintenance.go:208","msg":"completed snapshot read; closing"}
{"level":"info","ts":1594817675.8860555,"caller":"snapshot/v3_snapshot.go:142","msg":"fetched snapshot","endpoint":"https://127.0.0.1:2379","size":"6.0 MB","took":0.123743001}
{"level":"info","ts":1594817675.886203,"caller":"snapshot/v3_snapshot.go:152","msg":"saved","path":"/tmp/snapshot-pre-boot.db"}
Snapshot saved at /tmp/snapshot-pre-boot.db
$ ls -l /tmp/snapshot-pre-boot.db
-rw-------. 1 root root 6017056 7月 15 21:54 /tmp/snapshot-pre-boot.d
疑似障害
etcdに障害が発生したと想定して、保存されているデータストアを削除します。
$ sudo ls /var/lib/etcd/member
snap wal
$ sudo rm -r /var/lib/etcd/member
データストアを削除すると、DefaultのClusterIPを除いて全てのPod、Serviceなどがなくなっています。
$ kubectl get pod
No resources found in default namespace.
$ kubectl get pod -n kube-system
No resources found in kube-system namespace.
$ kubectl get all -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 100s
リストア
データストアの復元
バックアップから削除したデータストアを新しいディレクトリに復元します。
$ sudo ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
> --cacert=/etc/kubernetes/pki/etcd/ca.crt \
> --name=master \
> --cert=/etc/kubernetes/pki/etcd/server.crt \
> --key=/etc/kubernetes/pki/etcd/server.key \
> --data-dir /var/lib/etcd-from-backup \
> --initial-cluster=master=https://127.0.0.1:2380 \
> --initial-cluster-token=etcd-cluster-1 \
> --initial-advertise-peer-urls=https://127.0.0.1:2380 \
> snapshot restore /tmp/snapshot-pre-boot.db
{"level":"info","ts":1594818586.6703568,"caller":"snapshot/v3_snapshot.go:296","msg":"restoring snapshot","path":"/tmp/snapshot-pre-boot.db","wal-dir":"/var/lib/etcd-from-backup/member/wal","data-dir":"/var/lib/etcd-from-backup","snap-dir":"/var/lib/etcd-from-backup/member/snap"}
{"level":"info","ts":1594818586.7758226,"caller":"mvcc/kvstore.go:380","msg":"restored last compact revision","meta-bucket-name":"meta","meta-bucket-name-key":"finishedCompactRev","restored-compact-revision":2195612}
{"level":"info","ts":1594818586.790849,"caller":"membership/cluster.go:392","msg":"added member","cluster-id":"7581d6eb2d25405b","local-member-id":"0","added-peer-id":"e92d66acd89ecf29","added-peer-peer-urls":["https://127.0.0.1:2380"]}
{"level":"info","ts":1594818586.8051481,"caller":"snapshot/v3_snapshot.go:309","msg":"restored snapshot","path":"/tmp/snapshot-pre-boot.db","wal-dir":"/var/lib/etcd-from-backup/member/wal","data-dir":"/var/lib/etcd-from-backup","snap-dir":"/var/lib/etcd-from-backup/member/snap"}
etcd Podの再構成
etcd Podのマニフェスト(/etc/kubernetes/manifests/etcd.yaml)を復元した環境に合わせて編集して、Podを再構成します。
編集するのは以下の2点です。
- データストアディレクトリの編集
- 初期クラスタトークンの追加
以下のようにマニフェストを編集します。
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
component: etcd
tier: control-plane
name: etcd
namespace: kube-system
spec:
containers:
- command:
- etcd
- --advertise-client-urls=https://10.20.30.10:2379
- --cert-file=/etc/kubernetes/pki/etcd/server.crt
- --client-cert-auth=true
- --data-dir=/var/lib/etcd-from-backup #変更
- --initial-advertise-peer-urls=https://10.20.30.10:2380
- --initial-cluster=k8s-master=https://10.20.30.10:2380
- --key-file=/etc/kubernetes/pki/etcd/server.key
- --listen-client-urls=https://127.0.0.1:2379,https://10.20.30.10:2379
- --listen-metrics-urls=http://127.0.0.1:2381
- --listen-peer-urls=https://10.20.30.10:2380
- --name=k8s-master
- --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
- --peer-client-cert-auth=true
- --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
- --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
- --snapshot-count=10000
- --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
- --initial-cluster-token=etcd-cluster-1 #追記
image: k8s.gcr.io/etcd:3.4.3-0
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 8
httpGet:
host: 127.0.0.1
path: /health
port: 2381
scheme: HTTP
initialDelaySeconds: 15
timeoutSeconds: 15
name: etcd
resources: {}
volumeMounts:
- mountPath: /var/lib/etcd-from-backup #変更
name: etcd-data
- mountPath: /etc/kubernetes/pki/etcd
name: etcd-certs
hostNetwork: true
priorityClassName: system-cluster-critical
volumes:
- hostPath:
path: /etc/kubernetes/pki/etcd
type: DirectoryOrCreate
name: etcd-certs
- hostPath:
path: /var/lib/etcd-from-backup #変更
type: DirectoryOrCreate
name: etcd-data
status: {}
マニフェストを編集したらPodが自動的に再構成されて起動します。
$ docker ps | grep etcd
077d822d6e04 303ce5db0e90 "etcd --advertise-cl…" 19 seconds ago Up 19 seconds k8s_etcd_etcd-k8s-master_kube-system_9eedf34b89e004fe9144efbb95696ed8_0
65490828eb3d k8s.gcr.io/pause:3.1 "/pause" 39 seconds ago Up 38 seconds k8s_POD_etcd-k8s-master_kube-system_9eedf34b89e004fe9144efbb95696ed8_0
確認
etcdが復元されましたので、PodやServiceを確認します。
$ kubectl -n kube-system get pod
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-77c4b7448-j5qk8 0/1 Running 2 47h
calico-node-2hc9b 0/1 Running 132 140d
calico-node-cgdgk 1/1 Running 129 140d
calico-node-tkcz5 0/1 Running 122 140d
coredns-66bff467f8-csxsv 1/1 Running 1 2d
coredns-66bff467f8-sq7vh 1/1 Running 1 47h
etcd-k8s-master 1/1 Running 0 2d
kube-apiserver-k8s-master 1/1 Running 7 2d
kube-controller-manager-k8s-master 1/1 Running 3 2d
kube-proxy-6x2wd 1/1 Running 2 2d
kube-proxy-cksqs 1/1 Running 2 2d
kube-proxy-m76p2 1/1 Running 2 2d
kube-scheduler-k8s-master 1/1 Running 3 2d
metrics-server-fbc46dc5f-z4rmv 1/1 Running 1 47h
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-dep-5589d85476-nhc7q 1/1 Running 1 47h
nginx-dep-5589d85476-xdrhg 1/1 Running 1 47h
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd ClusterIP 10.97.210.85 <none> 80/TCP 9d
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 140d
load-balancer LoadBalancer 10.111.156.47 10.20.30.150 8080:30002/TCP 42d
nginx-svc ClusterIP 10.110.96.251 <none> 8080/TCP 9d
各Pod、Serviceの「AGE」の値を見ると、再作成されたのではなく、元の環境が復元されたことがわかりますね。
まとめ
クラスタやリソースの構成が変わった時に、バックアップは定期的に取っておきたいですね。
また、リストアは定期的にやるものではありませんが、いざという時に備えてリストアのテストもやっておきたいですね。