Kubernetes 실무자를 위한 Nomad
Kubernetes 실무자를 위한 Nomad
이 페이지는 워크로드 스케줄러로서의 Kubernetes와 Nomad를 비교하고, 워크로드가 어떻게 정의·스케줄링되는지, 그리고 서로의 아키텍처에 서로 다른 구성 요소가 어떻게 대응되는지 설명해요. 이 페이지의 비교는 Kubernetes 개발자와 관리자를 위한 것이에요. Kubernetes를 Nomad와 비교한 높은 수준의 개요는 Nomad 소개 페이지의 "Nomad versus Kubernetes" 섹션을 참고하세요.
출처: 문서
본문
클러스터 아키텍처 (Cluster architectures)
Kubernetes와 Nomad 모두 서버가 스케줄링을 관리하고 클러스터 운영을 유지하며 클라이언트가 워크로드를 실행하는 서버·클라이언트 노드 시스템을 구현해요.
Kubernetes
Kubernetes 클러스터의 두 주요 구성 요소는 서버(제어 플레인 control plane)와 클라이언트(워커 노드 worker nodes)예요.
제어 플레인은 워크로드 스케줄링 같은 클러스터 전체 작업과 클러스터 이벤트 감지·대응을 담당해요. 워커와는 분리된 노드에서 실행돼요. 제어 플레인을 단일 노드에 배포하거나 더 높은 가용성을 위해 여러 노드에 배포할 수 있어요.
Kubernetes 제어 플레인에는 다음과 같은 중요한 구성 요소가 있어요:
- kube-apiserver는 제어 플레인의 프론트엔드 역할을 하고 Kubernetes API 서버를 노출해요.
- etcd는 클러스터의 모든 데이터를 포함하는 키-값 저장소예요.
- kube-scheduler는 새로 생성된 Pod를 감시하고 워커 노드에 할당해요.
- kube-controller-manager는 노드, 잡, 서비스 계정 컨트롤러 같은 클러스터의 컨트롤러 프로세스를 실행해요. 각 컨트롤러는 각자의 프로세스를 담당하는 추가 구성 요소예요.
워커 노드는 하나 이상의 애플리케이션 컨테이너 그룹인 Pod를 호스팅하는 인프라예요. Pod 안의 컨테이너는 일반적으로 밀접하게 결합되어 있으므로 애플리케이션 구성 요소는 자체 Pod를 가져요. 예를 들어 프론트엔드, 백엔드, 데이터베이스를 가진 3계층 애플리케이션에서 각 구성 요소는 자체 Pod에서 실행되고 Service를 통해 다른 구성 요소와 통신해요.
각 워커 노드에는 다음 구성 요소가 있어요:
- kubelet은 컨테이너가 Pod 안에서 실행되도록 하는 책임을 져요. 워커 노드에서 실행되는 장수 에이전트예요.
- kube-proxy는 클러스터 안팎의 Pod 사이의 통신을 위한 네트워킹 규칙을 유지하고 촉진하는 선택적 장수 에이전트예요.
- 컨테이너 런타임은 컨테이너의 실행을 관리해요. 인기 있는 런타임에는 containerd와 Docker 엔진이 있어요.
Nomad
Nomad 클러스터의 두 주요 구성 요소는 서버 노드 와 클라이언트 노드 예요.
서버 노드는 잡 수락, 클라이언트 관리, 태스크 배치 계산을 담당해요. 태스크(task) 는 제약 조건이 있고 컴퓨팅 리소스가 필요한 Nomad의 작업 단위예요. 서버는 태스크의 필요한 리소스와 잡 스펙에 정의된 다른 제약 조건에 따라 클라이언트의 최적 배치를 찾기 위해 태스크를 스케줄링해요.
Kubernetes의 제어 플레인 노드와 달리 Nomad 서버는 다른 클라우드 region의 클러스터에서 실행할 수 있어요. 이 region들은 서로 독립적이고 데이터가 그 사이에 복제되지 않아요. 대신 다른 region의 서버는 gossip 프로토콜을 사용해 클러스터 어디에서나 잡 제출을 지원하고 다른 region의 상태를 조회해요.
클라이언트 노드는 워크로드 실행을 담당해요. 클라이언트는 RPC를 사용해 자신의 region의 서버와 통신해요. 서버에 스스로를 등록하고, liveness 하트비트를 보내고, 할당을 기다리고, 할당 상태를 업데이트해요. 할당(allocation) 은 워크로드 스펙의 태스크를 클라이언트 노드에 매핑한 것으로, 특정 노드에서 일련의 태스크가 실행되어야 한다는 선언을 포함해요. 클라이언트 노드는 또한 워크로드를 실행하는 데 필요한 Docker 같은 애플리케이션 런타임인 태스크 드라이버를 포함해요.
아키텍처 비교 (Architecture comparison)
Kubernetes는 제어 플레인과 노드에 다양한 프로세스를 설치해야 해요. 그러나 Nomad는 단일 바이너리이며 서버 또는 클라이언트 에이전트로 구성해요.
용어 (Terminology)
다음 차트는 Kubernetes와 Nomad가 사용하는 아키텍처 용어 사이의 등가성을 나열해요.
| Kubernetes | Nomad |
|---|---|
| 제어 플레인 (Control plane) | 서버 노드 |
| 워커 노드 (Worker node) | 클라이언트 노드 |
| kube-apiserver | Nomad HTTP API. Nomad 바이너리에 내장 |
| etcd | 직접적인 대응물 없음. 클라이언트가 로컬 data_dir에 데이터를 저장 |
| kube-scheduler | Nomad 바이너리에 내장 |
| kube-controllermanager | Nomad 바이너리에 내장 |
| kubelet | Nomad 바이너리에 내장된 Nomad 에이전트 |
| kube-proxy | 직접적인 대응물 없음. 많은 작업이 Nomad 서비스 디스커버리로 처리 |
| 컨테이너 런타임 (Container runtime) | 태스크 드라이버 |
서버 노드 (Server node)
이 다이어그램은 Kubernetes 제어 플레인과 Nomad 서버의 차이를 보여줘요.
Nomad 서버 에이전트는 클러스터 상태를 유지하고 워크로드 스케줄링을 수행하는 단일의 가벼운 프로세스예요.
클라이언트 노드 (Client node)
이 다이어그램은 단일 프로세스인 Kubernetes 워커 노드와 Nomad 클라이언트의 차이를 보여줘요.
클라이언트 에이전트는 노드에 지문을 등록하고 스케줄링을 위해 Nomad 서버에 정보를 제공해요. 클라이언트는 태스크가 실행 중인지 확인하고 그 수명주기를 관리해요.
태스크 드라이버는 런타임 구성 요소예요. Nomad는 Docker, Java, exec, QEMU 같은 내장 드라이버를 제공해요. 또한 태스크 드라이버 시스템은 플러그인이 가능해서 어떤 커뮤니티 플러그인이든 사용하거나 직접 만들 수 있어요.
프로덕션 제어 플레인 배포 (Production control plane deployment)
이 다이어그램은 일반적인 Kubernetes 배포와 Nomad 배포의 차이를 보여줘요.
네트워킹 (Networking)
Kubernetes 클러스터는 일반적으로 다음 IP 네트워크를 가져요:
- 노드 네트워크: 노드가 연결된 물리적 네트워크.
- Pod 네트워크: Kubernetes에서 각 pod는 자체 고유 IP를 가져요. Pod 네트워크는 노드 네트워크와 분리되어 있고, 많은 사용자가 pod와 노드 사이에 트래픽을 라우팅하기 위해 오버레이 네트워크를 구현하기로 선택해요.
- 서비스 네트워크: 서비스는 영구 IP 주소를 가진 pod 그룹을 나타내는 Kubernetes 리소스예요. 서비스 네트워크는 일반적으로 Pod 및 Node 네트워크와 분리된 가상 IP 시스템이에요.
이러한 분리된 네트워크 때문에 외부 애플리케이션은 Kubernetes 클러스터 안의 애플리케이션과 직접 통신할 수 없어요. 대부분의 사용자는 인그레스 컨트롤러를 배포하고 그것을 Kubernetes 클러스터의 단일 진입점으로 노출하기로 선택해요.
이 다이어그램은 Kubernetes와 Nomad 네트워킹의 차이를 보여줘요.
Nomad의 기본 네트워크는 노드 네트워크예요. 각 태스크 그룹 인스턴스는 노드 IP 네트워크를 사용하고 동적 포트 할당을 통해 자체 포트를 가져요. 가상 IP나 추가 오버레이 네트워크가 필요 없으므로 Nomad 클러스터 네트워크는 기존 엔터프라이즈 네트워크의 일부가 될 수 있어요.
Kubernetes에서 Service와 kube-proxy는 pod를 추적하고 트래픽을 그쪽으로 라우팅하는 책임이 있어요. Nomad 프로덕션 배포에서는 이 기능을 위해 HashiCorp Consul을 통합할 것을 권장해요.
워크로드 정의 (Workload definitions)
Kubernetes와 Nomad 모두 선언적 스펙 파일로 정의된 워크로드를 지원해요. 이 구성에서 워크로드가 있기를 원하는 상태를 선언하면 오케스트레이터가 그 선언된 상태와 일치하도록 워크로드를 스케줄링해요.
Kubernetes
Kubernetes의 워크로드는 일련의 스펙에 선언된 애플리케이션과 함께 YAML 파일로 정의돼요. 여기에는 다음이 포함되지만 이에 국한되지 않아요:
- Deployments: 이 스펙은 하나 이상의 애플리케이션 컨테이너를 배포해요.
- Services: 이 스펙은 하나 이상의 컨테이너를 노출하는 서비스를 배포해요.
- Config Maps: 이 스펙은 민감하지 않은 애플리케이션 데이터를 정의해요.
- Secrets: 이 스펙은 민감한 애플리케이션 데이터를 정의해요.
프론트엔드, 백엔드, 데이터베이스가 있는 예시 3계층 애플리케이션은 다음으로 구성될 거예요:
- 각 계층에 대한 Deployment 스펙
- 각 계층에 대한 Service 스펙
- 각 계층에 대한 Config Map 스펙
- 데이터베이스에 대한 Secret 스펙
Kubernetes가 추가 스펙으로 다른 유형의 워크로드를 수용할 수 있으므로 요구되는 스펙 수가 늘어날 수도 있어요.
- Deployment와 ReplicaSet은 데이터를 저장하지 않는 애플리케이션 프록시 같은 지속적인 무상태 워크로드를 선언해요.
- StatefulSets은 다른 애플리케이션 서비스가 접근할 수 있도록 데이터를 디스크에 저장하는 데이터베이스 같은 지속적인 상태 저장 워크로드에 필요해요.
- DaemonSet은 특정 노드에 로컬인 지속 워크로드(예: 특정 노드의 디렉터리에서 캐시 파일을 주기적으로 삭제하는 가비지 컬렉션 워크로드)에 필요해요.
- Jobs은 완료될 때까지 실행되는 워크로드(예: 업스트림 애플리케이션에 대한 연결을 테스트하고 종료하는 워크로드)에 필요해요.
Nomad
Nomad의 워크로드는 Hashicorp Configuration Language (HCL)를 사용하는 잡 스펙(jobspec) 파일로 정의돼요. jobspec은 워크로드의 각 구성 요소에 대한 선언적 구성을 포함해요:
- 컨테이너 세부 사항을 정의하는 태스크
- 애플리케이션 포트를 노출하는 네트워크 설정
- 애플리케이션을 포트에서 사용할 수 있게 하는 서비스
- 잡에 대한 메타데이터
프론트엔드, 백엔드, 데이터베이스가 있는 예시 3계층 애플리케이션은 하나의 jobspec 파일로 정의돼요. jobspec에서 다른 계층을 논리적으로 분리하려면 group 블록을 사용하세요. jobspec을 Nomad 서버에 제출하면 Nomad가 선언된 구성 요소를 호환 가능한 노드에 할당해요.
스펙 비교 (Specification comparison)
이 차트는 Kubernetes와 Nomad가 사용하는 워크로드 용어 사이의 매핑을 보여줘요.
| Kubernetes | Nomad |
|---|---|
| Deployment | Service Job |
| StatefulSet | Service Job |
| DaemonSet | System Job |
| Job | Batch 또는 System batch job |
| CronJob | 주기적 블록이 있는 Batch |
| Pod | Task |
| Init containers | Prestart 태스크 |
| Sidecar containers | Sidecar 태스크 |
| Service | service 블록 정의 |
| Ingress | 없음. 대신 외부 로드 밸런서 사용 |
| Volumes | 호스트 볼륨 또는 CSI 볼륨 |
| ConfigMaps | Variables |
| Secrets | secret 블록 (Variables 사용) |
| Liveness, readiness, startup probes | check 블록 |
워크로드 스케줄링 (Workload scheduling)
스케줄링은 워크로드의 요구 사항과 클러스터의 상태를 평가해 워크로드를 배치할 적절한 워커 또는 클라이언트 노드를 찾는 프로세스예요.
Kubernetes
kube-scheduler는 노드에 할당되지 않은 새로 생성된 Pod를 감시해요. 노드가 Pod의 리소스, affinity 또는 anti-affinity, 데이터 지역성 요구 사항을 충족하면 실현 가능(feasible)으로 표시돼요. 이 프로세스는 요구 사항을 충족하지 않는 노드를 필터링한 다음 남은 노드에 점수를 매겨 노드 할당을 결정해요. 여러 노드가 같은 점수를 가지면 하나가 무작위로 선택돼요. 마지막으로 노드가 선택되면 API 서버에 알려 바인딩이 생성돼요.
Nomad
Nomad 서버는 평가 브로커를 실행하는 리더 서버에서 오는 평가를 처리하는 스케줄러 워커를 실행해요. 이 스케줄러 워커들은 생성, 업데이트, 축출할 할당 집합을 포함하는 할당 계획을 생성해요. Nomad의 스케줄링 프로세스에는 네 가지 주요 구성 요소가 있어요:
- 노드: 워크로드를 실행하는 Nomad 클라이언트.
- 잡: 제약 조건과 리소스 요구 사항에 묶인 실행할 태스크의 선언적 설명.
- 할당: 특정 노드에서 일련의 태스크가 실행되어야 한다는 선언을 포함하는 태스크의 클라이언트 노드 매핑.
- 평가: 외부 상태(원하는 상태든 드러난 상태든)가 변경될 때마다 생성되는 계획.
다음 단계 (Next steps)
Turn a Kubernetes manifest into a Nomad job specification guide에 접근하세요.
Nomad와 Kubernetes를 심도 있게 비교한 다음 블로그를 검토하세요:
- A Kubernetes User's Guide to HashiCorp Nomad
- The Kubernetes to Nomad Cheat Sheet
- A Kubernetes User's Guide to HashiCorp Nomad Secret Management