K8s 파드 환경에 노드 이름(NodeName) 주입
1. 컨테이너 격리의 한계: 자신이 실행된 호스트를 모름
과거 에서 쿠버네티스(K8s) 위에서 동작하는 분산 추적 시스템(Distributed Tracing) 및 APM(Application Performance Monitoring) 에이전트를 개발하고 배포할 당시 부딪힌 문제였습니다.
우리가 흔히 아는 물리 서버 환경에서는 애플리케이션 안에서 hostname 명령어 한 줄이면 자신이 떠 있는 서버의 이름을 알 수 있습니다. 하지만 컨테이너 베이스로 띄워진 파드(Pod) 내부의 프로세스들은 K8s가 쳐놓은 고립된 uts namespace 안에 갇혀 있어서, 자신이 물리적으로 수십 개의 워커 노드(Node) 중 어느 장비에서 실행 중인지 알 방법이 없었습니다.
모니터링 데이터나 로그를 중앙 서버로 쏠 때 어느 노드에서 발생한 데이터인지 식별표(Tag)가 없으면 인프라 전체의 토폴로지 맵(Topology Map)을 그릴 수 없었기 때문에, 파드 스스로 호스트 노드명을 알아내어 환경 변수 캐시에 담아두는 기능이 매우 절실했습니다.
2. 해결책: Downward API와 메타데이터 주입
쿠버네티스는 자체적인 시스템 메타데이터를 파드 내부 파일 시스템이나 환경 변수로 꽂아 넣어주는 기능인 Downward API를 제공합니다.
단어 뜻 그대로, 상위 계층인 쿠버네티스 시스템(Control Plane)이 가지고 있는 파드 및 클러스터의 정보를 하위 계층인 파드 내부의 컨테이너(Downward)로 내려주는(Inject) 역할을 합니다. 시스템 엔지니어가 애플리케이션 코드를 뜯어고칠 필요 없이, 배포용 매니페스트(YAML) 선언 한 줄만으로 동적 정보를 컨테이너 프로세스에 환경 변수(Environment Variable) 형태로 깔끔하게 전달할 수 있습니다.
Downward API를 통해 노드 이름(spec.nodeName)뿐만 아니라 파드의 IP(status.podIP), 네임스페이스(metadata.namespace), 파드 이름(metadata.name) 등 다양한 정보를 넘겨줄 수 있습니다.
3. 매니페스트 fieldRef 설정 및 구현
파드의 컨테이너 env 설정 시 기존의 단순 value: "my-value" 형식이 아닌, valueFrom.fieldRef 스펙을 사용하여 파드가 배포된 시점의 K8s 정보를 동적으로 끌어옵니다.
실제 적용 예시 (YAML)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-monitoring-agent
spec:
replicas: 3
selector:
matchLabels:
app: monitoring-agent
template:
metadata:
labels:
app: monitoring-agent
spec:
containers:
- name: agent-container
image: my-company/metrics-agent:latest
env:
# 1. 호스트 노드 이름 주입 (핵심)
- name: MY_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
# 2. 파드 자신의 이름 주입
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
# 3. 파드의 내부 IP 주입
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
# 4. 배포된 네임스페이스 주입
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace위와 같이 배포하면, agent-container 내부에서 동작하는 Node.js 앱이라면 process.env.MY_NODE_NAME, Java 스프링 앱이라면 System.getenv("MY_NODE_NAME") 코드로 자신이 떠 있는 부모 물리/가상 서버의 호스트명(예: worker-node-03)을 런타임에 손쉽게 획득할 수 있습니다.
4. 결론 및 회고
이 단순하고 강력한 Downward API 체계를 도입한 덕분에, 저희 사내 시스템의 메트릭 수집 모듈의 백엔드 소스코드 자체에는 단 한 줄의 인프라 종속성 코드도 넣지 않았습니다.
오직 인프라 배포 계층(K8s YAML)의 수정만으로 애플리케이션 코어 로직에 컨텍스트를 성공적으로 주입(Dependency Injection)하여, 개발 영역과 인프라 운영 영역을 완벽하게 분리(Decoupling)하는 유의미한 성과를 거두었습니다. 인프라 정보가 필요한 애플리케이션(예: 분산 로깅, 서비스 디스커버리, 클러스터링 기반 솔루션)을 컨테이너라이징 할 때 가장 먼저 숙지해야 할 필수 지식입니다.