상세 컨텐츠

본문 제목

Kubernetes ConfigMap, Secret, Ingress 제대로 이해하기 — 앱이 뜨는 것과 운영 가능한 것은 다르다

AI DevOps

by thisnorm 2026. 4. 27. 18:00

본문

Pod가 Running 상태라고 해서 운영 가능한 상태는 아닙니다. 진짜 운영 가능한 애플리케이션은 환경별 설정이 분리되어 있고, 민감 정보가 코드 밖에서 관리되며, 외부 트래픽 진입 경로가 설계되어 있어야 합니다. 이번 글에서는 그 세 가지를 담당하는 ConfigMap, Secret, Ingress를 정리합니다.

왜 하드코딩이 문제인가

코드에 설정값을 직접 박아 넣으면 두 가지 문제가 생깁니다.

보안 관점

  • Git 저장소에 비밀번호가 노출됩니다
  • Docker 이미지 레이어에 값이 남습니다
  • 팀원 누구나 접근할 수 있는 정보가 됩니다

운영 관점

  • 설정 하나 바꾸려면 전체 재빌드가 필요합니다
  • 개발/운영 환경 분기가 코드 레벨에서 생깁니다
  • 같은 이미지를 여러 환경에 재사용할 수 없습니다

12-Factor App 원칙: 설정은 환경에서 주입하고, 코드와 분리해야 합니다.

ConfigMap vs Secret — 무엇이 다른가

기준은 하나입니다. "이 값이 공개되면 보안 사고가 나는가?"

종류 용도 예시
ConfigMap 노출되어도 큰 문제 없는 비민감 설정 APP_ENV, LOG_LEVEL, PUBLIC_API_URL
Secret 절대 노출되면 안 되는 민감 설정 DB_PASSWORD, API_KEY, JWT_SECRET

ConfigMap 사용법

YAML 구조

apiVersion: v1
kind: ConfigMap
metadata:
  name: team-board-config
  namespace: default
data:
  APP_ENV: "production"
  LOG_LEVEL: "info"

핵심: data 필드에 키-값 쌍을 정의합니다. 모든 값은 문자열로 저장되므로 숫자도 따옴표로 감쌉니다.

주입 방식 — 환경변수 vs 파일 마운트

방식 언제 쓰나 특징
envFrom / env process.env, os.getenv()로 읽을 때 Pod 재시작 시에만 새 값 반영
volume 마운트 nginx.conf처럼 파일 형태가 필요할 때 ConfigMap 변경 시 파일 자동 갱신

적용 확인 방법

kubectl get configmap team-board-config
kubectl describe configmap team-board-config
kubectl exec -it [pod-name] -- env | grep APP_ENV
kubectl rollout restart deployment/team-board-app

자주 하는 실수

  • 키 이름 오타: configMapKeyRef.key가 data의 키와 정확히 일치해야 합니다
  • 이름 오타: Pod가 CreateContainerConfigError 상태가 되면 kubectl get configmap으로 확인합니다
  • 민감 정보를 ConfigMap에 저장: 비밀번호는 반드시 Secret으로 분리합니다

Secret — base64는 암호화가 아니다

Secret의 data 필드 값이 알 수 없는 문자로 보여서 암호화된 것으로 오해하기 쉽습니다.

cGFzc3dvcmQ= 이건 password를 base64로 인코딩한 것입니다. 누구나 즉시 복호화할 수 있습니다.

echo "cGFzc3dvcmQ=" | base64 -d  # → password

Secret이 안전한 이유는 base64가 아니라, etcd 암호화 설정, RBAC 접근 제어, 네트워크 격리 때문입니다.

YAML 구조 — stringData 방식 권장

apiVersion: v1
kind: Secret
metadata:
  name: team-board-db-secret
  namespace: default
type: Opaque
stringData:
  DB_HOST: "postgres-service"
  DB_USER: "boarduser"
  DB_PASSWORD: "s3cur3P@ss!"
  DB_NAME: "teamboard"

stringData는 평문으로 입력하면 Kubernetes가 자동으로 base64로 저장합니다. 단, 이 파일을 Git에 올리면 절대 안 됩니다.

Ingress — Service만으로 충분한가

Service만 쓰면 서비스마다 별도 포트(30001, 30002…)가 필요하고 도메인 기반 라우팅이 불가능합니다. Ingress를 추가하면 하나의 진입점(80/443)으로 통합할 수 있습니다.

host 기반 vs path 기반 라우팅

방식 사용 시점 예시
host 기반 서브도메인으로 서비스를 나눌 때 app.example.com → team-board-service
path 기반 하나의 도메인 아래 여러 서비스를 운영할 때 example.com/api → api-service

Ingress YAML 구조

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: team-board-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: team-board.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 8080

Ingress Controller를 별도로 설치해야 합니다

Ingress 리소스는 라우팅 규칙을 선언하는 설계도일 뿐입니다. 실제로 동작하려면 Controller가 필요합니다.

# minikube 환경
minikube addons enable ingress

운영 환경에서는 nginx-ingress-controller, Traefik, AWS ALB Ingress Controller 중 환경에 맞는 것을 선택합니다.

정리

리소스 역할
ConfigMap 비민감 설정을 이미지 밖으로 분리, 재빌드 없이 설정 변경 가능
Secret 민감 정보 보호, base64 인코딩(암호화 아님) + RBAC으로 접근 제어
Ingress 외부 트래픽 단일 진입점, host/path 기반 라우팅, TLS 한 곳에서 관리

설정 분리는 단순한 코드 정리가 아닙니다. 동일한 이미지를 여러 환경에 재사용하고, 민감 정보를 코드 바깥에서 관리하고, 외부 트래픽 흐름을 선언적으로 설계하는 것이 운영 가능한 애플리케이션의 기준입니다.

반응형

관련글 더보기