쿠버네티스 교과서 - 02 - 파드와 디플로이먼트로 컨테이너 실행하기

jjunhwan.kim·2024년 5월 1일
0

쿠버네티스

목록 보기
1/2
post-thumbnail

노드

  • 노드는 하나의 서버 컴퓨터를 말한다. 정확히 말하면 컨테이너 런타임이 실행되는 환경을 말하는 것 같다. 하나의 OS 환경을 말하는 것 같다.(가상머신 포함)

클러스터

  • 여러 개의 서버 노드로 구성된 하나의 논리적 단위이다.

파드

  • 쿠버네티스가 하나 이상의 컨테이너를 관리하는데 사용하는 단위를 말한다.
  • 파드 하나는 하나 이상의 컨테이너를 포함한다. 대부분 하나의 컨테이너를 포함한다. 따라서 파드를 '쿠버네티스가 컨테이너를 실행하는 수단'으로 생각해도 크게 틀리지 않다.
  • 파드에는 IP 주소가 부여된다. 파드에 포함된 컨테이너들은 이 IP 주소를 공유한다.
  • 쿠버네티스가 직접 컨테이너를 실행하지는 않는다. 해당 노드에 설치된 컨테이너 런타임에게 맡긴다. 컨테이너 런타임은 도커 또는 다른 것이 될 수 있다. 즉 파드는 컨테이너를 추상화시킨 것이다.
  • 파드는 생성할 때 한 노드에 배정된다. 이 파드를 관리하고 파드에 포함된 컨테이너를 실행하는 책임도 이 노드가 맡는다. 노드는 컨테이너 런타임 인터페이스라는 공통 API를 이용하여 컨테이너 런타임과 연동한다.
  • 컨테이너가 파드로 추상화되었기 때문에 컨테이너가 삭제되어도 파드는 그대로 이어 새로운 컨테이너를 추가하여 파드의 상태를 복원한다. 이 것이 바로 쿠버네티스가 제공하는 자기수복성의 첫 번째 부분이다.
# 컨테이너 하나를 담은 파드를 실행한다. kiamol/ch02-hello-kiamol 도커 이미지를 hello-kiamol 이라는 이름으로 파드를 생성한다. 
kubectl run hello-kiamol --image=kiamol/ch02-hello-kiamol

# 파드가 준비 상태가 될 때까지 기다린다.
kubectl wait --for=condition=Ready pod hello-kiamol

# 클러스터에 있는 모든 파드의 목록을 출력한다.
kubectl get pods

# 파드의 상세 정보를 확인한다.
kubectl describe pod hello-kiamol
# 파드 하나의 기본 정보를 출력한다.
kubectl get pod hello-kiamol

# 특정 항목을 지정해서 출력한다.
kubectl get pod hello-kiamol --output custom-columns=NAME:metadata.name,NODE_IP:status.hostIP,POD_IP:status.podIP

# JSONPath로 복잡한 출력을 구성한다.
kubectl get pod hello-kiamol -o jsonpath='{.status.containerStatuses[0].containerID}'
# 로컬 컴퓨터의 8080 포트로 들어오는 트래픽을 파드의 80번 포트로 전달한다.
kubectl port-forward pod/hello-kiamol 8080:80

디플로이먼트

  • 파드는 노드에 배정되며, 노드가 고장날 경우 파드는 유실된다. 쿠버네티스는 유실된 파드를 새 파드로 대체하지 않는다.
  • 컨트롤러 객체는 이런 불편함을 해결해준다. 컨트롤러 객체는 다른 리소스를 관리하는 쿠버네티스 리소스이다.
  • 컨트롤러는 쿠버네티스 API와 연동하여 시스템의 현재 상태를 감시하다가 '바람직한 상태'와 차이가 생기면 필요에 따라 그 차이를 바로잡는다.
  • 쿠버네티스에 여러 컨트롤러 객체 중 파드를 주로 관리하는 컨트롤러 객체가 디플로이먼트이다. 어떤 노드가 고장나 파드가 유실되면, 디플로이먼트가 대체 파드를 다른 노드에 실행한다.
  • 정리하면, 디플로이먼트는 파드를 관리하고 파드는 컨테이너를 관리한다.
# 디플로이먼트 hello-kiamol-2를 생성한다.
kubectl create deploy hello-kiamol-2 --image=kiamol/ch02-hello-kiamol
  • 디플로이먼트 실행 결과로 디플로이먼트 이름 뒤에 랜덤 문자열이 추가된 hello-kiamol-2-787f8db75d-ctqwn 파드가 생성된다.
NAME                              READY   STATUS    RESTARTS      AGE
hello-kiamol                      1/1     Running   1 (92m ago)   8d
hello-kiamol-2-787f8db75d-ctqwn   1/1     Running   0             2m40s
  • 위에서는 디플로이먼트를 생성하였지만 파드는 직접 생성하지 않았다. 디플로이먼트를 쿠버네티스 API를 통해 동작 중인 리소스를 파악하고, 자신이 관리해야 할 파드가 없다는 것을 발견하고 다시 쿠버네티스 API를 통해 파드를 생성한다. 결과적으로 디플로이먼트만 만들면 파드는 디플로이먼트가 만들어준다.
  • 모든 쿠버네티스 리소스는 키-값 쌍 형태의 레이블을 가진다. 디플로이먼트는 레이블을 통해 자신이 관리해야 할 리소스를 추적한다.
  • 레이블을 통해 디플로이먼트와 파드는 느슨하게 연결될 수 있다.
  • 느슨하게 연결된다는 말은, 디플로이먼트는 자신이 관리하는 파드 목록을 직접 유지하지 않아도 되므로 직접적인 관계를 갖지 않는다는 말이다. 디플로이먼트는 레이블 셀렉터를 가지고 있으므로 쿠버네티스 API를 통해 자신이 관리하는 리소스를 찾아볼 수 있다.
# 디플로이먼트가 부여한 파드의 레이블을 출력한다.
kubectl get deploy hello-kiamol-2 -o jsonpath='{.spec.template.metadata.labels}'

# 아래와 같이 출력된다.
{"app":"hello-kiamol-2"}
# app:hello-kiamol-2 레이블을 가진 파드 목록을 출력한다.
kubectl get pods -l app=hello-kiamol-2

# 아래와 같이 출력된다.
NAME                              READY   STATUS    RESTARTS   AGE
hello-kiamol-2-787f8db75d-ctqwn   1/1     Running   0          24m
  • 레이블을 사용하여 리소스 간 관계를 파악하는 것은 쿠버네티스에서 자주 쓰는 중요한 패턴이다.
  • 컨트롤러 객체는 레이블 셀렉터를 통해 자신이 관리하는 리소스인지 판단한다.
# 모든 파드 이름과 레이블을 출력한다.
kubectl get pods -o custom-columns=NAME:metadata.name,LABELS:metadata.labels

# app=hello-kiamol 레이블을 가진 파드의 app 레이블을 수정한다.
kubectl label pods -l app=hello-kiamol-2 --overwrite app=hello-kiamol-x

# 다시 파드 목록을 조회한다.
kubectl get pods -o custom-columns=NAME:metadata.name,LABELS:metadata.labels

# 아래와 같이 hello-kiamol-2 파드가 생성된다.
hello-kiamol                      map[run:hello-kiamol]
hello-kiamol-2-787f8db75d-4v7lk   map[app:hello-kiamol-2 pod-template-hash:787f8db75d]
hello-kiamol-2-787f8db75d-ctqwn   map[app:hello-kiamol-x pod-template-hash:787f8db75d]
  • 위에서 파드의 레이블을 수정하면 디플로이먼트는 레이블 셀렉터(app:hello-kiamol-2)와 일치하는 파드가 사라졌기 때문에 새로운 파드를 만든다.
  • 파드의 레이블을 수정하면 디버깅에 유용하다. 원하는 파드를 컨트롤러 객체의 관리에서 제외하고 직접 적속하여 문제를 확인할 수 있다.
  • 컨트롤러 객체는 사라진 파드의 대체 파드를 생성하므로 애플리케이션은 계속 동작할 수 있다.
  • 반대로 컨트롤러 객체가 만들지 않은 파드의 레이블을 수정하여 컨트롤러 객체의 관리하에 있도록 할 수도 있다.
# app 레이블이 부여된 모든 파드 이름과 레이블을 출력한다.
kubectl get pods -l app -o custom-columns=NAME:metadata.name,LABELS:metadata.labels

# app 레이블을 원래대로 수정한다.
kubectl label pods -l app=hello-kiamol-x --overwrite app=hello-kiamol-2

# 다시 파드 목록을 조회한다.
kubectl get pods -l app -o custom-columns=NAME:metadata.name,LABELS:metadata.labels

# 대체 파드로 생성되었던 hello-kiamol-2-787f8db75d-4v7lk 파드는 삭제되고 처음 생성된 파드가 다시 컨트롤러 객체에서 관리된다.
hello-kiamol-2-787f8db75d-ctqwn   map[app:hello-kiamol-2 pod-template-hash:787f8db75d]
  • 디플로이먼트도 포트포워딩을 설정할 수 있다. 디플로이먼트가 자신의 파드 중 하나를 트래픽 전달 대상으로 삼는다.
# 로컬 컴퓨터에서 디플로이먼트로 포드포워딩을 설정한다.
kubectl port-forward deploy/hello-kiamol-2 8080:80

애플리케이션 매니페스트

  • 애플리케이션 매니페스트는 애플리케이션을 기술하는 스크립트이다. 지금까지 명령어로 생성했던 리소스들을 애플리케이션 매니페스트에 정의한다.
  • 애플리케이션 매니페스트는 선언적 스크립트이다. kubectl run 또는 kubectl create는 명령형이다.
  • 명령형은 일일히 할 일을 직접 지시하는 방식이고, 선언적 방식은 최종 결과가 어떻게 되어야 하는지 알려주고 과정은 신경쓰지 않는다.
  • 아래와 같이 파드 매니페스트 파일을 생성한다.
# 매니페스트 스크립트는 쿠버네티스 API 버전과 정의하려는 리소스의 유형을 정의하면서 시작한다.
apiVersion: v1
kind: Pod

# 리소스의 메타데이터에는 이름(필수)과 레이블(비필수)이 있다.
metadata:
  name: hello-kiamol-3

# 리소스의 실제 정의 내용이다. 파드는 실행할 컨테이너를 정의한다. 컨테이너 이름과 이미지로 정의한다.
spec:
  containers:
    - name: web
      image: kiamol/ch02-hello-kiamol
  • kubectl apply 명령어를 사용해 애플리케이션 매니페스트를 통해 애플리케이션을 배포한다.
# 매니페스트 파일로 애플리케이션을 배포한다.
kubectl apply -f pod.yaml
# 파드 목록을 조회한다.
kubectl get pods

# 아래와 같이 hello-kiamol-3 파드가 실행된다.
NAME                              READY   STATUS    RESTARTS       AGE
hello-kiamol                      1/1     Running   1 (3d2h ago)   11d
hello-kiamol-2-787f8db75d-ctqwn   1/1     Running   0              3d
hello-kiamol-3                    1/1     Running   0              2d23h
  • URL을 통해 배포도 가능하다.
kubectl apply -f https://raw.githubusercontent.com/sixeyed/kiamol/master/ch02/pod.yaml
  • 아래는 좀 더 고수준 리소스인 디플로이먼트에 대한 애플리케이션 매니페스트이다.
# 디플로이먼트 API 버전은 apps/v1 이다.
apiVersion: apps/v1
kind: Deployment

# 디플로이먼트 이름
metadata:
  name: hello-kiamol-4

# 디플로이먼트가 자신의 관리 대상을 결정하는 레이블 셀렉터를 정의한다.
# app 레이블의 값이 hello-kiamol-4
spec:
  selector:
    matchLabels:
      app: hello-kiamol-4

  # 디플로이먼트가 파드를 만들 때 이 템플릿을 사용한다.
  template:
    metadata:
      labels:
        app: hello-kiamol-4

    # 파드의 정의에 컨테이너 이름과 이미지 이름을 정의한다.
    spec:
      containers:
        - name: web
          image: kiamol/ch02-hello-kiamol
  • 파드와 동일하게 kubectl apply 명령어를 사용해 애플리케이션을 배포한다.
kubectl apply -f deploy.yaml
  • app=hello-kiamol-4 레이블을 가진 파드를 조회하면 디플로이먼트가 생성한 파드가 조회된다.
# 레이블이 app=hello-kiamol-4인 파드 목록을 조회한다.
kubectl get pods -l app=hello-kiamol-4

# 레이블이 app=hello-kiamol-4인 파드 목록이 출력된다.
NAME                              READY   STATUS    RESTARTS   AGE
hello-kiamol-4-568f7fbc88-ndbnh   1/1     Running   0          4m57s
  • 정리하면 애플리케이션의 정의를 YAML 파일에 기술하고, kutectl apply 명령어를 수행하면 YAML에 정의된 리소스가 없으면 쿠버네티스가 생성한다.

파드에서 실행 중인 애플리케이션 접근

  • 실제 애플리케이션은 컨테이너속에서 동작한다. kubectl을 사용하면 파드 안에 있는 컨테이너에 접근할 수 있다.
  • 컨테이너 안에서 명령을 실행하거나 로그를 열람하거나 파일을 복사할 수 있다.
  • 아래 처럼 컨테이너에 접속하여 명령어를 수행할 수 있다.
# 파드 IP 주소를 확인한다.
kubectl get pod hello-kiamol -o custom-columns=NAME:metadata.name,POD_IP:status.podIP

# 컨테이너 안에서 명령어를 실행한다. hello-kiamol 파드 내부의 쉘을 실행한다. -- 뒤에 컨테이너 안에서 실행할 명령어를 입력한다. 아래 명령어를 수행하면 컨테이너의 쉘이 현재 터미널에 연결된다.
kubectl exec hello-kiamol -it -- sh

# 컨테이너 안에서 명령어를 입력해 IP주소를 확인한다. 파드의 IP 주소와 같다.
hostname -i
  • 컨테이너의 애플리케이션 로그를 확인할 수도 있다. --tail=2 옵션은 로그의 최근 두 줄만 출력하라는 의미이다.
# 쿠버네티스를 통해 컨테이너의 최근 로그를 출력한다.
kubectl logs --tail=2 hello-kiamol

# 도커를 통해 컨테이너의 최근 로그를 출력한다. 쿠버네티스를 통한 로그와 일치한다.
docker logs --tail=2 $(docker container ls -q --filter label=io.kubernetes.container.name=hello-kiamol)
  • 디플로이먼트를 통해 파드를 생성한경우 파드 이름에 무작위 문자열이 포함된다. 이 이름을 직접 입력할 필요 없이 레이블로 파드를 참조하여 로그를 조회할 수 있다.
# 디플로이먼트가 생성한 파드 안에 들어있는 컨테이너에서 웹 애플리케이션을 호출한다.
kubectl exec deploy/hello-kiamol-4 -- sh -c 'wget -O - http://localhost > /dev/null'

# 위의 파드의 로그를 조회한다.
kubectl logs --tail=2 -l app=hello-kiamol-4
  • 파드 안의 파일시스템에 접근할 수 있다. 파드 안의 파일을 로컬 컴퓨터로 복사하거나 로컬 컴퓨터의 파일을 파드 안으로 복사할 수 있다.
# 파드 안의 index.html을 로컬 컴퓨터의 현재 경로에 복사한다.
kubectl cp hello-kiamol:/usr/share/nginx/html/index.html ./index.html

# 복사된 파일 내용을 확인한다.
cat ./index.html

# 로컬 컴퓨터에 복사된 파일을 다시 파드 안의 /tmp 디렉토리 안에 복사한다.
kubectl cp ./index.html hello-kiamol:/tmp/

쿠버네티스 리소스 관리

  • 컨트롤러 객체가 관리하는 리소스를 직접 삭제하면 컨트롤러가 다시 해당 리소스를 생성한다.

  • 예를 들어 모든 파드를 삭제하고 조회해보면 직접 생성한 파드는 삭제되고 디플로이먼트가 생성한 파드는 다시 생성된다.

# 모든 파드를 조회한다.
kubectl get pods

NAME                              READY   STATUS    RESTARTS       AGE
hello-kiamol                      1/1     Running   1 (3d3h ago)   12d
hello-kiamol-2-787f8db75d-ctqwn   1/1     Running   0              3d1h
hello-kiamol-3                    1/1     Running   0              3d
hello-kiamol-4-568f7fbc88-ndbnh   1/1     Running   0              46m

# 모든 파드를 삭제한다.
kubectl delete pods

pod "hello-kiamol" deleted
pod "hello-kiamol-2-787f8db75d-ctqwn" deleted
pod "hello-kiamol-3" deleted
pod "hello-kiamol-4-568f7fbc88-ndbnh" deleted

# 모든 파드를 조회한다.
kubectl get pods

# 디플로이먼트가 생성한 파드는 다시 생성된다.
NAME                              READY   STATUS              RESTARTS   AGE
hello-kiamol-2-787f8db75d-z5fqb   1/1     Running             0          5s
hello-kiamol-4-568f7fbc88-b49b6   0/1     ContainerCreating   0          5s
  • 정리하면 컨트롤러 객체 없이 생성된 리소스는 삭제시 바로 삭제된다. 컨트롤러 객체(예를 들면 디플로이먼트)로 생성된 파드는 삭제되어도 디플로이먼트가 파드가 사라진 것을 감지하고 대체 파드를 생성한다.

  • 따라서 컨트롤러 객체가 관리하는 리소스를 삭제하려면 해당 컨트롤러 객체를 삭제해야한다. 컨트롤러 객체는 삭제될 때 자신이 관리하던 리소스를 제거하고 삭제된다.

# 디플로이먼트 목록을 확인한다.
kubectl get deploy

NAME             READY   UP-TO-DATE   AVAILABLE   AGE
hello-kiamol-2   1/1     1            1           3d1h
hello-kiamol-4   1/1     1            1           50m

# 디플로이먼트를 모두 삭제한다.
kubectl delete deploy --all

deployment.apps "hello-kiamol-2" deleted
deployment.apps "hello-kiamol-4" deleted

# 파드 목록을 조회한다.
kubectl get pods

# 모두 삭제됭 리소스가 발견되지 않는다.
No resources found in default namespace.

0개의 댓글