Kubernetes에서 Pods 및 Services에 대한 궁극적인 가이드

Kubernetes는 강력한 컨테이너 오케스트레이션 플랫폼이지만, 그 잠재력을 최대한 활용하기 위해서는 핵심 구성 요소를 이해하는 것이 중요하며, 그 중에서도 팟(pod)과 서비스(service)가 기본적인 역할을 합니다. 이 기사에서는 이들이 무엇인지, 그리고 Kubernetes 클러스터 내에서 실행되는 애플리케이션에 대한 접근을 노출하고 관리하기 위해 어떻게 함께 작동하는지에 대해 알아보겠습니다.

팟이란 무엇인가?

은 Kubernetes에서 생성하고 관리할 수 있는 가장 작은 배포 가능한 컴퓨팅 단위입니다.

팟을 생성하기 전에 Kubernetes 클러스터에서 사용 가능한 API 리소스를 확인해 봅시다. kubectl api-resources 명령어를 사용할 수 있습니다. 이 명령어는 Kubernetes API 서버에서 지원하는 API 리소스를 나열하며, 여기에는 짧은 이름, API 그룹, 네임스페이스 여부가 포함됩니다. 이는 특히 사용자 정의 리소스를 다루거나 새로운 Kubernetes 기능을 탐색할 때 클러스터의 기능을 이해하는 데 유용합니다. kubectl explain 명령어는 개별 리소스에 대한 자세한 정보를 제공하여 이를 보완합니다.

간단한 Nginx 컨테이너를 실행하는 팟을 위한 기본 팟 구성 파일을 생성해 봅시다.

파일 이름을 nginx-pod.yaml로 생성합니다:

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

사용된 용어에 대한 간단한 설명은 다음과 같습니다:

  • apiVersion: v1: API 버전을 지정합니다.
  • kind: Pod: 이 구성이 팟에 대한 것임을 나타냅니다.
  • metadata:name: 팟의 이름입니다.
  • 메타데이터: 레이블: Pod를 구성하고 선택하는 데 사용할 수 있는 키-값 쌍입니다.
  • 스펙:컨테이너: Pod에서 실행될 컨테이너의 목록입니다.
  • 스펙:컨테이너:이름: 컨테이너의 이름입니다.
  • 스펙:컨테이너:이미지: 사용할 컨테이너 이미지입니다 (이 경우 최신 Nginx 이미지).
  • 스펙:컨테이너:포트: 컨테이너에서 노출할 포트입니다.

구성 파일을 적용하고 Pod를 생성하려면 kubectl을 사용하십시오:

  • kubectl apply -f nginx-pod.yaml

생성되었는지 확인하고 실행 중인 Pod의 상태를 확인하려면 다음을 실행하십시오:

  • kubectl get pods

다음과 유사한 출력이 표시되어야 합니다:

Shell

 

NAME         READY   STATUS    RESTARTS    AGE
nginx-pod    1/1     Running   0           10s

다음으로 Pod를 삭제하십시오:

  • kubectl delete pod nginx-pod

다음과 유사한 출력이 표시되어야 합니다:

Shell

 

kubectl get pod
No resources found in default namespace.

서비스란 무엇인가요?

Kubernetes의 Nginx Pod에 서비스를 만들면 Nginx 애플리케이션을 노출하고 클러스터 내외에서 접근할 수 있게 됩니다. Nginx Pod에 서비스를 만드는 단계별 가이드는 다음과 같습니다.

이미 실행 중인 Nginx Pod가 있는지 확인하려면, 없는 경우 nginx-pod.yaml이라는 YAML 파일을 만들어 주십시오:

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

Pod 구성을 적용하십시오:

nginx-service.yaml 파일을 생성하여 Service를 정의합니다.

YAML

 

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
       targetPort: 80
  type: ClusterIP

다음 사항을 주의해야 합니다:

  • selector: Nginx 팟과 일치하는 레이블 셀렉터입니다.
  • app: nginx: Nginx 팟의 레이블과 일치해야 합니다.
  • type: ClusterIP: Service의 유형입니다. ClusterIP는 클러스터 내에서만 Service에 접근할 수 있습니다. NodePort나 LoadBalancer를 사용하여 Service를 외부로 노출시킬 수도 있습니다.

kubectl을 사용하여 Service 구성을 적용합니다:

  • kubectl apply -f nginx-service.yaml
  • kubectl get services
Shell

 

NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
nginx-service    ClusterIP   10.96.0.1        <none>        80/TCP    10s

Service가 ClusterIP 유형이므로 클러스터 내에서만 접근할 수 있습니다. 클러스터 외부에서 접근하려면 Service 유형을 NodePort나 LoadBalancer로 변경할 수 있습니다.

NodePort를 사용하여 Service를 외부로 노출하려면 nginx-service.yaml 파일을 수정합니다:

YAML

 

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
       targetPort: 80
      nodePort: 30007  # Specify a node port in the range 30000-32767 (optional)
  type: NodePort

업데이트된 Service 구성을 적용합니다:

  • kubectl apply -f nginx-service.yaml

이제 노드의 IP 주소와 노드 포트(예: http://<node-ip>:30007)를 사용하여 Nginx 애플리케이션에 액세스할 수 있습니다.

멀티 컨테이너 팟

단일 컨테이너를 포드당 사용하는 것은 최대의 세분화와 분리를 제공합니다. 그러나 때때로 여러 컨테이너를 단일 포드 내에 배포하는 것이 유익한 시나리오가 있습니다. 이러한 보조 컨테이너는 다양한 역할을 수행할 수 있습니다: 로깅을 처리하거나 기본 컨테이너를 보완하는 역할(사이드카 개념), 외부 시스템에 대한 프록시 역할(앰배서더 개념), 또는 데이터를 외부 형식에 맞게 수정하는 역할(어댑터 개념). 이러한 보조 컨테이너는 기본 컨테이너가 처리하지 않는 작업을 수행하여 기본 컨테이너를 보완합니다.

다음은 Nginx 서버를 실행하는 기본 컨테이너와 로깅을 처리하는 사이드카 역할을 하는 보조 컨테이너를 포함하는 Kubernetes 포드 구성의 예입니다. 사이드카 컨테이너는 Nginx 접근 로그를 tail하는 방법을 보여주기 위해 BusyBox와 같은 간단한 로깅 컨테이너를 사용합니다.

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-with-logging-sidecar
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx
  - name: log-sidecar
    image: busybox:latest
    command: ["sh", "-c", "tail -f /var/log/nginx/access.log"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx
  volumes:
  - name: shared-logs
    emptyDir: {}

그 다음에는 다음을 수행합니다:

  • YAML 구성을 파일에 저장합니다, 예: nginx-with-logging-sidecar.yaml
  • 구성을 적용합니다: kubectl:kubectl apply -f nginx-with-logging-sidecar.yaml
  • 포드가 실행 중인지 확인합니다: kubectl get pods
  • 사이드카 컨테이너의 로그를 확인하여 Nginx 접근 로그를 확인합니다: kubectl logs -f <pod-name> -c log-sidecar.

이 단계를 따르면 기존 Pod를 삭제하고 새 구성을 적용하여 Nginx 컨테이너와 로깅을 위한 사이드카 컨테이너가 있는 Pod를 설정할 수 있습니다. 이를 통해 쿠버네티스 클러스터에서 새 구성이 활성화되고 실행되도록 할 수 있습니다.

쿠버네티스의 다중 컨테이너 Pod는 더 유연하고 효율적인 응용 프로그램 배포와 관리를 가능하게 합니다.

다중 컨테이너 Pod 패턴

사이드카 패턴

사이드카 컨테이너는 로깅, 구성 관리 또는 프록시와 같은 보조 기능을 제공하여 기본 응용 프로그램을 향상시킬 수 있습니다. 이 패턴은 주 컨테이너를 수정하지 않고도 기능을 확장하는 데 도움이 됩니다. 사이드카 컨테이너는 주 응용 프로그램 컨테이너로부터 로그를 수집하고 전달하여 로깅을 처리할 수 있습니다.

앰배서더 패턴

앰배서더 컨테이너는 프록시 역할을 하여 주 응용 프로그램과 외부 서비스 간의 통신을 관리합니다. 이를 통해 통합과 구성을 간단하게 할 수 있습니다. 앰배서더 컨테이너는 SSL 종료 또는 API 게이트웨이 기능을 처리할 수 있습니다.

앰배서더 패턴은 주 응용 프로그램과 외부 서비스 간의 통신을 관리하기 위해 사이드카 컨테이너를 사용하는 것을 포함합니다. 이 패턴은 프록시, 로드 밸런싱 또는 안전한 연결 관리와 같은 작업을 처리할 수 있어서 주 응용 프로그램 컨테이너로부터 복잡성을 추상화할 수 있습니다.

  • 주 응용 프로그램 컨테이너: HTTP 요청을 수행하는 간단한 웹 서버
  • 앰배서더 컨테이너: 외부 API로의 요청을 관리하기 위해 구성된 Envoy 프록시
YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: app-with-ambassador
spec:
  containers:
  - name: web-app
    image: python:3.8-slim
    command: ["python", "-m", "http.server", "8000"]
    volumeMounts:
    - name: config-volume
      mountPath: /etc/envoy
  - name: envoy-proxy
    image: envoyproxy/envoy:v1.18.3
    args: ["-c", "/etc/envoy/envoy.yaml"]
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: config-volume
      mountPath: /etc/envoy
  volumes:
  - name: config-volume
    configMap:
      name: envoy-config

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: envoy-config
data:
  envoy.yaml: |
    static_resources:
      listeners:
      - name: listener_0
        address:
          socket_address:
            address: 0.0.0.0
            port_value: 8080
        filter_chains:
        - filters:
          - name: envoy.filters.network.http_connection_manager
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
              stat_prefix: ingress_http
              route_config:
                name: local_route
                virtual_hosts:
                - name: local_service
                  domains: ["*"]
                  routes:
                  - match:
                      prefix: "/"
                    route:
                      cluster: external_service
              http_filters:
              - name: envoy.filters.http.router
      clusters:
      - name: external_service
        connect_timeout: 0.25s
        type: LOGICAL_DNS
        lb_policy: ROUND_ROBIN
        load_assignment:
          cluster_name: external_service
          endpoints:
          - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: api.example.com
                    port_value: 80

이 예제는 쿠버네티스에서 앰배서더 패턴을 보여주며, Envoy 프록시가 기본 애플리케이션 컨테이너를 위한 외부 통신을 관리하는 중개자로 작용합니다. 이 패턴은 통신의 복잡성을 추상화하고 모듈성과 유지 관리성을 향상시키는 데 도움이 됩니다.

어댑터 패턴

어댑터 컨테이너는 기본 애플리케이션과 외부 시스템 간의 데이터를 수정하거나 변환하여 호환성과 통합을 보장합니다. 예를 들어, 어댑터 컨테이너는 로그 데이터를 외부 로깅 서비스의 요구 사항에 맞게 재포맷할 수 있습니다.

쿠버네티스의 어댑터 패턴은 사이드카 컨테이너를 사용하여 기본 애플리케이션 컨테이너와 외부 시스템 간의 데이터를 변환하는 것을 포함합니다. 이는 기본 애플리케이션이 외부 시스템이 제공하거나 요구하는 형식과 다른 특정 형식의 데이터를 요구할 때 유용할 수 있습니다.

예를 들어, 사용자 정의 형식으로 로그를 생성하는 기본 애플리케이션 컨테이너가 있다고 가정해 보겠습니다. 이러한 로그를 특정 표준 형식으로 요구하는 외부 로깅 서비스에 전송해야 합니다. 어댑터 컨테이너를 사용하여 로그 데이터를 외부 서비스에 전송하기 전에 필요한 형식으로 변환할 수 있습니다.

  • 기본 애플리케이션 컨테이너: 사용자 정의 형식으로 로그를 작성하는 간단한 애플리케이션입니다.
  • 어댑터 컨테이너: 사용자 정의 로그를 읽고, 이를 JSON 형식으로 변환하여 외부 로깅 서비스에 전송하는 컨테이너입니다.
YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: app-with-adapter
spec:
  containers:
  - name: log-writer
    image: busybox
    command: ["sh", "-c", "while true; do echo \"$(date) - Custom log entry\" >> /var/log/custom/app.log; sleep 5; done"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/custom
  - name: log-adapter
    image: busybox
    command: ["sh", "-c", "tail -f /var/log/custom/app.log | while read line; do echo \"$(echo $line | sed 's/ - / - {\"timestamp\": \"/;s/$/\"}/')\" >> /var/log/json/app.json; done"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/custom
    - name: json-logs
      mountPath: /var/log/json
  - name: log-sender
    image: busybox
    command: ["sh", "-c", "while true; do cat /var/log/json/app.json | grep -v '^$' | while read line; do echo \"Sending log to external service: $line\"; done; sleep 10; done"]
    volumeMounts:
    - name: json-logs
      mountPath: /var/log/json
  volumes:
  - name: shared-logs
    emptyDir: {}
  - name: json-logs
    emptyDir: {}

이 예시는 Kubernetes에서 어댑터 패턴을 보여주며, 어댑터 컨테이너가 기본 애플리케이션 컨테이너의 데이터를 외부 시스템에 전송하기 전에 필요한 형식으로 변환합니다. 이 패턴은 사이드카 컨테이너 내에서 데이터 형식 변환을 처리하여 애플리케이션과 외부 서비스의 통합을 돕습니다.

요약

요약하자면, 파드:

  • Kubernetes에서 가장 작은 배포 단위입니다.
  • 실행 중인 프로세스의 단일 인스턴스를 나타냅니다.
  • 하나 이상의 컨테이너를 포함할 수 있습니다.

서비스:

  • 파드에 접근하기 위한 안정적인 IP 주소와 DNS 이름을 제공합니다.
  • 일련의 파드에 걸쳐 로드 밸런싱을 가능하게 합니다.
  • 클러스터 내에서 서비스 검색을 용이하게 합니다.

Source:
https://dzone.com/articles/the-ultimate-guide-to-kubernetes-pods-and-services