Post

쿠버네티스 배포 흐름 한 번에 정리 (1) 큰 그림 — 모두 API 서버만 본다

이 시리즈를 쓰는 이유

매일 배포를 하는데도 “helm upgrade를 치면 그 사이에 누가 무엇을 하느냐”를 말로 설명하려 하면, 나는 늘 “새 파드가 생성되고…”에서 init 컨테이너로 건너뛰었다. 그 사이에 있는 API 서버, 컨트롤러, 스케줄러가 통째로 빠졌다. 운영은 하는데 내부 동작은 비어 있었다는 뜻이다.

그래서 “코드 push부터 사용자 요청이 파드에 닿기까지”를 한 번에 정리하기로 했다. 목표는 두 가지다.

  1. 쿠버네티스를 깊이 몰라도, 이 시리즈를 다 읽고 나면 배포 한 번이 일어나는 과정이 머릿속에 한 줄로 이어지게 한다
  2. 내가 잊을 때마다 다시 와서 5분 안에 복기할 수 있게 한다
편내용한 줄
(1) 큰 그림규칙 3개와 단계 7개모두 API 서버만 본다
(2) 파드가 만들어지기까지①트리거 ②체인 ③웹훅 ④노드장부에 올리고, 끼워 넣고, 띄운다
(3) 트래픽을 받기까지⑤Ready ⑥교체 ⑦요청 흐름Running이라고 트래픽을 받는 게 아니다
(4) 장애 때 거꾸로 쓰기 + 복기증상표, 틀렸던 것, 셀프 체크흐름을 거꾸로 따라가면 원인이 나온다

예시는 내가 운영하는 구성(Jenkins/ArgoCD 배포, Istio 사이드카, Vault Agent Injector)을 기준으로 했다. 교과서 예시보다 실제로 보이는 이름과 엮어야 기억에 남기 때문이다. 리소스 이름은 공개 글이라 일반적인 이름(app 네임스페이스, api-backend, web-nginx)으로 바꿨다.


먼저 용어 다섯 개

이것만 알면 시리즈 전체를 읽을 수 있다. 처음 보는 사람을 위해 넣었고, 아는 사람은 건너뛰면 된다.

용어한 줄 설명비유
Pod(파드)컨테이너가 실제로 도는 가장 작은 단위. 컨테이너 여러 개가 한 파드에 같이 있을 수 있다요리 한 접시
ReplicaSet(RS)“이 모양의 파드를 N개 유지하라”는 오브젝트같은 요리 N접시 주문서
DeploymentReplicaSet을 관리하며 버전 교체(롤링 업데이트)를 맡는 오브젝트메뉴판. 메뉴가 바뀌면 새 주문서를 만든다
Service / EndpointSlice파드 여러 개 앞에 붙는 고정 주소 / 그 주소 뒤에 실제로 어떤 파드가 있는지의 목록대표 전화번호 / 지금 전화 받을 수 있는 직원 명단
사이드카앱 컨테이너 옆에 같이 붙어 도는 보조 컨테이너 (Istio의 istio-proxy, Vault의 vault-agent)요리 옆에 붙는 반찬

한 줄

모두 API 서버에 쓰고, 각자 API 서버를 지켜보다가, 자기 차례가 오면 자기 일만 한다.

시리즈 전체가 이 한 줄의 반복이다. “누가 하나요?”라는 질문이 오면 답은 항상 이 꼴이다.

○○가 API 서버에서 △△가 바뀐 걸 보고 □□를 한다.


규칙 세 개

규칙 1. etcd에 쓰는 건 API 서버뿐이다

etcd는 클러스터의 모든 상태가 저장되는 데이터베이스다. 컨트롤러도, 스케줄러도, kubelet도, Helm도, ArgoCD도 etcd를 직접 건드리지 않고 전부 API 서버를 거친다.

  • 왜: 인증·인가·검증을 한 곳에서 하기 위해서다. 누구나 etcd를 직접 건드리면 통제할 지점이 없다. 2편에서 볼 “웹훅”도 이 한 곳에 끼어 있기 때문에 모든 파드에 빠짐없이 적용된다

규칙 2. 컨트롤러는 조정 루프(reconcile loop)를 돈다

1
원하는 상태(spec)를 본다 → 실제 상태(status)를 본다 → 다르면 차이를 줄인다 → 반복
  • 왜: “한 번 명령하고 끝”이 아니라 “계속 맞춰 가는” 구조라서, 파드가 죽어도 누가 다시 만들라고 시키지 않아도 다시 생긴다
  • ArgoCD도 같은 원리다. Git이 원하는 상태, 클러스터가 실제 상태다. 쿠버네티스를 이해하면 ArgoCD가 덤으로 이해된다

규칙 3. 컴포넌트끼리 서로 부르지 않는다

Deployment 컨트롤러는 ReplicaSet 컨트롤러에게 “파드 만들어”라고 호출하지 않는다. API 서버에 ReplicaSet을 쓸 뿐이고, ReplicaSet 컨트롤러는 API 서버를 watch(감시)하다 새 ReplicaSet을 보고 움직인다.

  • 왜: 서로 직접 호출하면 하나가 죽었을 때 연쇄로 멈춘다. API 서버라는 게시판 하나만 보게 하면, 각자 독립적으로 죽고 살아나도 상태는 게시판에 남아 있다
  • 이 규칙 때문에 3편의 “종료 순간 함정”이 생긴다. 서로 기다려 주지 않기 때문이다

비유 하나 — 식당 주문 장부

규칙 세 개를 한 장면으로 묶으면 이렇다.

쿠버네티스식당하는 일
API 서버 + etcd주문 접수대 + 장부장부에 쓰는 건 접수대만 한다
Deployment 컨트롤러점장“메뉴가 바뀌었네 → 새 주문서(ReplicaSet)를 장부에 올리자”
ReplicaSet 컨트롤러주방장“이 요리는 2접시여야 하는데 0접시네 → 접시(Pod) 2개를 장부에 올리자”
어드미션 웹훅장부에 올리기 직전의 검수원“이 접시엔 반찬(사이드카)을 꼭 붙여야 해”
스케줄러자리 배정 담당“자리가 남는 테이블(노드)에 배정”
kubelet테이블 담당 요리사“내 테이블에 배정된 접시를 실제로 만든다”

아무도 서로에게 말을 걸지 않는다. 모두 장부만 본다. 이 장면 하나만 기억하면 나머지는 따라온다.


단계 7개 — 전체 지도

코드 push부터 요청이 파드에 닿기까지 단계 7개 배포 한 번은 이 7단계로 나뉜다. ①~④는 2편, ⑤~⑦은 3편에서 다룬다

외우는 문장: 트리거 → 체인 → 웹훅 → 노드 → Ready → 교체 → 요청

단계한 줄다루는 편
① 트리거배포 도구가 Deployment를 바꿔 API 서버에 보낸다2편
② 체인Deployment → ReplicaSet → Pod가 “장부에” 올라간다2편
③ 웹훅저장 직전에 init 컨테이너와 사이드카가 끼워진다2편
④ 노드스케줄러가 노드를 고르고 kubelet이 실제로 띄운다2편
⑤ Readyreadiness를 통과해야 트래픽 대상 목록에 들어간다3편
⑥ 교체새 파드가 준비된 뒤 옛 파드를 내린다3편
⑦ 요청사용자 요청이 Gateway → nginx → 백엔드로 간다3편

⑦을 꼭 붙인다. “코드 push부터 요청이 파드에 닿기까지“라는 질문에 ①~⑥만 말하면 절반만 답한 것이다. 나는 처음에 ⑦을 통째로 빼먹었다.


“누가?”의 사슬 — 10개 주체를 한 장에

7단계를 움직이는 주체를 순서대로 세우면 아래와 같다. 빨간 번호는 내가 처음 설명할 때 빠뜨린 단계다. 빠뜨린 것이 거의 다 보라색(컨트롤 플레인)이다. 내가 직접 설정하지 않고 쿠버네티스가 알아서 해 주는 부분이라 의식하지 못했던 것이다.

배포 명령이 도착한 뒤 쿠버네티스 안에서 누가 무엇을 하나 모든 화살표는 “API 서버에 쓴다 → 다음 주체가 watch로 알아챈다”의 반복이다


1편 한 장 요약

  • 한 줄: 모두 API 서버에 쓰고, 각자 지켜보다가, 자기 차례에 자기 일만 한다
  • 규칙 3개: etcd엔 API 서버만 쓴다 / 컨트롤러는 조정 루프 / 서로 부르지 않는다(watch)
  • 비유: 식당 장부. 점장(Deployment) → 주방장(RS) → 검수원(웹훅) → 자리 배정(스케줄러) → 요리사(kubelet)
  • 단계 7개: 트리거 → 체인 → 웹훅 → 노드 → Ready → 교체 → 요청
읽고 나서 바로 확인 — Deployment 컨트롤러는 ReplicaSet 컨트롤러에게 어떻게 일을 시키나?

시키지 않는다. API 서버에 ReplicaSet을 쓰면, ReplicaSet 컨트롤러가 watch로 보고 반응한다. (규칙 3)

다음 편: (2) 파드가 만들어지기까지 — helm upgrade 한 줄이 컨테이너 다섯 개짜리 파드가 되는 과정

This post is licensed under CC BY 4.0 by the author.

© noah. Some rights reserved.