Native sidecar 마이그레이션, 이거 하나만 조심하면 된다
오늘 알게 된 건데, 아직도 Istio sidecar나 Vault agent를 그냥 containers[]에 박아넣고 쓰시는 분들 꽤 많더라. 우리 팀도 그랬다. 근데 최근 클러스터 1.33 올리면서 native sidecar (초기 컨테이너 restartPolicy: Always)로 싹 옮겼는데, 딱 하나 함정이 있어서 공유한다.
뭐가 좋아졌나
원래 sidecar 패턴의 고질병이 두 개였다. 하나는 앱 컨테이너보다 sidecar가 늦게 뜨면 초기 요청이 실패하는 거. 또 하나는 Job에서 sidecar가 안 죽어서 Pod가 Completed로 안 넘어가는 거. Vault agent injector 쓰는 팀이면 다들 겪어봤을 거다.
Kubernetes 1.33에서 native sidecar가 stable 됐고, 이제는 initContainers[]에 넣고 restartPolicy: Always만 붙이면 된다:
spec:
initContainers:
- name: vault-agent
image: hashicorp/vault:1.17
restartPolicy: Always # 이 한 줄이 sidecar로 만든다
# ...
containers:
- name: app
image: myapp:latest
이러면 vault-agent가 먼저 뜨고, Ready 상태가 되어야 앱 컨테이너가 시작된다. 그리고 앱이 끝나면 sidecar도 SIGTERM 받고 알아서 종료된다. 진짜 깔끔하다.
근데 조심할 게 하나 있다
terminationGracePeriodSeconds 계산이 예전이랑 다르다. 우리는 이걸 놓쳐서 배포 하나 완전 말아먹었다.
Native sidecar는 앱 컨테이너가 먼저 SIGTERM 받고 종료된 후에야 sidecar에 SIGTERM이 간다. 즉, Pod 전체 grace period 안에서 앱 종료 시간 + sidecar 종료 시간이 모두 끝나야 한다는 뜻이다. 예전 sidecar 패턴처럼 병렬로 죴는 게 아니다.
우리 앱은 in-flight 요청 flush에 20초 걸리고, Vault agent는 토큰 lease revoke에 15초 정도 걸린다. 예전에는 grace period 30초로 잡아도 문제없었는데 (병렬로 처리되니까), native로 바꾸고 나서 gracefully 종료가 안 되고 강제 kill 당하는 케이스가 늘었다. kubectl get events 뒤져보니 FailedPreStopHook 로그가 잔뜩 찍혀 있더라.
결국 terminationGracePeriodSeconds: 60으로 늘렸다. 대충 (앱 종료 시간 + sidecar 종료 시간) * 1.5 정도 잡는 게 안전한 것 같다.
마이그레이션 순서
우리는 이렇게 했다:
- 스테이징에 native sidecar로 배포 → grace period 로그 관찰 (1주일)
- 낮은 트래픽 서비스부터 프로덕션 rollout
- Job/CronJob은 마지막에. Pod completion 동작 바뀌는 게 가장 크리티컬해서.
Job에서 특히 편해졌다. 예전에는 Vault agent 안 죽어서 Job이 Complete 안 되는 거 workaround 하려고 sidecar에 exit 0 트리거 파일 감시하는 스크립트까지 넣었었는데, 그거 다 지워버렸다. 코드 200줄 정도 줄었다.
정리하면
restartPolicy: Always 붙이는 건 쉬운데, grace period 재계산 안 하면 곤란해질 수 있다. 프로덕션 옮기기 전에 반드시 앱 shutdown + sidecar shutdown 시간 재고 여유 두고 잡자. 다른 팀에서 다른 함정 겪은 분 있으면 댓글로 알려주세요.