nayoungs
항상 끈기있게
nayoungs
  • 분류 전체보기 (274)
    • Cloud (21)
      • AWS (15)
      • Azure (3)
      • NCP (2)
      • GCP (1)
    • DevOps (68)
      • Docker (16)
      • Kubernetes (50)
      • CICD (2)
    • IaC (25)
      • Ansible (17)
      • Terraform (8)
    • Certification (4)
    • 금융 IT (5)
    • AI (3)
    • Linux (47)
    • 미들웨어 (5)
    • Programming (7)
      • GoLang (3)
      • Spring (4)
    • CS (25)
      • 네트워크 (17)
      • 운영체제 (5)
      • Web (1)
      • 개발 상식 (2)
      • 데이터베이스 (0)
    • Algorithm (59)
      • 프로그래머스 (36)
      • 백준 (18)
      • 알고리즘 정리 (5)
    • ETC (5)

블로그 메뉴

  • 홈
  • 방명록

공지사항

인기 글

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
nayoungs

항상 끈기있게

DevOps/Kubernetes

[Kubernetes] k8s Workload : Pod

2022. 5. 17. 20:17
728x90

📌Index

  • 파드(Pod)란?
  • Pod 생성 및 관리
  • YAML 파일로 파드 정의
  • Pod 디자인
  • Pod 포트 포워딩



✔️ 파드(Pod)란?

워크로드는 쿠버네티스에서 구동되는 애플리케이션이다.

워크로드가 단일 컴포넌트이거나 함께 작동하는 여러 컴포넌트이든 관계없이,

쿠버네티스에서는 워크로드를 일련의 파드 집합 내에서 실행한다.

 

Pod는 하나 이상의 컨테이너 그룹으로, 컨테이너를 실행하기 위한 오브젝트이다.

쿠버네티스에서 관리할 수 있는 가장 작은 Workload는 Pod이다.

즉, 쿠버네티스는 컨테이너를 직접 컨트롤하지 않고, 파드만 관리할 수 있다

참고로 하나의 파드는 하나의 호스트에만 배치되고, 하나의 노드에 배치된다.

 

파드의 사용
  1. 단일 컨테이너를 실행하는 파드 파드가 하나의 컨테이너만 포함하는 경우이다. 파드는 단순히 컨테이너를 둘러싼 래퍼이며, 쿠버네티스는 컨테이너를 직접 관리하는 대신 파드를 관리한다.
  2. 함께 작동해야 하는 여러 컨테이너를 실행하는 파드 함께 배치된 컨테이너는 밀접한 결합성을 가지며 리소스를 공유한다. 이들은 하나의 결합된 서비스 단위를 형성한다.

 

하나의 파드에는 밀접한 관계를 가진 컨테이너를 배치해야 한다.

WordPress를 예시로 생각해보자. 하나의 파드에 WordPress 컨테이너와 MySQL 컨테이너를 두어도 될까❔

불가능한 것은 아니나, 하나의 파드에 wordpress 컨테이너와 mysql 컨테이너를 두는 것은 Anti-Pattern이다.

하나의 파드에는 반드시 하나의 Main Application만 있을 수 있어야 한다.

파드는 특정 노드에 배치되는데, 해당 노드에 문제가 발생한다면 서비스를 사용할 수 없게 될 수 있다.

logs와 같이 떨어져 있으면 의미가 없는 경우에만 하나의 파드에 배치한다.



✔️ Pod 생성 및 관리

명령형 커맨드로 파드 실행
$ kubectl run
$ kubectl run NAME --image=image [--env="key=value"] [--port=port] [--dry-run=server|client] [--overrides=inline-json]
[--command] -- [COMMAND] [args...] [options]

예시

$ kubectl run myweb --image httpd
pod/myweb created

 

파드 상세 정보 확인
$ kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
myweb   1/1     Running   0          46s
  • NAME : Pod의 이름
  • READY : 준비된 컨테이너의 개수/컨테이너의 총 개수
  • RESTARTS : 재시작 횟수
  • AGE : 현재를 기준으로 만들어진 시각


-o wide 옵션을 사용하면 더 상세한 정보까지 확인할 수 있다.

$ kubectl get pods -o wide
NAME    READY   STATUS    RESTARTS   AGE     IP            NODE    NOMINATED NODE   READINESS GATES
myweb   1/1     Running   0          2m58s   10.233.96.1   node2   <none>           <none>

원하는 형식으로 etcd에 저장된 로우 데이터를 확인하는 것도 가능하다.

$ kubectl get pods -o yaml
$ kubectl get pods -o json

 

kubectl describe

 

좀 더 깔끔하게 정돈된 형태로 확인할 수 있다.

$ kubectl describe pods myweb
Name:         myweb
Namespace:    default
Priority:     0
Node:         node2/192.168.100.101
Start Time:   Tue, 17 May 2022 01:37:27 +0000
Labels:       run=myweb
Annotations:  cni.projectcalico.org/containerID: d934f2835963f3a41399d163e4831b1019a6d26cfaf8313078a6e0641bdfcc03
              cni.projectcalico.org/podIP: 10.233.96.1/32
              cni.projectcalico.org/podIPs: 10.233.96.1/32
Status:       Running
IP:           10.233.96.1
IPs:
  IP:  10.233.96.1
Containers:
  myweb:
    Container ID:   containerd://a4c734defa9212f176c05f3318560b0c218ab65ca2f021d7157e0c7cbd2bf0f3
    Image:          httpd
    Image ID:       docker.io/library/httpd@sha256:2d1f8839d6127e400ac5f65481d8a0f17ac46a3b91de40b01e649c9a0324dea0
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Tue, 17 May 2022 01:38:07 +0000
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-2g9hd (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  kube-api-access-2g9hd:
    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  6m57s  default-scheduler  Successfully assigned default/myweb to node2
  Normal  Pulling    6m57s  kubelet            Pulling image "httpd"
  Normal  Pulled     6m38s  kubelet            Successfully pulled image "httpd" in 18.992429786s
  Normal  Created    6m17s  kubelet            Created container myweb
  Normal  Started    6m17s  kubelet            Started container myweb

여기서 Events는 지정한 리소스의 lifecycle에 대한 정보이다.

Events 정보는 kubectl describe를 통해서만 확인할 수 있다.

로그라고도 할 수 있는데, 쿠버네티스에서 리소스 자체에 대한 이벤트 로그로, 시간 순으로 나타난다.

 

 

Events에 대해서 더 자세히 살펴보기. 

 

더보기

설명을 위해 임의로 번호를 붙였다

 

Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
 1.  Normal  Scheduled  6m57s  default-scheduler  Successfully assigned default/myweb to node2
 2.  Normal  Pulling    6m57s  kubelet            Pulling image "httpd"
 3.  Normal  Pulled     6m38s  kubelet            Successfully pulled image "httpd" in 18.992429786s
 4.  Normal  Created    6m17s  kubelet            Created container myweb
 5.  Normal  Started    6m17s  kubelet            Started container myweb

     

   1. 파드를 만들 때 가장 먼저 하는 것은 스케쥴링으로, 스케쥴러가 어느 노드에 배치할지 결정해야 한다.

       첫 번째 이벤트가 default-scheduler로부터 생성된 것을 확인할 수 있다.

 

    2. node2의 kubelet으로부터 이미지를 pulling 한다.

       1번에서 스케쥴러가 node2에 배치했기 때문이다.

 

    3. Pulled이므로, 이미지 pulling이 완료되었다.

 

    4. kubelet이 myweb 컨테이너를 생성했다.

 

    5. kubelet이 myweb 컨테이너를 실행하였다.

 

 

만약 Pod가 제대로 작동이 안 한다면 크게 2가지를 봐야 한다.

  • Pod가 제대로 만들어졌는지 -> 오브젝트 리소스 자체의 로그 확인
  • 컨테이너는 제대로 만들어졌으나, 애플리케이션이 잘 실행 안될 때 --> 애플리케이션 로그 확인(아래에서 설명)

 

애플리케이션 로그 확인하기
$ kubectl logs [Pod]

kubectl get pods와 같이 서브 커맨드 뒤에 종류를 지정하는 것이 일반적인데,

애플리케이션 로그를 볼 수 있는 것은 pod 밖에 없기 때문에 별도로 pods를 붙이지 않는다.

$ kubectl logs myweb

 

파드 삭제
$ kubectl delete pods [pod]

예시

$ kubectl delete pods myweb



⭐알아둘 사항

ubuntu:focal 이미지를 사용해서 pod를 생성해보자

$ kubectl run myubuntu --image ubuntu:focal

시간이 조금 지난 뒤 확인해보면 CrashLoopBackOff 상태가 되는 것을 확인할 수 있다.

$ kubectl get pods
NAME       READY   STATUS             RESTARTS       AGE
myubuntu   0/1     CrashLoopBackOff   2 (18s ago)    7m38s

kubectl describe pods 명령어를 통해 이벤트 로그를 확인해보자

Events:
  Type     Reason     Age               From               Message
  ----     ------     ----              ----               -------
  Normal   Scheduled  49s               default-scheduler  Successfully assigned default/myubuntu to node3
  Normal   Pulled     7s (x4 over 48s)  kubelet            Container image "ubuntu:focal" already present on machine
  Normal   Created    7s (x4 over 48s)  kubelet            Created container myubuntu
  Normal   Started    7s (x4 over 48s)  kubelet            Started container myubuntu
  Warning  BackOff    7s (x5 over 47s)  kubelet            Back-off restarting failed container

마지막 이벤트에 Back-off restarting failed container를 확인할 수 있다.

pod는 종료되지 않는 애플리케이션을 실행하는 것이 기본 원칙인데,

쿠버네티스는 기본적으로 무조건 detach모드로 실행한다.

ubuntu는 원래 attach모드(-it)로만 실행해야 유효하기 때문에, 애플리케이션이 종료되었기 때문이다.

참고로 -d 옵션은 기본이기 때문에 안 붙여도 되고, -it 옵션을 제공하기는 한다.

$ kubectl run myubuntu2 --image ubuntu:focal -it bash



✔️ YAML 파일로 파드 정의

명령형이랑 섞어서 사용해도 상관없다.

myweb.yaml

apiVersion: v1
kind: Pod
metadata:
  name: myweb
spec:
  containers:
    - name: myweb
      image: httpd

파드 생성

$ kubectl create -f myweb.yaml

파드 확인

$ kubectl get -f myweb.yaml
NAME    READY   STATUS    RESTARTS      AGE
myweb   1/1     Running   1 (22m ago)   4h53m

상세 정보 확인 및 이벤트 정보 확인

$ kubectl describe -f myweb.yaml

파드 삭제

$ kubectl delete -f myweb.yaml



✔️ Pod 디자인

파드 생성 다이어그램

Web Server가 메인 기능

  • 단일 컨테이너 : 일반적인 형태
  • 멀티 컨테이너 : 메인 애플리케이션이 존재하고, 메인 애플리케이션 기능을 확장하기 위한 컨테이너를 배치
    • Main Car(메인), Side Car(보조)

 

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

하나의 Pod는 네트워크와 볼륨을 공유한다.

Pod는 네트워크를 공유하므로, Pod에는 하나의 IP만 부여된다.

 

사이드카 패턴

The Distributed System ToolKit: Patterns for Composite Containers | Kubernetes

Composite Container == Multi Container

3가지 타입 : 큰 범위에서 보면 모두 사이드카인데, 기능적으로 분류한 것이다.

  • 사이드카 : 메인 컨테이너의 기능을 확장 (예: Log Saving)
  • 앰버서더 : 네트워크 흐름을 컨테이너 내부에서 pod 외부로의 흐름을 가지고 있는 사이드카 (예: Proxy)
    • 내부에서 외부로 나가는 트래픽을 조정
  • 어댑터 : 네트워크의 흐름이 외부에서 내부로의 흐름을 가지고 있는 사이드카
    • 컨테이너의 출력을 표준화, 로그를 가공해서 포맷팅(표준화)

파드는 보조적인 기능을 하는 사이드카를 함께 올리는 것이지 메인 앱을 함께 올리는 것은 안티 패턴이다

 

⭐알아둘 사항

다음 yaml 파일을 통해 파드를 생성해보자.

myweb.yaml

apiVersion: v1
kind: Pod
metadata:
  name: myweb
spec:
  containers:
    - name: myweb
      image: httpd
    - name: myweb2
      image: httpd
$ kubectl create -f myweb.yaml

시간이 조금 지난 뒤 kubectl get pods로 확인해보면 2개의 컨테이너 중 1개만 준비된 상태이며,

STATUS가 CrashLoopBackoff인 것을 확인할 수 있다.

$ kubectl get pods
NAME    READY   STATUS             RESTARTS      AGE
myweb   1/2     CrashLoopBackOff   1 (20s ago)   27s

kubectl describe로 상세 정보를 확인해보자

Containers:
  myweb:
    Container ID:   containerd://bcbebcc7b1a80523e9a10b31da831a18b426b005f134fdc31b2376ee92e80766
    Image:          httpd
    Image ID:       docker.io/library/httpd@sha256:2d1f8839d6127e400ac5f65481d8a0f17ac46a3b91de40b01e649c9a0324dea0
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Tue, 17 May 2022 10:41:34 +0000
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-pdj86 (ro)
  myweb2:
    Container ID:   containerd://bbd5515d5fe51161004306dd5f70de320e167ace1de3682f111a0bbb097d307a
    Image:          httpd
    Image ID:       docker.io/library/httpd@sha256:2d1f8839d6127e400ac5f65481d8a0f17ac46a3b91de40b01e649c9a0324dea0
    Port:           <none>
    Host Port:      <none>
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       Error
      Exit Code:    1
      Started:      Tue, 17 May 2022 10:43:19 +0000
      Finished:     Tue, 17 May 2022 10:43:19 +0000
    Ready:          False
    Restart Count:  4
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-pdj86 (ro)

myweb1은 정상적으로 실행되지만, myweb2 계속 Start과 Backoff 을 반복하고 있다. 왜 그럴까❔

파드는 동일한 네트워크를 공유하므로, 포트가 겹치기 때문이다.

그런데 왜 myweb1이 아닌, myweb2가 안 되는 것일까?

Containers는 리스트로, 순서가 있다. myweb1이 먼저 생성되기 때문이다.

 

참고로 아래의 명령을 실행하면 에러가 발생한다.

$ kubectl logs myweb
error: a container name must be specified for pod myweb, choose one of: [myweb myweb2]

Pod에 컨테이너가 한 개일 때는 컨테이너를 지정하지 않아도 되지만, 여러 개로 구성된 경우 컨테이너를 지정해야 한다.

-c 옵션을 통해 컨테이너를 지정할 수 있다.

$ kubectl logs myweb -c myweb2
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.233.92.11. Set the 'ServerName' directive globally to suppress this message
(98)Address already in use: AH00072: make_sock: could not bind to address [::]:80
(98)Address already in use: AH00072: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down
AH00015: Unable to open logs

could not bind to address : 포트 에러가 난 것을 확인할 수 있다.

 

또한 pod에 컨테이너가 몇 개이든 하나의 노드(node3)에 배치되는 것을 확인할 수 있다.

$ kubectl get pods -o wide
NAME    READY   STATUS             RESTARTS      AGE     IP             NODE    NOMINATED NODE   READINESS GATES
myweb   1/2     CrashLoopBackOff   6 (69s ago)   7m11s   10.233.92.11   node3   <none>           <none>

다음 명령어로 네트워크를 공유하는 것도 확인할 수 있다

$ kubectl describe pods



✔️ Pod 포트 포워딩

파드의 포트 포워딩이 가능은 하나, 파드의 포트 포워딩은 외부로 노출시키기 위해 사용하는 것이 아니다.

포그라운드(foreground) 상태로 작동하며, 테스트 & 디버깅 목적으로 사용한다.

$ kubectl port-forward TYPE/NAME [options] [LOCAL_PORT]:[REMOTE_PORT]

쿠버 네티스는 외부에 노출시키기 위해 네트워크(서비스) 오브젝트를 사용해야 한다.

 

💻 실습

myweb.yaml

apiVersion: v1
kind: Pod
metadata:
  name: myweb
spec:
  containers:
    - name: myweb
      image: httpd
      ports:
        - containerPort: 80
          protocol: TCP     
$ kubectl create -f myweb.yaml

0~1023번 포트는 열려면 관리자 권한이 필요하므로 8080 포트로 진행한다.

$ kubectl port-forward pods/myweb 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

다른 터미널 창을 열어 확인해보면 정상적으로 작동하는 것을 확인할 수 있다.

$ curl localhost:8080
<html><body><h1>It works!</h1></body></html>



 

 

728x90
저작자표시 비영리 (새창열림)
    'DevOps/Kubernetes' 카테고리의 다른 글
    • [Kubernetes] k8s Label, LabelSelector, Annotations
    • [Kubernetes] k8s Namespace (feat. 이름과 UID)
    • [Kubernetes] k8s 오브젝트(Objects)
    • [Kubernetes] Kubespray로 쿠버네티스 설치하기
    nayoungs
    nayoungs
    안되면 될 때까지

    티스토리툴바