이 글은 “[Udemy] CKA with Practice Tests” 강의를 수강하며 정리한 내용을 바탕으로 작성한 내용입니다.
컨테이너 인프라 환경이란?
리눅스 운영체제의 커널 하나에서 여러 개의 컨테이너가 격리된 상태로 실행되는 인프라 환경입니다.
여기서 컨테이너는 목적을 위해 독립적으로 작동하는 프로세스입니다.
각 컨테이너는 CPU, 네트워크, 메모리 같은 시스템 자원을 독자적으로 사용하도록 할당된 개별 실행 환경을 갖습니다.
PID도 컨테이너 안에 격리돼 관리되기 때문에, 컨테이너 내부에서 실행되는 애플리케이션들은 서로 영향을 미치지 않고 독립적으로 작동합니다.
리눅스는 하나의 호스트 운영체제 안에서 이 격리를 두 가지 방식으로 제공해왔습니다.
| 매커니즘 | 역할 |
| cgroup (Control Group) | CPU, 메모리, 디스크 I/O 등 시스템 자원을 프로세스 단위로 분리해 할당하고 제한합니다 |
| namespace | PID, 네트워크, 마운트, UTS 등 실행 공간을 프로세스별로 격리해 관리합니다 |
다만 이걸 직접 다루려면 파일 시스템 설정부터 자원 관리까지 복잡한 과정을 직접 처리해야 했습니다.
이 복잡한 과정을 명령어로 추상화해 쉽게 만들어준 도구가 Docker입니다.
Docker를 사용하면 컨테이너를 생성할 때 개별적인 실행 환경 분리와 자원 할당을 자동으로 처리해줍니다.
SnowFlake 서버
다수의 관리자가 수백 대의 서버를 함께 관리하는 경우, 사람마다 패키지를 업데이트하거나 설정을 바꾸면서 서버마다 환경이 조금씩 달라지기 시작합니다.
이렇게 설정의 일관성이 깨진 서버를 SnowFlake 서버라고 합니다. 각 프로그램을 컨테이너로 구현하면 이런 서버 환경의 파편화를 방지할 수 있습니다.
컨테이너 인프라 환경의 구성 요소
컨테이너 엔진
컨테이너를 생성하고 관리하는 소프트웨어입니다. 컨테이너 이미지의 빌드, 실행, 중지, 삭제 등의 생명주기를 담당합니다.
대표적으로 Docker, containerd, CRI-O가 있으며, 쿠버네티스 1.20 버전 이후부터는 Docker를 직접 런타임으로 사용하는 방식이 deprecated되어 현재는 containerd나 CRI-O를 주로 사용합니다.
컨테이너 이미지
컨테이너 실행에 필요한 파일 시스템과 종속성을 패키징한 것입니다.
애플리케이션 실행에 필요한 라이브러리, 설정 파일, 실행 파일 등을 하나의 이미지로 묶어두기 때문에 어떤 환경에서 실행하더라도 동일한 결과를 보장합니다.
이미지는 레이어(Layer) 구조로 이루어져 있어, 변경된 레이어만 새로 빌드하고 나머지는 캐시를 재사용합니다.
오케스트레이션 도구
여러 개의 컨테이너를 조정하고 관리하기 위한 도구입니다.
컨테이너의 배포, 확장, 로드 밸런싱, 서비스 디스커버리 등을 자동화합니다.
대표적으로 Kubernetes, Docker Swarm, Apache Mesos가 있으며, 현재는 Kubernetes가 사실상의 표준으로 자리잡았습니다.
Docker만으로는 부족했던 것들
Docker 덕분에 컨테이너 하나를 띄우는 건 쉬워졌습니다. 하지만 실제 서비스를 운영하다 보면 아래와 같은 상황이 찾아옵니다.
- 컨테이너가 갑자기 죽으면 누가 자동으로 살려주나?
- 사용자가 갑자기 몰리면 컨테이너를 빠르게 늘릴 수 있나?
- 서버가 수십 대라면 어느 서버에 어떤 컨테이너를 올려야 하나?
- 새 버전 배포 시 서비스 중단 없이 롤링 업데이트를 할 수 있나?
- 여러 컨테이너 간의 네트워크 통신은 어떻게 관리하나?
컨테이너 수가 늘어날수록 이런 문제들을 수동으로 관리하는 것은 현실적으로 불가능합니다.
바로 이 지점에서 컨테이너 오케스트레이션(Container Orchestration)의 필요성이 생깁니다.
쿠버네티스(Kubernetes)란?
컨테이너화된 애플리케이션을 배포, 관리, 확장하는 프로세스를 자동화하는 컨테이너 오케스트레이션 플랫폼입니다.
구글은 내부적으로 수십억 개의 컨테이너를 관리하는 Borg 시스템을 운영해왔고, 이 경험을 바탕으로 2014년 쿠버네티스를 오픈소스로 공개했습니다. 이름은 그리스어로 "조타수(키잡이)" 를 의미하며, 로고의 방향타가 여기서 유래했습니다.
이후 CNCF(Cloud Native Computing Foundation)에 기증되면서 AWS, Azure, GCP 등 주요 클라우드 벤더가 모두 지원하는 표준으로 자리잡았습니다.
쿠버네티스의 핵심 철학은 선언적 구성(Declarative Configuration)입니다.
"컨테이너를 3개 실행해라"라고 명령하는 방식이 아니라, "컨테이너가 항상 3개 실행 중인 상태여야 한다"고 선언하면 쿠버네티스가 현재 상태를 지속적으로 감시하면서 원하는 상태를 유지합니다. 컨테이너가 하나 죽으면 자동으로 새로 띄우는 것도 이 철학에서 비롯됩니다.
쿠버네티스 전체 구조
쿠버네티스를 이루는 가장 기본 단위는 파드(Pod)입니다.
파드는 1개 이상의 컨테이너로 이루어져 있으며, 파드 안의 컨테이너들은 네트워크 네임스페이스와 스토리지 볼륨을 서로 공유합니다.
파드는 쿠버네티스로부터 클러스터 내부 IP를 부여받아 다른 파드와 통신할 수 있습니다.
컨테이너 → 파드(Pod) → 워커 노드(Worker Node) → 클러스터(Cluster)
파드들은 워커 노드 단위로 관리되며, 워커 노드와 마스터 노드(Control Plane)가 모여 쿠버네티스 클러스터를 구성합니다.
Control Plane (마스터 노드)
클러스터 전체의 상태를 관리하고 의사결정을 내리는 역할을 합니다.
| 컴포넌트 | 역할 |
| API Server | 쿠버네티스의 모든 요청이 거치는 진입점입니다. kubectl 명령, 내부 컴포넌트 간 통신 모두 API Server를 통합니다. REST API 형태로 동작하며, 요청에 대한 인증/인가/유효성 검사를 담당합니다 |
| etcd | 클러스터의 모든 상태 정보를 저장하는 분산 키-값 데이터베이스입니다. 파드의 수, 노드 상태, 설정 정보 등 클러스터의 모든 데이터가 여기에 저장됩니다. etcd가 손상되면 클러스터 전체 상태를 잃을 수 있기 때문에 주기적인 백업이 중요합니다 |
| Scheduler | 새로 생성된 파드를 어느 노드에 배치할지 결정합니다. 노드의 가용 자원, 파드의 리소스 요청량, 어피니티 규칙 등을 종합적으로 고려해 최적의 노드를 선택합니다 |
| Controller Manager | 클러스터가 원하는 상태를 유지하도록 지속적으로 감시하고 조정합니다. Deployment Controller, ReplicaSet Controller 등 다양한 컨트롤러가 하나의 프로세스로 실행됩니다 |
Worker Node
실제 컨테이너(파드)가 실행되는 서버입니다.
| 컴포넌트 | 역할 |
| kubelet | 각 노드에서 실행되는 에이전트입니다. API Server로부터 파드 스펙을 받아 컨테이너를 실행하고, 파드의 상태를 주기적으로 API Server에 보고합니다 |
| kube-proxy | 각 노드에서 네트워크 규칙을 관리합니다. 서비스(Service) 오브젝트를 기반으로 파드 간 트래픽 라우팅과 로드 밸런싱을 담당합니다 |
| Container Runtime | 실제 컨테이너를 실행하는 엔진입니다. kubelet의 요청을 받아 컨테이너 이미지를 pull하고 컨테이너를 실행합니다. containerd, CRI-O 등이 있습니다 |
요청 흐름
사용자가 kubectl로 파드 생성을 요청했을 때의 전체 흐름입니다.
① kubectl apply
↓
② API Server (인증 → 인가 → 유효성 검사)
↓
③ etcd에 상태 저장
↓
④ Scheduler가 배치 노드 결정
↓
⑤ kubelet이 컨테이너 실행
↓
⑥ Controller Manager가 상태 지속 감시
- kubectl apply — 요청 시작
사용자가 YAML 파일을 작성하고 kubectl apply -f pod.yaml 명령을 실행합니다. kubectl은 이 요청을 HTTP REST 형태로 변환해 API Server로 전달합니다. - API Server — 요청 검증
API Server는 모든 요청의 진입점으로, 요청을 처리하기 전에 세 단계를 거칩니다.- 인증(Authentication): 요청을 보낸 주체가 누구인지 확인합니다. kubeconfig에 설정된 인증서, 토큰, 서비스 어카운트 등을 통해 신원을 검증합니다.
- 인가(Authorization): 해당 주체가 요청한 작업을 수행할 권한이 있는지 확인합니다. 쿠버네티스는 기본적으로 RBAC(Role-Based Access Control) 방식을 사용합니다.
- 유효성 검사(Admission Control): 요청의 내용이 클러스터 정책에 맞는지 검사합니다. 예를 들어, 리소스 제한이 설정되지 않은 파드는 거부하는 정책을 적용할 수 있습니다.
- etcd에 상태 저장
API Server는 검증이 완료된 파드 오브젝트를 etcd에 저장합니다.
이 시점에서 파드의 상태는 Pending이며, 아직 어느 노드에 배치될지 결정되지 않은 상태입니다.
etcd에 저장된 것은 "이 파드가 존재해야 한다"는 의도(desired state)를 기록한 것입니다. 실제 컨테이너는 아직 실행되지 않았습니다. - Scheduler — 배치 노드 결정
- Filtering: 파드를 실행할 수 없는 노드를 먼저 걸러냅니다. 노드의 가용 CPU/메모리가 파드의 requests 값보다 부족한 경우, 노드가 NotReady 상태인 경우, Taint가 설정된 노드에 Toleration이 없는 경우 등이 해당됩니다.
- Scoring: 필터링을 통과한 노드들에 점수를 매겨 가장 적합한 노드를 선택합니다. 자원 여유가 많은 노드, 이미 동일한 이미지가 캐시된 노드 등에 높은 점수를 부여합니다.
Scheduler는 API Server를 통해 노드가 배정되지 않은 파드(spec.nodeName이 비어있는 파드)가 있음을 감지합니다. 그리고 아래 두 단계를 거쳐 최적의 노드를 선택합니다. - kubelet — 컨테이너 실행
kubelet은 파드가 실행된 이후에도 Liveness Probe, Readiness Probe를 통해 컨테이너의 상태를 지속적으로 점검합니다.1. API Server로부터 파드 스펙(spec) 수신 2. Container Runtime(containerd 등)에 컨테이너 실행 요청 3. Container Runtime이 이미지 pull 후 컨테이너 기동 4. 컨테이너 실행 결과를 API Server에 보고 (Running / Failed 등) 5. 이후에도 주기적으로 파드 상태를 API Server에 보고
각 워커 노드에서 실행 중인 kubelet은 API Server를 주기적으로 감시합니다. 자신의 노드에 배정된 파드가 생겼음을 감지하면 아래 순서로 컨테이너를 실행합니다. - Controller Manager — 상태 지속 감시
Controller Manager는 클러스터의 현재 상태(actual state)가 사용자가 선언한 원하는 상태(desired state)와 일치하는지 지속적으로 감시합니다.
예를 들어, Deployment로 파드 3개를 선언했는데 하나가 갑자기 종료됐다면, ReplicaSet Controller가 이를 감지하고 API Server에 새 파드 생성을 요청합니다. 이후 위의 2~5 번의 흐름으로 파드가 다시 복구됩니다.
이것이 쿠버네티스가 자가 치유(Self-healing)를 제공하는 원리입니다.
'DevOps > kubernetes' 카테고리의 다른 글
| 1-3. Worker Node 컴포넌트 (kubelet, kube-proxy) (0) | 2026.05.16 |
|---|---|
| 1-2. Control Plane 컴포넌트 (etcd, API Server, Controller Manager, Scheduler) (0) | 2026.05.09 |
| [kubernetes] 파드, 컨테이너, 도커, 쿠버네티스의 관계 (0) | 2023.06.24 |