도입부: 온프레미스 K8S에서 AWS EKS로 이전하면서 리소스 명명 규칙을 정리하다가, Service 이름 변경 하나로 애플리케이션이 기동 실패하는 케이스를 겪었습니다. 이 글에서는 Kubernetes의 Service 환경변수 자동 주입이 어떻게 충돌을 만들었는지와, 운영에서 재발을 막기 위한 가드를 정리합니다.
배경: EKS 이전 후 “가독성”을 위한 명명 규칙 정리
EKS로 이전하면서 리소스 이름을 일관되게 정리하고 싶었습니다. 특히 Service 이름에 관습적으로 붙이던 -service 같은 접미사를 제거하면 리소스가 더 깔끔해 보입니다.
예를 들어 Redis Service를 아래처럼 변경했습니다.
redis-service→redis
그런데 이 “가독성 개선”이 런타임 장애로 이어졌습니다.
Kubernetes의 숨은 기능: Service 환경변수 자동 주입(Service Links)
Kubernetes는 같은 네임스페이스 내 Service 정보를 Pod에 환경변수로 자동 주입할 수 있습니다. 대표적으로 다음과 같은 형태의 변수가 컨테이너에 들어옵니다.
REDIS_SERVICE_HOSTREDIS_SERVICE_PORTREDIS_PORT(예:tcp://10.x.x.x:6379같은 문자열)
여기서 중요한 점은 Service 이름이 곧 환경변수 prefix가 된다는 사실입니다. 즉 Service 이름이 redis라면 REDIS_* 형태의 환경변수가 주입될 가능성이 커집니다.
실제 장애 시나리오: .env 변수와 K8S 자동 주입 변수가 충돌
저희 서비스는 관습적으로 .env 기반 설정을 많이 쓰고, 애플리케이션이 REDIS_HOST, REDIS_PORT 같은 키를 읽도록 되어 있었습니다.
그런데 Service 이름을 redis로 바꾸는 순간, Pod 내부에는 Kubernetes가 주입한 REDIS_PORT가 생기거나(혹은 기존 값과 경합하거나) 앱의 설정 로직에 따라 예상치 못한 값이 선택될 수 있습니다.
특히 이번 케이스는 REDIS_PORT 값의 “타입”이 문제였습니다.
- 애플리케이션 기대:
REDIS_PORT=6379(숫자) - Kubernetes 주입:
REDIS_PORT=tcp://10.x.x.x:6379(문자열 URL 형태)
결과적으로 애플리케이션이 문자열을 포트로 파싱하려다 실패하면서 기동에 실패했습니다.
제가 이 문제에서 얻은 교훈은 단순합니다.
- Service 이름 변경 = 주입 환경변수 이름/키 변경
- “가독성”을 위한 변경도, 내부 동작(자동 주입)과 맞물리면 운영 장애로 이어질 수 있습니다.
해결: enableServiceLinks: false로 Service 환경변수 자동 주입 끄기
가장 직접적인 해결책은 Deployment(또는 PodSpec)에서 Service Links를 비활성화하는 것입니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
enableServiceLinks: false
containers:
- name: app
image: my-app:latest
이 설정을 적용하면, Kubernetes가 같은 네임스페이스의 Service 정보를 환경변수로 자동 주입하지 않게 되어 REDIS_* 같은 충돌 가능성을 크게 줄일 수 있습니다.
트레이드오프도 있습니다
대화에서 정리된 것처럼, enableServiceLinks: false를 “필수”로 가져가면 예측 가능성과 안전성은 올라갑니다. 다만 다음 같은 단점도 고려해야 합니다.
- 일부 레거시 앱/서드파티 컨테이너가
*_SERVICE_HOST/PORT자동 주입에 의존하는 경우, 설정 누락이 바로 장애로 이어질 수 있습니다. - 디버깅 시 “Pod에 자동으로 들어오는 힌트 정보”가 줄어듭니다.
그래도 운영 안정성을 우선한다면, 저희처럼 .env 중심이고 관습적 환경변수 키가 많은 조직에서는 기본값을 false로 두는 선택이 합리적이라고 봤습니다.
운영에서 사이드이펙트를 줄이는 검증 절차(가드) 제안
이번 장애를 겪고 나서 “서비스명 정리” 같은 변경은 아래 순서로 검증하는 게 효과적이라고 느꼈습니다.
1) 개발자와 “필수 환경변수” 목록을 먼저 합의합니다
대화에서도 결론이 났듯이, 우선 개발자와 협의해서 컨테이너(애플리케이션)가 반드시 사용하는 환경변수 키를 정리해야 합니다.
- 특히
HOST,PORT,URL계열은 충돌 시 장애 전파가 큽니다. - DB/Redis뿐 아니라 메시지 브로커, 외부 API 엔드포인트도 동일하게 위험합니다.
2) 네임스페이스의 Service 목록으로 “충돌 후보 키”를 역으로 계산합니다
“필수 변수만” 보면 놓치는 함정이 있습니다. Service가 새로 추가되거나 이름이 바뀌면, 자동 주입되는 키도 바뀌기 때문입니다.
따라서 운영 가드로는 다음 접근이 더 안전합니다.
- 네임스페이스의 Service 이름 목록 → (K8S 규칙에 따라) 생성될 환경변수 prefix 추정
- 우리 앱에서 쓰는
.env키들과 비교 → 충돌 후보 탐지 - 충돌 가능성이 있는 Service 이름은 금지하거나, 워크로드에
enableServiceLinks: false를 강제
3) “명명 규칙 변경”은 배포 전 체크리스트에 포함합니다
리소스 이름 변경은 코드 변경이 없어서 가볍게 느껴지지만, 실제로는 아래 항목을 체크리스트로 강제하는 편이 좋습니다.
- Service 이름 변경 시, 동일 네임스페이스의 워크로드에서 환경변수 충돌 가능성 점검
.env/Secret/ConfigMap 키 네이밍 규칙 점검(예:REDIS_*처럼 Service prefix와 겹치는 관습이 있는지)- (가능하다면) 스테이징에서 실제 Pod의
env를 확인해 차이를 비교
마무리
Kubernetes에서는 “이름”이 단순한 라벨이 아니라, 환경변수 자동 주입 같은 런타임 동작을 바꾸는 트리거가 될 수 있습니다. 저희는 앞으로 명명 규칙을 정리할 때 enableServiceLinks: false를 기본 가드로 두고, Service 이름 변경을 배포 체크리스트에 포함해 같은 유형의 장애를 줄이려고 합니다.