'Tool/Kubernetes'에 해당하는 글 13건

kubernetes 를 사용하면서 불편했던 점 중에 하나는 서비스 로깅이었다. 로컬에서 가장 자주 사용하던 명령어가 바로...

 

> kubectl logs -n namespace -f <pod-name>

 

배포(deployment) 하고 나서 로깅/디버깅을 위해 pod 리스트를 나열하고 pod-name 으로 로깅하는 짓이 가장 번거로웠다. 지금은 pod 가 한 10개 정도인데... 창을 10개를 띄워놓을 수도 없고... 그래서 실시간으로 pods 정보를 보여주고, 해당 로그를 스트리밍으로 좀 더 편하게 볼 수 있는 툴을 찾아보기로 했다.

 

쿠버네티스 모니터링 도구를 찾아보니 꽤나 많이 보이는데 그 중에 몇 가지만 테스트해 보았다.

 

  1. Kubernetes Dashboard
    심플하다. 시스템 모니터는 다른 모든 툴들도 기본적으로 잘 동작한다. CPU / RAM / Workload 등... 하지만 서비스 로깅이 불편하다. 5초 reload 방식... 이것도 대부분의 툴들이 마찬가지.

  2. Prometheus / Grafana
    설치 개복잡. Helm 을 사용하면 조금 편함. 잘나가다가 promtail 설정에서 막혔음. Fargate 사용 유저는 엄청난 고뇌가 필요할 듯... 몇가지 대안은 있었지만 로그 하나 보겠다고 굳이 일 벌리고 싶지 않았음. 가장 보편적이기도 하고, Custom / 확장도 좋은 것 같고... 대부분의 회사들이 사용하니 이건 써봐야겠지?

  3. Datadog
    시스템 통합으로 사용하고는 있으나... 쿠버네티스에 특화되어 있다기 보다는 로깅 분석에 어울리는... 그렇다고 안되는 건 없는... 그렇다고 굳이 유료 결제할 필요도 없는...?

  4.  Lens (Desktop) 
    Kubernetes IDE 답게 쿠버네티스에 특화되어 있음. 얼핏보면 외관은 Prometheus 와 흡사. 클릭 몇번으로 설치 완료. Attach Pod / logs 메뉴로 실시간 로깅은 잘됨. 혼자쓰기 괜츈.

 

kubernetes-lens

 

 

 


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,



Master


위 그림은 쿠버네티스 클러스터의 아키텍처이다. 좌측의 마스터 컴포넌트는 클러스터의 제어영역(control plane) 을 제공하여, 클러스터에 관한 전반적인 결정을 수행하고 클러스터 이벤트를 감지하고 반응한다. 마스터 컴포넌트는 클러스터 내에 어떤 노드에서든 동작할 수 있지만, 일반적으로 클러스터와 동일한 노드 상에서 구동시킨다. 아래는 마스터 내에서 동작하는 바이너리 컴포넌트들이며 쿠버네티스 초기화시 자동 설치된다.


kube-apiserver

쿠버네티스 API 로, 외부/내부에서 관리자의 원격 명령을 받을 수 있는 컴포넌트이다.


etcd

모든 클러스터 데이터를 저장하는 고가용성 키-값 저장소로, etcd 데이터에 대한 백업 계획은 필수이다.


kube-scheduler

생성된 파드를 노드에 할당해 주는 컴포넌트이다. 이것을 스케줄링이라 하며, 리소스/하드웨어/소프트웨어/정책/워크로드 등을 모두 참고하여 가장 최적화된 노드에 파드를 배치하게 될 것이다.


kube-controller-manager

아래의 컨트롤러들을 구동하는 컴포넌트이다.

- Node Controller : 노드가 다운되었을 때 알림와 대응에 관한 역할을 한다.

- Replication Controller : 지정된 수의 파드들을 유지시켜 주는 역할을 한다.

- Endpoints Controller: 서비스와 파드를 연결시켜 엔드포인트 오브젝트를 만든다.

- Service Account & Token Controllers: 새로운 네임스페이스에 대한 기본 계정과 API 접근 토큰을 생성한다.



Node


우측 하단의 노드 컴포넌트(Minions) 는 마스터 컴포넌트에 의해 관리되며 VM 이나 물리 장치가 될 수 있다. 동작중인 파드를 유지시키고 쿠버네티스 런타임 환경을 제공한다. 아래는 노드 내에서 동작하는 바이너리 컴포넌트들이며 노드 오브젝트 생성시 자동 설치된다.


kubelet

클러스터의 각 노드에서 실행되는 에이전트로, 컨테이너들이 파드에서 실행 중인지, 이상이 없는지 확인한다.


kube-proxy

호스트 상의 네트워크 규칙으로 커넥션 포워딩을 수행함으로서 쿠버네티스 Service 가 가능하도록 한다.


Container Runtime

컨테이너 런타임은 컨테이너의 동작을 책임지며, 쿠버네티스에서 지원하는 컨테이너 런타임은 다음과 같다. 

Docker, containerd, cri-o, rktlet, Kubernetes CRI (Container Runtime Interface) 구현체.




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

쿠버네티스에서는 배포 방법으로 블루/그린 배포, 카나리 배포, 롤링 업데이트 등을 사용할 수 있다. 롤링 업데이트 방식은 운영중인 어플리케이션의 파드 수를 하나씩 줄이고, 새로운 어플리케이션의 파드 수를 하나씩 늘려가며 변경하는 방법이다. 쿠버네티스는 어플리케이션 이미지를 업데이트 하면 롤링 업데이트 방식으로 배포를 진행할 것이다. 쿠버네티스에서 배포 업데이트는 버전으로 관리되고, 이전의 안정적인 버전으로도 복구가 가능하다.


다음 테스트는 kubernetes-bootcamp:v1 이미지를 사용 중인 서비스 환경에서 v2 이미지로 교체하였을 때 어플리케이션의 배포 진행을 파악하고, 다시 v1 이미지로 복원하는 시나리오 이다.


4개의 파드에 kubernetes-bootcamp:v1 이미지를 구동하여, 이미 서비스로 운영중임을 확인.


$ kubectl get deployment -o wide
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS            IMAGES                                         SELECTOR
kubernetes-bootcamp   4/4     4            4           11m   kubernetes-bootcamp   gcr.io/google-samples/kubernetes-bootcamp:v1   run=kubernetes-bootcamp
cs


해당 deployment 에 어플리케이션 이미지를 교체할 때,  kubectl edit deployment  명령을 사용하거나  kubectl set image  명령을 사용할 수 있다.


$ kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2
cs


위 명령은 deployment 에 다른 이미지를 사용하도록 변경하고, 롤링 업데이트를 시작하도록 한다. 업데이트 확인.


$ kubectl get deployment -o wide
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS            IMAGES                             SELECTOR
kubernetes-bootcamp   4/4     4            4           26m   kubernetes-bootcamp   jocatalin/kubernetes-bootcamp:v2   run=kubernetes-bootcamp
cs


잠시 후에 서비스 ip 로 접근해 보면, 다음과 같이 새로운 v2 버전의 파드에 로드 밸런싱 되는 것을 확인할 수 있다.


$ curl service_ip
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5bf4d5689b-nqlrr | v=2
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5bf4d5689b-tjdrs | v=2
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5bf4d5689b-b6sdv | v=2
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5bf4d5689b-sr2aw | v=2
cs


그렇다면 업데이트 과정을 살펴보자.


$ kubectl describe deployment
Scaled up replica set kubernetes-bootcamp-6bf84cb898 to 4
Scaled up replica set kubernetes-bootcamp-5bf4d5689b to 1
Scaled down replica set kubernetes-bootcamp-6bf84cb898 to 3
Scaled up replica set kubernetes-bootcamp-5bf4d5689b to 2
Scaled down replica set kubernetes-bootcamp-6bf84cb898 to 2
Scaled up replica set kubernetes-bootcamp-5bf4d5689b to 3
Scaled down replica set kubernetes-bootcamp-6bf84cb898 to 1
Scaled up replica set kubernetes-bootcamp-5bf4d5689b to 4
Scaled down replica set kubernetes-bootcamp-6bf84cb898 to 0
cs


새로 생성된 ReplicaSet(5bf4d5689b) 의 파드 수가 하나씩 늘어나고, 동시에 ReplicaSet(6bf84cb898) 의 파드 수가 줄어들며 롤링 업데이트가 진행되는 것을 확인할 수 있다. 




만약에 경우에 이전 버전의 업데이트로 돌아가려면  rollout undo  명령으로 가능하다.


$ kubectl rollout undo deployments/kubernetes-bootcamp
deployment.extensions/kubernetes-bootcamp rolled back
 
$ curl service_ip
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5bf4d5689b-nqlrr | v=1
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5bf4d5689b-tjdrs | v=1
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5bf4d5689b-b6sdv | v=1
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5bf4d5689b-sr2aw | v=1
cs


여기서 또 다시 rollout undo 명령을 실행하면 v1 버전보다 더 예전의 업데이트가 아닌 바로 전인 v2 버전으로 다시 돌아가는 것에 주의하자.




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

파드에서 어플리케이션이 비정상 작동을 할 경우에 대비하여 Liveness/Readiness Probe 를 설정할 수 있다. Liveness Probe 는 컨테이너가 정상적으로 구동 중 인지를 체크할 수 있다. 결과가 정상이 아니면 컨테이너를 재시작한다. Readiness Probe 는 파드가 트래픽을 처리할 준비가 되어 있는지를 체크한다. 결과가 정상이 아니면 해당 파드는 로드밸런스에서 제외된다. 두가지 Probe 에 대하여 설정한 대로 노드의 kubelet 이 주기적으로 상태 체크를 하게 되며, 결과가 비정상일 경우 해당 파드는 not ready 상태로 변경된다. 


아래처럼 readiness/liveness probe 를 가진 파드를 생성해 보자.


apiVersion: v1
kind: Pod
metadata:
  name: "healthy-monolith"
  labels:
    app: monolith
spec:
  containers:
    - name: monolith
      image: kelseyhightower/monolith:1.0.0
      ports:
        - name: http
          containerPort: 80
        - name: health
          containerPort: 81
      resources:
        limits:
          cpu: 0.2
          memory: "10Mi"
      livenessProbe:
        httpGet:
          path: /healthz
          port: 81
          scheme: HTTP
        initialDelaySeconds: 5
        periodSeconds: 15
        timeoutSeconds: 5
      readinessProbe:
        httpGet:
          path: /readiness
          port: 81
          scheme: HTTP
        initialDelaySeconds: 5
        timeoutSeconds: 1
cs


각 Liveness/Readiness Probe 에 대해서 체크하는 방법으로는 Command / HTTP / TCP 등이 있는데 위 예제에서는 HTTP 를 사용하였다. livenessProbe 의 경우 http://ip:81/healthz 에 접근했을 때 응답코드가 2xx, 3xx 이면 정상이다. readinessProbe 도 마찬가지로 http://ip:81/readiness 에 접근했을 때 응답코드가 2xx, 3xx 이면 정상이다. initialDelaySeconds 는 컨테이너가 준비되고 probe 를 실행하기 까지의 대기 시간이다. periodSeconds 는 probe 체크를 반복할 시간 설정이다. 



Liveness 테스트


아래와 같이 토글 주소를 반복 실행하여 probe 의 성공과 실패를 반복할 경우 어떤 변화가 생기는지 알아보자. 아마도 실패를 할 경우 컨테이너의 restart 카운팅이 늘어나며, 컨테이너가 자동으로 재시작 될 것이다.


$ kubectl get pods healthy-monolith -w
NAME               READY     STATUS    RESTARTS   AGE
healthy-monolith   1/1       Running   0         29m
 
$ kubectl port-forward healthy-monolith 10081:81
$ curl http://127.0.0.1:10081/healthz/status
$ curl http://127.0.0.1:10081/healthz/status
 
$ kubectl get pods healthy-monolith -w
NAME               READY     STATUS    RESTARTS   AGE
healthy-monolith   1/1       Running   0         29m
healthy-monolith   0/1       Running   1         30m
healthy-monolith   1/1       Running   1         30m
healthy-monolith   0/1       Running   2         31m
healthy-monolith   1/1       Running   2         31m
cs



Readiness 테스트


아래와 같이 토글 주소를 반복 실행하여 probe 의 성공과 실패를 반복할 경우 어떤 변화가 생기는지 알아보자. 아마도 실패를 할 경우 해당 파드는 not ready 상태가 되며 로드밸런스에서 제외되는데, 로드밸런스 테스트는 생략한다 ^^;


$ kubectl port-forward healthy-monolith 10081:81
$ curl http://127.0.0.1:10081/readiness/status
$ curl http://127.0.0.1:10081/readiness/status
$ curl http://127.0.0.1:10081/readiness/status
 
$ kubectl get pods healthy-monolith -w
NAME               READY     STATUS    RESTARTS   AGE
healthy-monolith   1/1       Running   0          13m
healthy-monolith   0/1       Running   0          16m
healthy-monolith   1/1       Running   0          17m
healthy-monolith   0/1       Running   0          17m
 
$ kubectl describe pods healthy-monolith
Conditions:
  Type              Status
  Initialized       True
  Ready             False
  ContainersReady   False
  PodScheduled      True
 
Events:
  Type    Reason     Age   From                                              Message
  ----    ------     ----  ----                                              -------
  Normal  Scheduled  1m    default-scheduler                                 Successfully assigned default/healthy-monolith to gke-bootcamp-default-pool-bb4d9176-tpk5
  Normal  Pulling    1m    kubelet, gke-bootcamp-default-pool-bb4d9176-tpk5  pulling image "kelseyhightower/monolith:1.0.0"
  Normal  Pulled     1m    kubelet, gke-bootcamp-default-pool-bb4d9176-tpk5  Successfully pulled image "kelseyhightower/monolith:1.0.0"
  Normal  Created    1m    kubelet, gke-bootcamp-default-pool-bb4d9176-tpk5  Created container
  Normal  Started    1m    kubelet, gke-bootcamp-default-pool-bb4d9176-tpk5  Started container
 Warning  Unhealthy  8s (x15 over 2m)  kubelet, gke-bootcamp-default-pool-bb4d9176-tpk5  Readiness probe failed: HTTP probe failed with statuscode: 503
cs




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

hello minikube 글에서 어플리케이션 배포부터 노출까지 알아봤었는데 그 때의 배포 명령이 기억 나는가?


$ kubectl create deployment hello-node --image=gcr.io/hello-minikube-zero-install/hello-node

deployment.extensions "hello-node" created


위와 같이 kubectl create deployment 명령 다음에 배포에 관련된 정보나 상태 등의 spec 을 inline 으로 나열하였었다. 명령의 이러한 파라미터들은 JSON 형식으로 변환되어 쿠버네티스 API 로 전달된 후 처리된다. 이렇게 kubectl 명령에 inline 으로 파라미터나 플러그 등을 나열하는 것을 명령형(Imperative) 커맨드라고 하며, 주로 일회성 작업을 할 때 사용한다. 나열될 파라미터 수가 적을 때 사용하면 유용하다.


또 한가지 배포에 관련된 정보나 상태 등의 spec 을 상세하게 나열하는 대신 파일(.yaml) 안에 정의하는 방법을 사용할 수도 있는데, 이것을 명령형 오브젝트 구성(Imperative object configuration) 이라고 한다. 다음과 같이 로컬 파일이나 url 상의 파일을 지정하여 사용할 수 있다.


$ kubectl create -f deployment.yaml

$ kubectl create -f https://k8s.io/examples/application/deployment.yaml


위 yaml 예제 파일에는 다음과 같이 3개의 nginx 파드를 생성하는 내용이 담겨 있다.


apiVersion: apps/v1

kind: Deployment

metadata:

  name: nginx-deployment

  labels:

    app: nginx

spec:

  replicas: 3

  selector:

    matchLabels:

      app: nginx

  template:

    metadata:

      labels:

        app: nginx

    spec:

      containers:

      - name: nginx

        image: nginx:1.7.9

        ports:

        - containerPort: 80


.yaml(야믈) 파일은 위처럼 공백 문자를 이용한 들여쓰기로 구조체를 구분하며, 리스트, 해시, 스칼라 데이터의 조합을 모두 표현할 수 있다. 각 항목들을 살펴보면 통신할 api 버전, 생성할 오브젝트 종류, 이름, 식별자, 파드 수, 어플리케이션 이름, 컨테이너 이미지 정보, 연결포트 등이 정의되어 있으며, 쿠버네티스 API 는 이 정의대로 Deployment 를 생성하게 된다. 운영시에는 inline 방식의 명령형 커맨드 보다는 .yaml 파일에 오브젝트를 정의하는 명령형 오브젝트 구성을 주로 사용하게 되며, 위처럼 아주 깔끔하고, 명확하게 오브젝트의 의도를 한눈에 파악할 수 있다. 물론 .yaml 파일을 작성하는 방법이나 오브젝트 정의 방법을 숙지해야 하는 것은 함정!



오브젝트 정의 방법을 간단하게 살펴보자.


쿠버네티스에서 가장 중요한 것은 무엇일까. 아마도 위에 정의한 것 처럼 사용자가 원하는 리소스 및 스펙이 계속해서 유지되는 것이 가장 중요할 것이다. 즉, 사용자가 바라는 상태(desired state) 를 계속해서 유지해야 한다. 배포될 어플리케이션(pod)의 워크로드 정보를 나타내는 클러스터 정보(namespace), 네트워크(service), 디스크 리소스(volume) 를 쿠버네티스의 기본 오브젝트라고 한다. 또한 기본 오브젝트들을 편리하게 관리하기 위한 컨트롤러들이 있다. 파드 복제 수(ReplicaSet), 배포(Deployment), 상태관리API(StatefulSet), 파드를 모든 노드에 복제(DaemonSet), 단일실행(Job) 들이 그것이다. 이러한 오브젝트들은 위와 같이 .yaml 파일에 정의하여 생성/업데이트/삭제 등의 관리를 할 수 있다.


아래는 오브젝트 정의에 필요한 필수 요소이다.

  • apiVersion - 이 오브젝트를 생성하는데 사용할 API 버전
  • kind - 생성할 오브젝트 종류
  • metadata - 오브젝트를 식별할 수 있는 고유 이름
  • spec - 오브젝트 특유의 중첩된 필드를 포함하며, 오브젝트마다 정확한 포맷이 다르므로 관리할 오브젝트의 spec 포맷을 확인한다.


$ kubectl create -f deployment.yaml


위의 deployment 오브젝트 정보를 담은 .yaml 파일을 실행하면 아래와 같이 nginx 를 구동하는 3개의 파드가 생성된 것을 확인할 수 있다.


$ kubectl get pods -o wide

NAME                                READY     STATUS    RESTARTS   AGE       IP            NODE

nginx-deployment-76bf4969df-4tvtv   1/1       Running   0          30m       172.17.0.10   minikube

nginx-deployment-76bf4969df-8d5sk   1/1       Running   0          30m       172.17.0.9    minikube

nginx-deployment-76bf4969df-g6v79   1/1       Running   0          30m       172.17.0.8    minikube





WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,