6.1.4 [실습] YAML 파일을 이용한 파드 생성 및 관리
쿠버네티스에서는 대부분의 리소스(파드, 디플로이먼트, 서비스 등)를 선언적(declarative) 방식으로 관리합니다. 이는 “무엇을 어떻게 해라”고 명령하는 절차적 방식이 아니라, “시스템이 이러이러한 상태가 되기를 원한다”고 원하는 상태(desired state)를 기술하는 방식입니다. 그리고 이 원하는 상태를 기술하는 데 주로 사용되는 것이 바로 YAML(YAML Ain’t Markup Language) 형식의 파일입니다. YAML은 사람이 읽고 쓰기 쉬운 데이터 직렬화 형식으로, 들여쓰기를 통해 계층 구조를 표현합니다.
6.1.4.1 간단한 파드 정의 파일 작성
가장 먼저, 우리가 생성하고자 하는 파드의 모습을 YAML 파일로 정의해 보겠습니다. 이번 실습에서는 가장 널리 사용되는 웹 서버 중 하나인 Nginx 컨테이너를 실행하는 간단한 파드를 만들어 볼 것입니다.
텍스트 편집기(예: VS Code, Vim, Notepad++ 등)를 열고, 다음과 같은 내용으로 파일을 작성해 봅시다. 파일 이름은 my-first-pod.yaml 정도로 하겠습니다.
자, 이 YAML 파일의 각 항목이 무엇을 의미하는지 자세히 살펴보겠습니다. 마치 파드의 ‘설계도’와도 같습니다.
- apiVersion: 이 오브젝트(여기서는 파드)를 생성하는 데 사용할 쿠버네티스 API 버전을 명시합니다. 파드, 서비스, 레플리카셋 등 대부분의 핵심 오브젝트는 v1 API 그룹에 속합니다. 각 쿠버네티스 API 버전은 특정 기능 세트를 지원하며, 시간이 지남에 따라 새로운 버전이 추가되거나 기존 버전이 변경될 수 있습니다. kubectl api-versions 명령을 통해 현재 클러스터에서 사용 가능한 API 버전 목록을 확인할 수 있습니다.
- kind: 생성하려는 오브젝트의 종류를 명시합니다. 우리는 파드를 만들 것이므로 Pod이라고 지정했습니다. 쿠버네티스에는 Deployment, Service, Namespace, ConfigMap, Secret 등 다양한 종류의 오브젝트가 있으며, kind 필드를 통해 어떤 종류의 리소스를 정의하는지 명확히 합니다.
- metadata: 오브젝트에 대한 메타데이터, 즉 부가 정보를 정의하는 섹션입니다. 이 정보는 오브젝트를 식별하고, 검색하고, 그룹화하는 데 사용됩니다.
- name: 파드의 고유한 이름을 지정합니다. 여기서는 my-nginx-pod으로 정했습니다. 이 이름은 현재 네임스페이스 내에서 유일해야 하며, kubectl 명령어로 특정 파드를 지칭할 때 사용됩니다. 이름은 보통 소문자 영숫자와 하이픈(-)으로 구성되며, 숫자로 시작할 수 없습니다.
- labels: 파드에 레이블을 할당합니다. 레이블은 키-값 쌍으로 구성되며, 오브젝트를 식별하고 조직화하는 데 사용되는 핵심 메커니즘입니다. 예를 들어, app: my-nginx는 이 파드가 ‘my-nginx’라는 애플리케이션에 속한다는 것을, environment: development는 개발 환경용이라는 것을 나타냅니다. 레이블은 나중에 특정 파드들을 선택(select)하여 서비스에 연결하거나, 디플로이먼트의 관리 대상으로 삼는 등 매우 다양하게 활용됩니다. 하나의 오브젝트에는 여러 개의 레이블을 가질 수 있습니다.
- spec: 파드가 실제로 어떻게 동작해야 하는지, 즉 원하는 상태(desired state)를 상세히 기술하는 가장 중요한 섹션입니다. 파드의 ‘본체’에 해당하며, 파드가 어떤 컨테이너를 실행하고, 어떤 볼륨을 사용하며, 어떤 재시작 정책을 가질지 등을 정의합니다.
- containers: 파드 내에서 실행될 컨테이너들의 목록을 정의하는 배열입니다. (YAML에서 – 기호는 배열의 요소를 나타냅니다.) 파드는 하나 이상의 컨테이너를 가질 수 있지만, 여기서는 하나의 컨테이너만 정의했습니다. 각 컨테이너는 자신만의 설정(이름, 이미지, 포트, 환경 변수, 볼륨 마운트 등)을 가집니다.
- name: 컨테이너의 이름을 지정합니다. 이 이름은 파드 내에서 유일해야 하며, 로그를 확인하거나 컨테이너에 접속할 때 (kubectl logs <pod-name> -c <container-name>, kubectl exec -it <pod-name> -c <container-name> — /bin/bash 등) 특정 컨테이너를 지칭하는 데 사용됩니다. nginx-container로 정했습니다.
- image: 컨테이너를 생성하는 데 사용할 컨테이너 이미지의 이름을 지정합니다. 여기서는 공개 컨테이너 레지스트리인 Docker Hub에 있는 공식 nginx 이미지의 1.25 버전을 사용하도록 지정했습니다. 이미지 이름은 보통 <레지스트리_주소>/<저장소_이름>/<이미지_이름>:<태그> 형식으로 구성되지만, Docker Hub의 공식 이미지인 경우 <이미지_이름>:<태그>만으로도 충분합니다. 버전을 명시하지 않고 nginx 또는 nginx:latest라고만 하면 가장 최신 버전을 가져오지만, 이는 예기치 않은 버전 변경으로 이어질 수 있으므로, 운영 환경에서는 항상 특정 버전 태그를 명시하는 것이 안정적인 운영을 위한 모범 사례입니다.
- ports: 컨테이너가 외부에 노출(listen)할 포트 정보를 정의하는 배열입니다.
- containerPort: 80: nginx-container가 파드 내부 네트워크의 80번 포트에서 요청을 기다린다는 것을 명시합니다. 이 containerPort는 정보 제공의 목적이 강하며, 파드 외부로 자동으로 이 포트가 노출되는 것은 아닙니다. 즉, 이 설정만으로는 클러스터 외부나 다른 노드에서 이 파드의 80번 포트로 직접 접근할 수 없습니다. 파드 외부로 서비스를 노출하기 위해서는 별도의 ‘서비스(Service)’ 오브젝트를 생성해야 합니다. 하지만 이 containerPort 정보는 파드 내 다른 컨테이너와의 통신이나, 나중에 서비스 오브젝트를 정의할 때 참조되는 중요한 정보입니다. Nginx 웹 서버는 기본적으로 80번 포트에서 HTTP 요청을 받습니다.
- containers: 파드 내에서 실행될 컨테이너들의 목록을 정의하는 배열입니다. (YAML에서 – 기호는 배열의 요소를 나타냅니다.) 파드는 하나 이상의 컨테이너를 가질 수 있지만, 여기서는 하나의 컨테이너만 정의했습니다. 각 컨테이너는 자신만의 설정(이름, 이미지, 포트, 환경 변수, 볼륨 마운트 등)을 가집니다.
YAML 파일 작성 시 유의사항:
- 들여쓰기(Indentation): YAML은 들여쓰기를 통해 데이터의 계층 구조를 표현합니다. 스페이스 2칸 또는 4칸을 일관되게 사용하는 것이 일반적입니다. 탭(tab) 문자는 사용하지 않는 것이 좋습니다. 들여쓰기가 잘못되면 YAML 파싱 오류가 발생하거나 의도치 않은 구조로 해석될 수 있습니다.
- 키-값 쌍: 대부분의 데이터는 키: 값 형태로 표현됩니다. 콜론(:) 뒤에는 반드시 공백이 하나 이상 있어야 합니다.
- 주석(Comments): # 기호로 시작하는 줄은 주석으로 처리되어 무시됩니다. 설명을 추가하거나 특정 부분을 임시로 비활성화할 때 유용합니다.
자, 이제 이 my-first-pod.yaml 파일을 여러분의 작업 디렉터리에 저장하십시오. 이 파일은 쿠버네티스에게 “이러한 명세와 메타데이터를 가진 Nginx 파드를 만들어 주십시오”라고 요청하는 주문서와 같습니다.
7.1.4.2 파드 생성, 조회, 로그 확인, 접속
이제 우리가 정성껏 작성한 YAML 파일을 사용하여 쿠버네티스 클러스터에 실제 파드를 만들어 보겠습니다. 그리고 생성된 파드의 상태를 확인하고, 로그를 보고, 심지어 파드 내부로 들어가 보는 작업까지 진행해 봅시다.
1. 파드 생성 (kubectl apply)
터미널에서 다음 명령어를 실행하여 my-first-pod.yaml 파일에 정의된 대로 파드를 생성합니다.
- kubectl apply: 쿠버네티스에게 리소스의 상태를 선언적으로 적용하라는 명령어입니다. 이 명령어는 지정된 파일의 내용과 클러스터의 현재 상태를 비교하여, 필요한 경우 생성, 업데이트 또는 (때로는) 삭제 작업을 수행하여 파일에 정의된 ‘원하는 상태’로 만듭니다. -f 옵션은 파일로부터 리소스 정의를 읽어오겠다는 의미입니다. (-f는 –filename의 약자입니다.)
- 만약 명령이 성공적으로 실행되면 pod/my-nginx-pod created 와 같은 메시지가 출력될 것입니다. 이는 쿠버네티스 API 서버가 우리의 요청을 받아들였고, my-nginx-pod이라는 이름의 파드 생성을 시작했다는 의미입니다.
2. 파드 조회 (kubectl get, kubectl describe)
파드가 성공적으로 생성되었는지, 그리고 현재 어떤 상태인지 확인해 보겠습니다.
- 간단한 상태 확인 (kubectl get pods):이 명령을 실행하면 현재 네임스페이스에 있는 파드들의 목록과 간략한 상태 정보가 표 형태로 출력됩니다.클립보드에 복사
- 각 열의 의미는 다음과 같습니다:클립보드에 복사
- NAME: 파드의 이름 (my-nginx-pod)
- READY: 파드 내의 컨테이너 중 현재 준비(ready) 상태인 컨테이너의 수 / 파드 내의 총 컨테이너 수. 1/1은 총 1개의 컨테이너 중 1개가 준비되었다는 의미입니다. (준비성 프로브(Readiness Probe)가 설정되어 있다면, 해당 프로브가 성공해야 준비 상태가 됩니다. 여기서는 프로브가 없으므로 컨테이너가 실행되면 바로 준비 상태로 간주될 수 있습니다.)
- STATUS: 파드의 현재 단계(Phase)입니다. Running은 파드가 정상적으로 실행 중이라는 의미입니다. 처음 생성 직후에는 Pending (이미지 다운로드 중 또는 스케줄링 대기) 또는 ContainerCreating 상태를 잠시 거칠 수 있습니다.
- RESTARTS: 파드 내 컨테이너들이 재시작된 횟수입니다. 0은 재시작 없이 정상적으로 실행 중이라는 의미입니다. 만약 이 숫자가 계속 증가한다면 컨테이너에 문제가 있을 가능성이 높습니다.
- AGE: 파드가 생성된 후 경과된 시간입니다.
- o wide 옵션을 추가하면 더 많은 정보(예: 파드가 실행 중인 노드의 IP, 파드의 IP)를 볼 수 있습니다.
- 클립보드에 복사
- 상세 정보 확인 (kubectl describe pod <pod-name>):특정 파드에 대한 더 자세한 정보를 원한다면 kubectl describe pod 명령을 사용합니다.이 명령은 파드의 메타데이터(이름, 네임스페이스, 레이블, 어노테이션 등), 명세(컨테이너 정보, 볼륨 정보 등), 현재 상태(IP 주소, 단계, 조건, 컨테이너 상태 등), 그리고 가장 중요한 이벤트(Events) 목록을 보여줍니다. 이벤트 목록은 파드의 생명 주기 동안 발생한 주요 사건들(예: 스케줄링 성공, 이미지 다운로드 시작/완료, 컨테이너 생성/시작)을 시간 순서대로 보여주므로, 파드 생성에 문제가 있거나 상태가 이상할 때 원인을 파악하는 데 매우 유용합니다.클립보드에 복사
3. 파드 로그 확인 (kubectl logs -c )
파드 내에서 실행 중인 컨테이너가 출력하는 로그를 확인하는 것은 디버깅과 상태 모니터링에 필수적입니다.
- 만약 파드 내에 컨테이너가 하나뿐이라면 위와 같이 컨테이너 이름을 생략할 수 있습니다.
- 만약 파드 내에 여러 컨테이너가 있다면 -c <container-name> 또는 –container <container-name> 옵션을 사용하여 특정 컨테이너의 로그를 지정해야 합니다. 우리의 경우 nginx-container 하나만 있으므로 위 명령으로 Nginx 컨테이너의 표준 출력(stdout) 및 표준 에러(stderr) 로그를 볼 수 있습니다. Nginx의 경우 초기에는 접근 로그가 거의 없겠지만, 만약 외부에서 접근이 있었다면 해당 로그가 보일 것입니다.
- f 또는 –follow 옵션을 추가하면 실시간으로 새로운 로그를 계속해서 스트리밍하여 볼 수 있습니다 (Ctrl+C로 종료)클립보드에 복사
- -previous 옵션을 사용하면, 컨테이너가 재시작된 경우 이전 컨테이너 인스턴스의 로그를 확인할 수 있습니다 (문제가 발생하여 재시작된 컨테이너의 원인을 파악할 때 유용).
- f 또는 –follow 옵션을 추가하면 실시간으로 새로운 로그를 계속해서 스트리밍하여 볼 수 있습니다 (Ctrl+C로 종료)
4. 파드 내 컨테이너에 접속 (kubectl exec -it -c — )
때로는 실행 중인 컨테이너 내부로 직접 들어가서 상태를 확인하거나, 특정 명령을 실행해보고 싶을 때가 있습니다. kubectl exec 명령을 사용하면 마치 SSH로 원격 서버에 접속하듯이 컨테이너 내부의 셸에 접근할 수 있습니다.
- kubectl exec: 실행 중인 컨테이너 내부에서 명령을 실행합니다.
- i (–stdin): 표준 입력(stdin)을 활성화합니다. 셸과 상호작용하려면 필요합니다.
- t (–tty): TTY(가상 터미널)를 할당합니다. 이 역시 대화형 셸을 사용하기 위해 필요합니다. -it는 함께 자주 사용됩니다.
- my-nginx-pod: 명령을 실행할 파드의 이름입니다.
- -: kubectl exec 명령어 자체의 옵션과 컨테이너 내부에서 실행할 명령 및 인자를 구분하는 역할을 합니다. 이 뒤에 나오는 것이 컨테이너 내부에서 실행될 실제 명령어입니다.
- /bin/bash: 컨테이너 내부에서 실행할 명령어입니다. 여기서는 Bash 셸을 실행하여 대화형 세션을 시작합니다. (만약 해당 컨테이너 이미지에 /bin/bash가 없다면 /bin/sh 등을 시도해 볼 수 있습니다. Nginx 공식 이미지에는 기본적으로 Bash가 포함되어 있습니다.)
위 명령을 실행하면 프롬프트가 root@my-nginx-pod:/# 와 같이 변경되면서 Nginx 컨테이너 내부로 접속된 것을 확인할 수 있습니다. 이제 여기서 리눅스 명령어들(예: ls /usr/share/nginx/html, cat /etc/nginx/nginx.conf, ps aux)을 실행하여 컨테이너 내부 파일 시스템을 탐색하거나 실행 중인 프로세스를 확인할 수 있습니다.
컨테이너 내부에서의 작업이 끝나면 exit 명령을 입력하여 셸을 종료하고 원래 터미널로 돌아올 수 있습니다.
5. 파드 삭제 (kubectl delete pod <pod-name> 또는 kubectl delete -f <filename.yaml>)
실습이 끝났으니, 우리가 생성했던 파드를 삭제하여 클러스터 자원을 정리하겠습니다.
- 이름으로 파드 삭제:성공적으로 삭제되면 pod “my-nginx-pod” deleted 메시지가 출력됩니다.클립보드에 복사
- YAML 파일로 파드 삭제:파드를 생성할 때 사용했던 YAML 파일을 이용하여 삭제할 수도 있습니다.이 방식은 kubectl apply -f로 생성한 리소스를 동일한 파일로 삭제할 때 일관성을 유지할 수 있다는 장점이 있습니다.클립보드에 복사
파드 삭제 요청을 보내면, 쿠버네티스는 파드 내의 컨테이너들에게 종료 신호(기본적으로 SIGTERM)를 보내고, 일정 시간(grace period, 기본 30초) 내에 정상적으로 종료되지 않으면 강제 종료(SIGKILL)합니다. kubectl get pods 명령으로 확인해보면 Terminating 상태를 거쳐 목록에서 사라지는 것을 볼 수 있습니다.
이것으로 YAML 파일을 이용한 파드 생성 및 기본적인 관리 실습을 마쳤습니다! 간단한 실습이었지만, 쿠버네티스에서 가장 기본적인 작업 흐름인 ‘정의(YAML) -> 적용(apply) -> 확인(get/describe/logs) -> 상호작용(exec) -> 삭제(delete)’ 과정을 직접 경험해 보셨습니다.