Skip to content

ConfigMaps & Secrets: The 12-Factor Way

Trong Kubernetes, việc quản lý cấu hình (Configuration) và dữ liệu nhạy cảm (Secrets) tách biệt khỏi mã nguồn (Code) là một nguyên tắc cốt lõi, tuân thủ chặt chẽ triết lý 12-Factor App. Bài này sẽ đi sâu vào cách xử lý cấu hình chuẩn "Production-Ready".

1. The Problem: Hardcoded Configs

Hãy tưởng tượng bạn có một ứng dụng kết nối Database, và bạn hardcode URL kết nối ngay trong code hoặc Dockerfile:

python
# BAD PRACTICE: Hardcoded Configuration
db_url = "jdbc:postgresql://dev-db:5432/myapp"

Vấn đề: Khi bạn muốn deploy lên môi trường Production (prod-db), bạn buộc phải sửa code và rebuild lại toàn bộ Docker Image.

  • Tốn kém: Tốn thời gian build lại, tốn băng thông đẩy image.
  • Rủi ro: Image ở Dev và Prod không giống hệt nhau (vi phạm nguyên tắc "Build once, deploy anywhere").

👉 Giải pháp: Tách cấu hình ra khỏi Image. Inject chúng vào lúc Runtime.

2. ConfigMap (The Plain Text Store)

ConfigMap là object dùng để lưu trữ dữ liệu cấu hình không nhạy cảm (non-confidential data) dưới dạng key-value.

Cơ chế hoạt động

Bạn có thể inject ConfigMap vào Pod theo 2 cách chính:

  1. Environment Variables: Biến môi trường cho process.
  2. Mounted Volumes: File cấu hình (ví dụ nginx.conf) nằm trong container.

💡 Pro Tip: The subPath Trick

Một vấn đề "kinh điển" của Newbie: Khi mount một ConfigMap làm file config (ví dụ /etc/nginx/nginx.conf), mặc định K8s sẽ ghi đè (overwrite) toàn bộ thư mục target /etc/nginx/. Các file có sẵn khác trong thư mục đó sẽ bị mất.

Để chỉ mount đúng 1 file mà không làm ảnh hưởng các file khác, hãy dùng subPath:

yaml
volumeMounts:
  - name: nginx-config
    mountPath: /etc/nginx/nginx.conf # Đường dẫn đích
    subPath: nginx.conf              # Key trong ConfigMap

3. Secrets (The Sensitive Store)

Secret tương tự ConfigMap nhưng dùng cho dữ liệu nhạy cảm (Passwords, OAuth Tokens, SSH Keys).

CAUTION

Base64 is NOT Encryption! Kubernetes lưu Secret dưới dạng Base64 encoded string. Bất kỳ ai có quyền truy cập vào cụm K8s (hoặc file YAML) đều có thể decode nó dễ dàng (echo "..." | base64 -d).

  • Secret KHÔNG được mã hóa mặc định khi lưu trong etcd (trừ khi bật Encryption at Rest).
  • Tính năng bảo mật chính của Secret là nó được lưu trên RAM (tmpfs) của Worker Node thay vì ghi xuống ổ cứng, giảm nguy cơ bị lộ data khi ổ cứng bị trộm/scan.

HPN Standard: Security First

Tại HPN, chúng ta tuân thủ nghiêm ngặt:

  1. NEVER commit Secrets to Git: Dù là repo private, việc lưu plaintext secret trong Git là lỗ hổng bảo mật nghiêm trọng.
  2. Use Enterprise Solutions:
    • Sealed Secrets (Bitnami): Mã hóa Secret thành SealedSecret (an toàn để commit Git), chỉ Controller trong Cluster mới decrypt được.
    • External Secrets Operator (ESO): Sync secret từ các Vault chuyên dụng (AWS Secrets Manager, HashiCorp Vault) vào K8s.

4. Injection Methods: Env Vars vs Volumes

Làm sao ứng dụng đọc được Config/Secret?

Method A: Environment Variables (Simple)

Thích hợp cho các giá trị đơn lẻ (DB_HOST, API_KEY). Ứng dụng đọc bằng os.environ['DB_HOST'].

yaml
env:
  - name: DB_HOST
    valueFrom:
      configMapKeyRef:
        name: app-config
        key: db_host

Lưu ý: Nếu update ConfigMap, Pod cần restart để nhận ENV mới.

Method B: Volumes (Dynamic Updates - Deep Tech)

Thích hợp cho file config (nginx.conf, settings.json). K8s mount ConfigMap thành file trong Container.

Tính năng mạnh mẽ: Khi bạn update ConfigMap, K8s sẽ tự động update nội dung file trong Container (sau delay khoảng 1-2 phút) mà không cần restart Pod. Ứng dụng cần có cơ chế "watch file change" để reload config (như Nginx reload, hoặc code tự watch).

5. Visual Summary


Next Step: Module 5: Storage & Persistence