[kubernetes] POD

728x90

Pod

공식 문서: https://kubernetes.io/ko/docs/concepts/workloads/pods/

  • 파드는 컨테이너의 모음이다. 하나의 파드에 한 개 이상의 컨테이너가 있을 수 있다.
  • 쿠버네티스는 컨테이너를 직접 관리하지 않는다. 쿠버네티스에서 관리하는 가장 작은 워크로드는 파드이다.

kubelet 이 서비스인 이유

kubelet 은 api-server, cm, 스케줄러 등 쿠버네티스의 필수 불가결한 리소스들을 실행시켜주는 역할을 하기 때문에 파드가 아닌 서비스로서 동작한다. 만약 kubelet 까지 파드로 구성되어 있다면 kubernetes 를 띄울 녀석이 존재하지가 않기 때문에 서비스로 동작을 한다.

정적 파드

정적 파드 는 API 서버가 관찰하는 대신 특정 노드의 kubelet 데몬에 의해 직접 관리된다.

대부분의 파드는 컨트롤 플레인(예를 들어, 디플로이먼트)에 의해 관리되고, 정적 파드의 경우, kubelet이 각 정적 파드를 직접 감독한다(실패하면 다시 시작한다).

정적 파드는 항상 특정 노드의 Kubelet 하나에 바인딩된다. 정적 파드의 주요 용도는 자체 호스팅 컨트롤 플레인을 실행하는 것이다. 즉, kubelet을 사용하여 개별 컨트롤 플레인 컴포넌트를 감독한다.

kubelet은 자동으로 각 정적 파드에 대한 쿠버네티스 API 서버에서 미러 파드를 생성하려고 한다. 즉, 노드에서 실행되는 파드는 API 서버에서 보이지만, 여기에서 제어할 수는 없다는 의미이다.

/etc/kubernetes/manifest 에서 yml 파일로 pod 를 작성한 후 실행하면 정적 파드가 생성된다.

kubectl 명령의 서브 명령

kubectl 에서 자주 사용하는 서브 명령어

  • create
  • get
  • describe
  • logs
  • delete
  • replace
  • patch
  • apply
  • diff

명령형 커맨드로 파드 생성

kubectl run myweb --image httpd

kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
myweb   1/1     Running   0          26s

kubectl get pods -o wide
NAME    READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
myweb   1/1     Running   0          2m21s   10.233.109.1   node-3   <none>           <none>

파드 상세 정보

kubectl get pods -o yaml 를 사용해서 yaml 형태로 etcd 에서 원본 데이터를 가져온다.

-o wide, -o json 등으로 원하는 포맷팅으로 가져올 수 있다.

kubectl get pods -o yaml
apiVersion: v1
items:
- apiVersion: v1
  kind: Pod
  metadata:
    annotations:
      cni.projectcalico.org/containerID: ba98ccabd6b2b011e9654d76181414a90e7eec9729e207ceb6391d513bccfab2
      cni.projectcalico.org/podIP: 10.233.109.1/32
      cni.projectcalico.org/podIPs: 10.233.109.1/32
    creationTimestamp: "2022-05-17T01:38:18Z"
    labels:
      run: myweb
    name: myweb
    namespace: default
    resourceVersion: "18433"
    uid: 4741205a-6581-4ab6-bae5-dc0f6ac35dbc
  spec:
    containers:
    - image: httpd
      imagePullPolicy: Always
      name: myweb
      resources: {}
      terminationMessagePath: /dev/termination-log
      terminationMessagePolicy: File
      volumeMounts:
      - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
        name: kube-api-access-ff6tf
        readOnly: true
    dnsPolicy: ClusterFirst
    enableServiceLinks: true
    nodeName: node-3
    preemptionPolicy: PreemptLowerPriority
    priority: 0
    restartPolicy: Always
    schedulerName: default-scheduler
    securityContext: {}
    serviceAccount: default
    serviceAccountName: default
    terminationGracePeriodSeconds: 30
    tolerations:
    - effect: NoExecute
      key: node.kubernetes.io/not-ready
      operator: Exists
      tolerationSeconds: 300
    - effect: NoExecute
      key: node.kubernetes.io/unreachable
      operator: Exists
      tolerationSeconds: 300
    volumes:
    - name: kube-api-access-ff6tf
      projected:
        defaultMode: 420
        sources:
        - serviceAccountToken:
            expirationSeconds: 3607
            path: token
        - configMap:
            items:
            - key: ca.crt
              path: ca.crt
            name: kube-root-ca.crt
        - downwardAPI:
            items:
            - fieldRef:
                apiVersion: v1
                fieldPath: metadata.namespace
              path: namespace
  status:
    conditions:
    - lastProbeTime: null
      lastTransitionTime: "2022-05-17T01:38:19Z"
      status: "True"
      type: Initialized
    - lastProbeTime: null
      lastTransitionTime: "2022-05-17T01:38:38Z"
      status: "True"
      type: Ready
    - lastProbeTime: null
      lastTransitionTime: "2022-05-17T01:38:38Z"
      status: "True"
      type: ContainersReady
    - lastProbeTime: null
      lastTransitionTime: "2022-05-17T01:38:19Z"
      status: "True"
      type: PodScheduled
    containerStatuses:
    - containerID: containerd://8129401885bc9f1e85e5051c514be51183a784134ad58c2581461e1a2d46e6f7
      image: docker.io/library/httpd:latest
      imageID: docker.io/library/httpd@sha256:2d1f8839d6127e400ac5f65481d8a0f17ac46a3b91de40b01e649c9a0324dea0
      lastState: {}
      name: myweb
      ready: true
      restartCount: 0
      started: true
      state:
        running:
          startedAt: "2022-05-17T01:38:38Z"
    hostIP: 192.168.100.105
    phase: Running
    podIP: 10.233.109.1
    podIPs:
    - ip: 10.233.109.1
    qosClass: BestEffort
    startTime: "2022-05-17T01:38:19Z"
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

describe

kubectl describe pods myweb
Name:         myweb
Namespace:    default
Priority:     0
Node:         node-3/192.168.100.105
Start Time:   Tue, 17 May 2022 01:38:19 +0000
Labels:       run=myweb
Annotations:  cni.projectcalico.org/containerID: ba98ccabd6b2b011e9654d76181414a90e7eec9729e207ceb6391d513bccfab2
              cni.projectcalico.org/podIP: 10.233.109.1/32
              cni.projectcalico.org/podIPs: 10.233.109.1/32
Status:       Running
IP:           10.233.109.1
IPs:
  IP:  10.233.109.1
Containers:
  myweb:
    Container ID:   containerd://8129401885bc9f1e85e5051c514be51183a784134ad58c2581461e1a2d46e6f7
    Image:          httpd
    Image ID:       docker.io/library/httpd@sha256:2d1f8839d6127e400ac5f65481d8a0f17ac46a3b91de40b01e649c9a0324dea0
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Tue, 17 May 2022 01:38:38 +0000
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-ff6tf (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  kube-api-access-ff6tf:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  6m22s  default-scheduler  Successfully assigned default/myweb to node-3
  Normal  Pulling    6m21s  kubelet            Pulling image "httpd"
  Normal  Pulled     6m9s   kubelet            Successfully pulled image "httpd" in 12.366300856s
  Normal  Created    6m4s   kubelet            Created container myweb
  Normal  Started    6m3s   kubelet            Started container myweb

event 는 myweb pod 의 라이프 사이클이다.

맨 처음 디폴트 스케줄러에 의해 이벤트가 발생한다. 노드-3 에 파드를 배치했다.

kubelet 이 httpd 이미지를 풀링한다. httpd 폴링이 완료되고 kubelet 이 myweb 컨테이너를 생성하고 실행한다.

파드를 생성했을 때 컨테이너가 제대로 작동하지 않을 경우 kubectl describe pods 로 파드 자체의 로그를 확인하고 그 후에 애플리케이션의 로그를 확인한다.

애플리케이션의 로그를 확인하기 위해서는 kubectl logs <파드_이름> 명령어로 확인 가능하다.

파드 삭제

kubectl delete pods <파드_이름>

YAML 파일로 파드 정의

kubectl explain pods

myweb.yml

apiVersion: v1
kind: Pod
metadata:
  name: myweb
spec:
  containers:
    - name: myweb
      image: httpd
      ports:
      - containerPort: 80
        name: myweb
        protocol: TCP

Workload resources for managing pods

일반적으로 싱글톤(singleton) 파드를 포함하여 파드를 직접 만들 필요가 없다. 대신, 디플로이먼트(Deployment) 또는 잡(Job)과 같은 워크로드 리소스를 사용하여 생성한다. 파드가 상태를 추적해야 한다면, 스테이트풀셋(StatefulSet) 리소스를 고려한다.

쿠버네티스 클러스터의 파드는 두 가지 주요 방식으로 사용된다.

  • 단일 컨테이너를 실행하는 파드. "파드 당 하나의 컨테이너" 모델은 가장 일반적인 쿠버네티스 유스케이스이다. 이 경우, 파드를 단일 컨테이너를 둘러싼 래퍼(wrapper)로 생각할 수 있다. 쿠버네티스는 컨테이너를 직접 관리하는 대신 파드를 관리한다.
  • 함께 작동해야 하는 여러 컨테이너를 실행하는 파드. 파드는 밀접하게 결합되어 있고 리소스를 공유해야 하는 함께 배치된 여러 개의 컨테이너로 구성된 애플리케이션을 캡슐화할 수 있다. 이런 함께 배치된 컨테이너는 하나의 결합된 서비스 단위를 형성한다. 예를 들어, 하나의 컨테이너는 공유 볼륨에 저장된 데이터를 퍼블릭에 제공하는 반면, 별도의 사이드카 컨테이너는 해당 파일을 새로 고치거나 업데이트한다. 파드는 이러한 컨테이너, 스토리지 리소스, 임시 네트워크 ID를 단일 단위로 함께 래핑한다.

하나의 파드에는 반드시 하나의 메인 어플리케이션만 있어야 한다. 파드에 여러 컨테이너가 있을 경우에는 메인 어플리케이션 + 메인 어플리케이션을 서포팅하는 다른 컨테이너여야 한다.

하나의 파드에 메인 애플리케이션이 여러개 띄워지면 안된다. -> 안티 패턴이다.

예를 들어 하나의 파드안에 메인이 되는 웹서버가 있고 해당 웹서버로 코드를 가져오거나 정적인 파일을 가져오는 메인 앱을 서포팅하는 앱과 웹서버에서 보내준 로그를 로그 서버로 보내는 메인 앱을 서포팅하는 앱으로 파드가 구성될 수 있다.

하나의 파드는 하나의 호스트(노드)에 배치된다. 즉, 파드 안여 여러 대의 컨테이너가 있어도 하나의 호스트(노드)에 모두 배치된다.

파드 디자인

사이드카 패턴: https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns/

  • 단일 컨테이너: 가장 일반적인 형태, 대부분의 파드는 단일 컨테이너로 이루어져 있다.
  • 멀티 컨테이너: 메인 애플리케이션이 존재하고 메인 애플리케이션 기능을 확장하기 위한 컨테이너를 배치
    • sidecar: 기능의 확장
    • ambassador: proxy/LB
    • adaptor: 출력의 표준

파드는 응집력있는 서비스 단위를 형성하는 여러 협력 프로세스(컨테이너)를 지원하도록 설계되었다. 파드의 컨테이너는 클러스터의 동일한 물리 또는 가상 머신에서 자동으로 같은 위치에 배치되고 함께 스케줄된다. 컨테이너는 리소스와 의존성을 공유하고, 서로 통신하고, 종료 시기와 방법을 조정할 수 있다.

 

예를 들어, 다음 다이어그램에서와 같이 공유 볼륨의 파일에 대한 웹 서버 역할을 하는 컨테이너와, 원격 소스에서 해당 파일을 업데이트하는 별도의 "사이드카" 컨테이너가 있을 수 있다.

일부 파드에는 앱 컨테이너 뿐만 아니라 초기화 컨테이너를 갖고 있다. 초기화 컨테이너는 앱 컨테이너가 시작되기 전에 실행되고 완료된다.

파드는 기본적으로 파드에 속한 컨테이너에 네트워킹과 스토리지라는 두 가지 종류의 공유 리소스를 제공한다.

 

파드는 딱 하나의 IP 주소를 부여 받는다. 즉, 파드 안에 몇 개의 컨테이너가 있든 간에 모두 같은 IP 주소를 사용한다. → 공유 네트워크

파드에 볼륨을 설정해주면 해당하는 볼륨을 파드 안의 모든 컨테이너가 접근할 수 있고 사용할 수 있다. → 공유 스토리지

포트 및 포트 포워딩

테스트 & 디버깅 목적이다.

kubectl port-forward pods/<파드_이름> 8080:80
728x90