k8s 이론 공부

Part 1 - 왜 k8s 인가?

Ai와 함께 공부하자 2026. 4. 2. 15:54
728x90
반응형

Chapter 1. 컨테이너 이전의 세계

* 서버 한 대에 다 올리던 시절

2000년대 초반을 상상해보자. 회사에서 서비스를 하나 만들었다. Apache 웹서버, Java 애플리케이션, MySQL DB — 가지를 물리 서버 대에 설치했다.

돌아간다. 그런데 문제가 하나둘 생긴다.

  • 문제 1: 서로 발목을 잡는다. Java 앱이 메모리를 많이 먹으면 MySQL이 느려진다. 하나가 죽으면 같은 서버의 다른 것도 영향을 받는다.
  • 문제 2: 환경이 꼬인다. Java 앱 A는 Java 8이 필요하고, 앱 B는 Java 11이 필요하다. 같은 서버에 두 버전을 공존시키는 건 악몽이다. 라이브러리 버전 충돌도 마찬가지다.
  • 문제 3: 확장이 어렵다. 트래픽이 늘어서 웹서버만 늘리고 싶은데, 서버 한 대에 다 묶여있으니 서버 전체를 복제해야 한다. DB까지 같이 복제할 순 없지 않은가.

문제들을 해결하려고 가상화(Virtualization) 등장했다.

용어: 가상화(Virtualization) — 물리 서버 한 대 위에 소프트웨어로 가상의 컴퓨터 여러 대를 만드는 기술이다. VMware, VirtualBox, KVM 같은 것들이 이에 해당한다. 각 가상 컴퓨터를 VM(Virtual Machine)이라고 부른다.

VM 쓰면 서버 대에서 A VM, B VM, DB VM 분리할 있다. 서로 독립된 OS 돌아가니까 라이브러리 충돌도 없고, 하나가 죽어도 다른 VM 멀쩡하다.

그런데 VM에도 단점이 있다.

 

* VM의 한계

VM 하나마다 OS 전체 들어간다. Ubuntu CentOS, 커널부터 시스템 라이브러리까지 통째로다.

그래서:

  • VM 하나가 최소 수백 MB ~ 수 GB의 디스크를 먹는다.
  • 부팅하는 데 수십 초 ~ 수 분이 걸린다.
  • 같은 물리 서버에 올릴 수 있는 VM 수가 제한적이다.

운영을 해보면 VM 수십~수백 대를 관리하는 것이 어떤 느낌인지 것이다. VM마다 OS 패치도 해야 하고, 보안 업데이트도 따로 해야 한다.

여기서 핵심적인 질문이 나온다:

앱을 서로 격리하고 싶은 건데, OS 전체를 복제해야 하나?”

질문의 답이 컨테이너.

 


 

Chapter 2. 컨테이너란 무엇인가

* OS 커널은 공유하고, 앱만 격리한다

용어: 커널(Kernel) — OS의 핵심 엔진이다. 하드웨어(CPU, 메모리, 디스크, 네트워크)를 직접 제어하고, 프로세스 관리, 파일 시스템 접근 등을 담당한다. Linux에서 uname -r로 확인할 수 있는 그 커널이다.

컨테이너의 핵심 아이디어는 이것이다: 호스트 OS 커널을 같이 쓰되, 앱이 자기만의 파일 시스템, 네트워크, 프로세스 공간을 갖게 하자.

이걸 가능하게 하는 Linux 커널 기능이 가지 있다.

1) 네임스페이스(Namespace) — 격리를 담당

용어: Linux 네임스페이스(Namespace) — 프로세스가 볼 수 있는 시스템 자원의 범위를 제한하는 Linux 커널 기능이다. 참고로 이것은 나중에 배울 K8s의 Namespace와는 별개 개념이다.

PID namespace: 컨테이너 안의 프로세스는 자기 컨테이너 안의 프로세스만 보인다.

  • Network namespace: 컨테이너마다 독립적인 네트워크 인터페이스, IP, 포트 공간을 가진다.
  • Mount namespace: 컨테이너마다 독립적인 파일 시스템 뷰를 가진다.
  • UTS namespace: 컨테이너마다 자기 hostname을 가질 수 있다.

2) cgroups(Control Groups) — 자원 제한을 담당

용어: cgroups — 프로세스 그룹이 사용할 수 있는 CPU, 메모리, 디스크 I/O 등의 양을 제한하는 Linux 커널 기능이다.

네임스페이스가너는 이것만 있어라면, cgroups너는 이만큼만 있어이다.

가지를 조합하면: 같은 커널 위에서 돌아가지만, 앱은 마치 자기만의 서버에서 도는 것처럼 느끼게 된다.

*  VM vs 컨테이너 비교

[ VM 방식 ]                    [ 컨테이너 방식 ]

┌──────────┐ ┌──────────┐     ┌──────┐ ┌──────┐ ┌──────┐
│  App A   │ │  App B   │     │App A │ │App B │ │App C │
├──────────┤ ├──────────┤     ├──────┤ ├──────┤ ├──────┤
│Guest OS  │ │Guest OS  │     │ Libs │ │ Libs │ │ Libs │
│(Ubuntu)  │ │(CentOS)  │     └──┬───┘ └──┬───┘ └──┬───┘
└────┬─────┘ └────┬─────┘        │        │        │
     │            │           ┌──┴────────┴────────┴──┐
┌────┴────────────┴─────┐     │   Container Runtime    │
│    Hypervisor         │     │   (Docker 등)          │
├───────────────────────┤     ├────────────────────────┤
│    Host OS            │     │    Host OS (커널 공유)  │
├───────────────────────┤     ├────────────────────────┤
│    Hardware           │     │    Hardware             │
└───────────────────────┘     └────────────────────────┘

VM 각각 Guest OS 전체를 들고 있고, 컨테이너는 앱과 필요한 라이브러리만 들고 있다. 그래서:

  • 컨테이너 이미지 크기: 수십 MB (VM: 수 GB)
  • 시작 시간: 1~2초 (VM: 수십 초~분)
  • 같은 하드웨어에 훨씬 더 많은 앱을 올릴 수 있다

 

* 컨테이너 이미지란?

용어: 컨테이너 이미지(Container Image) — 앱을 실행하는 데 필요한 모든 것(코드, 라이브러리, 설정 파일, 환경 변수)을 하나의 패키지로 묶은 것이다. “앱 설치 USB”라고 생각하면 된다.

이미지는 읽기 전용이다. 이미지를 실행하면 그게 컨테이너 된다. 붕어빵 (이미지) 붕어빵(컨테이너) 관계다. 하나의 이미지로 컨테이너를 100개든 1000개든 만들 있다.

이미지는 Dockerfile이라는 레시피로 만든다:

FROM python:3.11-slim          # 베이스 이미지 (Python이 설치된 가벼운 Linux)
WORKDIR /app                   # 작업 디렉토리 설정
COPY requirements.txt .        # 의존성 파일 복사
RUN pip install -r requirements.txt  # 패키지 설치
COPY . .                       # 앱 코드 전체 복사
CMD ["python", "app.py"]       # 컨테이너 시작 시 실행할 명령

Dockerfile docker build 하면 이미지가 만들어지고, docker run 하면 컨테이너가 실행된다.

용어: 레이어(Layer) — Dockerfile의 각 명령(FROM, RUN, COPY 등)이 하나의 레이어를 만든다. 레이어는 읽기 전용이고 캐싱된다. 코드만 바꾸면 COPY 레이어부터만 다시 빌드하면 되니까 빠르고 효율적이다.

 


 

Chapter 3. 컨테이너만으로는 부족하다

* 컨테이너 1~2개일 때는 행복하다

docker run으로 컨테이너 띄우고, 돌아가고, 문제가 생기면 docker restart 하면 된다. 그런데 실무에서는 이런 상황이 벌어진다.

  • 상황 1: 수십~수백 개의 컨테이너.
    • 마이크로서비스 아키텍처로 가면 하나의 서비스가 수십 개의 컨테이너로 구성된다. 프론트엔드, 백엔드 API 여러 개, DB, 캐시, 메시지 큐, 로그 수집기…
용어: 마이크로서비스(Microservices) — 하나의 큰 앱(모놀리스)을 기능별로 작은 서비스들로 쪼개는 아키텍처다. 예: “주문 서비스”, “결제 서비스”, “사용자 서비스”가 각각 독립적으로 배포·확장된다.
  • 상황 2: 컨테이너가 죽으면?
    • Docker 자체는 “컨테이너가 죽으면 자동으로 새로 띄워줘”라는 기능이 기본적으로 약하다. --restart=always 옵션이 있지만, 그 서버 자체가 죽으면? 다른 서버에서 자동으로 띄워주지는 못한다.
  • 상황 3: 트래픽이 늘면?
    • “지금 웹서버 컨테이너 3개인데, 5개로 늘려줘” — 수동으로 하려면 어느 서버에 빈자리가 있는지 확인하고, 거기서 docker run 하고, 로드밸런서에 등록하고… 이걸 매번 해야 한다.
  • 상황 4: 업데이트.
    • v1.0에서 v1.1로 업데이트할 때, 100개 컨테이너를 한꺼번에 내리면 서비스 중단이다. 몇 개씩 순차적으로 교체하고 싶은데, 수동으로 해야 한다.
  • 상황 5: 서버 여러 대에 분산.
    • 서버가 10대 있을 때, 어떤 컨테이너를 어떤 서버에 배치할지 — CPU, 메모리 여유를 보고 결정해야 한다.

모든 사람이 하면 운영자가 밤낮으로 일해야 한다. 그래서 필요한 컨테이너 오케스트레이션(Container Orchestration)이다.

용어: 오케스트레이션(Orchestration) — 오케스트라 지휘자가 수십 명의 연주자를 조율하듯, 수많은 컨테이너의 배포, 확장, 네트워킹, 복구를 자동으로 관리하는 것이다.

 


 

Chapter 4. Kubernetes 탄생

* Google의 비밀 병기, Borg

Google 2000년대 초반부터 내부적으로 Borg라는 시스템을 써왔다. Gmail, YouTube, Google Search — Google 모든 서비스가 Borg 위에서 돌아갔다. 수십만 대의 서버에서 수십억 개의 컨테이너를 관리하는 시스템이었다.

2014, Google Borg 경험과 교훈을 바탕으로 오픈소스 프로젝트를 시작한다. 그게 Kubernetes(쿠버네티스).

용어: Kubernetes — 그리스어로 “조타수, 항해사”라는 뜻이다. K와 s 사이에 8글자가 있어서 K8s라고 줄여 쓴다. CNCF(Cloud Native Computing Foundation)에서 관리하는 오픈소스 프로젝트이며, 현재 컨테이너 오케스트레이션의 업계 표준이다.

 

* K8s가 해주는 것들

문장으로: 너는 원하는 상태(desired state) 선언해. 나머지는 K8s 알아서 할게.”

이게 K8s 가장 중요한 철학이다. 선언적 관리(Declarative Management)라고 한다.

예를 들어 이렇게 말하는 것이다: “nginx 컨테이너를 3 띄워줘. 각각 CPU 0.5코어, 메모리 256MB . 항상 3개가 유지돼야 .”

이걸 YAML 파일로 작성해서 K8s 전달하면:

  • K8s가 클러스터 안에서 자원 여유가 있는 노드를 찾아서 컨테이너를 배치한다. (스케줄링)
  • 컨테이너 하나가 죽으면 자동으로 새 걸 띄운다. (자가 치유)
  • 트래픽이 늘면 3개에서 5개로 늘린다. (오토스케일링)
  • v1에서 v2로 업데이트할 때 하나씩 교체한다. (롤링 업데이트)
  • 문제가 생기면 이전 버전으로 돌린다. (롤백)
  • 컨테이너들 앞에 로드밸런서를 자동으로 붙여준다. (서비스 디스커버리)

※ 명령적 vs 선언적

명령적(Imperative) — “이렇게 해라

  1. 서버 A에 SSH 접속해
  2. docker pull nginx 해
  3. docker run -d -p 80:80 nginx 해
  4. 방화벽에 80포트 열어
  5. 로드밸런서에 서버 A 등록해

선언적(Declarative) — “이런 상태가 되길 원해

spec:
  replicas: 3
  containers:
    - name: nginx
      image: nginx
      ports:
        - containerPort: 80

명령적은 “How(어떻게)” 지시하고, 선언적은 “What(무엇을)” 선언한다.

선언적 방식의 장점은 K8s 현재 상태와 원하는 상태의 차이를 스스로 감지하고 맞춰준다 것이다. 컨테이너가 2개밖에 돌고 있으면? K8s “3개여야 하는데?” 하고 1개를 띄운다. 과정을 Reconciliation Loop(조정 루프)라고 부른다. K8s 전체를 관통하는 핵심 메커니즘이다.

728x90
반응형
LIST

'k8s 이론 공부' 카테고리의 다른 글

부록: 핵심 용어 사전 (가나다순)  (0) 2026.04.02
Part 5 — 운영과 확장  (0) 2026.04.02
Part 4 — 네트워킹과 스토리지  (0) 2026.04.02
Part 3 — 핵심 리소스  (0) 2026.04.02
Part 2 — K8s 아키텍처  (0) 2026.04.02