파드(Pod)란?

artp·2024년 12월 30일

kubernetes

목록 보기
2/18
post-thumbnail

파드(Pod)란?

도커에서는 하나의 프로그램을 실행하는 단위를 컨테이너(Container)라고 부릅니다. 쿠버네티스에서는 이와 유사하게 프로그램 실행 단위를 파드(Pod)라고 부르며, 파드는 쿠버네티스의 기본 실행 단위입니다.

즉, 파드(Pod)쿠버네티스에서 하나의 애플리케이션(프로그램)을 실행하는 가장 작은 단위입니다.

주요 특징

  1. 쿠버네티스에서 가장 작은 배포 단위

    • 모든 애플리케이션은 최소 하나의 파드 형태로 실행됩니다.
  2. 파드와 컨테이너의 관계

    • 일반적으로 하나의 파드하나의 컨테이너를 포함합니다.
    • 다만, 특정 상황에서는 하나의 파드가 여러 개의 컨테이너를 포함하기도 합니다. 이 경우, 컨테이너들은 공통된 작업을 수행하거나 서로 보완적인 역할을 하기 위해 함께 배치됩니다. 예를 들어, 하나의 컨테이너는 애플리케이션을 실행하고, 다른 컨테이너는 로그를 수집하는 역할을 할 수 있습니다. 이들은 동일한 네트워크와 스토리지를 공유합니다.
  3. 컨테이너(Container)란?

    • 파드 내부에서 실행되는 도커의 실행 단위입니다.

예시

  • 결제 서버 애플리케이션을 실행한다고 가정:
    1. "2개의 결제 서버가 띄워져 있다" → 2개의 결제 서버 파드(Pod)가 실행되고 있다.
    2. "1개의 결제 서버가 죽었다" → 1개의 결제 서버 파드(Pod)가 종료되었다.
    3. "업로드 서버를 하나 띄우자" → 업로드 서버를 하나의 파드(Pod)로 실행하자.

쿠버네티스에서 파드(Pod)의 동작 방식

쿠버네티스는 도커와 마찬가지로 이미지를 기반으로 애플리케이션을 실행합니다.
즉, 파드(Pod)는 특정 도커 이미지에서 컨테이너를 생성하여 애플리케이션을 실행합니다.

  • 이미지(Image): 애플리케이션의 실행 환경과 설정을 포함하는 템플릿입니다.
    예를 들어, nginx 이미지라면 Nginx 웹 서버를 실행하기 위한 설정이 담겨 있습니다.

파드는 다음과 같은 과정을 통해 동작합니다:
1. 사용자가 실행하려는 애플리케이션에 대한 이미지를 지정합니다.
2. 쿠버네티스가 해당 이미지를 기반으로 컨테이너를 생성합니다.
3. 이 컨테이너가 파드에 포함되어 실행됩니다.

실습 #1: 웹 서버(Nginx)를 파드(Pod)로 띄워보기

쿠버네티스에서 웹 서버(Nginx)를 실행하기 위해 파드(Pod)를 생성합니다. 파드를 생성하는 방법에는 크게 두 가지가 있습니다.

  1. CLI 명령어를 직접 사용하는 방법
  2. YAML 파일을 작성하여 생성하는 방법

실제 현업에서는 YAML 파일을 주로 사용합니다. 이유는 YAML 파일을 활용하면 구성(스펙)을 명확하게 문서화하고, 버전 관리(Git)를 통해 쉽게 추적할 수 있기 때문입니다. 따라서, 이번에는 YAML 파일을 사용해 파드를 생성하는 방법을 알아보겠습니다.

1. YAML 파일 작성하기

nginx-pod.yaml

apiVersion: v1 # Pod를 생성할 때 사용하는 API 버전 (Pod 생성 시에는 항상 v1 사용)
kind: Pod # 생성할 리소스 종류를 Pod로 명시
metadata:
  name: nginx-pod # Pod의 이름 (리소스를 구분하는 고유 식별자)
spec:
  containers:
    - name: nginx-container # 컨테이너 이름 (Pod 내부에서 사용)
      image: nginx # 생성할 컨테이너에 사용할 Docker 이미지
      ports:
        - containerPort: 80 # 실제 작동에는 영향을 미치지 않으며, 문서화 목적 (Dockerfile의 EXPOSE와 유사)

nginx-pod.yaml 설명:

  • apiVersion: 리소스를 생성할 때 사용할 API 버전을 지정합니다. 파드를 생성할 경우 항상 v1을 사용합니다.
  • kind: 생성할 리소스의 종류를 지정합니다. 여기서는 Pod를 명시합니다.
  • metadata: 파드의 이름 및 기타 메타데이터 정보를 담습니다.
    • name: 파드의 이름으로, 리소스를 구분하기 위한 고유 식별자입니다.
  • spec: 파드의 세부 구성 정보를 정의합니다.
    • containers: 파드에 포함될 컨테이너의 리스트입니다.
      - name: 컨테이너 이름을 지정합니다. (같은 파드 내에서 컨테이너를 식별)
      - image: 사용할 Docker 이미지를 지정합니다. 여기서는 nginx 이미지를 사용합니다.
      - ports: 컨테이너가 사용하는 포트를 명시적으로 나타냅니다.
      - containerPort: 컨테이너 내부에서 사용하는 포트 번호를 지정합니다.

      참고: containerPort는 실제 작동에는 영향을 미치지 않고, 주로 문서화 목적으로 사용됩니다. Dockerfile에서의 EXPOSE와 유사한 역할을 합니다.

❗️YAML 문법 작성 시 들여쓰기는 Tab 대신 반드시 띄어쓰기(Space)를 사용해야 합니다.

2. YAML 파일을 기반으로 파드(Pod) 생성하기

YAML 파일을 작성한 후, kubectl 명령어를 사용하여 파드를 생성합니다.

$ kubectl apply -f nginx-pod.yaml
  • -f: 명령어 뒤에 YAML 파일의 경로를 지정합니다.
  • 명령 실행 후, Kubernetes가 YAML 파일의 내용을 읽고, 해당 리소스를 생성합니다.

3. 파드(Pod) 상태 확인하기

파드가 제대로 생성되었는지 확인하려면 다음 명령어를 실행합니다.

$ kubectl get pods

출력 예시:

NAME         READY   STATUS    RESTARTS   AGE
nginx-pod    1/1     Running   0          10s
  • NAME: 파드의 이름
  • READY: 컨테이너가 준비된 상태(예: 1/1이면 정상 실행)
  • STATUS: 파드의 현재 상태 (Running, Pending, Completed 등)
  • RESTARTS: 파드가 재시작된 횟수
  • AGE: 파드가 생성된 이후 경과 시간

파드 상태가 Running이 아닌 경우

  • Pending: 컨테이너가 아직 시작되지 않았음
  • CrashLoopBackOff: 컨테이너 실행 중 에러가 발생하여 재시작을 반복 중

4. 파드(Pod)의 상세 정보 확인

생성된 파드의 더 자세한 정보를 보려면 다음 명령어를 사용합니다.

$ kubectl describe pod nginx-pod
  • Events: 파드 생성 시 발생한 이벤트 로그
  • Containers: 파드 내부 컨테이너의 상태 및 정보
  • IP: 파드의 클러스터 내부 IP 주소

5. 결과 확인

파드는 잘 생성되었으나, 접속이 안 되는 결과를 확인할 수 있습니다.

6. 파드(Pod)로 띄운 프로그램에 접속이 안 되는 이유

이유 #1. 파드 네트워크와 로컬 네트워크가 분리되어 있음

  • 파드 네트워크는 클러스터 내부에서만 통신 가능

    • 쿠버네티스에서 각 파드는 고유한 네트워크(IP 주소)를 가지고 있습니다.
    • 이 네트워크는 클러스터 내부에서만 유효하며, 로컬 컴퓨터(호스트)와는 분리되어 있습니다.
    • 따라서 로컬 컴퓨터에서 파드로 직접 접근할 수 없습니다.
  • 보안 설계상 분리

    • 기본적으로 쿠버네티스는 클러스터 내부와 외부를 격리하여 보안을 강화합니다.
    • 로컬 네트워크와 파드 네트워크가 분리되어 있어야, 클러스터 내부의 리소스를 외부로부터 보호할 수 있습니다.

이유 #2. 파드 내부에서 실행 중인 프로그램의 포트가 외부에 노출되지 않음

  • 컨테이너 내부에서만 접근 가능

    • 파드 안의 Nginx 웹 서버는 컨테이너 내부에서만 접근 가능합니다.
    • 기본적으로 파드 내부 포트는 외부(로컬)로 열려 있지 않기 때문에, 로컬 컴퓨터에서는 접근할 수 없습니다.
  • 외부 접근을 위한 추가 설정 필요

    • 파드 내부 포트를 외부에서 접근하려면 별도의 설정이 필요합니다.
      • 포트 포워딩: 로컬 컴퓨터와 파드 간에 포트를 연결해주는 작업.
      • 서비스(Service): 쿠버네티스에서 파드의 네트워크를 외부로 노출시키는 리소스.

7. 파드(Pod)로 띄운 프로그램에 접속하기

7-1. 파드 내부로 들어가서 접근

파드 내부로 접속하여 Nginx로 요청을 보내고, 웹 페이지가 정상적으로 응답하는지 확인합니다.

kubectl exec -it [파드명] -- bash
  • 파드 내부 환경에 접속하기 위한 명령어입니다.
  • 비슷한 도커 명령어: docker exec -it [컨테이너 ID] bash
kubectl exec -it nginx-pod -- bash
  • nginx-pod라는 이름의 파드 내부에 접속합니다.

파드 내부에서 curl 명령어를 사용해 Nginx로 요청을 보냅니다.

curl localhost:80
  • localhost:80은 Nginx가 기본적으로 사용하는 포트입니다.
  • 이 명령어를 실행하면, Nginx가 제공하는 웹 페이지의 응답을 확인할 수 있습니다.

정리

쿠버네티스에서는 파드(Pod) 내부에 있는 컨테이너들이 같은 네트워크를 함께 사용합니다.

즉, 파드 내부에서 localhost로 요청을 보내면, 같은 파드 안에 있는 Nginx와 바로 통신할 수 있습니다.
쉽게 말해, 파드 안의 컨테이너들은 하나의 컴퓨터를 같이 사용하는 것처럼 동작하기 때문에, 서로 요청을 주고받기가 매우 간단합니다.

그래서 파드 내부로 들어가서 localhost:80으로 요청을 보내면 Nginx가 응답할 수 있습니다.

7-2. 파드의 내부 네트워크를 외부에서 접속할 수 있도록 포트 포워딩(포트 연결)

파드 내부의 Nginx에 로컬 환경에서도 접근하려면 포트 포워딩(port forwarding)을 설정해야 합니다. 포트 포워딩은 로컬 컴퓨터의 포트와 파드 내부 포트를 연결해 주는 작업입니다.

포트 포워딩 명령어

kubectl port-forward pod/[파드명] [로컬 포트]:[파드 포트]
  • [파드명]: 포트 포워딩을 설정할 대상 파드의 이름
  • [로컬 포트]: 로컬 컴퓨터에서 사용할 포트 번호
  • [파드 포트]: 파드 내부에서 Nginx가 사용하는 포트 번호

Nginx 파드 포트 포워딩

sudo kubectl port-forward pod/nginx-pod 80:80
  • 로컬 컴퓨터의 포트 80과 파드 내부의 포트 80을 연결합니다.
  • 이 명령어를 실행하면, 로컬 환경에서 http://localhost:80으로 Nginx에 접근할 수 있습니다.


8. 파드(Pod) 삭제

8-1. 포트 포워딩 종료

  • 포트 포워딩 중지: 포트 포워딩을 종료하려면 Control + C를 눌러 실행 중인 프로세스를 종료합니다.

8-2. 파드 삭제

파드 삭제 명령어

kubectl delete pod [파드명]

Nginx 파드 삭제

kubectl delete pod nginx-pod
  • 이 명령어를 실행하면 nginx-pod가 클러스터에서 삭제됩니다.

실습 #2: 백엔드(Spring Boot) 서버를 파드(Pod)로 띄워보기

Spring Boot 프로젝트 생성

Spring Initializr에서 기본적인 스프링 부트 프로젝트를 생성한 후, 간단한 REST API를 구현합니다.

@RestController
public class AppController {
	@GetMapping("/)
    public String home() {
    	return "Hello, World"
    }
}
  • / 엔드포인트로 요청하면 "Hello, World"를 응답합니다.

Dockerfile 작성

스프링 부트 애플리케이션을 컨테이너로 실행하기 위해 Dockerfile을 작성합니다.

FROM openjdk:17-jdk

COPY build/libs/*SNAPSHOT.jar app.jar

ENTRYPOINT ["java", "-jar", "/app.jar"]
  • FROM openjdk:17-jdk: OpenJDK 17 기반 이미지 사용
  • COPY build/libs/*SNAPSHOT.jar app.jar: 빌드된 JAR 파일을 컨테이너 내부에 복사
  • ENTRYPOINT: 컨테이너 실행 시 Spring Boot 애플리케이션을 실행

1. Spring Boot 프로젝트 빌드

Gradle을 사용하여 JAR 파일을 빌드합니다.

$ ./gradlew clean build
  • 빌드가 완료되면 build/libs/ 디렉토리에 JAR 파일이 생성됩니다.

2. Dockerfile을 바탕으로 이미지 빌드

Dockerfile을 기반으로 이미지를 생성합니다.

$ docker build -t spring-server .
  • spring-server라는 이름의 이미지를 생성합니다.

3. 이미지 생성 확인

$ docker image ls

4. 매니페스트 파일 작성(Spring-pod.yaml)

쿠버네티스에서 파드를 생성하기 위한 매니페스트 파일을 작성합니다.

apiVersion: v1
kind: Pod
metadata:
  name: spring-pod
spec:
  - name: spring-container
    image: spring-server
    ports:
      - containerPort: 8080
  • apiVersion: v1
    • 쿠버네티스 리소스를 정의할 때 사용하는 API 버전을 지정합니다.
    • 여기서는 Pod 리소스를 생성하기 위해 v1 버전을 사용합니다.
  • kind: Pod
    • 생성할 리소스의 종류를 지정합니다.
    • 여기서는 Pod를 생성합니다.
  • metadata
    • 리소스의 이름 및 메타데이터를 정의하는 부분입니다.
    • name: spring-pod:
      • 생성할 Pod의 이름을 지정합니다.
      • 클러스터 내에서 Pod를 구분하는 고유 식별자가 됩니다.
  • spec
    • Pod의 구성과 내부 컨테이너 정보를 정의합니다.
    • Containers:
      • 이 Pod에 포함될 컨테이너 목록을 정의합니다.
      • Pod는 하나 이상의 컨테이너를 가질 수 있습니다.
  • - name: spring-container
    • Pod 내부에서 실행될 컨테이너의 이름입니다.
    • Pod 내부에서 컨테이너를 구분하기 위한 것으로, 외부에서 보이는 Pod의 이름과는 다릅니다.
  • image: spring-server
    • 컨테이너를 생성할 때 사용할 Docker 이미지의 이름입니다.
    • 여기서는 로컬 또는 Docker Hub 또는 다른 레지스트리에 저장된 spring-server 이미지를 사용합니다.
  • ports
    • 컨테이너가 사용하는 네트워크 포트를 명시합니다.
    • containerPort: 8080
      • 이 컨테이너는 8080 포트를 사용합니다.
      • containerPort는 컨테이너 내부에서 사용하는 포트를 명시하는 것(문서화 목적)으로, 외부에서 바로 접근할 수 있는 설정은 아닙니다.
      • 외부 접근이 필요하면 Service 리소스를 추가로 설정해야 합니다.

5. 매니페스트 파일을 기반으로 파드(Pod) 생성

작성한 매니페스트 파일을 사용하여 파드를 생성합니다.

$ kubectl apply -f spring-pod.yaml

6. 파드(Pod) 생성 확인

$ kubectl get pods
  • STATUSImagePullBackOff인 경우, 이미지를 Pull 받아오는 과정에서 문제가 발생했음을 나타냅니다.

7. 파드(Pod)가 정상적으로 생성되지 않은 이유 - 이미지가 없다는 에러가 발생하는 이유 (이미지 Pull 정책)

Spring Boot 프로젝트를 컨테이너 이미지로 빌드하고 이를 기반으로 파드를 생성했지만, ImagePullBackOff라는 에러가 발생했습니다.
이 문제는 쿠버네티스의 이미지 Pull 정책(Image Pull Policy) 때문에 발생한 것입니다.

이미지 풀 정책(Image Pull Policy)이란?

이미지 풀 정책(Image Pull Policy)이란 쿠버네티스가 매니페스트 파일을 읽어 파드를 생성할 때, 이미지를 어떻게 가져올지 결정하는 정책입니다.

이미지 Pull 정책의 종류

1. Always

  • 로컬에서 이미지를 가져오지 않고, 무조건 원격 레지스트리(DockerHub, ECR 등)에서 이미지를 가져옵니다.

2. IfNotPresent

  • 먼저 로컬에서 이미지를 찾고, 없을 경우에만 원격 레지스트리에서 가져옵니다.

3. Never

  • 로컬에서만 이미지를 가져옵니다.

기존의 매니페스트 파일 확인 (spring-pod.yaml)

apiVersion: v1
kind: Pod
metadata:
  name: spring-pod
spec:
  containers:
    - name: spring-container
      image: spring-server
      ports:
        - containerPort: 8080

Pull 정책의 기본 동작

  • 이미지 태그가 latest이거나 명시되지 않은 경우, 기본적으로 Always로 동작합니다.
    • 로컬 이미지를 사용하지 않고 원격 레지스트리(DockerHub, ECR 등)에서 이미지를 가져옵니다.
  • 이미지 태그가 latest가 아닌 경우, 기본적으로 IfNotPresent로 동작합니다.
    • 먼저 로컬에서 이미지를 찾고, 없을 경우 원격 레지스트리에서 가져옵니다.

해결: 매니페스트 파일 수정 (Pull 정책 설정)

로컬 이미지를 사용하려면 imagePullPolicy: IfNotPresent를 설정해야 합니다.

apiVersion: v1
kind: Pod
metadata:
  name: spring-pod
spec:
  containers:
    - name: spring-container
      image: spring-server
      ports:
        - containerPort: 8080
      imagePullPolicy: IfNotPresent

기존 파드 삭제 후 다시 생성

1. 기존 파드 삭제

$ kubectl delete pod spring-pod

2. 수정된 매니페스트 파일로 파드 생성

$ kubectl apply -f spring-pod.yaml

3. 파드 상태 확인

$ kubectl get pods

Spring Boot 서버 응답 확인

방법 1. 파드 내부로 들어가서 요청 보내기

파드 내부에 접속합니다.

$ kubectl exec -it spring-pod -- bash

요청을 확인합니다.

$ curl localhost:8080

방법 2. 포트 포워딩 활용

로컬 포트와 파드 포트를 연결합니다.

$ kubectl port-forward pod/spring-pod 

브라우저에서 확인합니다.
http://localhost:1234로 접속하여 Spring Boot 서버의 응답을 확인합니다.

파드 삭제

작업이 끝난 후 파드를 삭제하려면 아래 명령어를 입력합니다.

$ kubectl delete pod spring-pod

실습 #3: 백엔드(Spring Boot) 서버 3개 띄워보기

실제 서비스 운영 중 트래픽이 증가하면 서버의 부하가 커질 수 있습니다. 이를 해결하기 위해 서버를 수평적 확장(서버의 개수를 늘리는 방식)하는 방법을 사용합니다. 이번에는 백엔드(Spring Boot) 서버를 3대로 늘려보는 과정을 실습해 보겠습니다.

실습 #2. 백엔드(Spring Boot) 서버를 파드(Pod)로 띄워보기에서 사용한 프로젝트를 다음과 같이 수정합니다.

매니페스트 파일(spring-pod.yaml) 수정

기존 프로젝트의 매니페스트 파일(spring-pod.yaml)을 수정하여 Spring Boot 서버를 3개로 확장합니다.
spring-pod.yaml 파일에 3개의 Pod를 정의합니다. 각 Pod는 같은 이미지를 사용하지만 고유한 이름으로 구분됩니다.

apiVersion: v1
kind: Pod

metadata:
  name: spring-pod-1

spec:
  containers:
    - name: spring-container
      image: spring-server
      ports:
        - containerPort: 8080
      imagePullPolicy: IfNotPresent

---
apiVersion: v1
kind: Pod

metadata:
  name: spring-pod-2

spec:
  containers:
    - name: spring-container
      image: spring-server
      ports:
        - containerPort: 8080
      imagePullPolicy: IfNotPresent

---
apiVersion: v1
kind: Pod

metadata:
  name: spring-pod-3

spec:
  containers:
    - name: spring-container
      image: spring-server
      ports:
        - containerPort: 8080
      imagePullPolicy: IfNotPresent
  • Pod 이름: 각 Pod는 spring-pod-1, spring-pod-2, spring-pod-3으로 구분됩니다.
  • 컨테이너 이미지: 모두 spring-server 이미지를 사용합니다.
  • 포트: 컨테이너 내부에서 8080번 포트를 사용합니다.
  • imagePullPolicy: IfNotPresent로 설정하여, 로컬에 이미지가 없으면 외부에서 이미지를 가져옵니다.

매니페스트 파일을 기반으로 파드(Pod) 생성

수정한 매니페스트 파일을 기반으로 Pod를 생성합니다.

$ kubectl apply -f spring-pod.yaml

파드(Pod) 생성 확인

$ kubectl get pods

profile
donggyun_ee

0개의 댓글