1편 ([Kubernetes] 쿠버네티스 환경 배포를 위한 오브젝트 개념)에서 쿠버네티스의 구조(Pod·Deployment·Service·etcd)를 정리했다. 이번 편은 그 구조 위에서 배포를 준비하는 표준 배포 경로, 이미지 태그 전략, 그리고 클러스터가 새 이미지를 보게 만드는 세 가지 명령어에 대해서 정리해본다.
실무 배포 가이드를 따라가며 배운 것들을 일반적인 흐름으로 재구성했다. 예시는 계속 가상의 앱 myapp(API 서버 myapp-web + background worker myapp-worker)이다.
1. 배포의 표준 경로
코드를 고치고 서비스에 반영하는 일반적인 구성은 아래와 같다.
git push ──▶ CI (GitHub Actions 등) ──▶ registry ──▶ 클러스터
① 테스트 │ ▲
② docker build │ │ 노드가 pull
③ docker push ───────────────────────┘ │
④ 배포 반영 (매니페스트 갱신 or kubectl) ───────────────┘
CI/CD: git push를 신호로 빌드·테스트·배포를 자동 실행하는 파이프라인. CI(Continuous Integration)가 빌드·테스트, CD(Continuous Deployment)가 배포 반영을 맡는다.
사람이 하는 건 git push까지고 나머지는 파이프라인이 한다. ④의 "배포 반영"은 뒤에 나올 배포 명령 중 하나이거나 GitOps(1편 3절)라면 git의 매니페스트 변경을 ArgoCD와 같은 툴이 감지해 자동 반영한다.
별도로 CI/CD를 구축하지 않았다면 같은 단계를 사람이 명령어로 입력하면 된다.
docker build -t registry.example.com/myapp:20260916-001 .
docker push registry.example.com/myapp:20260916-001
kubectl set image deploy/myapp-web myapp-web=registry.example.com/myapp:20260916-001
수동이든 자동이든 본질은 같다 — 이미지를 registry에 올리고, 클러스터가 새 이미지를 보게 만든다. 1편에서 본 대로 이미지를 pull 하는 주체는 노드이므로 배포하는 쪽은 "올리고 지목"까지만 하면 된다. 이 글은 이 두 동작을 파고든다: 무엇을 올리나(2절 이미지 태그), 어떻게 지목하나(3절 명령).
2. 이미지 태그 전략
이미지의 속성 중에는 ID와 태그가 있다. 이미지 ID는 내용의 해시이고, 태그는 ID에 붙은 별칭이다. 한 ID에 태그 여럿이 붙을 수 있다. git으로 치면 commit 해시와 branch 이름의 관계다.
여기서 태그가 두 종류로 갈린다.
| 종류 | 예 | 성질 |
|---|---|---|
| 불변(immutable) 태그 | 20260916-001, v1.4.2, commit 해시 |
한 번 붙이면 다른 이미지로 옮기지 않는다 |
| 가변(mutable) 태그 | latest, stable, dev |
push 할 때마다 다른 이미지를 가리키게 된다 |
배포는 불변 태그로 한다. 이게 이 절의 결론이다. 불변 태그를 사용해야 하는 이유는 아래에 나오는 가변 태그(대표적으로 latest)의 문제들이다.
- latest는 "최신"이 아니다. 그냥 이름이 latest인 태그다. push 하는 사람이 옮겨 줘야 움직인다. "latest를 배포했는데 옛 코드가 돈다"의 원인 대부분이 여기다.
- 무엇이 배포됐는지 알 수 없다. Deployment가
myapp:latest를 보고 있으면,kubectl get deploy -o wide를 쳐도 "latest"라는 글자만 보인다. 그게 어제의 latest인지 오늘의 latest인지 클러스터 화면만으로는 알 수 없다. 날짜 태그면 태그 자체가 배포 기록이다. - 같은 태그 재사용은 노드 캐시에 배신당할 수 있다. 같은 태그로 덮어 push 하고 재시작하면 노드가 캐시된 옛 이미지를 그대로 쓰는 사례가 실제로 있다(뒤의 imagePullPolicy가 Always여도 환경에 따라 겪은 사례가 보고된다). 태그가 바뀌면 노드는 무조건 새로 받는다 — 캐시 문제 자체가 성립하지 않는다.
- 롤백할 이름이 없다. latest 하나로 운영하면 "직전 버전"을 가리킬 태그가 없어서 롤백하려면 그제서야 digest를 뒤져야 한다.
그래서 실무 패턴은 배포마다 고유한 태그를 만드는 것이다. 아래는 날짜를 기반으로 태그를 생성하는 예시이다.
TAG=$(date +%Y%m%d)-001 # 또는 git commit 해시, 버전 번호
docker build -t registry.example.com/myapp:$TAG .
docker push registry.example.com/myapp:$TAG
# latest 를 쓰더라도 배포용이 아니라 "가장 최근 빌드" 표시용 별칭으로만
배포 이력이 registry의 태그 목록에 그대로 남기 때문에 롤백을 하는 경우에는 직전 태그를 지목하면 된다.
imagePullPolicy
imagePullPolicy: Pod가 뜰 때 이미지를 registry에서 다시 받을지 정하는 설정.
| 값 | 동작 |
|---|---|
Always |
Pod가 뜰 때마다 registry에 확인한다 |
IfNotPresent |
노드에 이미 있으면 재사용한다 |
Never |
노드 로컬 이미지만 쓴다 |
imagePullPolicy는 이미지 태그에 따라 기본값이 설정된다. 태그가 latest면 Always, 그 외 태그면 IfNotPresent. 그래서 latest 운영에서 날짜 태그 운영으로 넘어갈 때 "IfNotPresent인데 같은 태그를 재사용하면 안 받는다"는 문제를 만날 수 있다. 이런 문제를 피하기 위해서는 불변 태그 원칙을 지켜서 매번 새 이름으로 지정해주면 된다.
3. 배포 명령 3가지 — apply, set image, rollout restart
클러스터가 새 이미지를 보게 만드는 방법이 세 개 있는데, 하나씩 정리해보겠다.
① kubectl apply -f: 선언 전체를 갱신 (정석)
# 매니페스트의 image: 를 새 태그로 고친 뒤
kubectl apply -f myapp-web.yaml
1편에서 본 대로 매니페스트 파일이 곧 배포의 입력이다. 파일의 image:를 고쳐서 apply 하면 이미지만 바뀌는 게 아니라 파일과 클러스터의 어긋남이 생기지 않는다. CI/CD와 GitOps가 쓰는 방식이 이것이다(파이프라인이 매니페스트의 태그를 갱신하고 apply 하거나, git에 커밋하면 ArgoCD가 반영). 이미지 외의 변경(환경변수, replicas, probe 설정)도 같은 명령으로 나간다.
② kubectl set image: 이미지 태그만 교체 (수동 배포·롤백)
kubectl set image deploy/myapp-web myapp-web=registry.example.com/myapp:20260916-001
클러스터 안의 Deployment 오브젝트에서 image: 필드 하나만 바꾼다. 빠르고 정확하지만 1편의 그 문제 — 파일과 클러스터가 어긋난다 — 를 만든다. 수동 배포 환경이나 급한 롤백에서 쓰고, 쓴 뒤에는 매니페스트 파일에도 같은 태그를 반영해 두는 게 원칙이다.
형식 주의: <컨테이너이름>=<이미지>에서 좌변은 컨테이너 이름이다. 보통 Deployment 이름과 같게 짓지만 다를 수 있고 다른 Deployment가 같은 컨테이너 이름을 쓰는 경우도 있다. 아래의 명령어를 통해 이름을 확인할 수 있다.
kubectl get deploy myapp-web -o jsonpath='{.spec.template.spec.containers[0].name}'
③ kubectl rollout restart: 이미지 변경 없이 재기동
kubectl rollout restart deploy myapp-web
같은 선언으로 Pod만 새로 만든다. 이미지 태그가 안 바뀌므로 원칙적으로 배포 명령이 아니라 재기동 명령이다. 메모리 초기화, 연결 재수립, ConfigMap 변경 반영(환경변수는 프로세스 시작 시 읽히므로)이 용도다. latest + Always 조합에서는 이 명령이 배포를 겸했지만 불변 태그 운영에서는 이미지 변경이 필요하기 때문에 그 역할이 ①②로 넘어간다.
비상용으로 kubectl delete pod도 있다 — Deployment가 다시 만들어 주므로 결과는 재기동과 같지만 restart가 새 Pod를 먼저 띄우고 옛 Pod를 내리는(무중단) 반면 delete는 먼저 내리므로 잠깐 끊긴다.
정리:
| 명령 | 바꾸는 것 | 쓰는 상황 |
|---|---|---|
apply -f |
선언 전체 | 정석 배포 (CI/CD·GitOps), 설정 변경 |
set image |
이미지 태그만 | 수동 배포, 롤백 |
rollout restart |
없음 (Pod만 교체) | 재기동, ConfigMap 반영 |
마치며
여기까지가 배포의 준비다. 이미지를 만들어 불변 태그를 붙였고(1·2절) 클러스터에 새 이미지를 지목하는 세 가지 방법을 갈랐다(3절).
다음 글에서는 실행할 이미지를 지목하는 순간 클러스터 안에서는 무슨 일이 벌어지고, 새 Pod와 옛 Pod는 어떤 순서로 교체되고, "배포 성공"은 무엇으로 판정하며, 잘못됐으면 어떻게 되돌리는지 등을 정리해보겠다.
'Infra > Kubernetes' 카테고리의 다른 글
| [Kubernetes] 쿠버네티스 배포 이후: 롤링 업데이트, 검증, 롤백 (1) | 2026.09.19 |
|---|---|
| [Kubernetes] 쿠버네티스 환경 배포를 위한 오브젝트 개념 (1) | 2026.09.10 |