본문 바로가기

GitOps/Kubernetes

[Kubernetes] Pod

Pod

  • 기본 설명은 해당 글에 정리
  • 파드에 명령을 전달할 때 컨테이너를 지정하지 않으면 default 컨테이너가 수신

Pod Status

  • Pending: Control Plane에 생성 명령 전달 완료
  • ContainerCreating: 특정 노드에 스케줄링되어 컨테이너 생성 중
  • Running: 실행 중
  • Completed: 작업 완료 (배치 작업을 수행하는 Pod 한정)
  • Error: Pod에 에러 발생
  • CrashLoopBackOff: 지속적으로 에러가 발생하여 crash 반복

Pod 실행 예제

# nginx pod 실행
kubectl run nginx --image nginx

# 생성 확인
kubectl get pod

# 파드에 명령 전달
kubectl exec nginx -- apt-get update

# 컨테이너에 진입
kubectl exec -it nginx -- bash

Pod 정보 조회, 변경, 삭제 예제

# pod ip 확인
kubectl get pod nginx -o wide

# manifest 확인
kubectl get pod nginx - o yaml

# 상세 정보 확인
kubectl describe pod nginx

# 로그 확인
kubectl logs nginx

# 로그 스트림 유지
kubectl logs -f nginx

# 파드 수정
kubectl edit pod nginx

# 파드 삭제
kubectl delete pod nginx

Pod <-> 로컬 머신 데이터 교환 예제

# 예제 파일 생성
echo 'hello' > hello.txt

# 로컬 머신 -> 파드로 전송
kubectl cp hello.txt nginx:/tmp/hello.txt

# 파드에 명령 내려서 확인해보기
kubectl exec nginx -- cat /tmp/hello.txt

# 파드 -> 로컬 머신으로 전송
kubectl cp nginx:/tmp/hello.txt hello_from_container.txt

manifest 기반 pod 생성 예제

# nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx

 

# file(-f)기반 파드 생성
kubectl apply -f nginx.yaml

# 파일 수정
vi nginx.yaml

# 파드 업데이트 (생성과 명령 같음)
kubectl apply -f nginx.yaml

manifest command, args 지정 예제

  • command는 dockerfile의 ENTRYPOINT, args는 CMD를 override한다.
# test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  # 재시작 정책: 실패 시에만. 
  # 설정하지 않으면 command 이후 종료되면서 다시 재시작하기 때문에 설정해야 함.
  restartPolicy: OnFailure
  containers:
  - image: nginx
    name: nginx
    # 실행 명령
    command: ["/bin/echo"]
    # 파라미터
    args: ["hello"]

 

# 위의 manifest 사용
vi test.yaml
kubectl apply -f test.yaml

# command 확인
kubectl logs test

manifest env 지정 예제

# test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - image: nginx
    name: nginx
	# 환경 변수
    env:
    - name: hello
      value: "world"

 

# 파드 생성
vi test.yaml
kubectl apply -f test.yaml

# 환경 변수 확인
kubectl exec test -- env | grep hello

볼륨 연결 예제

  • pod의 host server는 node이다.
# test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - image: nginx
    name: nginx
    # 컨테이너에서 volume 설정
    volumeMounts:
    - mountPath: /data
      name: vol
  # node에서 volume 설정
  volumes:
  - name: vol
    hostPath:
      path: /tmp

 

# 위의 manifest 붙여넣기
vi test.yaml

# pod 생성
kubectl apply -f test.yaml

# pod 진입
kubectl exec -it test -- /bin/sh

# 마운트된 경로(/data) 이동
cd /data

# 파일 확인 (NODE의 /tmp 내부 파일이 있어야 함.)
ls

# 빈 파일 생성 후 exit
touch hello.txt
exit

# pod 정보(NODE) 확인
kubectl get pod test -o wide

# ssh를 통해 NODE로 진입
gcloud compute ssh gke-cluster-1-default-pool-0825305a-nxv2 --zone=us-central1-c

# /tmp 경로 확인 (hello.txt가 있는지)
ls /tmp

# 로컬 머신으로 복귀
exit

 

컴퓨팅 리소스 관리 예제

  • requests: 최소 사용량 보장 (보통 지속적 작업에 주로 사용하는 듯 함.)
  • limits: 최대 사용량 보장 (보통 단발성 작업에 주로 사용하는 듯 함.)
# requests.yaml
apiVersion: v1
kind: Pod
metadata:
  name: requests
spec:
  containers:
  - image: nginx
    name: nginx
    resources:
      # 최소 리소스 사용량
      requests:
        cpu: "250m" # 0.25core
        memory: "500Mi" # 500MB

 

# limits.yaml

apiVersion: v1
kind: Pod
metadata:
  name: limits
spec:
  restartPolicy: Never
  containers:
  - image: python:3.7
    name: limits
    command: ["python"]
    # 무한히 배열에 1 넣기
    args: ["-c","arr = []\nwhile True: arr.append(1)"]
    resources:
      # 최대 리소스 사용량 정리
      limits:
        cpu: "500m" # 0.5core
        memory: "1Gi" # 1GB

 

# 위의 limits.yaml 파일 붙여넣기
vi limits.yaml

# 파드 생성
kubectl appliy -f limits.yaml

# 지속적으로 상태 확인. 일정 시간이 지나면 Out Of Memory Killed(OOMKilled) 발생 (혹은 cpu 에러)
watch kubectl get pod limits

 


Pod 라이프사이클

  • 노드에 작업이 들어오면 새로운 Pod 생성
  • 파드는 자가 치유 X

재시작 정책 (restartPolicy)

  • Always: 항상
  • OnFailure: 실패 시에만
  • Never: 재시작 안 함.

파드 종료

  • 파드 종료 시에는 SIGTERM 신호 전송
  • 만약 컨테이너 이미지에 정의된 STOPSIGNAL이 SIGKILL이라면 SIGKILL 신호 전송
  • 일반적으로 kubectl delete 명령은 30초 이내에 정상적으로 수행됨
  • --grace-period 옵션을 지정하면 우아한 종료 유예 기간 재정의

grace-period 예제

# test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - image: nginx
    name: nginx

 

# 위의 test.yaml 붙여넣기
vi test.yaml

# 파드 생성
kubectl apply -f test.yaml

# 파드 즉시 삭제
k delete --grace-period=0 pod test

 


Pod Label

  • 레이블에 대한 기초적인 실습(pod, node에 레이블 추가)은 여기에서

nodeSelector

  • manifest에 정의하여 파드가 특정 레이블인 노드에 배치되도록 함.
  • 동일한 레이블인 노드가 여러 개라면 최적 노드로 배치됨

nodeSelector 예제

# test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - image: nginx
    name: nginx
  # 레이블로 노드 선택
  nodeSelector:
    nodeno: "1"

 

# 위의 manifest 붙여넣기
vi test.yaml

# 파드 생성
kubectl apply -f test.yaml

# nodeno == 1인 노드 확인
kubectl get nodes -L nodeno

# 파드가 속한 노드가 위에서 확인한 노드가 맞는지 확인
kubectl get pod test -o wide

nodeAffinity

  • Pod가 레이블을 통해 특정 노드에 스케줄링되도록 하는 규칙을 정의
  • requiredDuringSchedulingIgnoredDuringExecution: 반드시 충족돼야 하는 규칙
  • preferredDuringSchedulingIgnoredDuringExecution: 선호하는 규칙
  • IgnoredDuringExecution이므로 실행 중 레이블 변경에 대한 부분은 신경 쓰지 않음
  • nodeSelectorTerms들을 OR로 묶어서 조건 확인
  • matchExpressions는 key와 values에 대해 operator로 연산
# test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  # affinity 설정
  affinity:
    # nodeAffinity 설정
    nodeAffinity:
      # 필수 조건
      requiredDuringSchedulingIgnoredDuringExecution:
        # 내부 연산에 대해 OR로 묶어주는 nodeSelectorTerms
        nodeSelectorTerms:
          # 표현식 nodeno In ("1")에 대해 참인 노드를 match
          - matchExpressions:
            - key: nodeno
              operator: In
              values:
                - "1"
  containers:
  - name: nginx
    image: nginx

 

# 위의 manifest를 붙여넣기
vi test.yaml

# 파드 생성
kubectl apply -f test.yaml

# 노드 확인
# 만약 nodeno In ("3")으로 작성했다면 파드는 Pending됨
kubectl get pod test -o wide

 


Container Probe

  • kubelet에 의해 주기적으로 수행되는 진단
  • 컨테이너 내부에서 코드 실행 혹은 네트워크 요청 전송
  • 지금까지 만들었던 파드들은 모두 probe를 통과했던 것

체크 방법

  • exec: 지정된 명령어 실행. 상태 코드 0으로 종료되면 성공
  • grpc: gRPC를 사용하여 원격 프로시저 호출 수행. 응답 status가 SERVING이면 성공
  • httpGet: 컨테이너 IP를 통해  지정된 포트 및 경로로 HTTP GET 요청 수행. 상태 코드가 2~400번대면 성공
  • tcpSocket: 컨테이너 IP를 통해 지정된 포트로 TCP 검사 수행. 포트 활성화 및 즉시 연결 해제되면 성공

프로브 결과

  • Success: 성공
  • Failure: 실패
  • Unknown: 진단 자체가 실패

프로브 종류

  • livenessProbe: 컨테이너가 동작 중인지 여부를 나타냄
    • 실패 시: kubelet이 컨테이너를 kill하고 재시작 대상으로 바꿈
    • 제공하지 않은 경우: 기본적으로 Success 반환
  • readinessProbe: 컨테이너가 요청을 처리할 준비가 되었는지 여부를 나타냄
    • 실패 시: 엔드포인트 컨트롤러가 파드에 연관된 모든 서비스들의 엔드포인트에서 파드 IP 주소 제거
    • 기본 상태: Failure
    • 지원하지 않는 경우: 기본적으로 Success 반환
  • startupProbe: 컨테이너 내의 애플리케이션이 시작되었는지 나타냄
    • 실패 시: kubelet이 컨테이너를 kill하고 재시작 정책에 따라 처리됨
    • 성공 전까지: 다른 프로브 활성화 불가
    • 없는 경우: 기본 상태는 Success

livenessProbe 예제

  • 헬스 체크 기본값은 10초 동안 3번 실패하면 자가치유
# liveness.yaml
apiVersion: v1
kind: Pod
metadata:
  name: liveness
spec:
  containers:
  - name: nginx
    image: nginx
    livenessProbe:
      # 방법은 httpGet
      httpGet:
        # 기본적으로 nginx image는 /live경로를 제공하지 않기 때문에 실패할 것
        path: /live
        port: 80

 

# 위의 manifest 붙여넣기
vi liveness.yaml

# 파드 생성
kubectl apply -f liveness.yaml

# 로그 확인. failed가 떠야 정상
kubectl logs -f liveness

# 경로 생성
# 정상적이지 않지만, 암튼 liveness만 확인하므로 괜찮음
kubectl exec liveness -- touch /usr/share/nginx/html/live

# 상태 확인
kubectl logs -f liveness
kubectl get pod liveness

 

readinessProbe 예제 (+ exec)

# readiness.yaml
apiVersion: v1
kind: Pod
metadata:
  name: readiness
spec:
  containers:
  - name: nginx
    image: nginx
    readinessProbe:
      # exec를 사용하여 probe
      exec:
        command:
        - cat
        - /tmp/ready

 

# manifest 붙여넣기
vi readiness.yaml

# 파드 생성
kubectl apply -f readiness.yaml

# probe 확인 (Events를 확인했을 때, 실패해야 함)
kubectl describe pod readiness

# 경로를 생성해줌
kubectl exec readiness -- touch /tmp/ready

# probe 확인 (describe의 events가 최신화가 안 됐음. 이유를 찾아볼 것)
kubectl describe pod readiness
kubectl get pod readiness

 


Pod Multiple Container

  • 하나의 파드에 여러 컨테이너를 실행시킬 수 있음
  • initContainers: 초기화를 위해 먼저 실행되는 컨테이너
  • emptyDir: 동일 파드 내 컨테이너끼리의 공유 공간. 파드 삭제 시 삭제됨

다수 컨테이너 실행 예제

# multiple.yaml
apiVersion: v1
kind: Pod
metadata:
  name: multiple
spec:
  containers:
  # container 1
  - name: nginx
    image: nginx
  # container 2
  - name: curl
    image: curlimages/curl
    command: ["/bin/sh"]
    args: ["-c", "while true; do sleep 5; curl -s localhost; done"]

 

# manifest 붙여넣기
vi multiple.yaml

# 파드 생성
kubectl apply -f multiple.yaml

# 로그 확인 (-c 옵션으로 nginx container 확인)
kubectl logs -f multiple -c nginx

초기화 컨테이너 예제

# init.yaml
apiVersion: v1
kind: Pod
metadata:
  name: init
spec:
  restartPolicy: OnFailure
  containers:
  - name: busybox
    image: k8s.gcr.io/busybox
    command: [ "ls" ]
    args: [ "/tmp/moby" ]
    # 컨테이너의 /tmp 경로에 마운트
    volumeMounts:
    - name: workdir
      mountPath: /tmp
  # 초기화 컨테이너
  initContainers:
  - name: git
    image: alpine/git
    command: ["sh"]
    args:
    - "-c"
    - "git clone https://github.com/moby/moby.git /tmp/moby"
    # 초기화 컨테이너의 /tmp 경로에도 마운트
    volumeMounts:
    - name: workdir
      mountPath: "/tmp"
  # 공유 볼륨
  volumes:
  - name: workdir
    emptyDir: {}

 

# manifest 붙여넣기
vi init.yaml

# 파드 생성
kubectl apply -f init.yaml

# 파드 확인 (STATUS Init:0/1)
kubectl get pods

# 로그 확인 (git cloning 확인)
kubectl logs -f init-container -c git

# cloning 완료 확인 후 다시 파드 확인 (COMPLETED)
kubectl get pods

# 파드 로그 확인 (main container)
kubectl logs init

'GitOps > Kubernetes' 카테고리의 다른 글

[Kubernetes] Controller  (0) 2025.02.13
[Kubernetes] 리소스  (0) 2025.01.15
[Kubernetes] 클러스터 생성  (0) 2025.01.14
[Kubernetes] 개념  (0) 2025.01.13