Skip to content

Cấu hình

Tổng quan

Cấu hình di chuyển từ file .env của Docker Compose sang Kubernetes ConfigMap và Secret. Trên staging, secrets được tạo thủ công qua create-secrets.sh. Trên production, Sealed Secrets cung cấp mã hóa an toàn để lưu trong Git.

Tổ chức ConfigMap

Mỗi service có ConfigMap riêng với cấu hình không nhạy cảm. ConfigMap được tổ chức theo từng overlay (staging vs production) qua Kustomize.

ConfigMap Dùng chung

Các giá trị được chia sẻ qua tất cả backend service. Lưu ý khác biệt namespace cho service discovery và truy cập tầng dữ liệu.

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nx-shared-config
  namespace: nx-backend
data:
  NODE_ENV: staging

  # PostgreSQL via PgBouncer — nx-persistent namespace
  APP_ENV_POSTGRES_HOST: nx-pgbouncer.nx-persistent.svc.cluster.local
  APP_ENV_POSTGRES_PORT: "5432"
  APP_ENV_POSTGRES_USERNAME: nx_seller_operator
  APP_ENV_POSTGRES_DATABASE: nx_seller_core

  # Redis — cluster mode, 3 nodes (nx-broker namespace)
  APP_ENV_CACHE_REDIS_MODE: cluster
  APP_ENV_CACHE_REDIS_CLUSTER_NODES: "nx-redis-0.nx-redis-headless.nx-broker.svc.cluster.local:6379,nx-redis-1.nx-redis-headless.nx-broker.svc.cluster.local:6379,nx-redis-2.nx-redis-headless.nx-broker.svc.cluster.local:6379"

  # Kafka — CLIENT listener with SASL/SCRAM-SHA-512 (nx-broker namespace)
  APP_ENV_KAFKA_BROKERS: nx-kafka-0.nx-kafka-headless.nx-broker.svc.cluster.local:9092,nx-kafka-1.nx-kafka-headless.nx-broker.svc.cluster.local:9092,nx-kafka-2.nx-kafka-headless.nx-broker.svc.cluster.local:9092
  APP_ENV_KAFKA_SASL_ENABLE: "true"
  APP_ENV_KAFKA_SASL_MECHANISM: SCRAM-SHA-512
  APP_ENV_KAFKA_SASL_USERNAME: nx.staging
  # APP_ENV_KAFKA_SASL_PASSWORD is in nx-shared-secret

  # Service discovery — nx-backend namespace
  APP_ENV_IDENTITY_SERVICE_BASE_URL: http://nx-identity.nx-backend.svc.cluster.local:3000/v1/api/identity
  APP_ENV_COMMERCE_SERVICE_BASE_URL: http://nx-commerce.nx-backend.svc.cluster.local:3000/v1/api/commerce
  APP_ENV_PRICING_SERVICE_BASE_URL: http://nx-pricing.nx-backend.svc.cluster.local:3000/v1/api/pricing

  # Domains — staging
  APP_DOMAIN: sgw.staging.bana.com.vn
  HOOK_DOMAIN: hook.staging.bana.com.vn
yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nx-shared-config
  namespace: nx-backend
data:
  NODE_ENV: production
  LOG_LEVEL: info

  # Database — nx-persistent namespace
  DB_HOST: nx-postgresql.nx-persistent.svc.cluster.local
  DB_PORT: "5432"
  DB_NAME: nx_seller

  # Redis — nx-broker namespace
  REDIS_HOST: nx-redis.nx-broker.svc.cluster.local
  REDIS_PORT: "6379"

  # Kafka — nx-broker headless service DNS
  KAFKA_BROKERS: nx-kafka-0.nx-kafka-headless.nx-broker.svc.cluster.local:29092,nx-kafka-1.nx-kafka-headless.nx-broker.svc.cluster.local:29092,nx-kafka-2.nx-kafka-headless.nx-broker.svc.cluster.local:29092

  # Typesense — nx-search namespace
  TYPESENSE_HOST: nx-typesense.nx-search.svc.cluster.local
  TYPESENSE_PORT: "8108"

  # Service discovery — nx-backend namespace
  IDENTITY_URL: http://nx-identity.nx-backend.svc.cluster.local:3000
  COMMERCE_URL: http://nx-commerce.nx-backend.svc.cluster.local:3000
  SALE_URL: http://nx-sale.nx-backend.svc.cluster.local:3000
  SIGNAL_URL: http://nx-signal.nx-backend.svc.cluster.local:3000
  PAYMENT_URL: http://nx-payment-api.nx-backend.svc.cluster.local:3000

  # Domains — production (TBD)
  APP_DOMAIN: TBD
  HOOK_DOMAIN: TBD

  # OpenTelemetry — production only
  OTEL_EXPORTER_OTLP_ENDPOINT: http://nx-otel-collector.nx-watcher.svc.cluster.local:4317
  OTEL_SERVICE_NAME: bana

Khác biệt ConfigMap Staging vs Production

KeyStagingProduction
NODE_ENVstagingproduction
APP_ENV_POSTGRES_HOSTnx-pgbouncer.nx-persistent... (PgBouncer)nx-pgbouncer.nx-persistent... (PgBouncer)
APP_ENV_CACHE_REDIS_MODEclustercluster
APP_ENV_KAFKA_SASL_USERNAMEnx.stagingnx.production
APP_DOMAINsgw.staging.bana.com.vnTBD
HOOK_DOMAINhook.staging.bana.com.vnTBD
OTEL_EXPORTER_OTLP_ENDPOINTChưa đặthttp://nx-otel-collector.nx-watcher.svc.cluster.local:4317

TIP

Các URL service discovery (IDENTITY_URL, COMMERCE_URL, v.v.) giống nhau ở mọi môi trường vì chúng dùng DNS nội bộ cluster trong nx-backend. Chỉ các domain public-facing khác nhau.

ConfigMap theo Service

identity-specific config
yaml
# identity-specific config
apiVersion: v1
kind: ConfigMap
metadata:
  name: nx-identity-config
  namespace: nx-backend
data:
  APP_NAME: identity
  APP_PORT: "3000"
  APP_BASE_PATH: /v1/api/identity
  APP_ROLE: issuer
  # JWKS settings
  JWKS_ROTATION_INTERVAL: "86400"
  TOKEN_ACCESS_EXPIRY: "3600"
  TOKEN_REFRESH_EXPIRY: "604800"
payment-api specific config
yaml
# payment-api specific config
apiVersion: v1
kind: ConfigMap
metadata:
  name: nx-payment-api-config
  namespace: nx-backend
data:
  APP_NAME: payment
  APP_PORT: "3000"
  APP_BASE_PATH: /v1/api/payment
  APP_MODE: api
payment-worker specific config
yaml
# payment-worker specific config
apiVersion: v1
kind: ConfigMap
metadata:
  name: nx-payment-worker-config
  namespace: nx-backend
data:
  APP_NAME: payment
  APP_ENV_MQ_PAY_MODE: worker

Ánh xạ DNS từ Docker Compose sang K8s

Docker Compose (.env)K8s ConfigMapGhi chú
DB_HOST=nx-postgresqlAPP_ENV_POSTGRES_HOST=nx-pgbouncer.nx-persistent.svc.cluster.localPgBouncer pooler, cross-namespace cần FQDN
REDIS_HOST=nx-redisAPP_ENV_CACHE_REDIS_CLUSTER_NODES=nx-redis-{0,1,2}.nx-redis-headless.nx-broker...Cluster mode, 3 pod StatefulSet trong nx-broker
KAFKA_BROKERS=nx-kafka-1:29092,...APP_ENV_KAFKA_BROKERS=nx-kafka-0.nx-kafka-headless.nx-broker...:9092,...CLIENT listener port 9092 với SASL trong nx-broker
IDENTITY_URL=http://dev-nx-identity:3000APP_ENV_IDENTITY_SERVICE_BASE_URL=http://nx-identity.nx-backend.svc.cluster.local:3000/v1/api/identityCùng namespace (nx-backend), dạng ngắn cũng được

TIP

Trong cùng một namespace, tên DNS ngắn hoạt động: nx-identity:3000. Cross-namespace cần dạng đầy đủ \<svc\>.\<ns\>.svc.cluster.local. Tất cả backend service đều ở nx-backend; frontend service nằm ở nx-app. Các data service được chia qua nx-persistent, nx-broker, và nx-search.

Quản lý Secrets

Staging: Tạo Thủ công qua create-secrets.sh

Trên staging, secrets được tạo thủ công bằng script create-secrets.sh trong infrastructure/deployments/staging/manifests/02-secrets/. File YAML template định nghĩa cấu trúc; script hỏi giá trị thực và tạo K8s secret trực tiếp.

bash
# Run from the staging manifests directory
cd infrastructure/deployments/staging/manifests/02-secrets/
./create-secrets.sh

Production: Sealed Secrets

Sealed Secrets mã hóa secrets phía client để có thể lưu trong Git (chỉ production).

Workflow (Production)

bash
# 1. Create a regular secret YAML (DO NOT commit this)
cat <<EOF > secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: nx-identity-secret
  namespace: nx-backend
type: Opaque
stringData:
  DB_PASSWORD: "actual-password"
  JWT_SECRET: "actual-jwt-secret"
  JWKS_PRIVATE_KEY: "actual-private-key"
EOF

# 2. Seal it (encrypts with cluster's public key)
kubeseal --format yaml < secret.yaml > sealed-secret.yaml

# 3. Commit the sealed version
git add sealed-secret.yaml
rm secret.yaml  # Never commit the plain version

Tổ chức Secret

SecretNamespaceNội dung
nx-shared-secretnx-backendAPP_ENV_POSTGRES_PASSWORD, APP_ENV_CACHE_REDIS_PASSWORD, APP_ENV_KAFKA_SASL_PASSWORD
nx-identity-secretnx-backendES256 keys, mail credentials, SMS API keys
nx-payment-secretnx-backendPayment DB & Redis credentials
nx-commerce-secretnx-backendS3 credentials, VNPAY TVAN API key, Typesense key
nx-sale-secretnx-backendBasic auth credentials
nx-ledger-secretnx-backendEncryption key, S3 credentials
nx-postgresql-superuser-secretnx-persistentPostgres superuser credentials
nx-postgresql-app-secretnx-persistentApp user (nx_seller_operator) credentials
nx-postgresql-replication-secretnx-persistentStreaming replication credentials
nx-redis-secretnx-brokerREDIS_PASSWORD
nx-kafka-jaasnx-brokerCấu hình JAAS Kafka SASL/SCRAM
nx-kafka-scram-secretnx-brokerSCRAM username/password
nx-typesense-secretnx-searchTYPESENSE_API_KEY
staging-bana-tlsnx-internalTLS cert và key
bcr-registrynx-backend / nx-app / nx-internalContainer registry pull credentials

INFO

bcr-registryimagePullSecret cần thiết để pull image từ private registry bcr.bana.com.vn. Nó phải được tạo trong nx-backend, nx-app, và nx-internal và được tham chiếu trong tất cả Deployment spec hoặc ServiceAccount mặc định của namespace.

Cấu hình Pod

Pod tham chiếu cả config dùng chung và config theo service:

Pods reference both shared and service-specific configs:
yaml
spec:
  imagePullSecrets:
    - name: bcr-registry
  containers:
    - name: identity
      envFrom:
        # Shared config (DB_HOST, REDIS_HOST, etc.)
        - configMapRef:
            name: nx-shared-config
        # Service-specific config
        - configMapRef:
            name: nx-identity-config
        # Shared secrets (DB_PASSWORD, REDIS_PASSWORD)
        - secretRef:
            name: nx-shared-secret
        # Service-specific secrets
        - secretRef:
            name: nx-identity-secret
      env:
        # Downward API for Snowflake ID
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name

Phân cấp Cấu hình

Pod Environment
├── nx-shared-config      (ConfigMap) — shared across all services
├── nx-<service>-config   (ConfigMap) — service-specific overrides
├── nx-shared-secret      (Secret)    — shared credentials
└── nx-<service>-secret   (Secret)    — service-specific credentials

Các entry sau override entry trước khi key trùng. Điều này cho phép:

  • nx-shared-config đặt DB_HOST cho tất cả service
  • nx-identity-config có thể override bất kỳ key dùng chung nào nếu cần

Tham khảo Namespace

NamespaceMục đíchPhạm vi ConfigMap/Secret
nx-internalnginx-ingress, Traefik, cert-manager, API PortalTLS certs, cấu hình gateway, registry creds
nx-backendBackend servicesBackend configs, backend secrets, registry creds
nx-appFrontend appsFrontend configs, registry creds
nx-persistentPostgreSQLDatabase credentials
nx-brokerRedis, KafkaBroker credentials
nx-searchTypesenseSearch credentials
nx-watcherObservability stackCấu hình giám sát

Xác thực Môi trường

Mỗi service xác thực môi trường khi startup bằng Zod schema (pattern IGNIS). Nếu thiếu biến bắt buộc, pod fail nhanh với lỗi rõ ràng trong log.

typescript
// packages/identity/src/config/environment.ts
const envSchema = z.object({
  APP_ENV_POSTGRES_HOST: z.string(),
  APP_ENV_POSTGRES_PORT: z.coerce.number(),
  APP_ENV_POSTGRES_DATABASE: z.string(),
  APP_ENV_POSTGRES_USERNAME: z.string(),
  // ... all required vars
});

Đây là cùng validation dùng trong Docker Compose — không cần thay đổi.

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.