Kubernetes 핵심 정리

Kubernetes는 컨테이너화된 애플리케이션을 여러 서버에서 안정적으로 실행하고 관리하기 위한 오케스트레이션 플랫폼이다.

Docker를 사용하면 애플리케이션을 컨테이너로 패키징해서 실행할 수 있다.

문제는 애플리케이션과 컨테이너가 많아졌을 때부터 시작된다.

Server 1 -> Container A / Container B / Container C
Server 2 -> Container D / Container E / Container F

컨테이너가 수십, 수백 개로 늘어나면 직접 실행하고 관리하기 어렵다.

어떤 서버에 컨테이너를 배치할지, 장애가 발생하면 어떻게 다시 실행할지, 트래픽이 증가하면 어떻게 복제할지, 업데이트를 어떻게 수행할지 관리해야 한다.

Kubernetes는 이런 컨테이너 운영 작업을 선언적인 방식으로 관리한다.

Developer -> Desired State -> Kubernetes -> Container 실행
Developer -> Desired State -> Kubernetes -> 장애 복구
Developer -> Desired State -> Kubernetes -> Scale
Developer -> Desired State -> Kubernetes -> Load Balancing
Developer -> Desired State -> Kubernetes -> Rolling Update

Docker와 Kubernetes의 관계

Docker와 Kubernetes는 경쟁 관계로 이해하면 안 된다.

Docker는 주로 컨테이너를 만들고 실행하는 기술이고, Kubernetes는 여러 컨테이너를 배포하고 운영하는 시스템이다.

예를 들어 Docker를 사용하면 다음과 같이 컨테이너 하나를 실행할 수 있다.

Docker -> Game Server Container

Kubernetes를 사용하면 여러 서버에 컨테이너를 배치하고 상태를 관리할 수 있다.

Kubernetes Cluster -> Node 1 -> Game Server / API Server
Kubernetes Cluster -> Node 2 -> Game Server / Database Proxy
Kubernetes Cluster -> Node 3 -> Game Server / API Server

Kubernetes가 직접 애플리케이션 코드를 실행하는 것이 아니라 컨테이너 런타임을 통해 컨테이너를 실행한다.

현재 Kubernetes 환경에서는 containerd 같은 컨테이너 런타임을 많이 사용한다.


Kubernetes Cluster

Kubernetes의 전체 실행 환경을 Cluster라고 한다.

Cluster는 여러 Node로 구성된다.

Kubernetes Cluster -> Control Plane
Kubernetes Cluster -> Worker Nodes -> Node 1 / Node 2 / Node 3

Node는 실제로 컨테이너가 실행되는 서버다.

VM일 수도 있고 물리 서버일 수도 있다.

Control Plane은 Cluster 전체를 관리하고 Worker Node에서 애플리케이션이 실행된다.


Control Plane

Control Plane은 Kubernetes Cluster의 상태를 관리하는 영역이다.

대표적인 구성 요소는 다음과 같다.

Control Plane -> API Server / Scheduler / Controller Manager / etcd

각각 역할이 다르다.

API Server

Kubernetes의 중심 인터페이스다.

사용자가 kubectl로 명령을 실행하거나 다른 시스템이 Kubernetes API를 호출하면 API Server를 통해 Cluster와 통신한다.

kubectl -> API Server -> Kubernetes Resources

etcd

Kubernetes Cluster의 상태 데이터를 저장하는 분산 Key-Value Store다.

Pod이 몇 개 실행되어야 하는지, 어떤 설정이 적용되어 있는지 등의 Cluster 상태를 저장한다.

Scheduler

새로운 Pod을 어느 Node에서 실행할지 결정한다.

New Pod -> Scheduler -> Node 1 / Node 2 / Node 3

CPU나 메모리 같은 리소스와 여러 조건을 고려해서 적절한 Node를 선택한다.

Controller Manager

현재 상태와 사용자가 원하는 상태를 계속 비교하면서 필요한 작업을 수행한다.

이 부분이 Kubernetes의 핵심적인 특징과 연결된다.


선언적 관리

Kubernetes는 명령을 하나씩 직접 실행하는 방식보다 원하는 상태(Desired State)를 선언하는 방식을 사용한다.

예를 들어 다음과 같이 정의할 수 있다.

apiVersion: apps/v1
kind: Deployment

metadata:
  name: game-server

spec:
  replicas: 3

  selector:
    matchLabels:
      app: game-server

  template:
    metadata:
      labels:
        app: game-server

    spec:
      containers:
        - name: game-server
          image: my-game-server:1.0
          ports:
            - containerPort: 8080

여기서 중요한 부분은:

replicas: 3

이다.

개발자가 원하는 상태를 “게임 서버 Pod이 3개 실행되는 상태”라고 선언한 것이다.

Kubernetes는 현재 상태를 확인하고 원하는 상태와 다르면 조정한다.

Desired State -> replicas = 3 -> Kubernetes -> Current State -> Pod 3개 실행

Pod 하나가 죽으면 Kubernetes는 다시 Pod을 만들어 원하는 상태인 3개를 유지하려고 한다.

이것이 Kubernetes의 Controller 기반 동작 방식이다.


Pod

Pod은 Kubernetes에서 컨테이너가 실행되는 가장 기본적인 배포 단위다.

보통 하나의 애플리케이션 컨테이너를 하나의 Pod에 넣지만, 밀접하게 결합된 여러 컨테이너가 하나의 Pod에서 함께 실행될 수도 있다.

Pod -> Container

또는:

Pod -> Application Container / Sidecar Container

Pod은 자체적으로 애플리케이션을 장기간 관리하는 객체라기보다 Kubernetes가 컨테이너를 실행하고 관리하기 위한 단위에 가깝다.

실무에서는 Pod을 직접 관리하기보다 Deployment 같은 상위 리소스를 통해 관리하는 경우가 많다.


Deployment

Deployment는 애플리케이션의 Pod을 선언적으로 관리하기 위한 Kubernetes 리소스다.

예를 들어:

spec -> replicas: 3

이라고 하면 Kubernetes가 해당 애플리케이션의 Pod을 3개 유지하도록 관리한다.

Deployment -> ReplicaSet -> Pod / Pod / Pod -> Container

Deployment는 배포 버전 관리와 Rolling Update에도 사용된다.

이미 실행 중인 애플리케이션을 새로운 이미지 버전으로 업데이트할 수도 있다.

Version 1 -> Pod 1 / Pod 2 / Pod 3 -> Rolling Update -> Version 2 -> Pod 1 / Pod 2 / Pod 3

기존 Pod을 한꺼번에 제거하지 않고 점진적으로 새로운 버전으로 교체하는 방식이다.


Service

Pod에는 문제가 하나 있다.

Pod은 언제든 삭제되고 다시 생성될 수 있기 때문에 IP가 고정되어 있다고 가정하면 안 된다.

따라서 안정적인 접근 지점이 필요하다.

이 역할을 하는 것이 Service다.

Client -> Service -> Pod / Pod / Pod

Service는 여러 Pod을 하나의 논리적인 네트워크 엔드포인트로 묶어준다.

예를 들어 API 서버 Pod이 3개 실행 중이라면:

api-service -> API Pod 1 / API Pod 2 / API Pod 3

클라이언트는 각각의 Pod IP를 직접 알 필요 없이 Service를 통해 접근할 수 있다.


Ingress

외부에서 Kubernetes 내부의 HTTP/HTTPS 서비스를 접근할 때는 Ingress를 사용할 수 있다.

예를 들어 다음과 같은 구조다.

Internet -> Ingress -> frontend-service
Internet -> Ingress -> api-service

URL이나 Host 등을 기준으로 요청을 적절한 Service로 라우팅할 수 있다.

example.com -> frontend-service
api.example.com -> api-service

다만 최근 Kubernetes 생태계에서는 Gateway API도 사용되므로 Ingress만이 유일한 외부 트래픽 관리 방식은 아니다.


ConfigMap과 Secret

애플리케이션 설정을 컨테이너 이미지에 직접 넣는 것은 관리하기 좋지 않다.

예를 들어 개발 환경과 운영 환경의 설정이 다를 수 있다.

Development -> DB_HOST = dev-db
Production -> DB_HOST = prod-db

Kubernetes에서는 ConfigMap을 사용해 일반적인 설정값을 관리할 수 있다.

apiVersion: v1
kind: ConfigMap

metadata:
  name: game-config

data:
  LOG_LEVEL: "info"

비밀번호나 API Key 같은 민감한 값은 Secret을 사용할 수 있다.

ConfigMap -> 일반 설정
Secret -> 민감한 설정

다만 Kubernetes Secret이 기본적으로 모든 보안 문제를 해결해주는 것은 아니다. 저장 방식과 접근 권한, 암호화 설정 등을 별도로 고려해야 한다.


Namespace

하나의 Cluster에서 여러 환경이나 팀의 리소스를 논리적으로 분리할 때 Namespace를 사용할 수 있다.

Cluster -> namespace: dev -> Deployment / Service / ConfigMap
Cluster -> namespace: staging -> Deployment / Service / ConfigMap
Cluster -> namespace: production -> Deployment / Service / ConfigMap

리소스를 논리적으로 구분하고 권한이나 리소스 정책을 적용하는 데 활용할 수 있다.


Kubernetes의 장애 복구

Kubernetes를 사용하는 대표적인 이유 중 하나가 자동 복구다.

Deployment에서 다음과 같이 설정했다고 하자.

replicas: 3

현재 상태가:

Pod 1 / Pod 2 / Pod 3

인데 Pod 2가 장애로 종료되면:

Pod 1 / Pod 3

만 남는다.

Controller는 원하는 상태가 3개라는 것을 알고 있기 때문에 새로운 Pod을 생성한다.

Pod 1 / Pod 3 -> Pod 4

다시 원하는 상태에 맞춰진다.

이런 방식으로 Kubernetes는 현재 상태를 지속적으로 관찰하고 선언된 상태에 맞춰 조정한다.


Scaling

트래픽이 증가하면 애플리케이션의 Pod 수를 늘릴 수 있다.

Before -> Service -> Pod / Pod
After -> Service -> Pod / Pod / Pod / Pod / Pod

직접 Replica 수를 변경할 수도 있고, CPU 사용량이나 메모리 사용량 같은 지표를 기반으로 Horizontal Pod Autoscaler(HPA)를 사용할 수도 있다.

Traffic -> HPA -> Deployment -> Pod / Pod / Pod / Pod

트래픽이 줄어들면 Pod 수를 다시 줄이는 것도 가능하다.


Kubernetes에서 네트워크 구조

Kubernetes에서는 Pod 간 통신도 중요한 부분이다.

기본적인 구조를 단순화하면 다음과 같다.

Pod A -> Network -> Pod B

Pod끼리는 서로 통신할 수 있고 Service를 통해 특정 애플리케이션 그룹에 접근할 수도 있다.

Pod A -> Service -> Pod B / Pod C / Pod D

외부 요청은 일반적으로 Load Balancer, Ingress 또는 Gateway 같은 외부 접근 계층을 거쳐 Service와 Pod으로 전달된다.

External Request -> Load Balancer / Ingress / Gateway -> Service -> Pod

Kubernetes에서 저장소

Pod의 파일 시스템은 영구 저장소로 사용하기에 적합하지 않은 경우가 많다.

Pod이 삭제되고 새로 생성되면 기존 컨테이너의 파일이 사라질 수 있기 때문이다.

데이터를 지속적으로 보존해야 한다면 Persistent Volume 계열의 저장소를 사용할 수 있다.

Pod -> Persistent Volume -> Storage

예를 들어 데이터베이스처럼 상태를 유지해야 하는 애플리케이션은 별도의 영구 저장소가 필요하다.

다만 Kubernetes에서 데이터베이스까지 직접 운영할지는 별도의 판단이 필요하다. Managed Database를 사용하고 Kubernetes에서는 애플리케이션 서버만 운영하는 구조도 흔하다.


kubectl

Kubernetes를 관리할 때 가장 기본적으로 사용하는 CLI가 kubectl이다.

현재 Pod을 확인할 수 있다.

kubectl get pods

Deployment를 확인할 수도 있다.

kubectl get deployments

Pod의 상세 정보를 확인하려면:

kubectl describe pod <pod-name>

로그를 확인할 때는:

kubectl logs <pod-name>

Deployment를 배포할 때는:

kubectl apply -f deployment.yaml

여기서 apply가 Kubernetes의 선언적 관리 방식을 잘 보여준다.

개발자가 “이 명령을 순서대로 실행해서 컨테이너를 이렇게 만들어라”라고 지시하는 것보다 YAML에 원하는 상태를 정의하고 Kubernetes가 현재 상태를 그 상태에 맞추도록 한다.


Kubernetes를 실제 서버 구조에 적용하면

예를 들어 웹 서비스가 다음과 같이 구성되어 있다고 하자.

Internet -> Ingress / Load Balancer -> API Service -> API Pod / API Pod / API Pod -> External Database

API 서버가 여러 Pod으로 실행되고 있기 때문에 트래픽을 분산할 수 있다.

새로운 버전을 배포할 때는 Deployment가 Pod을 점진적으로 교체한다.

장애가 발생하면 Controller가 원하는 Replica 수를 유지하려고 한다.

설정값은 ConfigMap과 Secret으로 분리하고, 필요한 경우 HPA를 통해 Pod 수를 자동으로 조절한다.

이렇게 애플리케이션 실행뿐 아니라 배포, 네트워크, 장애 복구, 스케일링, 설정 관리까지 하나의 시스템에서 관리할 수 있다.


Kubernetes를 사용할 때 고려할 것

Kubernetes는 강력하지만 모든 서버에 필요한 것은 아니다.

작은 서비스 하나를 서버 한 대에서 실행하는 상황이라면 Docker Compose나 단순한 VM 배포가 더 적절할 수 있다.

Kubernetes를 도입하면 다음과 같은 개념을 함께 관리해야 한다.

Cluster -> Node -> Pod -> Deployment -> ReplicaSet -> Service -> Ingress / Gateway -> ConfigMap -> Secret -> Volume -> Namespace -> Resource -> RBAC -> Monitoring -> Logging

여기에 네트워크 정책, 스토리지, 인증, 관측성, 배포 전략까지 들어가면 시스템 복잡도가 상당히 올라간다.

따라서 “컨테이너를 사용하니까 Kubernetes를 써야 한다”는 접근은 맞지 않는다.

애플리케이션 규모와 운영 요구사항을 보고 선택해야 한다.


Kubernetes의 전체 구조

지금까지의 내용을 하나로 묶으면 다음과 같다.

Kubernetes Cluster -> Control Plane -> API Server / Scheduler / etcd
Kubernetes Cluster -> Worker Nodes -> Node 1 / Node 2 / Node 3 -> Pod -> Container

애플리케이션 배포 구조는 다음과 같이 연결된다.

Deployment -> ReplicaSet -> Pod / Pod / Pod -> Container

외부 요청은:

Client -> Load Balancer -> Ingress / Gateway -> Service -> Pod -> Application

설정과 데이터는 별도로 관리한다.

ConfigMap / Secret -> Pod
Pod -> Persistent Volume -> Storage

정리

Kubernetes를 이해할 때 가장 먼저 잡아야 하는 구조는 Cluster -> Node -> Pod -> Container다.

그 위에서 Deployment가 Pod의 원하는 상태를 관리하고, Service가 Pod에 안정적으로 접근할 수 있는 네트워크 엔드포인트를 제공한다.

Cluster -> Node -> Pod -> Container

그리고:

Deployment -> Pod 관리
Service -> 네트워크 접근
Ingress / Gateway -> 외부 트래픽 라우팅
ConfigMap / Secret -> 설정 관리
Volume -> 데이터 저장
HPA -> 자동 확장
Controller -> 원하는 상태 유지

Docker가 컨테이너를 만드는 기술이라면 Kubernetes는 그 컨테이너가 실제 운영 환경에서 어떻게 배치되고, 연결되고, 확장되고, 복구될지를 관리하는 시스템에 가깝다.

Kubernetes를 공부할 때 YAML 문법부터 외우기보다는 Pod, Deployment, Service, Controller, Cluster의 관계를 먼저 이해하는 것이 효율적이다. 이 구조가 잡히면 나머지 리소스들은 결국 이 운영 구조에 필요한 기능으로 연결된다.