쌩로그

[Kubernetes] 쿠버네티스 파드(Pod) 본문

Deploy/Kubernetes

[Kubernetes] 쿠버네티스 파드(Pod)

.쌩수. 2025. 2. 25. 15:43
반응형

목록

  1. 포스팅 개요
  2. 본론
      2-1. 파드 사용하기
      2-2. 파드 vs. 도커 컨테이너
      2-3. 완전한 애플리케이션으로서의 파드
  3. 요약

1. 포스팅 개요

이 포스팅은 위키북스 출판사의 '시작하세요! 도커/쿠버네티스'의 제 6장 쿠버네티스 시작하기를 학습하며 기록한 포스팅이다.

그 중 컨테이너를 다루는 기본 단위인 Pod에 대한 내용이다.

2. 본론

파드(Pod) : 컨테이너를 다루는 기본 단위

쿠버네티스에는 셀 수도 없을 만큼 많은 리소스 종류와 컴포넌트가 존재한다.
그중에서도 컨테이너 애플리케이션을 구동하기 위해 반드시 알아야 할 몇 가지 오브젝트가 있는데, 바로 파드(Pod), 레플리카셋(Replica Set), 서비스(Service), 디플로이먼트(Deployment)이다.

그중에 가장 기초가 되는 것이 파드디.

2-1. 파드 사용하기

  • 쿠버네티스에서는 컨테이너 애플리케이션의 기본 단위를 파드(Pod) 라고 부른다.
  • 파드는 1개 이상의 컨테이너로 구성된 컨테이너의 집합이다.
  • 파드는 쿠버네티스에서 가장 기초적이고 중요한 개념이기 때문에 반드시 이해하고 넘어가는 것이 좋다.
    • 도커 엔진에서는 기본 단위가 도커 컨테이너였고, 스웜 모드에서의 기본 단위는 여러 개의 컨테이너로 구성된 서비스(service)였다.
    • 이와 비슷한 맥락으로 쿠버네티스에서는 컨테이너 애플리케이션을 배포하기 위한 기본 단위로 파드라는 개념을 사용한다.
  • 1 개의 파드에는 1 개의 컨테이너가 존재할수도 있고, 여러 개의 컨테이너가 존재할 수도 있다.
    • 간단한 예시를 들어 Nginx 웹 서비스를 쿠버네티스에서 생성하려면 컨테이너와 파드를 어떻게 사용할 수 있을까?
      • 가장 쉬운 방법은 파드 1 개에 Nginx 컨테이너 1 개만을 포함해 생성하는 것다.
      • 만약 동일한 Nginx 컨테이너를 여러 개 생성하고 싶다면 1 개의 Nginx 컨테이너가 들어 있는 동일한 파드를 여러 개 생성하면 된다.
      • 이처럼 파드는 컨테이너 애플리케이션을 나타내기 위한 기본 구성 요소다.

파드의 개념을 좀 더 정확히 이해하기 위해서 Nginx 컨테이너로 구성된 파드를 직접 생성해보자.
다음 내용을 nginx-pod.yaml 이라는 이름으로 작성하자.

apiVersion: v1
kind: Pod
metadata:
  name: my-nginx-pod
spec:
  containers:
  - name: my-nginx-container
    image: nginx:latest
    ports:
    - containerPort: 80
      protocol: TCP

작성한 YAML 파일의 의미는 아래와 같다.
쿠버네티스의 YAML 파일은 일반적으로 apiVersion, kind, metadata, spec 네 가지 항목으로 구성한다.

  • apiVersion: YAML 파일에서 정의한 오브젝트의 API 버전을 나타낸다.
    • 오브젝트의 종류 및 개발 성숙도에 따라 apiVersion 의 설정값이 달라질 수 있다
  • kind : 이 리소스의 종류를 나타낸다.
    • 위의 YAML 파일에서 생성하려고 하는 것이 파드이기 때문에 Pod를 입력했다.
    • kind 항목에서 사용할 수 있는 리소스 오브젝트 종류는 kubectl api-resources 명령어의 KIND 항목에서 확인할 수 있다.
$ kubectl api-resources
NAME                                SHORTNAMES   APIVERSION                          NAMESPACED   KIND
...
pods                                po           v1                                  true         Pod
  • metadata: 라벨 주석(Annotation), 이름 등과 같은 리소스의 부가 정보들을 입력한다.
    • 위 예시에서는 name 항목에서 파드의 고유한 이름을 my-nginx-pod로 설정했다.
  • spec: 리소스를 생성하기 위한 자세한 정보를 입력한다.
    • 위 예시에서는 파드에서 실행될 컨테이너 정보를 정의하는 containers 항목을 작성한 뒤, 하위 항목인 image 에서 사용할 도커 이미지를 지정했다.
    • name 항목에서는 컨테이너의 이름을
    • ports 항목에서는 Nginx 컨테이너가 사용할 포트인 80을 입력했다.

작성한 YAML 파일은 kubectl apply -f 명령어로 쿠버네티스에 생성할 수 있다.
다음 명령어를 사용해 새로운 파드를 생성하자.

$ kubectl apply -f nginx-pod.yaml
pod/my-nginx-pod created
  • kubectl get〈오브젝트 이름〉을 사용하면 특정 오브젝트의 목록을 확인할 수 있다.
    • 예를 들어, kubectl get pods 명령어는 현재 쿠버네티스에 존재하는 파드의 목록을 출력다.
    • 방금 생성한 파드 1개가 출력될 것이다.
$ kubectl get pods
NAME           READY   STATUS    RESTARTS   AGE
my-nginx-pod   1/1     Running   0          9s

이 Nginx 파드를 생성할 때. YAML 파일에 사용할 포트(containerPort)를 정의하긴 했지만, 아직 외부에서 접근할 수 있도록 노출된 상태는 아니다.
따라서 파드의 Nginx 서버로 요청을 보내려면 파드 컨테이너의 내부 IP로 접근해야 한다.

  • kubectl describe 명령어를 사용하면 생성된 리소스의 자세한 정보를 얻어올 수 있다.
    • 예를 들어, 파드의 자세한 정보를 출력하고 싶다면 kubectl describe pods <파드 이름> 처럼 명령어를 사용하면 된다.
    • 이 명령어로 파드의 IP를 확인해보자.
$ kubectl describe pods my-nginx-pod
...
Status:           Running
IP:               192.168.xx.xx # 일부러 가림(그냥)
Containers:
  my-nginx-container:
    Container ID:   containerd:// ....
    Image:          nginx:latest
    Image ID:       docker.io/library/nginx@sha256:...
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Tue, 25 Feb 2025 05:19:51 +0000
    Ready:          True

위처럼 Nginx 파드에 대한 많은 정보가 출력될 것이다.
그중 파드의 IP 항목도 포함돼 있으며, 출력 결과에서 알 수 있듯이 파드의 IP가 나와있다.

  • 앞서 말했던 것처럼 이 IP는 외부에서 접근할 수 있는 IP가 아니기 때문에 클러스터 내부에서만 접근할 수 있다.
    • docker run 명령어에서 -p 옵션 없이 컨테이너를 실행한 것과 비슷하다고 생각하면 이해가 쉬울 것이다.
    • 쿠버네티스 외부 또는 내부에서 파드에 접근하려면 서비스(service)라고 하는 쿠버네티스 오브젝트를 따로 생성해야 한다.
    • 지금은 서비스 오브젝트 없이 IP만으로 Nginx 파드에 접근해 보자.
  • 클러스터의 노드 중 하나에 접속한 뒤 다음과 같이 Nginx 파드의 IP로 HTTP 요청을 전송하자.
    • 이로써 Nginx 파드가 정상적으로 실행 중인 것을 알 수 있다.
$ curl <describe에서 알려주고 있는 IP>
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

참고

클러스터의 노두로 접속하는 것이 여의치 않은 상황이라면 다음 명령어로 클러스터 내부에 테스트용 파드를 생성해 임시로 사용할 수도 있다.
일반적으로 클러스터 내부에서는 파드의 IP로 접근할 수 있다.

$ kubectl run -i  --tty --rm debug --image=alicek106/ubuntu:curl --restart=Never bash

If you don\'t see a command prompt, try pressing enter.

root@debug:/#  curl <IP>
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

root@debug:/#  exit # 테스트용 파드에서 빠져나오면 삭제된다.
pod "debug" deleted
pod default/debug terminated (Error)

이번에는 파드 컨테이너 내부로 직접 들어가보자.
docker exec 명령어와 비슷하게 쿠버네티스에서도 kubectl exec 명령으로 파드의 컨테이너에 명령어를 전달할 수 있다.
예를 들어 다음과 같이 my-nginx-pod에서 배시 셸을 실행하되, -it 옵션으로 셸을 유지할 수 있다.

# 아래의 명령어를 사용하자. $ kubectl exec -it my-nginx-pod bash
$ kubectl exec my-nginx-pod -i -t -- bash
root@my-nginx-pod:/# ls /etc/nginx/
conf.d  fastcgi_params  mime.types  modules  nginx.conf  scgi_params  uwsgi_params

root@my-nginx-pod:/# exit # 파드에서 파져나온다.

도커에서 docker logs 명령어를 사용했던 것처럼 쿠버네티스에서도 kubectl logs 명령어로 파드의 로그를 확인할 수 있다.
다음 명령어를 사용하면 Nginx 파드의 표준 출력 로그를 확인할 수 있다.
Nginx 서버에 접근했던 기록이 출력된다.

$ kubectl logs my-nginx-pod
...
192.168.x.x - - [25/Feb/2025:05:36:21 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.5.0" "-"
192.168.y.y - - [25/Feb/2025:05:42:25 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.35.0" "-"

오브젝트 삭제

쿠버네티스의 오브젝트kubectl delete -f 명령어로 쉽게 삭제할 수 있다.
다음 명령어는 nginx-pod.yaml 에 정의된 Nginx 파드를 삭제하는 명령어다.

$ kubectl delete -f nginx-pod.yaml

# or 
$ kubectl delete pod <파드 이름> 

# 예시 : 필자는 이렇게 지웠다.
$ kubectl delete pod my-nginx-pod
pod "my-nginx-pod" deleted

2-2. 파드 vs. 도커 컨테이너

  • 위의 기능들만 놓고 본다면 파드는 docker run으로 생성한 단일 nginx 컨테이너와 크게 다르지 않아 보이기도 한다.
  • 파드
    • 컨테이너 IP 주소를 가지고 있어 쿠버네티스 클러스터 내부에서 접근할 수 있고,
    • kubectl exec 명령어로 파드 컨테이너 내부로 들어갈 수도 있으며,
    • kubectl logs 명령어로 파드의 로그를 확인할 수도 있다.

쿠버네티스는 왜 도커 컨테이너'가 아니라 굳이 '파드'라는 새로운 개념을 사용하는 것일까?

쿠버네티스가 파드를 사용하는 이유는 컨테이너 런타임의 인터페이스 제공 등 여러 가지가 있지만, 그 이유 중 하나는 여러 리눅스 네임스페이스(namespace)를 공유하는 여러 컨테이너들을 추상화된 집합으로 사용하기 위해서이다.

이를 쉽게 이해할 수 있게 파드를 사용하는 예시를 하나 더 살펴보자.

kubectl get pods 명령어로 파드의 목록을 출력했을 때, READY 항목에서 1/1이라는 출력을 봤을 것이다.
Nginx 파드에는 1개의 컨테이너가 정의돼 있으며, 이 컨테이너는 정상적으로 준비됐다는 뜻이다.

$ kubectl get pods
NAME           READY   STATUS    RESTARTS   AGE
my-nginx-pod   1/1     Running   0          9s

실제로 대부분 쿠버네티스의 컨테이너 애플리케이션은 이처럼 1개의 컨테이너로 파드를 구성해 사용한다.
그런데 1/1이라는 항목에서 알 수 있듯이, 파드는 반드시 1개의 컨테이너로 구성해야하는 것은 아니다.
READY 항목은 파드의 컨테이너 개수에 따라 2/2도 될 수 있고, 3/3도 될 수 있 습니다.

그렇다면 이번에는 Nginx 파드에 새로운 우분투 컨테이너를 추가해 보겠습니다. 이전에 사용한 YAML 파일을 확장해 아래 내용으로 새로운 YAML 파일을 작성하자.

curl이 미리 설치된 우분투 이미지인 alicekl06/rr-test:curl 을 사용했으며, 이 컨테이너는 종료되지 않기 위해 tail -f /dev/ null이라는 단순한 동작만을 실행한다.

apiVersion: v1
kind: Pod
metadata:
  name: my-nginx-pod
spec:
  containers:
  - name: my-nginx-container
    image: nginx:latest
    ports:
    - containerPort: 80
      protocol: TCP
  - name: ubuntu-sidecar-container
    image: alicek106/rr-test:curl
    command: ["tail"]
    args: ["-f", "/dev/null"] # 컨테이너가 종료되지않도록 유지한다.

YAML에서 대시(-) 를 사용하는 항목은 여러 개의 항목을 정의할 수 있음을 의미한다.

예를 들어 위에서 사용한 spec.containers 의 하위 항목은 "-name: my-nginx-container" 와 같이 대시로 구분되며, 여러 개의 컨테이너를 정의할 수 있다.

따라서 이번에는 파드에 우분투 컨테이너 (ubuntu-sidecar-container) 를 하나 더 추가했다.


참고

  • 파드의 YAML 파일에서 사용되는 command와 args는 컨테이너 내부에서 가장 먼저 실행될 프로세스를 지정한다.
  • YAML 파일에서의 command는 도커 컨테이너의 Entrypoint와 동일하고, 파드에서의 args는 도커 컨테이너의 Cmd(커맨드)와 동일하다고 이해하면 쉽다.

앞서 파드를 생성했던 것처럼 kubectl apply -f 명령을 사용해 YAML 파일을 쿠버네티스에 적용한다.
시간이 조금 지나면 Nginx 파드에 2개의 컨테이너가 실행 중인 것을 확인할 수 있다,

$ kubectl apply -f nginx-pod-with-ubuntu.yaml
pod/my-nginx-pod created

$ kubectl get pods
NAME           READY   STATUS              RESTARTS   AGE
my-nginx-pod   0/2     ContainerCreating   0          13s

$ kubectl get pods
NAME           READY   STATUS    RESTARTS   AGE
my-nginx-pod   2/2     Running   0          26s
  • kubectl exec 명령어를 이용해 새롭게 추가된 우분투 컨테이너의 내부로 들어가 보자.
  • kubectl exec, logs 등과 같은 명령어를 사용할 때는 -c 옵션을 이용해 파드의 어떤 컨테이너에 대해 명령어를 수행할지 명시할 수 있다.
  • 다음 명령어는 앞서 파드에 추가한 컨테이너인 ubuntu-sidecar-container에서 배시 셸을 실행한다.
# 아래 명령어는 안 된다. 그 아래 것으로 하자.
#$ kubetctl exec my-nginx-pod  -i -t -- bash -c ubuntu-sidecar-container
$ kubectl exec my-nginx-pod -c ubuntu-sidecar-container -i -t -- bash
root@my-nginx-pod:/#

ubuntu-sidecar-container 컨테이너 내부에서 로컬호스트로 HTTP 요청을 전송하면 Nginx 서버의 응답이 도착하는 것을 확인할 수 있다.

root@my-nginx-pod:/# curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

이전 장에서 도커를 많이 사용해 봤다면 여기에서 뭔가 이상한 것을 눈치챘을 것다.
우분투 컨테이너가 Nginx 서버를 실행하고 있지 않은데도, 우분투 컨테이너의 로컬호스트에서 Nginx 서버로 접근이 가능하다.
이는 파드 내의 컨테이너들이 네트워크 네임스페이스 등과 같은 리눅스 네임스페이스를 공유해 사용하기 때문이다.


참고

네트워크 네임스페이스는 컨테이너의 고유한 네트워크 환경을 제공해주는 역할을 담당한다.
예를 들어 docker run 명령어로 docker0 브리지에 연결된 컨테이너가 생성됐다면, 그 컨테이너는 자기 자신만의 고유한 네트워크 네임스페이스를 가지게 된다.
그렇기 때문에 호스트 및 다른 컨테이너와 다른 고유한 IP를 유지할 수 있는 것이다.


도커의 네트워크 구조에는 docker run --net container:(컨테이너 이름) 옵션을 사용하는 “컨테이너 네트워크" 종류가 있다.
간단하게 상기하자면 컨테이너 네트워크 타입은 네트워크 네임스페이스를 컨테이너 간에 공유해 사용할 수 있도록 설정하기 때문에 여러 개의 컨테이너가 동일한 네트워크 환경을 가지게 된다.
쿠버네티스의 파드 또한 이러한 리눅스 네임스페이스의 공유 개념을 사용하고 있는 것이다.

그러나 파드가 공유하는 리눅스 네임스페이스에 네트워크 환경만 있는 것은 아니다.
1개의 파드에 포함된 컨테이너들은 여러 개의 리눅스 네임스페이스를 공유한다.
“파드 내부의 컨테이너들은 네트워크와 같은 리눅스 네임스페이스를 공유한다”라고 알고 넘어가자.

2-3. 완전한 애플리케이션으로서의 파드

  • 실제 쿠버네티스 환경에서는 1개의 컨테이너로 구성된 파드를 사용하는 경우가 많으며, 이후 다룰 대부분의 예시 또한 그러할 것이다.
  • 그렇다면 왜 하나의 파드에 여러 개의 컨테이너가 함께 포함돼야 하는지에 대해 의문점이 생길 수도 있다.
  • 여기서 한 가지 유의해야 할 점은 '하나의 파드는 하나의 완전한 애플리케이션'이라는 점이다.

Nginx 컨테이너는 그 자체만으로도 완전한 애플리케이션이기 때문에 하나의 파드에 2개의 Nginx 컨테이너가 정의되는 것은 바람직하지 않다.
따라서 우리가 처음에 생성했던 파드에서는 1개의 Nginx 컨테이너만을 정의했다.

컨테이너가 실행되기 위해 부가적인 기능이 필요하다면

  • 만약 Nginx 컨테이너가 실행되기 위해 부가적인 기능을 필요로 한다면 어떨까???
    • 예를 들어, Nginx의 설정 파일의 변경사항을 갱신해주는 설정 리로더(reloader) 프로세스나 로그를 수집해주는 프로세스는 Nginx 컨테이너와 함께 실행돼야 할 수 있다.
    • 이런 경우 파드의 주 컨테이너를 Nginx로 하되, 기능 확장을 위한 추가 컨테이너를 함께 파드에 포함시킬 수 있다.
    • 이렇게 파드에 정의된 부가적인 컨테이너를 사이드카(sidecar) 컨테이너라고 부르며, **사이드카 컨테이너는 파드 내의 다른 컨테이너와 네트워크 환경 등을 공유한다.
      • 때문에 파드에 포함된 컨테이너들은 모두 같은 워커 노드에서 함께 실행된다.

이러한 구조 및 원리에 따라 파드에 정의된 여러 개의 컨테이너는 하나의 완전한 애플리케이션으로서 동작하게 된다.
이것이 도커 컨테이너와 쿠버네티스 파드의 차이점이다.


참고

파드의 네트워크 네임스페이스는 Pause 라는 이름의 컨테이너로부터 네트워크를 공유받아 사용한다.
Pause 컨테이너는 네임스페이스를 공유하기 위해 파드별로 생성되는 컨테이너이며, Pause 컨테이너는 각 파드에 대해 자동으로 생성된다.

$ ps aux | grep pause
...
65535      22318  0.0  0.0    996   512 ?        Ss   05:06   0:00 /pause
...

도커 엔잔을 컨테이너 런타임으로 쓰고 있다면 docker ps 명령어로 pause 컨테이너를 직접 확인할 수 있다.

$ docker ps | grep nginx
# 나는 나오지 않는다.

3. 요약

  • 컨테이너 애플리케이션의 기본 단위를 파드(Pod) 라고 부른다.
  • 파드는 1개 이상의 컨테이너로 구성된 컨테이너의 집합이다.
  • 하나의 파드는 하나의 완전한 애플리케이션이라는 컨셉을 가진다.
  • 파드 내의 컨테이너들은 네트워크 네임스페이스 등과 같은 리눅스 네임스페이스를 공유해서 사용한다.
  • 파드에 정의된 부가적인 컨테이너를 사이드카(sidecar) 컨테이너라고 부르며, 사이드카 컨테이너는 파드 내의 다른 컨테이너와 네트워크 환경 등을 공유한다.

Pod에 대해 알아보면서 사용해봤고 도커의 컨테이너와는 어떻게 다른지, 어떤 컨셉을 가지는 지 알아봤다.

728x90
Comments