ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 쿠버네티스(kubernetes) 포드(POD)
    Kubernetes 2018. 6. 11. 09:00
    쿠버네티스는 컨테이너가 어떻게 생성/운영/삭제되는지를 관리하컨테이너 오케스트레이션 도구입니다. 하지만 실제로 쿠버네티스는 단일 컨테이너를 관리하는게 아니라 포드(POD)라는 단위로 컨테이너를 묶어서 관리합니다. 포드는 컨테이너 1개로 구성될수도 있고 여러개로 구성될수도 있습니다.
    앞에서 실행해봤던 간단한 예제들도 단일 컨테이너를 띄우는 것처럼 해봤지만 실제로는 포드 단위로 관리가 되었던 것입니다. 포드에 컨테이너 1개만 띄울때는 일반적인 경우에 컨테이너를 관리하는 것과 동일 하다고 보시면 됩니다. 하지만 쿠버네티스는 컨테이너를 직접 관리하지 않고 포드를 관리합니다.
    포드에 컨테이너 여러개를 한꺼번에 띄울때는 각 컨테이너가 각각의 역할을 하도록 구성할 수 있습니다. 하나의 포드에 속하는 컨테이너들은 모두 1개의 노드 안에 같이 실행됩니다. 포드 하나에 속하는 컨테이너들이 여러대의 노드에 흩어져서 실행되는 일은 없습니다. 포드 자체가 컨테이너들이 동일한 목적을 가지면서 자원을 공유하도록하는 목적을 가지기 때문입니다. 포드 안에 여러개의 컨테이너들은 다음 그림처럼 각각의 역할을 하도록 구성할 수 있습니다.




    그림을 보면 포드안에 컨테이너가 3개 떠 있고, 컨테이너나 마다 자신의 역할이 있는걸 볼 수 있습니다. 여기서 특징은 하나의 포드안에 있는 컨테이너들은 하나의 IP를 공유하도록 되어 있는 점입니다. 외부에서 이 포드에 접근할때는 그림에 있는 것 처럼 192.168.10.10이라는 IP로 접근할 수 있고, 포드내의 컨테이너들은 서로 통신이 필요한 경우 각 컨테이너 마다 포트(PORT)를 구분해서 사용함으로써 포드 내부 컨테이너간의 통신이 가능합니다.
    하나의 컨테이너가 모든 역할을 하도록 구성할수도 있지만, 그럴 경우에는 어쩔수 없이 복잡함을 가져가게 됩니다. 한 컨테이너에 프로세스를 2개 띄우도록 설정하는 것 자체도 간단치 않습니다. 시스템 시그널이나 종료 코드를 처리하는 것도 각 프로세스 별로 해줘야 하고, 컨테이너 하나가 여러 역할을 하다보면 관리 효율이 떨어지게 됩니다. 

    포드 생명주기
    포드는 생성되고 삭제되는 동안 생명주기(Lifecycle)를 가지고 있습니다. kubectl describe pods 명령을 이용하면 현재 포드의 상태를 볼 수 있습니다. 다음 그림에서 보이는 포드 상태중 Status 부분을 보면 현재 포드가 Running상태인걸 알 수 있습니다.


    Status에 올 수 있는 상태로는 Pending, Running, Succeeded, Failed, Unknown등이 올 수 있습니다. 각 상태의 의미는 다음과 같습니다.
    Pending : 쿠버네티스 시스템에 포드를 생성하도록 등록되었습니다. 아직 전체 컨테이너가 실행되고 있는 도중입니다. 이 상태는 이미지를 다운받아서 실행되고 있는 도중이라 포드내의 전체 컨테이너가 실행될때까지 시간이 걸립니다.
    Running : 포드내의 모든 컨테이너가 실행되고 있습니다. 위 그림에서도 running상태인 경우 이걸 의미합니다. 1개 이상의 컨테이너가 실행중이거나 시작 또는 재시작 상태일 수 있습니다.
    Succeeded : 포드내의 모든 컨테이너가 성공적으로 종료되었습니다. 재시작되지 않습니다.
    Failed : 포드내의 모든 컨테이너가 종료되었는데, 종료에 실패한 컨테이너가 있을 수 있습니다. 컨테이너 종료 코드가 0이 아니거나 시스템이 직접 컨테이너를 종료한 경우입니다.
    Unknown : 포드의 상태를 확인할 수 없는 경우입니다. 일반적으로 포드가 떠 있는 노드와 통신이 안될경우에 발생합니다.

    앞의 그림에서 Conditions 항목을 보면 포드의 현재 상태에 대한 정보를 알 수 있습니다. Type, Status로 구분되어 있습니다. Type은 어떤  정보인지를 보여주고, Status부분에 그 상태에 대한 값이 나와있습니다. Type에는 PodScheduled, Ready, Initialized, Unschedulable등의 값이 올 수 있고, Status에는 True, False, Unknown등의 값이 와서 상태를 보여줍니다.

    kubelet이 컨테이너 상태를 확인하는 방법
    컨테이너가 실행되고 난 후에는 kubelet이 주기적으로 컨테이너 상태를 확인하는데 여기에는 2가지 방법(Probe)이 있습니다.

    livenessProbe : 컨테이너가 실행됐는지 확인합니다. 이 상태확인이 실패하면 kubelet은 컨테이너를 죽이고, 재시작정책에 따라서 컨테이너를 재시작합니다. 컨테이너에 livenessProbe를 어떻게 할지 명시되어 있지 않으면 기본 상태는 성공(Success)으로 인식합니다.
    readinessProbe : 컨테이너가 실행된후 실제로 서비스 요청에 응답을 할수 있는 상태가 됐는지 확인합니다. 이 상태확인이 실패하면 엔드포인트 컨트롤러(endpoint controller)가 해당 포드가 연결된 모든 서비스(service)에서 이 포드의 엔드포인트 정보를 제거합니다. 첫번째 readinessProbe가 있기 전까지의 기본 상태값은 실패(Failure)입니다. readinessProbe를 어떻게 확인할지 명시되어 있지 않으면 기본 상태값은 성공(success)입니다.

    이렇게 2개의 상태 모니터링이 쿠버네티스의 장점이라고 볼 수 있습니다. readinessProbe를 별도로 둠으로써 컨테이너가 실행된 다음에 바로 서비스에 투입되어서 트래픽을 받는게 아니라, 실제 트래픽을 받을 준비가 된걸 확인한 후에 트래픽을 받도록 할 수 있습니다. 자바 같은 경우처럼 프로세스가 시작된 후에 앱이 초기화되기까지 시간이 걸리는 경우에 유용하게 사용할 수 있습니다. 그 뿐만 아니라 앱이 구동될때 대용량 데이터를 로딩해야 하거나, 컨테이너는 시작됐지만 앱의 환경설정 실수로 앱 구동이 되지 않는 경우등을 대비할 수 있습니다.


    실질적으로 컨테이너 상태에 대한 확인은 컨테이너가 구현한 핸들러(handler)를 kubelet이 호출해서 수행하는데, 핸들러는 3가지가 있습니다.
    ExecAction : 컨테이너 내부에서 지정된 명령어를 실행하고 종료코드가 0일때 성공(success)이라고 판단합니다.
    TCPSocketAction : 컨테이너의 지정된 IP와 포트로 TCP상태 확인을 하고 포트가 열려 있으면 성공(success)이라고 판단합니다.
    HTTPGetAction : 컨테이너의 지정된 IP, 포트, 경로로 HTTP GET요청을 보냅니다. 응답상태코드가 200에서 400 사이면 성공(success)이라고 판단합니다.

    상태확인을 했을때의 응답 결과는 다시 3가지로 분류됩니다.
    Success: 컨테이너가 상태확인에 성공
    Failure: 컨테이너가 상태확인에 실패
    Unknown: 상태확인자체가 실패해서 컨테이너 상태를 알수 없음.


    초기화 컨테이너(init container)
    초기화 컨테이너는 의미 그대로 앱 컨테이너(app container)가 실행되기 전에 포드의 초기화를 하는 역할을 합니다. 꼭 하나일 필요는 없고 여러개의 초기화 컨테이너가 있을 수 있습니다. 초기화 컨테이너가 여러개 있는 경우에는 하나가 실행이 완료된 후에 다음 컨테이너가 실행되는 방식으로 순서대로 실행됩니다. 초기화 컨테이너가 실행되다가 실패하면, 성공할때까지 재실행을 하게 됩니다.
    초기화 컨테이너는 앱 컨테이너와 대부분 비슷하게 동작하지만 몇가지 다른점이 있습니다. readinessProbe를 제공하지 않습니다. 초기화 컨테이너는 포드가 모두 준비되기 전에 실행된 후 종료하는 컨테이너 이기 때문에 readinessProbe 가 없습니다. 포드 명세에 초기화 컨테이너를 여러개 명시하면 파일에 적힌 순서대로 실행됩니다. 그렇게 초기화 컨테이너가 모두 실행되고 나면 앱 컨테이너가 시작됩니다.
    초기화 컨테이너는 보안적인 이유로 앱 컨테이너의 이미지와 같이 두면 안되는 코드를 별도로 관리할때 사용할 수 있습니다. 초기화 컨테이너가 완료되고 난 이후에 앱 컨테이너가 시작되기 때문에, 포드가 실행할때 앱컨테이너가 외부의 특정 조건이 만족할때까지 기다렸다가 실행되어야 하는 경우에도 초기화 컨테이너가 조건이 만족할때까지 대기하고 있다가 조건이 충족되고 나면 앱 컨테이너가 실행하도록 할 수도 있습니다. 

    다음을 보면 초기화 컨테이너를 설정하는 방법을 확인할 수 있습니다.
    apiVersion: v1
    kind: Pod
    metadata:
      name: myapp-pod
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp-container
        image: busybox
        command: ['sh', '-c', 'echo The app is running! && sleep 3600']
      initContainers:
      - name: init-myservice
        image: busybox
        command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
      - name: init-mydb
        image: busybox
        command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']


    포드 인프라 컨테이너(Pod infrastructure container)
    쿠버네티스에서 포드는 컨테이너들의 모음인데, 이때 항상 뜨는 컨테이너가 있습니다. pause라는 이름을 가진 컨테이너가 모든 포드에 뜨고 있습니다. pause는 "포드 인프라 컨테이너(Pod infrastructure container)"라고 하는데 포드에서 필요한 기본 네트워크를 가지고 실행됩니다. 그리고 포드내에서 PID 1을 가지고 실행되서 다른컨테이너에 대한 부모 컨테이너 역할을 하게 됩니다. 포드내의 다른 컨테이너들은 pause 컨테이너가 제공해주는 네트워크를 공유해서 사용하게 됩니다. 그래서 포드내의 다른 컨테이너들이 재실행됐을때는 포드의 IP가 변경되지 않고 유지되지만, pause컨테이너가 재실행되게 되면 포드내의 모든 컨테이너들이 재시작하게 됩니다. kubelet의 옵션을 살펴보면 --pod-infra-container-image이 있어서 pause가 아닌 다른 컨테이너를 포드 인프라 컨테이너로 지정할수도 있습니다.



    포드 Template





    댓글

Designed by Tistory.