
최근 새로운 회사로 이직을 하면서, 내 개발 환경에 가장 크고 낯선 변화가 찾아왔다. 바로 모든 서비스가 쿠버네티스(Kubernetes, K8s) 위에서 배포되고 운영되고 있다는 점이다.
이전까지는 도커(Docker)나 비교적 단순한 배포 환경에 익숙했다면, 새 직장에서는 수많은 마이크로서비스들이 거대한 클러스터 위에서 얽혀 돌아가고 있었다. 단순히 코드를 짜는 것을 넘어, 내 코드가 어떻게 서버에 올라가고 외부의 트래픽을 어떻게 맞이하는지 그 '인프라의 흐름'을 이해하지 못하면 이곳에서 제대로 된 개발과 디버깅을 하기 어렵겠다는 강렬한 위기감이자 필요성을 느꼈다.
로그 하나를 보려고 해도 파드(Pod)와 네임스페이스(Namespace)를 알아야 했고, 서비스 URL을 찾으려면 인그레스(Ingress) 설정 파일(YAML)을 읽을 줄 알아야 했다. 단순한 명령어 몇 개를 암기하는 수준을 넘어, 클러스터라는 큰 그림 안에서 K8s의 구성요소들이 어떻게 유기적으로 소통하는지 그 뼈대를 튼튼하게 잡고 싶어졌다.
1. 쿠버네티스, 도대체 왜 쓰는 걸까?
마이크로서비스 아키텍처(MSA)로 넘어오면서 컨테이너의 개수는 기하급수적으로 늘어났다. 사람이 일일이 띄우고, 죽으면 다시 살려내는 수동 관리는 불가능해졌다. K8s는 매니페스트(YAML) 파일에 "나는 이런 상태를 원해!"라고 선언해 두면, 시스템이 알아서 그 상태를 유지해 주는 든든한 관리자다.
- 자동 배포 (Rolling Update): 서비스 중단 없이 새로운 버전을 점진적으로 배포할 수 있다.
- 자동 복구 (Self-healing): 파드(Pod)에 장애가 발생하면 즉시 감지하고 새로운 파드를 띄워 복구한다.
- 자동 확장 (Auto Scaling): 트래픽이 몰리면 파드 수를 자동으로 늘리고, 줄어들면 다시 줄인다.
- 설정 관리: 애플리케이션 코드와 설정값(환경변수, 비밀번호 등)을 안전하게 분리할 수 있다.
2. K8s 아키텍처: 가장 큰 단위부터 파헤치기 (Top-Down)
K8s의 구조를 이해할 때는 가장 큰 단위인 클러스터에서 시작해, 내 코드가 실행되는 파드까지 내려가는 방식으로 접근하는 것이 직관적이다.
🏢 클러스터(Cluster)와 논리적 분리
- Cluster: 여러 대의 서버(노드)를 하나로 묶어 거대한 하나의 컴퓨터처럼 자원을 공유하는 단위다.
- Context: 회사에서는 개발용, 운영용 등 여러 개의 클러스터를 쓴다. Context는 내가 어떤 클러스터와 네임스페이스를 바라볼지 결정하는 'TV 리모컨' 같은 역할을 한다.
- Namespace: 하나의 클러스터 내부를 논리적으로 나누는 '가상의 칸막이'다. (예: dev, beta, production, app2 등 팀별/환경별로 격리)
🧠 노드 (Node) 구성
- Control Plane (Master Node): 클러스터 전체를 지휘하는 두뇌.
- 명령을 받는 창구인 API Server, 자원을 계산해 파드를 배치하는 Scheduler, 모든 상태를 저장하는 저장소 etcd, 현재 상태를 목표 상태로 무한히 맞추는 Controller Manager로 구성된다.
- Worker Node: 마스터의 명령을 받아 실제 애플리케이션 컨테이너(Pod)가 실행되는 작업장.
- Ingress Node (특수 목적): 외부 트래픽을 클러스터 내부로 받아들이는 관문 역할만 전담하도록 떼어둔 노드.
3. 내 코드가 살아 숨 쉬는 곳: 워크로드와 파드
🫛 파드 (Pod)
쿠버네티스의 가장 작은 배포 단위. 컨테이너를 감싸고 있는 '콩깍지'라고 보면 된다. 파드는 생성될 때마다 IP가 바뀌는 휘발성 자원이다. 굳이 컨테이너를 파드로 묶는 이유는, 앱과 로그 수집기처럼 항상 붙어 다녀야 하는 컨테이너들을 묶어 디스크와 네트워크(localhost)를 공유하게 하기 위함이다.
⚙️ 워크로드 (Workload)
파드는 소모품이라 죽으면 끝이다. 그래서 파드를 직접 띄우지 않고, 파드를 관리해 주는 워크로드를 통해 배포한다.
- ReplicaSet: 지정한 개수(Replica)의 파드가 항상 살아있도록 유지보수한다.
- Deployment: 실무에서 가장 많이 쓰는 배포 단위. ReplicaSet을 조종하여 버전을 관리하고 무중단 배포 및 롤백을 수행한다.
- Job / CronJob: 일회성 배치 작업이나 주기적인 작업(DB 마이그레이션, 정산 등)을 실행하고 종료한다.
4. 트래픽의 여정: 외부 요청은 어떻게 Pod로 갈까? 🚀
실제 백엔드 개발자에게 가장 중요한 네트워킹 흐름이다. 브라우저에서 친 도메인이 어떻게 내 코드까지 도달할까?

[ 외부 사용자 ] → [ Ingress ] → [ Service ] → [ Pod ]
- Ingress (외부 관문): 외부 인터넷 트래픽을 도메인(URL)이나 경로에 따라 클러스터 내부의 적절한 Service로 라우팅한다. SSL 인증서 처리도 여기서 한다.
- Service (내부 로드밸런서): 파드들의 IP가 계속 바뀌더라도, 고정된 IP/포트를 제공하여 요청을 살아있는 파드들에게 골고루 분산시켜 준다. (주로 ClusterIP 사용)
5. 실무 과제 부딪혀보기 & 트러블슈팅 기록
머리로만 이해하는 것과 터미널을 열고 직접 부딪혀보는 것은 천지 차이였다
🛠️ 실무 꿀팁 : 파드 로그 한 번에 보기
특정 파드의 이름을 복사해서 로그를 볼 수도 있지만, Deployment에 속한 모든 파드의 로그를 보거나 라벨(Label)로 묶어서 보는 것이 훨씬 편하다.
# deployment로 묶인 파드 로그 모아보기
kubectl logs -f deployment/app2-deployment -n default
# 에러만 걸러내고 싶을 때
kubectl logs -f deployment/app2-deployment -n default | grep "ERROR"
🎯 기존 YAML의 문제점 분석 (환경변수 하드코딩)
운영 중인 매니페스트 파일을 리뷰하다 보니 개선점이 보였다. APM 키나 Sentry DSN 같은 중요 설정값이 YAML에 하드코딩되어 있었다.
- 보안 문제: Git에 민감한 키가 그대로 노출됨.
- 유연성 부족: 환경(Dev/Beta/Prod)이 바뀔 때마다 YAML을 직접 수정해야 함.
- 네임스페이스 혼용: Sandbox 환경이 default 네임스페이스에 있어 다른 리소스와 섞일 위험 존재.
개선 방향: 이런 설정값들은 ConfigMap(비민감)과 Secret(민감)으로 분리하거나, 기존에 사용 중인 외부 보안 저장소(Vault)로 통합하여 YAML 파일 밖에서 동적으로 주입받도록 구조를 바꿔야 한다.
🎬 마치며
처음엔 수많은 YAML 파일과 낯선 개념들 때문에 막막했지만, 하나의 거대한 시스템이 어떻게 맞물려 돌아가는지 파악하고 나니 인프라가 조금씩 재밌어지기 시작했다.
'ETC > Infra' 카테고리의 다른 글
| Elasticsearch 활용한 검색 구현하기 - 2 (Springboot 연동) (0) | 2025.11.14 |
|---|---|
| Elasticsearch 활용한 검색 구현하기 - 1 (Docker로 Elasticsearch + Kibana 구축) (0) | 2025.11.13 |
| [Kafka] 기본 개념 및 Embedded Kafka를 통한 Kafka 테스트 (2) | 2024.11.27 |
댓글