이 문서에서는 Kubernetes 클러스터 운영 시 유용한 패턴과 방법론을 정리합니다.
Rollout (재시작) 전략
수동 재시작
다음 명령어로 Deployment를 안전하게 재시작할 수 있습니다.
kubectl rollout restart deployment <deployment-name>kubectl delete pod보다 안전하며, Rolling Update 방식으로 무중단 재시작이 가능합니다.
주기적 재시작
메모리 누수나 디스크 용량 증가 등 Application에 문제가 있을 때 임시 조치로 주기적 재시작이 필요한 경우가 있습니다.
Warning
주기적 재시작은 임시 조치입니다. 추후에 근본 원인(메모리 누수, 로그 또는 임시 파일 축적 등)을 파악하여 영구적인 해결책을 적용해야 합니다.
방법 1: crontab 사용
crontab -e*/10 * * * * kubectl rollout restart deployment <deployment-name>방법 2: Kubernetes CronJob 사용
apiVersion: batch/v1
kind: CronJob
metadata:
name: rollout-restart
spec:
schedule: "*/10 * * * *"
jobTemplate:
spec:
template:
spec:
serviceAccountName: rollout-restart-sa # 적절한 RBAC 권한 필요
containers:
- name: rollout-restart
image: alpine/kubectl:latest
command:
- kubectl
- rollout
- restart
- deployment
- <deployment-name>
restartPolicy: OnFailureGitOps 환경에서 Rollout 트리거
GitOps(ArgoCD, Flux 등)에서 이미지 태그 변경 없이 Rollout을 트리거하는 방법입니다.
Annotation 기반 트리거
Deployment의 annotation에 timestamp 등 고유한 값을 넣고, GitOps에서 이 값을 변경하면 Rollout이 발생합니다.
spec:
template:
metadata:
annotations:
rollout-trigger: "2025-12-12T10:00:00"Manifest List Digest
manifest list digest를 사용하면 아키텍처(arm64, amd64 등)에 맞는 이미지가 자동으로 선택됩니다. Digest를 변경하여 Rollout을 트리거할 수 있습니다.
App of Apps에서 컴포넌트 순서 보장 (sync wave)
여러 Helm 차트가 의존성 순서를 가질 때(예: Istio base(CRD) → istiod → gateway), 한 Application에 몰아넣으면 순서가 보장되지 않습니다. argocd.argoproj.io/sync-wave는 리소스 단위 annotation이지만 Argo CD Application 자체도 리소스이므로, App of Apps에서 차트마다 Application으로 분리하고 자식 Application에 sync-wave를 부여하면 차트(컴포넌트) 단위 순서를 잡을 수 있습니다.
# 자식 Application 각각에 부여
kind: Application
metadata:
name: istio-base # CRD 먼저
annotations:
argocd.argoproj.io/sync-wave: "1"
---
kind: Application
metadata:
name: istiod # 컨트롤 플레인
annotations:
argocd.argoproj.io/sync-wave: "2"
---
kind: Application
metadata:
name: istio-gateway
annotations:
argocd.argoproj.io/sync-wave: "3"- 낮은 wave가 Synced + Healthy가 된 뒤에야 다음 wave로 진행합니다. Argo CD는 Application에 built-in health check가 있어 자식 앱 완료를 기다립니다.
- 같은 Application 내부의 리소스 순서(ConfigMap/Secret → Migration Job → 앱)도 동일하게 리소스 sync-wave + PreSync Hook으로 제어합니다.1
Swap (노드)
- kubelet 기본값
failSwapOn: true— 노드에 swap이 켜져 있으면 kubelet이 기동에 실패합니다. 그래서 전통적으로 노드 swap 비활성화가 기본입니다. - v1.34부터 LimitedSwap이 GA되어,
failSwapOn: false+ cgroup v2 환경에서 swap을 의도적으로 활용할 수 있습니다. Pod별memory.swap.max를 비례 할당하며, Guaranteed QoS(requests=limits) Pod는 swap=0으로 격리됩니다. (위험했던 UnlimitedSwap은 v1.30에서 제거) - 정리: 기본은 비활성화 전제, 필요 시 LimitedSwap으로 선택적 활성화.2
PodDisruptionBudget과 오토스케일링
PDB가 너무 빡빡하면 cluster autoscaler가 노드를 scale-down 하지 못합니다. Pod을 다른 노드로 옮기려면 evict해야 하는데 PDB가 이를 막기 때문입니다.
- 막히는 전형:
maxUnavailable: 0,minAvailable이 replica 수와 같음, 또는 단일 replica +minAvailable: 1→ALLOWED DISRUPTIONS: 0 - 완화: replica를 2개 이상으로 HA 구성 /
minAvailable대신maxUnavailable사용 / 불필요하면 PDB 완화·제거 - 주의: PDB가
disruptionsAllowed > 0을 보여도 topology spread constraint와 겹치면 scale-down이 막히는 케이스가 있습니다.3
볼륨 / 스토리지 팁
emptyDir을 RAM(tmpfs) 기반으로 사용하기
emptyDir 볼륨은 기본적으로 노드의 디스크를 사용하지만, medium: Memory를 설정하면 RAM 기반 tmpfs로 동작합니다. 디스크 I/O가 병목인 임시 파일·캐시 용도에 유용합니다.
volumes:
- name: cache
emptyDir:
medium: Memory
sizeLimit: 512Mi주의할 점:
- tmpfs 사용량은 Pod의 memory limit에 포함됩니다. 여유 없이 쓰면 Pod가 OOMKilled 될 수 있으므로
sizeLimit과 컨테이너resources.limits.memory를 함께 조정합니다. - 데이터는 휘발성입니다. Pod 재시작·노드 재부팅 시 사라지므로 영속성이 필요한 데이터에는 쓰지 않습니다.
- 노드 전체 메모리를 소비하므로, 여러 Pod가 동시에 크게 쓰면 노드 압력(eviction)으로 이어질 수 있습니다.
공식 문서: emptyDir | Kubernetes Volumes