HomeAbout
[Kubernetes] Kubernetes 구성요소 완벽 정리: Pod, Service, 그리고 Controller
Docker & Kubernetes
[Kubernetes] Kubernetes 구성요소 완벽 정리: Pod, Service, 그리고 Controller
NASA1515
NASA1515
July 24, 2021
6 min

목차

01
✔ 개념정리
02
✌ Pod
03
👌 Service
04
👏 Name space
05
🐱‍🏍 라벨(label)
06
🎶 컨트롤러
07
😃 Kubernetes 배포에 대한 이해
08
✨ 고급 컨트롤러
09
🤦‍♂️ Job
10
🌹 Cron jobs

✔ 개념정리


오브젝트

  • Kubernetes를 이해하기 위해 가장 중요한 부분이 오브젝트입니다.
    가장 기본적인 구성단위가 되는 기본 오브젝트(Basic object)생성하고 관리하는 추가적인 기능을 가진 컨트롤러(Controller)와 이러한 오브젝트의 스펙(설정)이외에 추가정보인 메타 정보들로 구성이 된다고 보면 됩니다.

오브젝트 스펙 (Object Spec)

  • 오브젝트들은 모두 오브젝트의 특성 (설정정보)을 기술한 오브젝트 스펙 (Object Spec)으로 정의가 되고, 커맨드 라인을 통해서 오브젝트 생성 시 인자로 전달하여 정의를 하거나 또는 yaml이나 json 파일로 스펙을 정의할 수 있습니다.

기본 오브젝트 (Basic Object)

  • Kubernetes에 의해서 배포 및 관리되는 가장 기본적인 오브젝트는 컨테이너화되어 배포되는 애플리케이션의 워크로드를 기술하는 오브젝트로 4가지가 있습니다.
    • Pod : 컨테이너화된 애플리케이션
    • Service : 로드밸런서
    • Volume : 디스크
    • Namespace : 패키지

✌ Pod

  • Pod 는 Kubernetes에서 가장 기본적인 배포 단위로, 컨테이너를 포함하는 단위입니다. k8s의 특징중의 하나는 컨테이너를 하나씩 배포하는 것이 아니라 Pod 라는 단위로 배포하는데, Pod는 하나 이상의 컨테이너를 포함합니다.

간단한 Pod를 정의한 Yaml 입니다

apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
    image: nginx:1.7.9
    ports:
    - containerPort: 8090

  • apiVersion : 이 스크립트를 실행하기 위한 Kubernetes API 버전 (보통 v1을 사용)
  • kind : 리소스의 종류를 정의, (Pod)
  • metadata : 리소스의 각종 메타 데이타 정의 라벨이나 리소스의 이름 등 각종 메타데이타를 넣습니다.
  • spec : 리소스에 대한 상세한 스펙을 정의합니다.
    • Pod는 컨테이너를 가지고 있기 때문에, container 를 정의
    • 이름은 nginx
    • 도커 이미지 nginx:1.7.9 를 사용
    • 컨테이너 포트 8090을 오픈합니다.

여기서 의문 하나!!!

왜 POD 안에 한개 이상의 컨테이너를 가지는데, 개별적으로 하나씩 컨테이너를 배포하지 않고 여러개의 컨테이너를 Pod 단위로 묶어서 배포할까?


Pod는 다음과 두가지 특징을 가지고 있기 때문입니다.

  • Pod 내의 컨테이너는 IP와 Port를 공유합니다. 두 개의 컨테이너하나의 Pod를 통해서 배포되었을때 localhost를 통해서 통신이 가능합니다.
    컨테이너 A가 8080, 컨테이너 B가 7001로 배포가 되었을 때 B -> A를 호출 할 때 localhost:8080 으로 호출하면 되고 A -> B를 호출 할 때는 localhost:7001로 호출이 가능합니다.

  • Pod 내에 배포된 컨테이너간에는 디스크 볼륨을 공유할 수 있습니다. 요즘 APP은 실행할때 APP만 올라가는것이 아니라 Reverse proxy, 로그 수집기등 다양한 주변 솔루션이 같이 배포 됩니다. APP(Tomcat, node.js)와 로그 수집기를 다른 컨테이너로 배포하면 일반적인 경우 컨테이너에 의해서 파일 시스템이 분리되기 때문에 로그 수집기가 APP 컨테이너의 로그파일을 읽는 것이 불가능합니다. 하지만 k8s는 하나의 Pod 내에서 컨테이너들끼리 볼륨을 공유할 수 있기 때문에 다른 컨테이너의 파일을 읽어올 수 있습니다.

👌 Service

  • Pod볼륨을 이용하여, 컨테이너들을 정의하고, Pod를 서비스로 제공할 때 분산환경에서는 하나의 Pod로 서비스 하는 경우는 드물고 여러 Pod를 로드밸런서를 이용해서 하나의 IP와 포트로 묶어 서비스를 제공합니다. Pod의 경우에는 동적으로 생성 되고, 장애가 생기면 자동으로 재시작 되며 IP가 바뀌기 때문에 로드밸런서에서 Pod의 목록을 지정할 때는 IP주소를 이용하는 것은 어렵다. 또 오토 스케일링으로 인하여 Pod 가 동적으로 추가 또는 삭제되기 때문에 이렇게 추가/삭제된 Pod 목록을 로드밸런서가 유연하게 선택해 줘야 합니다.

그래서 사용하는 것이 라벨(label)라벨 셀렉터(label selector) 라는 개념입니다.

  • 라벨 셀렉터(label selector) : 어떤 Pod를 서비스로 묶을 것인지 정의하면 각 Pod를 생성할때 메타데이타 정보 부분라벨을 정의할 수 있습니다. 결과적으로 서비스는 라벨 셀렉터에서 특정 라벨을 가지고 있는 Pod만 선택하여 서비스에 묶게 됩니다.

  • 라벨이 “myapp”인 서비스만 분류해 서비스에 넣는다. 분류된 Pod 간 로드밸런싱을 통하여 외부로 서비스를 제공합니다.

위 서비스를 Yaml로 정의해보면 다음과 같습니다.

kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
    app: myapp
ports:
- protocol: TCP
    port: 80
    targetPort: 9376

  • kind : Service로 지정
  • apiVersion : v1으로 정의
  • metadate-name : my-service (서비스의 이름)
  • spec : 서비스에 대한 스펙을 정의
  • selector : 라벨 = app:myapp인 Pod 만을 선택해서 분류
  • ports
    protocol : TCP
    port : 80 포트로 서비스 targetPort : 80 포트 요청을 컨테이너의 9376 포트로 연결해 제공합니다

👏 Name space

  • 하나의 Kubernetes 클러스터내의 논리적인 분리 단위라고 보면 됩니다. Pod,Service 등은 NameSpace 별로 생성이나 관리가 되고 사용자의 권한 역시 NameSpace 별로 나눠서 부여할 수 있습니다.
    즉 하나의 클러스터 내에 개발/운영/테스트 환경이 있으면 클러스터를 개발/운영/테스트 3개의 NameSpace로 나눠 운영이 가능합니다.

네임스페이스 동작

  • 사용자 별로 네임스페이스 별 접근 권한을 다르게 운영할 수 있습니다.
  • 네임스페이스별로 리소스의 할당량을 지정할 수 있습니다. 즉 사용 가능한 리소스의 수를 지정할 수 있습니다. (ex : 개발팀 CPU 100, 운영팀 CPU 200)
  • NameSpace별로 리소스를 나눠서 관리할 수 있습니다.. (Pod, Service 등)

하지만 NameSpace는 논리적인 분리 단위일뿐 물리적이나 장치를 통해서 환경을 분리(Isolation)한 것이 아니다.

  • 즉 다른 NameSpace간의 pod 라도 통신은 가능합니다.

  • 위 처럼 네임스페이스를 분리하여 운영이 가능합니다.

🐱‍🏍 라벨(label)

  • 라벨은 Kubernetes의 리소스를 선택하는데 사용이 됩니다. 각 리소스는 라벨을 가질 수 있고 라벨 검색 조건에 따라서 특정 라벨을 가지고 있는 리소스만을 선택할 수 있습니다. 라벨을 선택하여 특정 리소스만 배포, 업데이트 할 수 있고 또는 라벨로 선택된 리소스만 Service에 연결하거나 특정 라벨로 선택된 리소스에만 네트워크 접근 권한을 부여하는 등이 가능합니다. 라벨은 metadata 섹션에 키/값 쌍으로 정의가 가능하며 하나의 리소스에는 하나의 라벨이 아니라 여러 라벨을 동시에 적용할 수 있습니다.

이해가 가장 빠른건 역시 정의해보는 거죠

"metadata": {
"labels": {
    "key1" : "value1",
    "key2" : "value2"
 }
}
  • 셀렉터를 사용하려면 오브젝트 스펙에서 selector 라고 정의하고 라벨 조건을 적어 놓으면 됩니다.

k8s는 두 가지 셀렉터를 제공합니다. 기본적으로 Equaility based selectorSet based selector 입니다.


  • Equality based selector : 같냐, 다르냐와 같은 조건을 이용하여, 리소스를 선택하는 방법

    environment = dev
    
    tier != frontend
    
    • 같이 등가 조건에 따라서 리소스를 선택합니다.

  • set based selector : Equality based 보다 향상된 셀렉터로 집합의 개념을 사용합니다.

    • environment in (production,qa) 는 environment가 production 또는 qa 인 경우
    • tier notin (frontend,backend)는 frontend도 아니고 backend도 아닌 리소스를 선택. 아래 nasa-service 라는 이름의 서비스를 정의했습니다.
      셀렉터에서 app: myapp 정의해서 Pod의 라벨 app이 myapp 것만 골라 이 서비스에 바인딩해서 9376 포트로 서비스 합니다.
    kind: Service
    apiVersion: v1
    metadata:
    name: my-service
    spec:
    selector:
        app: myapp
    ports:
        - protocol: TCP
        port: 80
        targetPort: 9376
    

🎶 컨트롤러

  • 앞에 있는 4개의 기본 오브젝트로, 애플리케이션을 설정하고 배포하는 것이 가능합니다. 이를 조금 더 편리하게 관리하기 위해서 컨트롤러라는 개념을 사용합니다.
    컨트롤러는 기본 오브젝트들을 생성하고 이를 관리하는 역할을 해준다. 컨트롤러의 종류는 아래와 같습니다.

  • Replication Controller : Pod를 관리해주는 역할, 지정된 숫자로 Pod를 기동, 관리하는 역할을 합니다.

    Replication Controller (RC)는 크게 3가지 파트로 구성되는데 아래와 같습니다.

    • Selector : 먼저 Pod selector는 라벨 기반이며, RC가 관리한 Pod를 가지고 오는데 사용합니다.

    • Replica 수 : RC에 의해서 관리되는 Pod의 수, 그 숫자만큼 Pod 의 수를 유지하도록 합니다.

    • Pod template : Pod에 대한 정보 (도커 이미지, 포트,라벨등)에 대한 정보를 정의 합니다.


아래 예를 보겠습니다.

스크린샷, 2020-09-16 10-00-43

  • ngnix라는 이름의 RC를 정의한 것으로label이 “app:ngnix”인 Pod들을 관리하고 3개의 Pod가 항상 운영되도록 설정합니다.
    Pod는 app:ngnix 라는 라벨을 가지며, 이름이 ngnix이고 nginx 이미지를 사용해서 생성하고 컨테이너의 포트는 80 번 포트를 이용해서 서비스를 제공합니다.

ReplicaSet

  • Replication Controller 의 업데이트 버전으로 생각하면 됩니다. ReplicaSet이 나옴으로 써 RC는 거의 사용하지 않습니다.
    두 서비스의 큰 차이는 없고 Replication Controller 는 Equality 기반 Selector를 이용하고 Replica Set은 Set 기반의 Selector를 이용합니다.

Deployment

  • Replication controller와 Replica Set의 상위 추상화 개념입니다. 실제 운영에서는 RS 나 RC를 바로 사용하는 것보다, 좀 더 추상화된 Deployment를 사용하게 됩니다.

😃 Kubernetes 배포에 대한 이해

  • Kubernetes의 Deployment 리소스를 이해하기 위해서 Kubernetes에서 Deployment 없이 어떻게 배포를 하는지에 대해서 이해를 해야 합니다.

다음과 같은 Pod와 RC가 있습니다.

스크린샷, 2020-09-16 10-12-28

  • 이제 애플리케이션이 업데이트되서 새로운 버전의 Container를 굽고 배포하는 두가지 시나리오에 대해서 설명하겠습니다.

블루/그린 배포

  • 블루(예전)버전으로 서비스 하고 있던 시스템을 그린(새로운)버전을 배포한 후 트래픽을 블루에서 그린으로 한번에 돌리는 방식입니다.
    여러 방법이 있지만 손쉬운 방법은 새로운 RC을 만들어 새로운 템플릿으로 Pod를 생성한 뒤 Pod 생성이 끝나면, 서비스를 새로운 Pod로 옮기는 방식입니다.

  • 후에, 배포가 완료되고 문제가 없으면 예전 버전의 RC 와 Pod를 지워줍니다.

롤링 업데이트 방식

  • Pod를 하나씩 업그레이드 해가는 방식입니다.

이 배포를 위해선 먼저 새로운 RC를 만든 뒤 기존 RC에서 replica 수를 하나 줄이고, 새로운 RC에는 replica 수를 하나만 줍니다.

  • 라벨이 동일하면 서비스는 자연히 새로운 RC에 의해 생성된 Pod를 서비스에 포함 시킨다.

다음으로 기존 RC의 replica를 하나 더 줄이고, 새로운 RC의 replica를 하나 더 늘립니다.


이후 기존 Pod가 하나더 서비스에서 빠지게 되고 새로운 버전의 Pod가 서비스에 추가됩니다.

  • 위의 작업을 반복하게 되면 아래 그림과 같이 예전 버전의 Pod가 모두 빠지고 새 버전의 Pod만 서비스 되게 됩니다.

  • 만약 배포가 잘못되었을 경우에는 기존 RC의 replica 수를 원래대로 올리고 새버전의 replicat 수를 0으로 만들어서 예전 버전의 Pod로 롤백이 가능합니다.
    이 과정은 kubectl rolling-update라는 명령으로 RC 단위로 컨트롤이 가능하지만 그래도 여전히 작업이 필요하고, 배포 과정을 모니터링 해야 합니다.
    그리고 가장 큰 문제는 kubectl rolling-update 명령은 클라이언트에서 실행 하는 명령으로 명령어 실행중에 클라이언트의 연결이 끊어 지면 배포작업이 비정상적으로 끊어질 수 있는 문제가 있습니다. 추가적으로, 롤백과정 역시 수동 컨트롤이 필요합니다. 그래서 이러한 과정을 자동화하고 추상화한 개념을 Deployment라고 보면 됩니다. Deployment는 Pod 배포를 위해서 RC를 생성하고 관리하는 역할을 하며 특히 롤백을 위한 기존 버전의 RC 관리등 여러가지 기능을 포괄적으로 포함하고 있습니다..



✨ 고급 컨트롤러

  • RC,RS,Deployment는 웹서버와 같은 일반적인 워크로드에 대해 Pod를 관리하기 위한 컨트롤러입니다. 실제 운영환경에서는 웹서버 이외의 데이타베이스 ,배치 작업, 데몬 서버등과 같이 다양한 형태의 워크로드 모델이 존재하는데 이를 지원하기 위해 k8s는 다양한 컨트롤러를 제공합니다.

DaemonSet

  • DaemonSet(DS)는 Pod가 각각의 노드에서 하나씩만 돌게 하는 형태로 Pod를 관리하는 컨트롤러입니다.
    RC나 RS에 의해서 관리되는 Pod 는 노드의 상황에 따라서 일반적으로 비균등적으로 배포가 되지만 DS에 의해 관리되는 Pod는 모든 노드에 균등하게 하나씩만 배포 됩니다. 이런 형태의 워크로드는 서버의 모니터링이나 로그 수집 용도로 많이 사용되는데 DS의 다른 특징중 하나는, 특정 Node들에만 Pod가 하나씩만 배포 되도록 설정이 가능합니다.

  • 로그나 모니터링 시나리오에서 특정 장비에 대한 모니터링을 하고자 할 때 이런 시나리오가 유효합니다.
    예를 들어 특정 장비(노드)에만 Nvme SSD를 사용하거나 GPU를 사용할 경우 그 장비가 설치된 노드만을 모니터링하면 됩니다.

스크린샷, 2020-09-16 11-07-18

  • DS는 특정 노드에만 Pod를 배포할 수 있도록 Pod의 “node selector”를 이용해서 특정 노드만을 선택할 수 있게 지원합니다.

🤦‍♂️ Job

  • 워크로드 모델중에서 배치나 한번 실행되고 끝나는 형태의 작업이 있을 수 있습니다.
    예를 들어 원타임으로 파일 변환 작업을 하거나, 또는 주기적으로 ETL 배치 작업을 하는 경우에는 웹서버 처럼 계속 Pod가 떠 있을 필요없이 작업을 할때만 Pod 를 띄우면 됩니다. 이러한 형태의 워크로드 모델을 지원하는 컨트롤러를 Job이라고 합니다

스크린샷, 2020-09-16 11-10-43

Job에 의해서 관리되는 Pod는 Job이 종료되면, Pod 를 같이 종료합니다.

  • Job을 정의할때는 보통 아래와 같이 컨테이너 스펙 부분에 image 뿐만 아니라 컨테이너에서 Job을 수행하기 위한 커맨드(command) 를 같이 입력합니다.
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
    spec:
    containers:
    - name: pi
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"] <<<----#####
    restartPolicy: Never
backoffLimit: 4

  • Job 컨트롤러에 의해서 실행된 Pod 는 이 command의 실행 결과에 따라서 Job이 실패한지 성공한지를 판단합니다. (프로세스의 exit 코드로 판단)
    Job이 종료되었는데, 결과가 실패라면,이 Job을 재실행할지 또는 끝낼지를 설정에 따라서 결정합니다.

하지만 만약 Job이 끝나기 전에 비정상적으로 종료된다면 어떻게 될것인가?

  • Kubernetes 클러스터에서 특정 노드가 장애가 났다고 가정하면 RC/RS에 의해서 관리되고 있는 Pod 는 자동으로 다른 노드에서 다시 자동으로 생성되서 시작될것이고 컨트롤러에 의해 관리되고 있지 않은 Pod 는 다시 다른 노드에서 기동되지 않고 사라질것입니다.

그렇다면 Job 에 의해서 관리되는 Pod는 어떻게 될것인가? -> 두가지 방법이 있습니다..

  1. 장애시 다시 시작하게 하거나
  2. 장애시 다시 시작하지 않게 할 수 있습니다.
  • 다시 시작의 개념은 작업의 상태가 보장되는것이 아닌 다시 처음부터 작업이 재 시작되는 것이기 때문에 resume이 아닌 restart의 개념입니다. 다시 시작 처음부터 작업을 시작하더라도 데이타가 겹치거나 문제가 없는 형태여야 합니다. 배치 작업의 경우 작업을 한번만 실행할 수 도 있지만
    같은 작업을 연속해서 여러번 수행하는 경우가 있습니다.. (데이타가 클 경우 범위를 나눠서 작업하는 경우) 이런 경우를 위해서 Job 컨트롤러는 같은 Pod를 순차적으로, 여러번 실행할 수 있도록 설정이 가능합니다. Job 설정에서 completion에 횟수를 주면, 같은 작업을 completion 횟수만큼 순차적으로 반복합니다.

스크린샷, 2020-09-16 11-17-47


  • 만약 여러 작업을 처리해야 하지만 순차성이 필요없고 병렬로 처리를 하고 싶다면 Job설정에서 parallelism 에 동시 실행할 수 있는 Pod의 수를 주면 지정된 수 만큼 Pod를 실행하여 completion 횟수를 병렬로 처리합니다.
    아래 그림은 completion이 5, parallelism이 2일 경우 하나의 노드에서 모든 Pod가 실행된다고 가정했을때, 실행 순서를 보여주는 그림입니다.

스크린샷, 2020-09-16 11-19-14

요약 : 총 2개의 POD 에서 병렬 실행, 5번 반복!!


🌹 Cron jobs

  • Job 컨트롤러에 의해서 실행되는 배치성 작업들에 대해서 고려할 점 중 하나는 이런 배치성 작업을 메뉴얼로 실행하는 것이 아닌 주기적으로 자동화해서 실행할 필요가 있습니다.는 것입니다. 이렇게 주기적으로 정해진 스케쥴에 따라 Job 컨트롤러에 의해 작업을 실행해주는 역할입니다.
    아래는 cron jobs 컨트롤러의 예제인데, job 컨트롤러와 설정이 다르지 않습니다.
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
    spec:
    template:
        spec:
        containers:
        - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
        restartPolicy: OnFailure

다른 점은 CronJob 스펙 설정 부분에 “schedule”이라는 항목이 있고 반복 조건을 unix cron과 같이 설정하면 됩니다.


Referance

조대협님 블로그


Tags

#Kubernetes
NASA1515

NASA1515

Data Engineer

Hello I'M Wonseok aka NASA1515

Expertise

Public Cloud
k8s/Docker
Python

Social Media

instagramwebsitelinkedingithub

Related Posts

[Kubernetes] VSCode (VisualStudio Code)로 Kubernetes 클러스터 관리 : 초보자를 위한 완벽 가이드
[Kubernetes] VSCode (VisualStudio Code)로 Kubernetes 클러스터 관리 : 초보자를 위한 완벽 가이드
2021-08-19
2 min

Topics

CloudDevelop

Social Media