오토에버 클라우드 2기 40일차
1. 쿠버네티스의 등장 배경
컨테이너 런타임 (Container Runtime)
컨테이너는 운영체제(OS) 수준에서 가상화를 수행하여, 하드웨어 수준에서 가상화하는 가상 머신(VM)에 비해 훨씬 가볍고 유연하게 동작함 OS 커널을 공유하므로 실행 속도가 빠르고, 자원 사용량이 적어 단일 시스템에서 더 많은 애플리케이션을 구동할 수 있음
컨테이너 런타임은 이러한 컨테이너를 실제로 생성하고 실행하며 전체 수명 주기를 관리하는 환경이자 도구.
- 주요 컨테이너 런타임
- Docker: 가장 널리 알려진 컨테이너 런타임으로, containerd 위에 사용 편의성을 위한 데몬과 CLI를 제공.
- containerd: Docker 사에서 개발하여 CNCF에 기증한 오픈소스 런타임으로, 컨테이너의 전체 수명 주기를 관리하는 핵심 기능을 제공
- CRI-O: RedHat 주도로 개발된 오픈소스 런타임으로, 쿠버네티스 CRI(Container Runtime Interface) 표준을 준수하도록 설계됨.
쿠버네티스가 Docker 지원을 중단했다는 것은 Docker 데몬 자체를 직접 제어하지 않는다는 의미이며, Docker가 내부적으로 사용하는 containerd는 여전히 완벽하게 호환됨.
컨테이너 오케스트레이션 (Container Orchestration)
컨테이너 기술이 보편화되면서, 수백, 수천 개의 컨테이너를 여러 서버에 걸쳐 안정적으로 관리해야 할 필요성이 대두됨
컨테이너 오케스트레이션은 다수의 컨테이너를 유기적으로 연결하고, 상태를 추적하며, 장애 발생 시 자동으로 복구하는 등, 복잡한 컨테이너 환경을 효과적으로 관리하기 위한 자동화 기술
- 주요 오케스트레이션 도구
- Docker Swarm: 사용법이 간단하여 소규모 환경에 적합
- Apache Mesos: 대규모 환경에서 검증되었으나, 생태계 구성이 복잡할 수 있음
- HashiCorp Nomad: 가볍고 간단한 기능이 필요한 환경에 적합
- Kubernetes: 초기 진입 장벽은 높지만, 강력한 기능과 폭넓은 생태계를 바탕으로 컨테이너 오케스트레이션의 사실상 표준(De facto standard)이 됨
2. 쿠버네티스(Kubernetes)란?
쿠버네티스(k8s)는 컨테이너화된 애플리케이션을 대규모로 배포, 확장 및 관리하기 위한 오픈소스 플랫폼. 여러 서버(노드)를 하나의 거대한 클러스터로 묶어, 개발자가 개별 서버의 존재를 신경 쓰지 않고 애플리케이션을 안정적으로 운영할 수 있게 함
쿠버네티스의 핵심 철학: “바람직한 상태 (Desired State)”
쿠버네티스는 명령형(imperative) 방식보다 선언형(declarative) 방식을 지향함. “컨테이너 A를 실행하라”고 일일이 명령하는 대신, “컨테이너 A가 3개 실행되고 있는 상태를 유지하라”와 같이 바람직한 상태를 YAML 파일에 정의
쿠버네티스는 현재 클러스터의 상태를 지속적으로 모니터링하며, 정의된 ‘바람직한 상태’와 달라지면 알아서 컨테이너를 생성하거나 삭제하여 상태를 일치시킴
쿠버네티스의 주요 특징
- 무중단 서비스 (롤링 업데이트): 서비스 중단 없이 애플리케이션을 안전하게 업그레이드하거나 롤백할 수 있음
- 효율적인 자원 사용: Pod가 사용할 CPU, 메모리 등의 자원을 사전에 지정하여 클러스터 전체의 자원을 효율적으로 관리
- 유연한 확장성 (Auto Scaling): 자원 사용량에 따라 Pod의 개수를 자동으로 늘리거나 줄여 트래픽 변화에 유연하게 대응
- 자가 치유 (Self-healing): 실행 중인 컨테이너에 문제가 생기면, 쿠버네티스가 이를 감지하고 자동으로 컨테이너를 재시작하거나 교체하여 서비스 연속성을 보장
- 클라우드 벤더 종속성 탈피: 대부분의 퍼블릭 클라우드(AWS, GCP, Azure 등)에서 쿠버네티스를 지원하므로, 특정 클라우드에 종속되지 않고 자유롭게 인프라를 이전하거나 확장할 수 있음
3. 쿠버네티스 아키텍처 (Architecture)
전체 구조

클러스터 (Cluster): 쿠버네티스에 의해 관리되는 노드(서버)들의 집합 전체 관리 시스템의 단위
노드 (Node): 클러스터에 속한 개별 서버(물리적 또는 가상) 역할에 따라 마스터 노드와 워커 노드로 나뉨
마스터 노드 (Control Plane): 클러스터 전체를 관리하고 제어하는 두뇌 역할 API 서버, 스케줄러, 컨트롤러 매니저 등의 핵심 컴포넌트가 실행됨
워커 노드 (Worker Node): 실제 컨테이너화된 애플리케이션(Pod)이 실행되는 일꾼 역할 Kubelet, 프록시, 컨테이너 런타임 등이 배치됨
Pod: 쿠버네티스에서 생성하고 관리할 수 있는 가장 작은 배포 단위. 하나 이상의 컨테이너를 포함
핵심 컴포넌트 (Component)
마스터 노드 (Control Plane) 컴포넌트
- API Server: 쿠버네티스 클러스터의 모든 상호작용이 거쳐가는 관문(Gateway)
kubectl명령이나 외부 요청을 받아 유효성을 검증하고, 다른 컴포넌트에 전달하는 역할을 함 - etcd: 클러스터의 모든 상태 정보(어떤 노드에 어떤 Pod가 있는지 등)를 저장하는 Key-Value 형태의 데이터베이스. 클러스터의 ‘진실의 원천(Source of Truth)’
- Scheduler: 새로 생성된 Pod를 어떤 워커 노드에 배치할지 결정하는 역할 각 워커 노드의 자원 상태 등을 고려하여 최적의 노드를 선택
- Controller Manager: 클러스터의 상태를 관리하는 다양한 컨트롤러들을 실행하는 컴포넌트 예를 들어, 특정 Pod가 다운되면 이를 감지하고 복제본을 다시 만드는 등의 역할을 수행
워커 노드 (Worker Node) 컴포넌트
- Kubelet: 각 워커 노드에서 실행되는 마스터 노드의 API 서버로부터 명령을 받아 컨테이너를 실행/중지하고, 노드와 컨테이너의 상태를 마스터에 보고함
- kube-proxy: 노드로 들어오는 네트워크 트래픽을 규칙에 따라 올바른 컨테이너로 전달(프록시)하는 역할 서비스(Service)의 실제 네트워킹을 구현
- Container Runtime: 컨테이너를 실제로 실행하는 도구 (예: containerd, CRI-O)
4. 쿠버네티스 핵심 오브젝트 (리소스)
워크로드 (Workload) API: 컨테이너 실행
Pod: 가장 작은 배포 단위. 고유한 IP를 가지며, 하나 이상의 컨테이너와 스토리지 볼륨을 포함할 수 있음
ReplicaSet: 지정된 수의 동일한 Pod 복제본이 항상 실행되도록 보장 직접 사용하는 경우는 드물고, 주로 Deployment에 의해 관리됨
1 2
apiVersion: apps/v1 kind: ReplicaSet
Deployment: ReplicaSet의 상위 개념으로, Pod의 배포와 업데이트(롤링 업데이트, 롤백 등)를 관리 상태 없는(Stateless) 애플리케이션 배포 시 가장 일반적으로 사용됨
1 2
apiVersion: apps/v1 kind: Deployment
DaemonSet: Docker Swarm의
global모드와 유사 클러스터의 모든 (또는 특정) 노드에 Pod를 하나씩 배포. 주로 로그 수집기나 모니터링 에이전트 배포에 사용StatefulSet: 데이터베이스처럼 각 Pod가 고유한 상태(고정된 이름, 안정적인 스토리지)를 가져야 하는 상태 있는(Stateful) 애플리케이션을 관리
Job / CronJob: 배치 작업처럼 한 번 실행되고 종료되는 작업을 위한 오브젝트
CronJob은 스케줄(예: 매일 자정)에 따라 Job을 실행
서비스 (Service) Type: 외부 노출 및 통신
Pod는 언제든 사라지고 다시 생성될 수 있어 IP가 계속 바뀜 서비스는 이렇게 동적으로 변하는 Pod 그룹에 고정된 접속 지점(엔드포인트)과 로드 밸런싱을 제공하는 핵심 오브젝트
ClusterIP (기본값): 클러스터 내부에서만 접근 가능한 고정 IP를 할당 다른 Pod들이 이 IP를 통해 서비스에 접근
NodePort: 클러스터의 모든 워커 노드에 특정 포트(30000-32767)를 열고,
<노드IP>:<노드포트>주소로 외부에서 서비스에 접근할 수 있게 함graph TD User[👤 사용자] subgraph "쿠버네티스 클러스터" subgraph "워커 노드 1" PodA[Pod A] end subgraph "워커 노드 2" KubeProxy2[kube-proxy @ Node2] end subgraph "워커 노드 3" PodB[Pod B] end end User -- "1 요청: Node2_IP:NodePort" --> KubeProxy2 KubeProxy2 -- "2 전체 Pod 목록 확인 후</br>가장 적절한 Pod 선택" --> PodA노드포드를 사용해도 적절한 pod를 찾아가지만(kube-proxy) 실제 서비스에서 노드포트를 사용하지 않는 이유는 해당 워커노드가 죽으면 전달하지 못하고 노드가 스케줄링으로 줄어들어서 없어질수도 있기 때문에 실제 서비스에서 노드밸런서(서비스단에서)가 필요하다
기능 NodePort(한계점)LoadBalancer(해결책)단일 진입점 노드 개수만큼 IP가 존재하고, 모두 변할 수 있음 변하지 않는 단 하나의 고정된 공인 IP를 제공 고가용성 사용자가 접속한 노드가 다운되면 접속 실패 상태 확인(Health Check)을 통해 다운된 노드를 감지하고, 건강한 노드에게만 트래픽을 자동 전달 트래픽 분산 모든 트래픽이 특정 노드로만 집중될 수 있음 외부에서 들어오는 트래픽을 모든 노드에 균등하게 분산 포트 사용 30000번대 이상의 높은 포트만 사용 가능 웹 표준 포트인 80(HTTP), 443(HTTPS) 사용 가능 LoadBalancer: 퍼블릭 클라우드(AWS, GCP 등) 환경에서 사용 시, 클라우드 제공업체의 로드 밸런서를 프로비저닝하고 서비스에 연결해 줌 외부 IP를 통해 접근 가능
graph TD %% --- 전체 사설망(VPC) 경계를 정의합니다 --- subgraph "VPC (사설 네트워크)" %% --- 외부와 통신하는 Web Tier (Public Subnet) --- subgraph "Web Tier (프론트엔드)" direction LR Web1[🌐 웹서버 Pod 1] Web2[🌐 웹서버 Pod 2] end %% --- 내부 통신만 하는 App Tier (Private Subnet) --- subgraph "Application Tier (백엔드)" direction LR ILB["<b>Internal Load Balancer</b><br/>(사설 IP만 가짐)"] App1[⚙️ 앱서버 Pod 1] App2[⚙️ 앱서버 Pod 2] App3[⚙️ 앱서버 Pod 3] end %% --- 통신 흐름을 정의합니다 --- %% Web Tier의 Pod들이 내부 로드밸런서로 요청을 보냅니다. Web1 -- "내부 API 요청" --> ILB Web2 -- "내부 API 요청" --> ILB %% 내부 로드밸런서는 App Tier의 Pod들에게 트래픽을 분산합니다. ILB -- "내부 로드 밸런싱" --> App1 ILB -- "내부 로드 밸런싱" --> App2 ILB -- "내부 로드 밸런싱" --> App3 end %% --- 외부 인터넷 사용자는 내부 로드밸런서에 직접 접근할 수 없음을 보여줍니다 --- Internet[👤 외부 인터넷 사용자] Internet -- "<font color=red>X 접근 불가 X</font>" --x ILB Internet -- "접근 가능" --> Web1 Internet -- "접근 가능" --> Web2
Ingress:
Service가 L4(TCP/UDP) 레벨에서 동작하는 것과 달리, Ingress는 L7(HTTP/HTTPS) 레벨에서 동작. URL 경로, 호스트 이름에 따라 요청을 다른 서비스로 라우팅하는 규칙을 정의graph TD User[👤 외부 사용자] --> DNS subgraph "클라우드 인프라" DNS -- "shop.my-website.com" --> LB[🌐 외부 LoadBalancer] end subgraph "쿠버네티스 클러스터" subgraph "워커 노드" Controller["<b>Ingress Controller Pod</b><br/>(NGINX 등)"] subgraph "쇼핑몰 서비스" ShopSvc[Service: shop-svc] --> ShopPod[Pod] end subgraph "블로그 서비스" BlogSvc[Service: blog-svc] --> BlogPod[Pod] end end IngressRules[📜 Ingress 규칙] end %% --- 흐름 정의 --- LB -- "1 트래픽 전달" --> Controller Controller -- "2 Ingress 규칙 조회" --> IngressRules Controller -- "3 'shop.my-website.com'<br/> 규칙에 따라<br/>shop-svc로 라우팅" --> ShopSvc특징 (Feature) Ingress를 사용하지 않을 때 (비효율적) Ingress를 사용할 때 (효율적, 권장) 외부 진입점 각 서비스마다 별개의 로드밸런서가 필요 단 하나의 로드밸런서를 모든 서비스가 공유 비용 서비스 개수만큼 클라우드 로드밸런서 비용이 발생하여 고비용 구조가 된다 로드밸런서 1개에 대한 비용만 발생하므로 매우 비용 효율적 라우팅 방식 L4 (IP, Port 기반의 단순 전달)만 가능 L7 (Host, URL 경로 기반의 지능적인 라우팅)이 가능 관리 포인트 여러 개의 IP와 로드밸런서 설정을 개별적으로 관리해야 해서 복잡 단일 진입점과 라우팅 규칙( IngressYAML)을 중앙에서 일관되게 관리할 수 있다SSL/TLS 인증 각 로드밸런서마다 개별적으로 SSL 인증서를 설정해야 한다 Ingress에서 SSL 인증서를 중앙 집중적으로 관리하고 적용할 수 있다
설정 및 스토리지 (Config & Storage) API
- ConfigMap / Secret: 설정값이나 비밀번호, API 키 등 민감한 정보를 Pod의 코드와 분리하여 관리
- PersistentVolume(PV) / PersistentVolumeClaim(PVC): Pod가 삭제되어도 데이터가 사라지지 않도록 영구 스토리지를 연결하는 메커니즘
클러스터 격리
- Namespace: 하나의 물리적 클러스터를 여러 개의 논리적인 가상 클러스터로 나누어 사용 리소스 격리 및 접근 제어에 사용
5. 쿠버네티스 통신 (Networking)
- Pod 내부 컨테이너 간 통신: 같은 Pod 내의 컨테이너들은 동일한 네트워크 네임스페이스를 공유하므로
localhost와 포트 번호로 직접 통신 - Pod 간 통신:
- CNI (Container Network Interface): 쿠버네티스는 자체적으로 복잡한 네트워크 구성을 제공하지 않음. 서로 다른 노드에 있는 Pod 간의 통신은 CNI 플러그인(예: Flannel, Calico)을 통해 구현됨
- 오버레이 네트워크(Overlay Network): CNI 플러그인은 물리적 네트워크 위에 가상의 네트워크 계층을 만들어, 모든 노드의 Pod들이 마치 동일한 네트워크에 있는 것처럼 통신할 수 있게 함
6. 쿠버네티스 제어: kubectl
kubectl은 쿠버네티스 클러스터와 상호작용하기 위한 커맨드 라인 인터페이스(CLI) 도구
- kubeconfig 파일:
kubectl은~/.kube/config파일에 저장된 클러스터 정보, 사용자 인증 정보, 컨텍스트 등을 참조하여 API 서버에 접속 - 컨텍스트(Context): 여러 클러스터를 관리할 때, 현재 작업 대상을 전환하는 기능
kubectl config use-context <컨텍스트이름>명령으로 전환
요청 흐름 예시
graph TD
%% --- 1. 외부 인터넷 영역 ---
subgraph "외부 인터넷 (Public Internet)"
User[👤 외부 사용자]
end
%% --- 2. 클라우드 VPC 영역 ---
subgraph "VPC (가상 사설 네트워크)"
ELB["External Load Balancer - Public IP"]
%% 2-1. Public Subnet: 외부와 통신하는 계층
subgraph "Web Tier - Public Subnet"
direction LR
Web1[🌐 웹서버 Pod 1]
Web2[🌐 웹서버 Pod 2]
end
%% 2-2. Private Subnet: 내부에서만 통신하는 계층들
subgraph "Application Tier - Private Subnet"
direction LR
ILB["Internal Load Balancer - Private IP"]
App1[⚙️ 앱서버 Pod 1]
App2[⚙️ 앱서버 Pod 2]
end
subgraph "Database Tier - Private Subnet"
direction LR
DB_Service["DB Service - ClusterIP"]
DB_Pod[(💾 DB Pod)]
end
%% --- 3. 전체 트래픽 흐름 정의 ---
%% 외부에서 Web Tier로의 흐름
User -- "1 url 접속" --> ELB
ELB -- "2 Web Tier로 트래픽 분산" --> Web1
ELB -- "2 Web Tier로 트래픽 분산" --> Web2
%% Web Tier에서 App Tier로의 흐름
Web1 -- "3 내부 API 요청" --> ILB
Web2 -- "3 내부 API 요청" --> ILB
ILB -- "4 App Tier로 트래픽 분산" --> App1
ILB -- "4 App Tier로 트래픽 분산" --> App2
%% App Tier에서 DB Tier로의 흐름
App1 -- "5 데이터 요청" --> DB_Service
App2 -- "5 데이터 요청" --> DB_Service
DB_Service -- "6 DB Pod로 연결" --> DB_Pod
%% --- 4. 접근 제어 시각화 ---
User -- "<font color=red>X 직접 접근 불가 X</font>" --x ILB
end