상황
인프라 온보딩을 받으면서 kubeconfig 열 개 남짓을 한 번에 병합했다. kubectl, helm, k9s, Lens… 툴체인 설치만 한나절이었는데, 정작 설치가 끝나고 나니 더 막막했다. 이름만 듣던 도구들이 한꺼번에 쏟아졌는데 각자 뭘 하는 앱이고, 언제 열어봐야 하는지가 정리가 안 됐다.
그래서 도구라던지, 사용법 자체를 이해하는 걸 포기하고, 내 코드가 배포돼서 사용자 화면에 뜨기까지의 흐름을 순서대로 세워봤다.
git push → CI (Docker 이미지 빌드 → 레지스트리 저장)
→ Helm values 에 새 이미지 버전 기록
→ ArgoCD 가 그걸 보고 Kubernetes 에 반영
→ Kubernetes 가 새 파드로 교체
→ 운영 중 상태는 Grafana / k9s 로 관측
포장 — Docker
앱을 어디서든 똑같이 도는 상자로 포장하는 도구.
"제 로컬에서는 되는데요"를 없애는 게 존재 이유다.
내 앱 + Node 버전 + 시스템 의존성까지 통째로 이미지로 굳혀버리면, 어느 서버에서 실행하든 같은 환경이 된다.
| 명령 | 뜻 |
|---|---|
docker build -t myapp . |
Dockerfile 대로 이미지 포장 |
docker run -p 3000:3000 myapp |
포장된 이미지 실행 |
docker ps / docker logs <id> |
뭐가 돌고 있나 / 로그 |
회사에서는 CI가 이 빌드를 대신 해서 이미지 저장소(ECR)에 올린다.
그래서 배포 파이프라인 로그에서 제일 먼저 보이는 게 docker build 단계다.
실행 — Kubernetes
그 상자 수십 개를 대신 돌려주는 관리자.
아파트 관리사무소라고 생각하면 편했다. 입주(배포), 퇴거(종료), 고장 신고 접수(죽으면 재기동), 이사(버전 교체 시 하나씩 갈아끼우기)를 사람 대신 해준다. 컨테이너를 담는 최소 단위가 파드(Pod) 고, "이 앱을 이런 스펙으로 몇 개 띄워라"라는 명세서가 deployment.yaml 이다.
kubeconfig 를 여러 개 병합한 이유도 여기서 이해됐다.
클러스터(관리사무소)가 환경/고객사별로 여러 개라서, kubectl ctx 로 "지금 어느 사무소에 말 걸지"를 바꾸는 거였다.
보는 법은 k9s 세 동작이면 일단 충분했다.
| 동작 | 뜻 |
|---|---|
:pods |
파드 목록 (Running 인지, RESTARTS 가 치솟는지) |
| 엔터 | 파드 상세 |
l |
로그 — 백엔드 디버깅의 시작점 |
화면이 500을 뱉으면 네트워크 탭 다음으로 여는 게 이 로그다.
s눌러서 멈추고 확인만 하고 에러 그냥 클로드에 긁어서 넣어~..
배포 동기화 — ArgoCD
git에 적힌 배포 상태와 클러스터의 실제 상태를 계속 비교해서 맞추는 지킴이.
사람이 kubectl 로 직접 배포하는 게 아니라, git(Helm 차트의 values)을 고치면 ArgoCD 가 클러스터를 git 대로 만들어준다. 이걸 GitOps 라고 부른다. "배포의 진실은 항상 git에 있다"는 발상.
실무에서 중요한 건 이거였다: CI가 values 파일에 새 이미지 버전을 적어놔도, ArgoCD 가 Sync 를 안 하면 클러스터는 옛날 그대로다. "머지했는데 dev에 반영이 안 돼요"의 단골 원인. 웹 UI에서 볼 건 두 개다.
| 상태 | 뜻 |
|---|---|
| Synced | git 과 클러스터가 일치 |
| Healthy | 떠 있는 파드들이 정상 |
둘 다 초록이면 배포는 끝난 거고, OutOfSync(노랑)면 Sync 버튼, 빨강이면 리소스 트리를 타고 내려가서 어느 파드가 죽었는지 본다.
관측 — Grafana
파드들의 CPU/메모리/재시작 횟수를 시계열 그래프로 보여주는 대시보드.
(수집은 보통 Prometheus 가 하고, Grafana 는 그리는 담당이다.)
로그와 역할이 다르다는 걸 이해하는 게 핵심이었다.
| 답해주는 질문 | |
|---|---|
| 로그 (k9s) | 무슨 일이 있었나 (문장) |
| 메트릭 (Grafana) | 언제부터 나빠졌나 (그래프) |
"파드가 자꾸 죽어요"라면 — 로그에서 죽기 직전 에러를 보고, Grafana 에서 그 시간대 메모리가 천장을 치는지(OOM) 본다.
둘을 같이 봐야 원인이 잡힌다고 한다.
장애 때 보는 순서
외울 건 도구가 아니라 이 순서 하나였다.
화면 이상
→ 네트워크 탭: 어떤 API 가 몇으로 실패? (404/502=라우팅, 500=앱 에러)
→ k9s: 파드 Running? 로그에 스택트레이스? ← 대부분 여기서 원인
→ 배포가 반영 안 된 거면 → ArgoCD Synced 확인
→ 반복 재시작이면 → Grafana 메모리/CPU
정리하며
정리하고 나서 알았는데, 이 구조는 낯선 게 아니었다.
나는 모니터링 시스템을 만드는 FE 개발자다 — 설비 데이터를 mqtt로 받아와 실시간 폴링해서 트렌드 차트를 그리고 임계치 알람을 띄우는 화면을 매일 만든다. Grafana 는 그걸 파드에 하고 있는 것뿐이었다. 대상이 컨테이너로 바뀌었을 뿐, 수집→시각화→알람이라는 구조는 내가 만들던 그것과 같았다.
막막함의 대부분은 도구가 어려워서가 아니라 이해가 없어서였다. 아직 바로 운영을 들어가기엔 걱정이 많이 앞서긴 하지만 ..ㅜㅜ
다음 장애 때 어느 계층부터 열어볼지 아는 것 — 온보딩에서 얻어야 할 건 그거면 충분한 것 같다.