Secret 을 사용한 애플리케이션 구성

KubernetesBeginner
지금 연습하기

소개

애플리케이션은 비밀번호, 토큰, 데이터베이스 자격 증명과 같이 컨테이너 이미지나 일반 매니페스트에 직접 포함해서는 안 되는 값을 필요로 하는 경우가 많습니다. Kubernetes Secret 은 이러한 민감한 구성 정보를 별도의 객체로 저장하며, Pod 가 시작될 때 이를 가져와 사용할 수 있도록 합니다.

이번 실습에서는 Secret 을 생성하고, 인코딩된 데이터를 주의 깊게 확인한 다음, 이를 애플리케이션 Pod 에 연결하고, Secret 을 업데이트한 후 Pod 를 재생성하여 애플리케이션이 새로운 값을 읽어오도록 할 것입니다. 이 실습은 Secret 의 핵심 워크플로우에 중점을 둡니다. 이후 실습에서는 환경 변수 연결 및 파일 기반 구성 마운트에 대해 더 자세히 다룰 예정입니다.

Secret 실습을 위한 네임스페이스 준비

이 단계에서는 Secret 실습을 위한 깨끗한 네임스페이스를 준비합니다.

/home/labex/project 디렉토리에서 시작합니다. 이 디렉토리에 하나의 Pod 매니페스트를 작성하게 됩니다.

mkdir -p /home/labex/project
cd /home/labex/project

Kubernetes API 서버에 접근 가능한지 확인합니다. VM 이 막 시작되어 노드가 아직 준비되지 않았다면, 몇 초 기다린 후 명령어를 다시 실행하세요.

kubectl get nodes --request-timeout=5s

예상 출력:

NAME         STATUS   ROLES           AGE   VERSION
labex-v135   Ready    control-plane   ...   v1.35...

애플리케이션 객체를 생성하기 전에 클러스터 네트워킹 Pod 가 준비 (Ready) 상태가 될 때까지 기다립니다.

kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s

예상 출력:

pod/calico-node-... condition met

ckad-prep-secrets라는 이름의 네임스페이스를 생성합니다.

kubectl create namespace ckad-prep-secrets

이 네임스페이스를 현재 컨텍스트의 네임스페이스로 설정합니다.

kubectl config set-context --current --namespace=ckad-prep-secrets

현재 네임스페이스를 확인합니다.

kubectl config view --minify --output 'jsonpath={..namespace}'; echo

예상 출력:

ckad-prep-secrets

Secret 생성 및 확인

이 단계에서는 소규모 애플리케이션을 위한 데이터베이스 연결 설정을 저장하는 Secret 을 생성합니다.

kubectl create secret generic 명령어는 일반 (opaque) Secret 을 생성합니다. generic은 Kubernetes 가 키에 특별한 내장 의미를 부여하지 않음을 의미합니다. 각 --from-literal 플래그는 Secret 에 하나의 키 - 값 쌍을 추가합니다.

kubectl create secret generic db-credentials \
  --from-literal=DB_USER=orders-app \
  --from-literal=DB_PASSWORD=dev-password-123 \
  --from-literal=DB_NAME=orders

예상 출력:

secret/db-credentials created

Secret 요약을 확인합니다.

kubectl get secret db-credentials

예상 출력:

NAME             TYPE     DATA   AGE
db-credentials   Opaque   3      ...

Secret 을 YAML 형식으로 확인합니다. Kubernetes 는 data 아래의 값을 base64 로 인코딩된 문자열로 저장하므로, 이 출력에서 원래의 비밀번호를 볼 수는 없습니다.

kubectl get secret db-credentials -o yaml

예상 출력:

data:
  DB_NAME: b3JkZXJz
  DB_PASSWORD: ...
  DB_USER: b3JkZXJzLWFwcA==
type: Opaque

Base64 인코딩은 암호화가 아닙니다. Secret 객체를 읽을 수 있는 사람은 누구나 그 값을 디코딩할 수 있습니다. 여기서는 비밀번호를 출력하지 않고 표현 방식이 어떻게 작동하는지 확인하기 위해 사용자 이름만 디코딩해 봅니다.

kubectl get secret db-credentials -o 'jsonpath={.data.DB_USER}' | base64 --decode; echo

예상 출력:

orders-app

Secret 을 사용하여 Pod 구성

이 단계에서는 Secret 을 환경 변수로 읽어오는 Pod 를 시작합니다.

envFrom.secretRef 필드는 Secret 의 모든 키를 컨테이너 환경으로 가져옵니다. 이는 이전 실습의 ConfigMap 패턴과 유사하지만, 값은 Secret 객체에서 가져옵니다. 이 Pod 의 명령어는 사용자 이름과 데이터베이스 이름을 출력하고, 비밀번호가 로드되었는지 여부만 확인합니다. 비밀번호 자체를 출력하지는 않습니다.

secret-reader-pod.yaml을 생성합니다.

cat > secret-reader-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: secret-reader
  labels:
    app: secret-reader
spec:
  terminationGracePeriodSeconds: 0
  containers:
  - name: reader
    image: busybox:1.36
    command:
    - /bin/sh
    - -c
    - 'echo user=${DB_USER}; echo database=${DB_NAME}; if [ -n "${DB_PASSWORD}" ]; then echo password-loaded; fi; sleep 3600'
    envFrom:
    - secretRef:
        name: db-credentials
EOF

Pod 매니페스트를 적용합니다.

kubectl apply -f secret-reader-pod.yaml

예상 출력:

pod/secret-reader created

Pod 가 준비 (Ready) 상태가 될 때까지 기다립니다.

kubectl wait --for=condition=Ready pod/secret-reader --timeout=120s

예상 출력:

pod/secret-reader condition met

Pod 로그를 읽습니다. 애플리케이션은 Secret 값이 사용 가능함을 확인하지만, 비밀번호 값은 표시되지 않습니다.

kubectl logs secret-reader -c reader

예상 출력:

user=orders-app
database=orders
password-loaded

Secret 업데이트 및 Pod 재생성

이 단계에서는 Secret 을 업데이트하고 Pod 를 재생성하여 컨테이너가 새로운 값을 받도록 합니다.

컨테이너 환경은 컨테이너가 시작될 때 캡처됩니다. Secret 이 환경 변수로 사용되는 경우, Secret 객체를 업데이트해도 이미 실행 중인 컨테이너 내부의 환경 변수는 다시 작성되지 않습니다. 애플리케이션이 업데이트된 Secret 값을 읽어야 할 때는 새로운 Pod 를 시작해야 합니다.

새로운 애플리케이션 사용자 및 비밀번호로 Secret 을 패치합니다.

kubectl patch secret db-credentials --type merge --patch '{"stringData":{"DB_USER":"orders-worker","DB_PASSWORD":"rotated-password-456","DB_NAME":"orders"}}'

예상 출력:

secret/db-credentials patched

DB_USER만 디코딩하여 업데이트된 사용자 이름을 확인합니다.

kubectl get secret db-credentials -o 'jsonpath={.data.DB_USER}' | base64 --decode; echo

예상 출력:

orders-worker

이전 Pod 를 삭제합니다.

kubectl delete pod secret-reader

예상 출력:

pod "secret-reader" deleted

동일한 매니페스트로 Pod 를 재생성하고 준비 상태가 될 때까지 기다립니다.

kubectl apply -f secret-reader-pod.yaml
kubectl wait --for=condition=Ready pod/secret-reader --timeout=120s

예상 출력:

pod/secret-reader created
pod/secret-reader condition met

로그를 다시 읽습니다. 이제 새로운 Pod 는 Secret 에서 업데이트된 사용자 정보를 확인하며, 여전히 원본 비밀번호를 출력하지 않습니다.

kubectl logs secret-reader -c reader

예상 출력:

user=orders-worker
database=orders
password-loaded

요약

Kubernetes Secret 을 생성하고, 인코딩된 데이터를 확인하고, 표현 방식을 이해하기 위해 민감하지 않은 키를 디코딩해 보았으며, Secret 을 애플리케이션 Pod 에 연결하고, Secret 업데이트 후 Pod 를 재생성하는 과정을 실습했습니다. 또한 민감한 구성을 다룰 때 중요한 습관인 '비밀번호 값을 로그에 출력하지 않고 애플리케이션이 비밀번호를 정상적으로 수신했는지 확인하는 방법'을 익혔습니다.