본문 바로가기
dev/kubernetes

Kubernetes - Pods

by igooo 2024. 7. 4.
728x90

Pods

Pod는 Kubernetes에서 생성하고 관리할 수 있는 배포 가능한 가장 작은 컴퓨팅 단위이며, 한 개 또는 여러 개의 컨테이너들의 묶음이다.
Kubernetes 클러스터의 Pod는 두 가지 방법으로 사용된다.

  • Pods that run a single container.: 하나의 Pod에 하나의 컨테이너를 사용하는 경우
  • Pods that run multiple containers that need to work together. : 여러 개의 컨테이너를 배치해서 사용하는 경우.

 

Using Pods

아래 예제는 nginx: 1.14.2 이미지를 실행하는 Pod 예제다.

apiVersion: v1
kind: Pod
metadata:
    name: nginx
spec:
    containers:
    - name: nginx
      image: nginx:1.14.2
      ports:
      - containerPort: 80

Pod는 일반적으로 직접 생성하지 않고 워크로드 리소스를 사용하여 생성한다.

 

 

Workload resources for managing pods

일반적으로 Pod를 직접 만들 필요는 없다. 대신 Deployment, Job, Statefulset 등의 워크로드 리소스를 사용하 여 Pod를 만든다.
각 Pod는 주어진 애플리케이션의 단일 인스턴스를 실행하도록 설계되어있고, 애플리케이션을 수평 확장 하는 경우 인스턴스 하나씩 여러 Pod를 사용하여 확장한다.(Replicated Pods)
Pod는 기본적으로 컨테이너에 대하여 네트워킹과(networking) 저장소(storage) 두 가지 종류의 공유 리소스
를 제공한다.

 

Pod Templates

일반적으로 많이 사용하는 Deployment를 사용하여 Pod 설정들에 대하여 알아본다.

apiVersion: apps/v1
kind: Deployment
metadata:
    name: java-application-deployment 
    lables:
        app: java-application
spec:
    selector:
        matchLabels:
            app: java-application
    minReadySeconds: 5
    revisionHistoryLimit: 1 
    strategy:
        rollingUpdate:
            maxUnavailable: 0
            maxSurge: "50%"
    template:
        metadata:
            labels:
                app: java-application
        Spec:
            initContainers:
            - name: init-myservice
              image: busybox: 1.28 
            command: ['sh', '-c', "until nslookup myservice.S(cat /val/run/secrets/kubernetes.."]
        containers:
        - name: app
          image: { image } 
          resources:
            requests:
              memory: "1Gi"
              cpu: "1"
            limits:
              memory: "1Gi" 
              cpu: "1"
          workingDir: /us/local/app
          args: ["--spring.profiles.active=production"] 
          envFrom:
          - secretRef:
              name: api-endpoint 
          env:
          - name: JAVA_TOOL_OPTIONS 
            value: "-XX: InitialRAMPercentage=70 - XX:MaxAMPercentage=70 - XX:MaxMetaspacesize=25"
          volumeMounts:
              - name: log-volume 
                mountPath: /us/local/app/logs
          ports
          - name: app-port
            containerPort: 8080
          - name: actuator-port 
            containerPort: 8089
          readinessProbe:
              httpGet:
                  path: /monitor/health/readiness 
                  port: actuator-port 
              initialDelaySeconds: 30
              periodSeconds: 5
              timeoutSeconds: 1
              failureThreshold: 10 
          livenessProbe:
              httpGet:
                  path: /monitor/health/liveness 
                  port: actuator-port
              initialDelaySeconds: 30
              periodSeconds: 5
              timeoutSeconds: 1
              failureThreshold: 10
        - name: fluent-bit 
          image: { image }
          resources:
            requests:
              memory: "1278i"
              cpu: "100m"
            limits:
              memory: "1278i"
              cpu: "100m"
          env:
            - name: LOG_DIR
              value: /us/local/app/logs
            - name: BROKERS_URLS 
              valueFrom:
                configMapKeyRef:
                  name: log-kafka-config 
                  key: log.kafka.brokers
          volumeMounts:
            - name: log-volume 
              mountPath: /us/local/app/logs
        affinity:
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms: 
            - matchExpressions
              - key: disktype
                operator: In 
                values:
                - ssd
        volumes:
        - name: log-volume 
          emptyDir: {}

 

Init Containers

            initContainers:
            - name: init-myservice
              image: busybox: 1.28 
            command: ['sh', '-c', "until nslookup myservice.S(cat /val/run/secrets/kubernetes.."]

initContainer는 앱 컨테이너가 시작되기 전에 실행되는 하나 이상의 컨테이너로 구성된다.

  • initContainer는 항상 완료될 때까지 실행된다.
  • 각 initContainer는 다음 initContainer가 시작되기 전에 성공적으로 완료되어야 한다.

Pod의 initContainer가 실행되면 kubelet은 성공할 때까지 해당 initContainer를 반복적으로 재시작한다.

 

 

Sidecar Container

Kubernetes v1.29[beta]
            initContainers:
            - name: logshipper
              image: alphine:lastest
              restartPolicy: Always
              command: ['sh', '-c', "tail -F /opt/logs.txt"]

Kubernetes v1.29 이하에서는 사이드카 패턴을 사용하려면 일반적으로 container에 사이드카 컨테이너를 정의해서 사용했다. 하지만  v1.29 이상에서는 initContainers에 restartPolicy를 Always로 설정하여 사이드카 컨테이너를 사용할 수 있다.
initContainer의 reastartPolicy를 Always로 설정하면 Pod의 전체 수명 동안 실행 상태를 유지한다.
이는 애플리케이션 컨테이너와 분리된 지원 서비스를 실행하는 데 도움이 될 수 있다. (ex 로그, 메트릭 수집, ...)

 

Pod Quality of Service Classes

Pod의 컨테이너는 resources.requests, resources.limits를 사용하여 리소스를 할당할 수 있고, resources 설정은 QoS 클래스라는 값으로 설정될 수 있다.

        containers:
        - name: app
          ...
          resources:
            requests:
              memory: "1Gi"
              cpu: "1"
            limits:
              memory: "1Gi" 
              cpu: "1"

 

Kubernetes는 실행하는 Pod를 분류하고 각 Pod를 specific quality of service((QoS) class에 할당한다.

Kubernetes는 QoS 클래스를 사용하여 Node Pressure를 겪고 있는 노드에서 어떤 Pod를 제거할지를 결정한다.

Qos는 Guarranteed, Burstable, BestEffort가 있고 BestEffort > Burstable > Guarranteed 순서로 Pod를 제거한다.

 

Guaranteed

가장 엄격한 리소스 제한이 있고 추방될 가능성이 가장 낮은 Pod다.

  • Pod 내의 모든 컨테이너에는 CPU와 memory 제한(imits)과 요청이(requests) 있어야 한다.
  • Pod 내의 모든 컨테이너에 대해 CPU와 memory 제한(imits)과 요청이(requests) 같아야 한다.

Burstable

요청에 따라 일부 하한 리소스 보장이 있지만 특정 제한이 필요하지 않은 Pod. 제한이 지정되지 않으면 노드 용량과 동일한 제한으로 기본 설정되어 리소스가 사용 가능한 경우 Pod가 리소스를 유연하게 늘릴 수 있다. Pod에는 리소스 제한이나 요청이 없는 컨테이너가 포함될 수 있으므로 Pod는 노드의 모든 리소스를 사용하려고 시도할 수 있다.

  • Pod의 Guaranteed 기준을 충족하지 않는다.
  • Pod에 있는 컨테이너 하나 이상에 memory 또는 CPU 요청이나 제한이 있다.

BestEffort

BestEffort의 Pod는 다른 QoS클래스의 Pod에 특별히 할당되지 않은 노드의 리소스를 사용할 수 있다. 예를 들어
16 CPU Core를 가진 노드에 4 CPU core를 사용하는 Guranteed Pods가 있는 경우 BestEffort는 남아있는 12
CPU Core를 원하는 만큼 사용하려고 할 수 있다.

  • Pod의 컨테이너 중 어느 것도 CPU, memory 제한이나 요청이 없는 경우

 

Container probes

          readinessProbe:
              httpGet:
                  path: /monitor/health/readiness 
                  port: actuator-port 
              initialDelaySeconds: 30
              periodSeconds: 5
              timeoutSeconds: 1
              failureThreshold: 10 
          livenessProbe:
              httpGet:
                  path: /monitor/health/liveness 
                  port: actuator-port
              initialDelaySeconds: 30
              periodSeconds: 5
              timeoutSeconds: 1
              failureThreshold: 10

probe는 컨테이너에서 주기적으로 수행하는 진단으로, 컨테이너 내부에서 코드를 실행하거나 네트워크 요청을 한다.

 

Check mechanisms

  • exec : 컨테이너 내부에서 지정된 명령으로 실행한다. 상태코드 0으로 종료되면 정상
  • grpc: gRPC를 사용하여 원격 프로시저 호출을 수행한다.
  • httpGet: 지정된 port와 경로에서 Pod의 IP 주소에 대한 HTTP GET 요청을 수행한다. (200 이상 400 미만의 HTTP Status로 응답하는 경우 성공)
  • tcpsocket: 지정된 port에서 Pod의 IP 주소에 대해 TCP 검사를 수행한다. (TCP port가 열려있으면 성공)

Types of probe

  • livenessProbe : 컨테이너가 실행 중인지 여부를 판단한다. 실패하면 컨테이너를 종료하고 재시작 정책에 따라 재시작한다.
  • readinessProbe : 컨테이너가 요청에 응답할 준비가 되었는지 여부를 판단한다. 실패하면 엔드포인트 컨트 롤러는 Pod와 일치하는 모든 서비스의 엔드포인트에서 Pod의 IP 주소를 제거한다.
  • startupProbe : 컨테이너 내의 애플리케이션이 시작되었는지 여부를 판단한다. startupProbe가 설정되면 성공할 때까지 모든 Probe는 비활성화된다.

 

Assign Pods to Nodes using Node Affinity

        affinity:
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms: 
            - matchExpressions
              - key: disktype
                operator: In 
                values:
                - ssd

Node Affinity를 사용하여 Kubernetes Pod를 특정 노드에 할당할 수 있고, Pod별로 모두 다른 Node에 할당할 수도 있다.

 

 

Resource sharing and communication

        containers:
        - name: app
          ......
          volumeMounts:
              - name: log-volume 
                mountPath: /us/local/app/logs
        - name: fluent-bit 
          ......
          volumeMounts:
            - name: log-volume 
              mountPath: /us/local/app/logs
        volumes:
        - name: log-volume 
          emptyDir: {}

Volume 공유
Kubernetes에서는 Volume을 통해 다양한 type의 저장공간을 지원해 주고, Pod에 컨테이너들은 이 Volume을 공유하는 것이 가능하다.
Network 공유
Pod 내부의 컨테이너들은 network를 공유한다. 간단히 말해서 localhost로 Pod안에 컨테이너 사이에 통신이 가능하다.

 

참고

 

 

'dev > kubernetes' 카테고리의 다른 글

nGrinder on K8S  (0) 2024.07.25
Kubernetes - Service  (0) 2024.07.02