쿠버네티스의 Etcd 살펴보기

etcd는 쿠버네티스 클러스터의 중요한 컴포넌트로서, 클러스터의 상태를 저장하고 있습니다. 클러스터에 필요한 설정 정보와, 포드와 서비스 같은 각 리소스들의 명세와 상태 정보 등을 저장하고 있습니다. 이 글에서는 etcd가 이러한 정보들을 어떻게 저장하는지에 대해서 간단히 알아볼 것입니다.

etcd

etcd 는 분산 시스템에서 사용할 수 있는 분산형 키-값 (key-value) 저장소 입니다 CoreOS에서 클러스터를 관리하기 위해서 사용했으며, 요즘은 쿠버네티스의 기본 데이터 저장소로 많이 사용하고 있습니다. etcd는 고가용성을 위하여 클러스터로 설치됩니다. 여러 노드의 통신은 래프트(Raft) 알고리즘에 의해 처리합니다. 연결된 노드들 중 리더를 선정하여 클러스터를 관리합니다. 데이터는 분산되어 저장하기 때문에 시스템 오류에 대한 내성을 가지고 있습니다. 클러스터의 노드는 홀수개로 이루어져야 하며, 최소 3개 이상의 노드가 필요합니다.

http://thesecretlivesofdata.com/raft/ 에서 래프트 알고리즘의 작동 방식을 설명하는 애니메이션을 볼 수 있습니다.

쿠버네티스의 etcd

쿠버네티스는 etcd를 기본 데이터 저장소로 사용합니다. 그래서 쿠버네티스를 설치하기 위해서는 etcd 가 필요합니다. 별도의 etcd 클러스터를 쿠버네티스 외부에 설치한 후 쿠버네티스에서 사용할 수 있습니다. 또는 쿠버네티스를 설치할때 컨트롤플레인 노드에 etcd를 포드로 같이 설치할 수 있습니다.

etcd 클러스터를 별도로 설치한 경우

다음은 그림은 etcd 클러스터를 외부에 설치한 경우를 나타낸 것입니다. 쿠버네티스 외부에 etcd 클러스터가 존재하고 kube-apiserver에서 해당 etcd 클러스터에 접속하여 데이터를 저장하고 읽어옵니다.

etcd 클러스터를 컨트롤 플레인 노드에 포드를 설치한 경우

다음 그림은 etcd 클러스터를 쿠버네티스 컨트롤 플레인 노드에 같이 설치한 경우를 나타낸 것입니다. 컨트롤 플레인 노드에 스태틱 포드(static pod) 형태로 etcd가 실행됩니다.

etcd 데이터 흐름 살펴보기

다음 명령어를 실행하여 포드를 생성해 보겠습니다.

$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.19.2
EOF

다음 그림은 포드를 생성했을 때 일어나는 일을 간단히 나타낸 것입니다.

  • 작성한 매니페스트는 kubectl 를 이용하여 kube-apiserver로 전달합니다.
  • kube-apiserver 는 포드를 생성하는 요청을 받은 후, 포드의 매니페스트를 etcd로 저장합니다.
  • kube-schedulerkube-apiserver 를 통해 포드 정보를 감시(watch)하고 있다가, 새로운 포드가 등록 된것을 감지하고, 포드가 실행 가능한 노드로 배치합니다. 포드의 정보에 배치될 노드의 정보를 추가한 후,kube-apiserver 를 통해 정보를 업데이트 합니다. kube-apiserver 는 업데이트 된 정보를 다시 etcd에 저장합니다.
  • kubelet 은 자신의 노드에 배치된 파드의 정보를 감지하고, 컨테이너를 실행시킵니다. 그리고, kube-apiserver 를 통해 상태 정보를 업데이트 합니다. kube-apiserver 는 업데이트 된 정보를 다시 etcd에 저장합니다.

쿠버네티스에서 etcd 정보 조회하기

쿠버네티스에서 사용되고 있는 etcd의 데이터를 조회하는 방법에 대해서 알아보겠습니다.

예제에 사용하는 쿠버네티스는 etcd가 컨트롤 플레인 노드에 스태틱 포드(static pod)로 같이 설치된 클러스터입니다.

쿠버네티스 클러스터가 정상적으로 설치되었다면, kube-system 네임스페이스에서 etcd 포드를 확인할 수 있습니다. 포드 이름은 일반적으로 etcd-노드명 입니다.

$ kubectl -n kube-system get pod
NAME                              READY   STATUS                   RESTARTS   AGE
...
etcd-node001                      1/1     Running                  0          229d
etcd-node002                      1/1     Running                  0          229d
etcd-node003                      1/1     Running                  1          229d
...

미러 포드(mirror pod)로 등록되어 있다면, etcd 포드를 확인할 수 있습니다.

etcdctl 사용하기

etcd 포드들 중 하나에 ps aux 명령어를 실행하여 etcd 서버의 주소를 확인해 보겠습니다.

$ kubectl -n kube-system exec -it etcd-node001 -- ps aux

PID   USER     TIME  COMMAND
    1 root      9d20 etcd --advertise-client-urls=https://10.203.163.116:2379,h
39283 root      0:00 ps aux

--advertise-client-urls 플래그의 값을 사용하여, etcd 클러스터에 명령을 실행해 보겠습니다. etcd 클러스터에 명령을 실행하기 위해서 etcdctl 이라는 유틸리티를 사용하겠습니다.

etcd의 데이터를 파일로 저장하기

etcdctl 실행할 때, v3 API를 사용하기 위해 ETCDCTL_API=3 을 붙입니다. 그리고, 접속 주소랑 인증을 위한 인증서 파일 경로를 플래그로 넘겨줍니다.

다음은 etcd에 저장된 데이터를 json 형식으로 저장하는 예제입니다.

$ ADVERTISE_URL="<https://10.203.163.116:2379>"

$ kubectl -n kube-system exec etcd-node001 -- sh -c \\
"ETCDCTL_API=3 etcdctl \\
--endpoints $ADVERTISE_URL \\
--cacert /etc/kubernetes/pki/etcd/ca.crt \\
--key /etc/kubernetes/pki/etcd/server.key \\
--cert /etc/kubernetes/pki/etcd/server.crt \\
get \\"\\" --prefix=true -w json" > etcd-data.json

저장된 데이터를 조회해 보기

다음은 etcd-data.json 파일의 일부분입니다. 파일을 살펴보면, 키와 값의 목록으로 이루어져 있는것을 알 수 있습니다. 키와 값들은 base64로 인코딩 되어 있기 때문에, 쉽게 알아 볼 수 없습니다.

{
  "header": {
    "cluster_id": 17306099881785348000,
    "member_id": 17264302005967186000,
    "revision": 66544117,
    "raft_term": 2
  },
  "kvs": [
    {
      "key": "L3JlZ2lzdHJ5L2FwaWV4dGVuc2lvbnMuazhzLmlvL2N1c3RvbXJlc291cmNlZGVmaW5pdGlvbnMvYWRhcHRlcnMuY29uZmlnLmlzdGlvLmlv",
      "create_revision": 6490,
      "mod_revision": 30436184,
      "version": 4,
      "value": "eyJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwiYXBpVmVyc2lvbiI6ImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxYmV0YTEi...생략..."
    },
    {
      "key": "L3JlZ2lzdHJ5L2FwaWV4dGVuc2lvbnMuazhzLmlvL2N1c3RvbXJlc291cmNlZGVmaW5pdGlvbnMvYXBpa2V5cy5jb25maWcuaXN0aW8uaW8=",
      "create_revision": 11406824,
      "mod_revision": 11406826,
      "version": 3,
      "value": "eyJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwiYXBpVmVyc2lvbiI6ImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxYmV0YTEiLCJtZXRhZGF0YSI6eyJuYW1lIjoiYXBpa2V5cy5jb25maWcuaXN0aW8uaW8iLCJ1aWQiOiJhMWFjMGZhMi0yZWM1LTQ1MzMtOGViOC1mZDMwY2JlMjQ0ZDgiLCJn...생략..."
    },
...

다음 명령어를 실행하면, 디코딩된 키값들을 조회해 볼 수 있습니다.

$ for k in $(cat etcd-data.json | jq '.kvs[].key' | cut -d '"' -f2); do echo $k | base64 --decode; echo; done

쿠버네티스의 전체 리소스들을 확인할 수 있습니다.

...
/registry/pods/istio-system/istio-citadel-58c6fb56fb-fs2gp
/registry/pods/istio-system/istio-egressgateway-64787c7b7d-7fblz
/registry/pods/istio-system/istio-galley-67f97d7c8b-wgb2r
/registry/pods/istio-system/istio-grafana-post-install-1.2.10-sl54z
/registry/pods/istio-system/istio-ingressgateway-66cd7b9b8b-hbfsl
...
/registry/services/endpoints/istio-system/istio-citadel
/registry/services/endpoints/istio-system/istio-egressgateway
/registry/services/endpoints/istio-system/istio-galley
/registry/services/endpoints/istio-system/istio-ingressgateway
...

nginx 포드의 리소스

앞서 예제에 있는 포드를 생성한 다음, etcd 데이터를 저장하였다면 다음과 같은 리소스들의 키 정보도 확인할 수 있습니다. 해당 포드의 이벤트 리소스와 포드 리소스 입니다.

/registry/events/default/nginx.1630e320224081de
/registry/events/default/nginx.1630e320535d4dd0
/registry/events/default/nginx.1630e32218d6d691
/registry/events/default/nginx.1630e3221ea631fb
/registry/events/default/nginx.1630e322284c4b56
...
/registry/pods/default/nginx

포드의 이벤트는 kubectl describe pod 포드네임 명령어를 이용하여 확인해 볼 수 있습니다.

$ kubectl describe pod nginx

“Events:”라는 부분에 포드 관련 이벤트가 조회되는 것을 확인할 수 있습니다. 이 이벤트는 시간이 지나면 자동으로 삭제되기 때문에, 안 보일수도 있습니다. (이벤트 지속 시간의 기본 설정 값은 1시간입니다.)

Name:         nginx
Namespace:    default
Priority:     0
...
Events:
  Type    Reason     Age    From                 Message
  ----    ------     ----   ----                 -------
  Normal  Scheduled  2m37s  default-scheduler    Successfully assigned default/nginx to worker-001
  Normal  Pulling    2m36s  kubelet, worker-001  Pulling image "nginx:1.19.2"
  Normal  Pulled     2m28s  kubelet, worker-001  Successfully pulled image "nginx:1.19.2"
  Normal  Created    2m28s  kubelet, worker-001  Created container nginx
  Normal  Started    2m28s  kubelet, worker-001  Started container nginx

특정 키로 조회해보기

특정 키의 값을 바로 조회해 볼 수도 있습니다. etcdctl 의 get 플래그에 키를 지정하면 됩니다. default 네임스페이스에 있는 nginx 라는 포드의 정보를 조회해 보겠습니다.

KEY="/registry/pods/default/nginx"

kubectl -n kube-system exec etcd-node001 -- sh -c \\
"ETCDCTL_API=3 etcdctl \\
--endpoints $ADVERTISE_URL \\
--cacert /etc/kubernetes/pki/etcd/ca.crt \\
--key /etc/kubernetes/pki/etcd/server.key \\
--cert /etc/kubernetes/pki/etcd/server.crt \\
get \\"$KEY\\" -w json" | jq '.kvs[].value' | cut -d '"' -f2 | base64 --decode

다음은 조회된 결과 입니다. 포드의 정보를 가지고 있는것을 확인할 수 있습니다. 문자열 데이터가 아닌 부분은 깨져 보이지만, 대충 어떤 의미를 가지는지는 확인할 수 있습니다.

k8s

v1Pod�
�
nginxdefault"*$1ae7d990-d09e-443b-a419-0d8bbc0ece232���b�
0kubectl.kubernetes.io/last-applied-configuration�{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"nginx","namespace":"default"},"spec":{"containers":[{"image":"nginx:1.19.2","name":"nginx"}]}}
z�
1
default-token-pz9rt2
default-token-pz9rt��
nginx
     nginx:1.19.2*BJJ
default-token-pz9rt-/var/run/secrets/kubernetes.io/serviceaccount"2j/dev/termination-logr
                                                                                         IfNotPresent����FileAlways 2
                                                                                                                     ClusterFirstBdefaultJdefaultRworker-001X`hr���default-scheduler�6
node.kubernetes.io/not-readyExists"	NoExecute(��8
node.kubernetes.io/unreachableExists"	NoExecute(�����
Running#

InitializedTru���*2
ReadyTru���*2'
ContainersReadyTru���*2$

PodScheduledTru���*2"*
                      10.233.166.02
                                   172.32.8.8���B�
nginx

��� (2
      nginx:1.19.2:_docker-pullable://nginx@sha256:b0ad43f7ee5edbc0effbc14645ae7055e21bc1973aee5150745632a24a752661BIdocker://9e8f506939d41129f61720813ee9cda07569e6628cf385fa71b692425d4be40cJ
BestEffortZ"

이상으로 etcd에 대해서 간단히 살펴보았습니다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다