동적 구성 관리: ConfigMap을 사용한 실시간 애플리케이션 업데이트
Kubernetes ConfigMap을 마운트된 파일로 사용하여 런타임 구성 업데이트를 수행하는 방법과 전파, subPath, 앱 재로드 동작에 관한 주의 사항을 설명합니다.
동적 구성 관리: ConfigMap을 사용한 실시간 애플리케이션 업데이트
Kubernetes는 애플리케이션 상태 관리를 위한 강력한 메커니즘을 제공하지만, 애플리케이션 설정을 변경하려면 이미지를 다시 빌드하거나 배포 파드를 재시작해야 하는 경우가 많습니다. 많은 마이크로서비스에서 이러한 다운타임이나 중단은 용납될 수 없습니다. 이때 ConfigMap이 매우 유용해집니다. ConfigMap은 기밀 정보가 아닌 구성 데이터를 키-값 쌍으로 저장하도록 설계된 Kubernetes 객체로, 구성을 애플리케이션 코드에서 분리합니다.
ConfigMap은 앱이 파일에서 설정을 읽고 다시 로드할 수 있을 때 동적 구성 관리에 도움이 됩니다. Kubernetes 부분은 설정의 절반에 불과합니다. 마운트된 ConfigMap 파일은 파드가 계속 실행되는 동안 변경될 수 있지만, 환경 변수는 그렇지 않으며, 애플리케이션이 새 값을 인지하고 적용해야 합니다.
ConfigMap 이해: 기본 개념
ConfigMap을 사용하면 구성 데이터를 키와 값의 집합으로 저장할 수 있습니다. Secret과 달리 ConfigMap은 로깅 수준, 외부 서비스 엔드포인트, 기능 플래그와 같은 민감하지 않은 구성 데이터를 대상으로 합니다.
샘플 ConfigMap 생성
구성 데이터는 YAML 매니페스트 내에서 직접 정의하거나 기존 파일이나 디렉터리에서 생성할 수 있습니다. 애플리케이션별 매개변수를 포함하는 app-settings라는 ConfigMap을 만들어 보겠습니다.
예: YAML로 ConfigMap 정의
apiVersion: v1
kind: ConfigMap
metadata:
name: app-settings
data:
# 키-값 쌍
LOG_LEVEL: "INFO"
API_ENDPOINT: "https://api.default.svc.cluster.local"
# 여러 줄 구성 파일 내용
application.properties: |
server.port=8080
feature.toggle.new_ui=false
이 ConfigMap은 세 가지 데이터를 제공합니다. 두 개의 간단한 키-값 쌍과 구성 파일을 시뮬레이션하는 하나의 복잡한 항목(application.properties)입니다.
파드에 구성 주입
ConfigMap은 환경 변수를 채울 수 있지만, 동적 업데이트의 핵심은 파드의 파일 시스템에 볼륨으로 마운트하는 데 있습니다. 볼륨으로 마운트되면 Kubernetes는 ConfigMap의 각 키를 지정된 디렉터리 내의 파일로 취급합니다.
방법 1: 볼륨 마운트 사용 (동적 접근 방식)
동적 업데이트를 위해 ConfigMap을 파드 사양에 마운트합니다.
예: ConfigMap 볼륨 마운트가 있는 파드 사양
apiVersion: v1
kind: Pod
metadata:
name: dynamic-app-pod
spec:
containers:
- name: my-app
image: my-registry/my-app:latest
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-settings
이 설정에서:
app-settingsConfigMap은config-volume이라는 볼륨에 연결됩니다.- 볼륨은 컨테이너 내부의
/etc/config에 마운트됩니다. - Kubernetes는 ConfigMap의 키에 해당하는 파일을
/etc/config내에 자동으로 생성합니다./etc/config/LOG_LEVEL파일에는INFO값이 포함됩니다./etc/config/application.properties파일에는 여러 줄 구성이 포함됩니다.
방법 2: 환경 변수 사용 (정적 접근 방식)
더 간단한 정적 값의 경우 환경 변수로 주입할 수 있습니다. 참고: 이렇게 채워진 환경 변수는 ConfigMap이 변경될 때 자동으로 업데이트되지 않으며, 파드를 다시 시작해야 합니다.
# Deployment 사양의 일부
containers:
- name: my-app
image: my-registry/my-app:latest
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-settings
key: LOG_LEVEL
모범 사례: 동적 업데이트를 위해서는 항상 구성 파일에 볼륨 마운트를 사용하세요.
실시간 업데이트 달성: 변경 사항 감시
ConfigMap이 업데이트되면 Kubernetes는 결국 이를 볼륨으로 마운트하는 파드에 변경 사항을 전파합니다. 정확한 타이밍은 kubelet 동기화 동작, 캐시 동작, 노드 부하에 따라 달라지므로 즉각적인 제어 플레인 푸시가 아닌 최종적 전파로 간주하세요.
Kubelet이 업데이트를 전파하는 방법
볼륨으로 사용되는 ConfigMap이 수정되면:
- kubelet은 동기화 주기 동안 주기적으로 업데이트를 확인하며 로컬 캐시에서 데이터를 제공할 수 있습니다.
- 업데이트가 감지되면 Kubelet은 호스트 파일 시스템의 마운트된 파일을 업데이트합니다.
- 실행 중인 컨테이너의 경우 ConfigMap 볼륨 내의 파일은 Kubernetes의 프로젝티드 볼륨 메커니즘을 통해 새로 고쳐집니다.
한 가지 일반적인 예외가 있습니다. subPath로 단일 ConfigMap 키를 마운트하면 ConfigMap이 변경될 때 해당 마운트된 파일이 업데이트되지 않습니다. 런타임 업데이트가 필요한 경우 일반 ConfigMap 볼륨 마운트를 사용하세요.
애플리케이션 측 감지
중요한 단계는 컨테이너 내에서 실행 중인 애플리케이션 코드가 이러한 파일 변경을 감지하고 대응하도록 설계되어야 한다는 것입니다.
예: 파일 감시를 위한 애플리케이션 로직 (개념적 Python)
대부분의 최신 애플리케이션은 내부 메커니즘이나 라이브러리를 사용하여 파일 시스템 이벤트(예: Linux의 inotify)를 감시합니다.
import time
import os
CONFIG_PATH = "/etc/config/application.properties"
def load_config(path):
# 파일 내용을 읽고 구문 분석하는 함수
with open(path, 'r') as f:
print(f"\n--- 구성 다시 로드됨 ---\n{f.read()}")
# 새 설정을 사용하여 서비스를 다시 초기화하는 로직
# 초기 로드
load_config(CONFIG_PATH)
# 지속적인 모니터링 루프
last_modified = os.path.getmtime(CONFIG_PATH)
while True:
current_modified = os.path.getmtime(CONFIG_PATH)
if current_modified != last_modified:
print("파일 변경 감지. 구성 다시 로드 중...")
load_config(CONFIG_PATH)
last_modified = current_modified
time.sleep(5) # 5초마다 확인
이 예제는 파일 수정 시간(mtime)을 폴링하는 방법을 보여줍니다. Kubelet이 파일을 업데이트하면 애플리케이션이 변경을 감지하고 구성을 동적으로 다시 로드할 수 있습니다.
파일 감시자 주의: ConfigMap 볼륨 업데이트는 마운트된 디렉터리 아래의 심볼릭 링크 대상을 대체할 수 있습니다. 감시자가 열린 파일 핸들 하나만 따르는 경우 업데이트를 놓칠 수 있습니다. 즉각적인 다시 로드보다 안정성이 더 중요하다면 디렉터리를 감시하거나 파일 내용을 폴링하세요.
동적 업데이트 워크플로: 단계별 예제
실행 중인 파드를 건드리지 않고 LOG_LEVEL을 INFO에서 DEBUG로 업데이트하는 과정을 살펴보겠습니다.
1단계: 초기 상태
파드가 실행 중이고 볼륨 마운트를 통해 ConfigMap을 사용하고 있는지 확인합니다.
2단계: ConfigMap 업데이트
kubectl edit 또는 kubectl apply를 사용하여 기존 ConfigMap을 수정합니다.
# kubectl edit를 사용하여 값을 직접 변경
kubectl edit configmap app-settings
# 다음 줄을 찾아 변경:
# LOG_LEVEL: "INFO"
# 다음으로 변경:
LOG_LEVEL: "DEBUG"
3단계: 전파 모니터링
kubelet이 변경 사항을 전파할 때까지 기다립니다. 일부 클러스터에서는 몇 초 이상 걸릴 수 있습니다.
애플리케이션이 /etc/config/LOG_LEVEL을 감시하고 있는 경우:
- Kubelet이 기본 파일을 업데이트합니다.
- 애플리케이션이 감시 메커니즘에 따라 변경을 감지합니다.
- 애플리케이션이 내부 로깅 구성을
DEBUG로 다시 로드합니다.
중요한 점은 파드 자체는 변경되지 않아 서비스 중단이 전혀 발생하지 않는다는 것입니다.
구성 관리 요약 및 고려 사항
볼륨 마운트와 함께 ConfigMap을 사용하는 것은 Kubernetes에서 동적 구성 업데이트를 달성하는 표준 방법입니다. 그러나 다음 사항을 염두에 두세요:
- 보안: ConfigMap은 데이터를 일반 텍스트로 저장합니다. 민감한 정보에는 Secret을 사용하세요.
- 불변성: 중요한 구성의 경우 생성 후 ConfigMap을 불변(
immutable: true)으로 만들어 실수로 런타임에 변경되는 것을 방지하는 것을 고려하세요. - 애플리케이션 인식: 동적 업데이트는 실행 중인 컨테이너가 구성 파일을 감시하고 다시 로드하는 방법을 알고 있는 경우에만 가능합니다.
- 롤백: 구성 변경을 롤백하려면 ConfigMap을 이전 상태로 업데이트하고 애플리케이션이 감지할 때까지 기다려야 합니다.
구성을 배포 아티팩트에서 분리하고 볼륨 마운트를 활용하면 Kubernetes 워크로드에서 강력하고 무중단 구성 매개변수 업데이트가 가능합니다.