Kubernetes 기초

HamJina·2026년 9월 9일

Kubernetes

목록 보기
1/3

1. Kubernetes (K8s) 소개

1-0. 이름의 유래

Kubernetes는 고대 그리스어로 배의 조타수(Helmsman) 를 의미한다. 컨테이너라는 화물을 실은 배를 조종하는 역할에서 따온 이름이다.

1-0-0. 쿠버네티스란

정의설명
플랫폼을 만들기 위한 플랫폼원시적인 기능들만 제공하고, 사용자가 필요한 구성을 결정해 자신만의 배포 플랫폼을 제작한다
오픈소스 플랫폼컨테이너화된 애플리케이션의 자동 배포, 확장 및 관리를 해주는 오픈소스 플랫폼이다

1-0-1. 쿠버네티스가 해결하는 문제

서버의 확장 관리는 어떻게 하는가

코드 한 줄을 바꾸거나 명령어 하나를 입력하면 몇 초 만에 똑같은 파드가 수십 개로 늘어난다. CPU 사용량이 올라가면 알아서 자동으로 늘려준다.

HPA (Horizontal Pod Autoscaler), Auto-scaling

문제가 생긴 서버의 재시작은

쿠버네티스는 의심이 많고 부지런한 감시자다. 파드가 응답이 없거나 죽으면 사람이 개입하기 전에 기존 파드를 버리고 새 파드를 만들어 교체해 둔다. 엔지니어는 아침에 출근해서 복구 이력 로그만 확인하면 된다.

Self-Healing

매번 패치할 때마다 야근과 주말 근무를 해야 하는가

무중단 배포 기능 덕분에 대낮에 서비스가 정상적으로 돌아가는 중에도 패치를 진행할 수 있다.

Rolling Update

기능 하나 때문에 서버 전체가 죽는 상황

기능별로 컨테이너와 파드를 쪼개 놓았기 때문에, 결제 파드가 터지더라도 로그인이나 장바구니 파드는 아무런 영향을 받지 않게 구성할 수 있다.

MSA 구조

새로운 환경으로 이전하려면

애플리케이션과 환경을 통째로 박스(컨테이너 이미지)에 담아 코드로 정의해 두었기 때문에, 밑바닥이 AWS든 네이버 클라우드든 상관없이 K8s 클러스터만 준비되어 있다면 그 코드를 그대로 가져다 실행할 수 있다.


핵심 기능 정리

문제쿠버네티스의 해결기능 이름
서버 확장 관리명령 한 번으로 파드 증설, CPU 사용량에 따라 자동 확장HPA / Auto-scaling
장애 서버 재시작죽은 파드를 감지해 자동으로 교체Self-Healing
배포 시 서비스 중단서비스 운영 중에도 무중단으로 패치Rolling Update
장애의 전체 확산기능별로 파드를 분리해 영향 범위를 격리MSA 구조
환경 이전의 어려움애플리케이션과 환경을 이미지로 코드화해 어디서든 실행이식성(Portability)

1-1. 왜 쿠버네티스가 필요한가

AS-IS: 쿠버네티스 도입 이전

컨테이너(또는 서버)를 운영자가 직접 관리하는 방식이었다. 트래픽이 몰려도 수동으로 서버를 늘려야 했고, 프로세스가 죽으면 사람이 알아채고 재시작해야 했으며, 배포도 수동 스크립트나 순차 작업에 의존했다.

이 방식의 한계:

  • 트래픽 급증 시 즉각적인 대응이 어려움 (스케일 아웃에 사람 손이 필요)
  • 장애 발생 시 감지와 복구까지의 시간(MTTR)이 길어짐
  • 배포 중 서비스 중단이 발생하기 쉬움
  • 운영 리소스가 반복 작업(재시작, 스케일링)에 소모됨

TO-BE: 쿠버네티스 도입 이후

쿠버네티스는 이런 반복적인 운영 작업을 선언적(Declarative)으로 자동화한다. "몇 개의 파드를 어떤 상태로 유지할지"만 정의하면, 나머지는 쿠버네티스 컨트롤 플레인이 지속적으로 감시하고 스스로 맞춰준다.

  • Deployment: 애플리케이션의 배포와 버전 관리를 선언적으로 처리한다. 원하는 상태(replica 수, 이미지 버전 등)를 명세하면 쿠버네티스가 실제 상태를 그 상태로 맞춰주고, 롤링 업데이트를 통해 무중단 배포가 가능해진다. AS-IS에서 수동으로 순차 배포하던 것과 달리, 배포 전략(RollingUpdate, Recreate 등)을 코드로 관리할 수 있다.
  • Auto Scaling: HPA(Horizontal Pod Autoscaler) 등을 통해 CPU/메모리 사용률이나 커스텀 메트릭 기준으로 파드 수를 자동으로 늘리고 줄인다. AS-IS에서는 트래픽 예측과 수동 증설이 필요했지만, 쿠버네티스는 실시간 지표를 기반으로 즉각 대응한다.
  • Auto Healing: 컨테이너나 파드가 비정상 상태(Liveness/Readiness Probe 실패, 크래시 등)가 되면 쿠버네티스가 자동으로 감지해 재시작하거나 새 파드로 교체한다. 사람이 장애를 인지하고 조치하기 전에 시스템이 스스로 복구하므로 장애 대응 시간이 크게 줄어든다.

핵심 차이점 요약

구분AS-IS (쿠버네티스 이전)TO-BE (쿠버네티스 도입 후)
배포수동/순차 배포, 중단 위험 존재Deployment로 선언적 관리, 무중단 롤링 업데이트
확장트래픽 대응이 수동, 반응 속도 느림Auto Scaling으로 지표 기반 자동 확장/축소
장애 대응사람이 감지 후 수동 복구Auto Healing으로 자동 감지 및 자가 복구
운영 부담반복 작업에 인력 소모선언적 설정으로 운영 자동화, 사람은 정책 설계에 집중

1-2. 클라우드 자동화 도구 전반과 비교한 쿠버네티스의 핵심 장점

  • 관리 단위: 클라우드의 Auto Scaling(예: 인스턴스 그룹, 관리형 컨테이너 서비스 등)은 인스턴스·태스크 단위 관리에 머무르지만, 쿠버네티스는 배포·네트워크·스토리지·설정까지 애플리케이션 전체를 하나의 API로 관리
  • 벤더 종속성: 각 클라우드의 자동화 도구는 해당 클라우드 생태계에 종속되지만, 쿠버네티스는 오픈소스 표준이라 어떤 클라우드·온프레미스에서도 동일한 방식으로 동작
  • 선언적 API 범용성: 클라우드 관리형 서비스는 제공사가 정한 정책 범위 안에서만 동작하지만, 쿠버네티스는 Controller/CRD로 사실상 어떤 리소스든 같은 방식으로 정의하고 관리 가능
  • 스케줄링 정교함: 대부분의 자동화 도구는 단순 규칙 기반 배치에 그치지만, 쿠버네티스는 어피니티·taint·토폴로지 분산 등 세밀한 조건으로 워크로드 배치를 제어
  • 생태계: 각 벤더의 도구는 자사 생태계 안에서만 확장 가능하지만, 쿠버네티스는 Helm·Istio·Prometheus·ArgoCD 등 벤더 중립적인 표준 생태계를 보유

1-3. VM과 Container 비교

구조 비교

        [ VM 방식 ]                          [ Container 방식 ]

┌──────┬──────┬──────┐              ┌──────┬──────┬──────┐
│ App  │ App  │ App  │              │ App  │ App  │ App  │
│ Bin  │ Bin  │ Bin  │              │ Bin  │ Bin  │ Bin  │
│ /Lib │ /Lib │ /Lib │              │ /Lib │ /Lib │ /Lib │
├──────┼──────┼──────┤              └──────┴──────┴──────┘
│Guest │Guest │Guest │                  ← 컨테이너 이미지
│  OS  │  OS  │  OS  │              ┌─────────────────────┐
├──────┴──────┴──────┤              │  Container Engine   │
│    Hypervisor      │              ├─────────────────────┤
├────────────────────┤              │      Host OS        │
│      Host OS       │              │  namespace + cgroups│
├────────────────────┤              ├─────────────────────┤
│    Host Server     │              │    Host Server      │
└────────────────────┘              └─────────────────────┘

       커널 N개                            커널 1개

VM의 구조

계층 구성

계층역할
Host Server물리 서버. CPU, 메모리, 디스크 등 실제 하드웨어
Host OS물리 서버에서 동작하는 운영체제
Hypervisor가상화 담당. 물리 자원을 논리적으로 분할해 각 VM에 할당
Guest OSVM마다 독립적으로 부팅되는 완전한 운영체제

특징

  • 독립성: Guest OS마다 커널이 분리되어 있어 서로 영향을 주지 않는다
  • 환경 자유도: Guest OS마다 다른 언어 런타임과 도구를 설치할 수 있다
    • 예: 동일 물리 서버에서 Guest OS A는 Java 17 + Gradle, Guest OS B는 Python 3.11 + pip

비용

  • 자원 중복: Guest OS 개수만큼 운영체제가 중복 실행된다
  • 기동 시간: 커널 부팅부터 수행하므로 수십 초 ~ 수 분 소요
  • 이미지 크기: OS 전체가 포함되어 수 GB 단위

Container의 구조

계층 구성

계층역할
Host Server물리 서버
Host OS운영체제. 커널을 모든 컨테이너가 공유
Container Engine컨테이너 이미지를 실행 (예: Docker)
Container Image애플리케이션(서비스) + 라이브러리 + 실행 바이너리를 패키징

특징

  • Guest OS 없음: Hypervisor와 Guest OS 계층이 존재하지 않는다
  • 커널 공유: 별도 OS를 부팅하지 않고 Host OS의 커널을 공유한다
  • 프로세스 단위 실행: 커널 입장에서 컨테이너는 하나의 프로세스다

격리 방식

컨테이너는 리눅스 커널의 두 기능으로 격리와 자원 제어를 수행한다.

기능담당
namespace커널 자원의 격리
cgroups자원 사용량의 제어

namespace — 커널 자원의 격리

정의

커널이 관리하는 시스템 자원을 프로세스 그룹 단위로 분리하는 커널 기능이다. 특정 namespace에 속한 프로세스는 해당 namespace에 할당된 자원만 인식하고 접근할 수 있다.

종류

namespace격리 대상
mnt파일시스템 마운트 포인트
pid프로세스 ID 공간
net네트워크 인터페이스, IP 주소, 포트, 라우팅 테이블
ipc프로세스 간 통신 자원 (공유 메모리, 세마포어, 메시지 큐)
uts호스트명, 도메인명
user사용자 ID(UID)와 그룹 ID(GID) 매핑

namespace의 역할 — 자원 격리

컨테이너는 Host OS의 커널을 공유한다. 별도 조치가 없다면 모든 컨테이너가 동일한 파일시스템, 동일한 포트, 동일한 프로세스 공간을 사용하게 되어 서로 충돌한다.

namespace는 커널이 관리하는 자원을 프로세스 그룹별로 분리해, 각 컨테이너가 자신에게 할당된 자원만 인식하도록 만든다. 그 결과 하나의 커널 위에서 여러 컨테이너가 독립된 환경처럼 동작할 수 있다.

cgroups — 자원 사용량의 제어

정의

프로세스 그룹이 사용할 수 있는 시스템 자원의 양을 할당하고 제한하는 커널 기능이다. namespace가 자원의 접근 범위를 결정한다면, cgroups는 자원의 사용량 상한을 결정한다.

제어 자원

자원제어 내용
CPUCPU 사용 시간의 비율 및 상한
Memory메모리 사용량 상한 (초과 시 프로세스 종료)
I/O블록 디바이스 읽기/쓰기 대역폭
Network네트워크 트래픽 분류 및 우선순위

적용 효과

  • 컨테이너에 메모리 512MB 제한을 설정하면 cgroups가 이를 강제한다
  • 제한을 초과하면 해당 프로세스가 종료된다
  • 컨테이너 단위로 적용되므로 하나의 컨테이너가 호스트 전체 자원을 점유하는 상황을 방지한다

핵심 차이 정리

구분VMContainer
가상화 대상하드웨어 (Guest OS 전체를 실행)프로세스 (namespace + cgroups로 격리)
커널Guest OS마다 독립된 커널Host OS의 커널을 공유
기동 시간수십 초 ~ 수 분수백 ms ~ 수 초
이미지 크기수 GB수십 MB ~ 수백 MB
자원 오버헤드큼 (OS가 중복 실행됨)작음 (프로세스 수준)
서버당 밀도수십 대수백 개
격리 수준커널까지 완전 분리커널 공유 (상대적으로 낮음)
OS 제약Host와 다른 OS 실행 가능Host 커널과 동일 계열만 실행 가능

1-4. Pod와 Container — 쿠버네티스에서의 역할

Pod의 정의

개념

  • 쿠버네티스가 생성하고 관리하는 가장 작은 배포 단위
  • 하나 이상의 컨테이너로 구성된다
  • 쿠버네티스는 개별 컨테이너가 아닌 Pod 단위로 스케줄링, 배포, 확장, 삭제를 수행한다

Pod 내 컨테이너의 제약

  • 항상 동일한 노드에 배치된다
  • 동일한 생명주기를 갖는다 (함께 생성되고 함께 종료된다)

Pod 단위로 묶는 이유

애플리케이션과 그 애플리케이션에 종속된 보조 프로세스를 하나의 논리적 단위로 다루기 위해서다.

Pod와 Container의 역할

PodContainer
역할배포·스케줄링의 단위, 네트워크와 스토리지의 경계애플리케이션 프로세스의 실행 단위
관리 주체쿠버네티스 스케줄러컨테이너 런타임
IP 주소Pod마다 하나씩 할당Pod의 IP를 공유
배치하나의 노드에 배치됨Pod 내부에 1개 이상 존재
생명주기생성과 삭제의 단위Pod 내부에서 개별 재시작 가능

Pod 내부의 공유 범위

┌─────────── Pod (IP: 10.244.1.7) ───────────┐
│                                             │
│  ┌──────────────┐      ┌──────────────┐    │
│  │ Container A  │      │ Container B  │    │
│  │              │      │              │    │
│  │ 개별 소유:   │      │ 개별 소유:   │    │
│  │  파일시스템  │      │  파일시스템  │    │
│  │  프로세스    │      │  프로세스    │    │
│  └──────┬───────┘      └──────┬───────┘    │
│         │                     │             │
│    ─────┴─────────────────────┴─────        │
│      공유: net namespace (동일 IP)          │
│            ipc namespace                    │
│            Volume                           │
└─────────────────────────────────────────────┘

공유되는 자원

자원내용제약
net namespace동일한 IP 주소를 가지며 localhost로 상호 호출 가능같은 포트 번호를 동시에 사용할 수 없음
ipc namespace공유 메모리를 통한 통신 가능
VolumePod 수준에서 정의하고 각 컨테이너가 마운트마운트를 선언해야 접근 가능

공유되지 않는 자원

자원내용
mnt namespace컨테이너별로 자신의 이미지에 포함된 파일시스템을 사용
pid namespace컨테이너별로 프로세스 공간이 분리됨

컨테이너 구성 예시

컨테이너 1개로 구성된 Pod

가장 일반적인 형태로, 하나의 애플리케이션을 하나의 Pod로 배포한다.

apiVersion: v1
kind: Pod
metadata:
  name: forday-api
spec:
  containers:
    - name: app
      image: forday-api:1.2.0
      ports:
        - containerPort: 8080

사이드카 — 메인 컨테이너에 보조 기능을 추가

  • 구성: 애플리케이션 컨테이너 + 로그 수집 컨테이너
  • 동작: 애플리케이션이 볼륨에 로그를 기록하면, 로그 수집 컨테이너가 같은 볼륨을 읽어 외부로 전송
  • 하나의 Pod로 묶는 이유: 두 컨테이너가 같은 노드에서 같은 볼륨을 바라봐야 하기 때문
apiVersion: v1
kind: Pod
metadata:
  name: forday-api
spec:
  volumes:
    - name: log-volume
      emptyDir: {}
  containers:
    - name: app
      image: forday-api:1.2.0
      ports:
        - containerPort: 8080
      volumeMounts:
        - name: log-volume
          mountPath: /var/log/app
    - name: log-collector
      image: fluent-bit:2.1
      volumeMounts:
        - name: log-volume
          mountPath: /var/log/app

Init Container — 메인 컨테이너보다 먼저 실행

  • 동작: 메인 컨테이너보다 먼저 실행되고, 정상 종료되어야만 메인 컨테이너가 시작된다
  • 용도: 데이터베이스 스키마 마이그레이션 등 애플리케이션 기동 전에 반드시 완료되어야 하는 작업
spec:
  initContainers:
    - name: db-migration
      image: forday-migration:1.2.0
  containers:
    - name: app
      image: forday-api:1.2.0

구성 시 판단 기준

  • 여러 컨테이너를 하나의 Pod에 넣는 경우: 보조 컨테이너가 메인 컨테이너와 생명주기를 완전히 공유해야 할 때
  • 분리해야 하는 경우: 독립적으로 확장되고 독립적으로 재시작되어야 할 때
    • 예: 애플리케이션 서버와 데이터베이스는 서로 다른 Pod로 구성한다

배포 시 Pod의 동작

전제 — Pod는 수정하지 않고 교체한다

Pod는 생성된 이후 내용을 변경하지 않는 것을 원칙으로 한다. 새로운 버전의 배포는 다음을 의미한다.

  • 기존 Pod의 이미지를 교체하는 것이 아니다
  • 새로운 Pod를 생성하고 기존 Pod를 삭제하는 것이다

동작 흐름 (forday-api:1.2.01.3.0)

[1] Deployment의 이미지 버전을 1.3.0으로 변경
        ↓
[2] 새 버전의 Pod 생성
      스케줄러가 배치할 노드를 선택
      → 이미지 다운로드 → 컨테이너 실행
        ↓
[3] 새 Pod가 정상 상태(Ready)가 될 때까지 대기
      Ready가 되어야 Service를 통해 트래픽을 전달받음
        ↓
[4] 기존 버전의 Pod 삭제
      Service에서 먼저 제외한 뒤 종료
        ↓
[5] Pod 개수만큼 [2]~[4]를 반복

롤링 업데이트(Rolling Update)

  • 새 Pod가 정상 동작을 확인받은 뒤에 기존 Pod를 제거한다
  • 배포 중에도 서비스 가능한 Pod가 항상 유지된다
  • 이것이 쿠버네티스가 무중단 배포를 제공하는 기본 원리다

Pod IP 변경과 Service

문제해결
Pod가 새로 생성될 때마다 IP 주소가 변경된다쿠버네티스는 Service 리소스를 제공한다
Pod IP를 직접 참조하면 배포 이후 통신이 끊긴다Service가 고정된 접근 지점을 제공하고, 현재 정상 상태인 Pod들에게 요청을 분배한다

따라서 애플리케이션 간 통신은 항상 Service를 통해 이루어져야 한다.

1-5. 클러스터 구조와 Pod 관리

Master Node와 Worker Node

┌──────────────── Master Node (Control Plane) ────────────────┐
│  API Server    스케줄러    컨트롤러                          │
│  = 명령을 받고, 배치를 결정하고, 상태를 감시               │
└─────────────────────────┬───────────────────────────────────┘
                          │ 지시
        ┌─────────────────┼─────────────────┐
        ▼                 ▼                 ▼
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ Worker Node1 │  │ Worker Node2 │  │ Worker Node3 │
│  Pod  Pod    │  │  Pod         │  │  Pod  Pod    │
└──────────────┘  └──────────────┘  └──────────────┘
        = 실제로 Pod(컨테이너)가 실행되는 서버
구분역할
Master Node클러스터의 두뇌. 사용자 명령을 받고, Pod를 어느 노드에 배치할지 결정하고, 현재 상태가 원하는 상태와 같은지 계속 감시한다
Worker Node실제 작업 서버. Master의 지시를 받아 Pod를 실행하고, 자신의 상태를 Master에 보고한다

사용자는 Worker Node를 직접 조작하지 않는다. Master에게 "이렇게 해달라"고 선언하면 Master가 Worker에 배분한다.

ReplicaSet

역할: Pod의 개수를 지정한 수만큼 유지한다

ReplicaSet (replicas: 3)
        │
        ├── Pod A  (Running)
        ├── Pod B  (Running)
        └── Pod C  (Running)

  Pod C 가 죽으면 ↓

        ├── Pod A  (Running)
        ├── Pod B  (Running)
        └── Pod D  (새로 생성)   ← ReplicaSet이 자동 생성
  • Pod가 죽거나 노드에 장애가 나면 새 Pod를 만들어 개수를 채운다 → Auto Healing
  • Pod 개수를 늘리라고 지시하면 그만큼 새로 생성한다 → Auto Scaling
  • 죽은 Pod를 되살리는 것이 아니라, 항상 새 Pod를 생성한다

계층 관계

Deployment  →  ReplicaSet  →  Pod  →  Container
   배포/버전 관리    개수 유지     배포 단위    실행 단위

사용자는 보통 ReplicaSet을 직접 만들지 않고 Deployment를 만든다. Deployment가 ReplicaSet을 생성하고, ReplicaSet이 Pod를 관리한다. 새 버전을 배포하면 Deployment가 새 ReplicaSet을 만들어 Pod를 교체한다.

0개의 댓글