Spring Core & Boot/Profile Groups & Production Patterns — gom profile, validate, blue/green
38/41
Bài 38 / 41~13 phútConfig, Profiles & LoggingMiễn phí lượt xem

Profile Groups & Production Patterns — gom profile, validate, blue/green

Profile groups (Boot 2.4+) gom nhiều profile thành một nhóm logic để kích hoạt bằng một tên. Bài này đào sâu cơ chế groups, multi-document YAML, mô phỏng inheritance qua include, và pattern production: secret management, blue/green canary, validate active profile khi startup.

TL;DR: Profile groups (spring.profiles.group) giải quyết bài toán "activate 5 profile rời mỗi deploy" bằng cách gom chúng dưới một tên logic: production = prod + prod-db + prod-cache + prod-tracing. Kích hoạt production, Boot tự include cả nhóm. Multi-document YAML (--- + on-profile) cho phép nhiều profile document trong một file. Inheritance mô phỏng qua spring.profiles.include hoặc thứ tự active. Production có 3 safeguard quan trọng: không hardcode secret (dùng env var ${VAR}), validate active profile khi startup (ApplicationReadyEvent), và blue/green canary qua pod env var. Bài này là tiếp nối trực tiếp của Profile — activation cơ bản: đã biết profile là gì, bài này đào sâu cách tổ chức và vận hành.

1. Vấn đề groups giải quyết

1.1 Anti-pattern: activate 5 profile rời

Không có groups, production deploy trông như này:

# Khi deploy production — 5 profile phai active
SPRING_PROFILES_ACTIVE=prod,prod-db,prod-cache,prod-tracing,prod-monitoring

Hệ quả thực tế khi làm theo cách này:

  • Dễ bỏ sót: operator quên prod-tracing → không có observability.
  • Khó review: README có nhiều dòng SPRING_PROFILES_ACTIVE dài, không nhất quán giữa team.
  • Brittle: thêm profile mới (prod-audit) → phải update mọi nơi đã hardcode chuỗi 5 profile.

1.2 Cơ chế groups

Profile groups (Boot 2.4+) là mapping trong config: group-name -> [profile1, profile2, ...]. Khi Boot thấy group-name trong danh sách active, nó expand thành toàn bộ profile của group đó trước khi tiến hành load config và register bean.

flowchart LR
    Activate["SPRING_PROFILES_ACTIVE=production"]
    Expand["Boot expand group:<br/>production -> prod, prod-db,<br/>prod-cache, prod-tracing"]
    Load["Load 4 application-*.yml<br/>Register @Profile bean cho ca 4"]
    Run["App chay voi 4 profile active"]

    Activate --> Expand --> Load --> Run

Khai báo group trong application.yml:

spring:
  profiles:
    group:
      production: prod, prod-db, prod-cache, prod-tracing
      staging: staging, staging-db, staging-cache
      development: dev, dev-db

Activate production:

java -jar app.jar --spring.profiles.active=production

Boot tự include 4 profile con. File config tách theo concern:

application-prod.yml           # Spring common prod config
application-prod-db.yml        # DataSource, connection pool
application-prod-cache.yml     # Redis config
application-prod-tracing.yml   # Micrometer, Zipkin, sampling

Mỗi file nhỏ, single concern, dễ review. Khi application-prod.yml phình to 200 dòng, group là cách clean.

Tại sao groups tốt hơn chuỗi profile rời

Groups tốt hơn vì chỉ một nơi định nghĩa thành phần của deployment profile. Thêm concern mới (vd prod-audit) chỉ cần thêm vào group definition — không sửa Kubernetes manifest, không sửa README, không sửa CI pipeline.

1.3 Group lồng và multi-group

Group có thể bao gồm group khác không? Không trực tiếp — Boot không resolve group transitive. Nhưng profile con có thể dùng spring.profiles.include để kéo thêm profile:

# application-prod.yml — prod tự include prod-base
spring:
  profiles:
    include: prod-base, prod-monitoring

Activate prod → Boot include prod-baseprod-monitoring theo. Cách này mô phỏng hierachy profile.

Multi-group cho phép deploy vào nhiều region từ một codebase:

spring:
  profiles:
    group:
      asia-east: prod-base, prod-asia-east, prod-monitoring
      eu-west: prod-base, prod-eu-west, prod-monitoring
      us-east: prod-base, prod-us-east, prod-monitoring

3 region — mỗi region kéo prod-base (DataSource pool, JPA config) và region-specific (DB URL, S3 endpoint). K8s manifest chỉ cần:

env:
  - name: SPRING_PROFILES_ACTIVE
    value: "asia-east"   # hoac eu-west, us-east

2. Multi-document YAML

2.1 Cú pháp và cơ chế

Multi-document YAML (Boot 2.4+) đặt nhiều document trong một file, ngăn cách bằng ---. Mỗi document có thể gắn với profile qua spring.config.activate.on-profile:

# application.yml — single file, 3 document
spring:
  application:
    name: order-service
  datasource:
    hikari:
      maximum-pool-size: 10   # default

---
spring:
  config:
    activate:
      on-profile: dev
  datasource:
    url: jdbc:postgresql://localhost:5432/dev
  logging:
    level:
      com.olhub: DEBUG

---
spring:
  config:
    activate:
      on-profile: prod
  datasource:
    url: ${PROD_DB_URL}
    hikari:
      maximum-pool-size: 50   # override default
  logging:
    level:
      com.olhub: INFO

Cơ chế Boot xử lý multi-document:

  1. Document 1 (không có on-profile): apply làm base cho mọi profile.
  2. Mỗi document sau: Boot kiểm tra on-profile — nếu match active profile thì merge với base, ghi đè key trùng.
  3. Thứ tự merge theo vị trí document trong file — document sau override document trước.

2.2 on-profile hỗ trợ expression

on-profile nhận cùng expression syntax với @Profile:

---
spring:
  config:
    activate:
      on-profile: "prod & monitoring"   # chi apply khi ca 2 profile active
  management:
    endpoints:
      web:
        exposure:
          include: health,metrics,prometheus

2.3 Khi nào dùng multi-document vs separate files

Tình huốngApproach
File ngắn (dưới 100 dòng), 2-3 profileMulti-document — một file, thấy tổng quan dễ
File dài, 5+ profile, nhiều team chỉnhSeparate files — ít merge conflict
Dùng profile groupsSeparate files — group reference file riêng
Quick prototypeMulti-document — không tạo nhiều file
Boot 2.3 tro ve truoc

Multi-document YAML dùng spring.config.activate.on-profile là cú pháp Boot 2.4+. Boot 2.3 trở về dùng spring.profiles (deprecated): spring: profiles: dev. Nếu upgrade từ Boot 2.3, cần migrate sang cú pháp mới.

3. Mô phỏng inheritance

Boot không có cơ chế "profile A extends profile B" trực tiếp. Có 2 pattern mô phỏng:

3.1 Common base + override qua thứ tự active

application.yml                   # base cho moi profile
application-prod-base.yml         # base prod (DataSource pool, JPA)
application-prod.yml              # prod-specific override
application-prod-canary.yml       # canary deployment override
# Active theo thu tu: base, prod-base, prod, prod-canary
SPRING_PROFILES_ACTIVE=prod-base,prod,prod-canary

Boot merge theo thứ tự — profile sau ghi đè profile trước. prod-canary có thể override một số property của prod (vd sampling.probability: 1.0 để trace mọi request trong canary pod).

3.2 spring.profiles.include — dependency tường minh

# application-prod.yml
spring:
  profiles:
    include: prod-base, prod-monitoring
  datasource:
    url: ${PROD_DB_URL}

Activate prod → Boot tự include prod-baseprod-monitoring. Đây là cách viết explicit dependency giữa profile — người đọc file thấy ngay "prod cần prod-base và prod-monitoring".

Khác biệt với group:

GroupInclude
Định nghĩa ởapplication.yml baseFile profile con (application-prod.yml)
Ai quyết includeNgười vận hành (operator) khi set activeAuthor của profile
FlexibilityOperator customize groupFixed bởi author

4. Production patterns

4.1 Secret management — không hardcode credential

Anti-pattern: credential nằm trong YAML commit lên Git:

# application-prod.yml — NGUY HIEM
spring:
  datasource:
    password: prod-secret-123   # hardcode, lo secret khi repo bi access

Ngay cả private repo cũng có rủi ro: repo bị clone, contributor rogue, log CI lộ. Pattern an toàn là tham chiếu env var:

# application-prod.yml — an toan
spring:
  datasource:
    url: ${PROD_DB_URL}              # tu env var, mandatory
    username: ${PROD_DB_USER}
    password: ${DB_PASSWORD}         # fail-fast neu missing (khong co default)

Khi Spring không tìm thấy biến env ${PROD_DB_URL} và không có giá trị default, app từ chối khởi động với IllegalArgumentException: Could not resolve placeholder. Đây là fail-fast có chủ đích.

Kubernetes Secret mount vào pod:

env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: app-secrets
        key: db-password
  - name: PROD_DB_URL
    valueFrom:
      secretKeyRef:
        name: app-secrets
        key: db-url

Với HashiCorp Vault, thêm spring-cloud-starter-vault-config — Boot tự fetch secret từ Vault path khi khởi động:

spring:
  cloud:
    vault:
      host: vault.internal
      token: ${VAULT_TOKEN}
      kv:
        enabled: true
        backend: secret
        default-context: order-service

4.2 Validate active profile tại startup — fail-fast

Typo trong profile name là silent bug: SPRING_PROFILES_ACTIVE=prdo khiến Boot chạy với 0 profile active — không load application-prod.yml, không register bean prod. App khởi động thành công nhưng dùng sai config.

Pattern phòng thủ: validate tại ApplicationReadyEvent — sau khi container fully started, trước khi accept traffic:

@Component
public class StartupValidator {

    @EventListener(ApplicationReadyEvent.class)
    public void validate(ApplicationReadyEvent event) {
        Environment env = event.getApplicationContext().getEnvironment();
        String[] active = env.getActiveProfiles();

        // Phai co it nhat 1 trong cac profile hop le
        Profiles allowed = Profiles.of("dev", "test", "staging", "prod");
        if (!env.acceptsProfiles(allowed)) {
            throw new IllegalStateException(
                "Active profiles must include one of: dev/test/staging/prod. Got: " +
                Arrays.toString(active)
            );
        }

        // Neu prod, validate critical property
        if (env.acceptsProfiles(Profiles.of("prod"))) {
            requireProperty(env, "spring.datasource.url");
            requireProperty(env, "spring.datasource.password");
        }
    }

    private void requireProperty(Environment env, String key) {
        if (!StringUtils.hasText(env.getProperty(key))) {
            throw new IllegalStateException("Missing required property: " + key);
        }
    }
}

Tại sao dùng ApplicationReadyEvent chứ không phải @PostConstruct hay ContextRefreshedEvent? Vì ApplicationReadyEvent fire sau khi toàn bộ container đã refresh xong và bean lifecycle hoàn tất — đây là điểm chắc chắn nhất. @PostConstruct chạy trong pha tạo bean — lúc đó có thể chưa đủ context.

Ket hop voi Spring Boot Actuator

Ngoài validator thủ công, Spring Boot Actuator cung cấp /actuator/env để debug runtime — liệt kê active profile và mọi property source. Không cần restart để kiểm tra cấu hình đang chạy.

4.3 Blue/green và canary deployment

Blue/green deployment chạy 2 phiên bản app song song và chuyển traffic sang phiên bản mới. Profile giúp phân biệt config giữa 2 phiên bản:

# application-prod-v2.yml — override config cho phien ban moi
spring:
  datasource:
    hikari:
      maximum-pool-size: 60        # tang pool cho v2
management:
  tracing:
    sampling:
      probability: 1.0             # trace 100% request o canary de debug

Kubernetes: 2 Deployment chia traffic:

# Deployment chinh (blue) - 90% pod
spec:
  replicas: 9
  template:
    spec:
      containers:
        - name: app
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: "production"     # group: prod + prod-db + prod-cache + prod-tracing
# Deployment canary (green) - 10% pod
spec:
  replicas: 1
  template:
    spec:
      containers:
        - name: app
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: "production,prod-v2"   # them prod-v2 override

Canary pod active 5 profile: prod, prod-db, prod-cache, prod-tracing (từ group production) và prod-v2 (trực tiếp). application-prod-v2.yml merge sau, override key cần thiết. Khi canary ổn định, dần tăng replicas canary và giảm main.

4.4 Failure runbook

Mode 1 — Profile typo, silent fallback:

  • Triệu chứng: startup log hiện No active profile set, falling back to 1 default profile.
  • Diagnose: /actuator/env check spring.profiles.active.
  • Remediate: StartupValidator (section 4.2) bắt được ngay lúc deploy.

Mode 2 — Profile conflict: 2 profile define cùng key:

  • Triệu chứng: config X có 2 giá trị khác nhau giữa 2 profile đều active.
  • Diagnose: /actuator/configprops liệt kê property source ưu tiên.
  • Remediate: thứ tự profile trong spring.profiles.active có chủ đích — profile sau ghi đè trước. Document priority rõ ràng trong README.

Mode 3 — Secret rotate, app vẫn dùng credential cũ:

  • Nguyên nhân: K8s Secret update không trigger pod restart.
  • Remediate: rolling restart pod sau khi rotate secret. Spring Cloud Config có @RefreshScope cho runtime refresh không restart.

5. Pitfall

Nhầm 1 — Tưởng group resolve transitive:

spring:
  profiles:
    group:
      production: prod, prod-db
      full-prod: production, prod-tracing   # SAI

Boot không expand production khi xử lý group full-prod — nó treat production như tên profile literal, không phải group. Kết quả full-prod active 2 profile: production (literal string, không có file application-production.yml) và prod-tracing.

Cách đúng: liệt kê đầy đủ trong group:

spring:
  profiles:
    group:
      full-prod: prod, prod-db, prod-tracing

Nhầm 2 — Secret trong YAML commit lên Git:

# application-prod.yml
spring:
  datasource:
    password: actual-password   # git history ghi nho mai mai

Xóa khỏi file không đủ — git log vẫn giữ. Dùng ${ENV_VAR} reference và rotate secret sau.

Nhầm 3 — Không validate profile, bug ngầm production:

App active wrong profile → dùng config dev trong prod (pool size thấp, log level DEBUG, DB localhost). Silent bug cho đến khi hết connection hoặc lộ data qua verbose log.

Luôn có StartupValidator tối thiểu check profile name hợp lệ.

Nhầm 4 — on-profile cú pháp Boot 2.3 lẫn Boot 2.4:

# Boot 2.3 syntax — deprecated
---
spring:
  profiles: dev    # deprecated
  datasource:
    url: jdbc:postgresql://localhost/dev

# Boot 2.4+ syntax — dung
---
spring:
  config:
    activate:
      on-profile: dev
  datasource:
    url: jdbc:postgresql://localhost/dev

Lẫn lộn cú pháp → Boot 2.4+ log warning "spring.profiles is no longer supported in document-specific sections" và có thể không apply document.

6. Cơ chế bên dưới — cách Boot expand group

Khi Spring Boot khởi động, ProfilesParser (trong spring-boot module) xử lý spring.profiles.group trước khi Environment được finalize. Thứ tự:

  1. Boot đọc spring.profiles.active từ env var / JVM property / application.yml.
  2. Với mỗi profile name trong danh sách active, Boot tra spring.profiles.group map — nếu có mapping thì thêm (không replace) các profile con vào danh sách active.
  3. Step 2 lặp lại cho các profile mới vừa thêm vào (nhưng không transitive cho group khác).
  4. Sau khi expand xong, Boot load application-{profile}.yml cho toàn bộ active profiles theo thứ tự ưu tiên.

Điểm quan trọng: expansion thêm vào, không thay thế. Sau expand production, active profile là [production, prod, prod-db, prod-cache, prod-tracing] — tên group production vẫn còn trong danh sách. Boot cũng thử load application-production.yml (thường không tồn tại, bỏ qua).

flowchart TB
    Input["active = [production]"]
    Lookup["Tra group map:<br/>production -> prod, prod-db,<br/>prod-cache, prod-tracing"]
    Expand["active = [production, prod,<br/>prod-db, prod-cache, prod-tracing]"]
    LoadYAML["Load application.yml<br/>application-prod.yml<br/>application-prod-db.yml<br/>application-prod-cache.yml<br/>application-prod-tracing.yml"]
    Merge["Merge theo thu tu uu tien"]
    BeanFilter["Register @Profile bean<br/>co profile match"]

    Input --> Lookup --> Expand --> LoadYAML --> Merge --> BeanFilter

7. Liên hệ các bài khác

  • Profile — activation, @Profile trên bean, expression: bài trước giải thích profile là gì và cơ chế activation cơ bản. Bài này xây trên nền đó với groups và production patterns.
  • Logging — SLF4J, log levels, config: module 06 bao gồm logging — profile thường dùng để set log level khác nhau theo môi trường (DEBUG cho dev, INFO cho prod). Hiểu profile groups trước khi config logging per-profile.
  • Spring Boot AutoConfiguration — cơ chế bên dưới: @ConditionalOnProfile là một trong các @Conditional autoconfiguration dùng để chỉ apply @Configuration class khi profile match — liên hệ trực tiếp với @Profile trong bài này.
  • Bean lifecycle phases: ApplicationReadyEvent (dùng trong StartupValidator) fire ở pha cuối lifecycle — hiểu lifecycle giúp chọn đúng event listener point.

Tóm tắt

  • Profile groups (spring.profiles.group): gom nhiều profile thành một tên logic. Activate tên group → Boot expand thành danh sách đầy đủ. Giải quyết bài toán activate 5 profile rời và tránh bỏ sót profile khi deploy.
  • Multi-document YAML (--- + spring.config.activate.on-profile): nhiều profile document trong một file. Document đầu là base; document sau merge + override khi profile match. Phù hợp cho file ngắn, 2-3 profile; dùng separate files khi file dài hoặc nhiều team chỉnh.
  • Inheritance mô phỏng qua spring.profiles.include (explicit dependency trong file profile) hoặc thứ tự cascade activation.
  • Secret management: không hardcode trong YAML. Dùng ${ENV_VAR} reference — app fail-fast nếu biến thiếu. Mount K8s Secret vào pod env var.
  • Startup validation: @EventListener(ApplicationReadyEvent.class) kiểm tra profile hợp lệ + critical property — bắt typo profile và thiếu config tại deploy time, không phải runtime.
  • Blue/green canary: 2 K8s Deployment khác nhau ở SPRING_PROFILES_ACTIVE — canary pod thêm profile override config. Profile group tách biệt concern rõ ràng.
  • Groups không transitive: Boot không expand group lồng trong group khác.

Tự kiểm tra

Tự kiểm tra
Q1
Tại sao dùng profile groups thay vì liệt kê thẳng SPRING_PROFILES_ACTIVE=prod,prod-db,prod-cache,prod-tracing? Khi nào groups không đủ?

Lý do dùng groups:

  • Single source of truth: định nghĩa "production cần những profile nào" ở một chỗ trong application.yml. Thêm profile mới chỉ sửa group definition, không sửa Kubernetes manifest / README / CI pipeline.
  • Tránh bỏ sót: chuỗi 5 profile dài dễ thiếu 1 khi copy-paste. Group đảm bảo tất cả được include tự động.
  • Readable: operator thấy production hiểu ngay "đây là full production stack" — không cần nhớ 5 tên profile con.

Khi groups không đủ:

  • Groups không transitive — Boot không expand group lồng trong group khác. Nếu cần hierachy phức tạp, dùng spring.profiles.include trong file profile con.
  • Groups định nghĩa tĩnh trong YAML. Nếu cần customize thành phần group theo runtime (vd chọn region dynamically), cần programmatic activation.
  • Group chỉ là expansion shorthand — không thay thế được profile expression prod & monitoring trên @Profile bean.
Q2
Cho đoạn YAML dưới đây — Boot merge document 1 và document 2 ra sao khi prod active? Giá trị cuối của hikari.maximum-pool-size là bao nhiêu?

Document 1: datasource.hikari.maximum-pool-size: 10 (no profile). Document 2: datasource.hikari.maximum-pool-size: 50 (on-profile: prod).

Giá trị cuối là 50.

Cơ chế Boot xử lý multi-document YAML:

  1. Document 1 (không có on-profile): apply làm base cho mọi profile. maximum-pool-size = 10.
  2. Document 2 (on-profile: prod): profile prod active → document này được merge vào. Key maximum-pool-size trùng → document sau ghi đè document trước.
  3. Kết quả cuối: maximum-pool-size = 50.

Nếu profile dev active thay vì prod, document 2 bị bỏ qua → giá trị giữ nguyên 10 từ base.

Đây chính là cách dùng multi-document để override default: document đầu là default safe, document sau là môi trường cụ thể. Pattern common: pool nhỏ cho dev, pool lớn cho prod; log level DEBUG cho dev, INFO cho prod.

Q3
Tại sao cần StartupValidator validate active profile tại ApplicationReadyEvent? Tại sao không đủ nếu chỉ kiểm tra log?

Lý do cần validator:

Typo profile name (vd prdo thay vì prod) khiến Boot chạy với 0 profile active — không load application-prod.yml, không register bean prod. App khởi động thành công nhưng dùng config sai. Không có lỗi nào xuất hiện ngay lập tức.

Silent failure này nguy hiểm hơn hard crash vì:

  • App dùng config dev trong prod (pool size nhỏ, DB localhost → down, log DEBUG → verbose).
  • Health check thấy app alive → không alert.
  • Bug chỉ lộ khi tải thật hoặc khi operator kiểm tra log thủ công.

Tại sao không đủ nếu chỉ kiểm tra log:

Log startup ghi "No active profile set" nhưng operator phải chủ động đọc log mỗi deploy — không scalable, dễ bỏ qua trong deploy pipeline bận. Validator fail-fast: app từ chối khởi động → pod không readiness, K8s rollout dừng ngay, deployment fail rõ ràng thay vì silent.

Tại sao ApplicationReadyEvent chứ không phải @PostConstruct:

ApplicationReadyEvent fire sau khi toàn bộ container refresh xong — điểm chắc chắn nhất mọi bean đã được tạo. @PostConstruct chạy trong pha tạo bean, lúc đó Environment đã có nhưng không phải điểm "officially ready". Dùng ApplicationReadyEvent đảm bảo app thực sự sẵn sàng trước khi reject nếu config sai.

Q4
Bạn cần deploy app ở 3 region: asia-east, eu-west, us-east. Mỗi region có DB URL riêng; common config (security, JPA pool) giống nhau. Thiết kế profile layout dùng groups thế nào?

Layout dùng groups + base profile:

# application.yml
spring:
profiles:
  group:
    asia-east: prod-base, prod-asia-east
    eu-west: prod-base, prod-eu-west
    us-east: prod-base, prod-us-east
# application-prod-base.yml — common cho moi region
spring:
datasource:
  hikari:
    maximum-pool-size: 50
jpa:
  hibernate:
    ddl-auto: validate
logging:
level:
  com.olhub: INFO
# application-prod-asia-east.yml — region-specific
spring:
datasource:
  url: ${ASIA_EAST_DB_URL}
cloud:
  aws:
    s3:
      endpoint: https://s3.ap-southeast-1.amazonaws.com

K8s manifest per region chỉ cần:

env:
- name: SPRING_PROFILES_ACTIVE
  value: "asia-east"   # hoac eu-west, us-east

Lợi ích layout này:

  • DRY: JPA pool, log level sống trong prod-base.yml — thay đổi một lần apply cho 3 region.
  • Isolation: DB URL region-specific trong file riêng — sửa asia-east không chạm eu-west.
  • Thêm region mới: tạo prod-ap-south.yml + thêm group ap-south: prod-base, prod-ap-south. Không duplicate base config.

Anti-pattern cần tránh: 3 file application-asia-east.yml, application-eu-west.yml, application-us-east.yml mỗi file 150 dòng duplicate 80% → cập nhật common rule phải sửa 3 file → dễ inconsistent.

Q5
Blue/green deployment dùng 2 K8s Deployment: order-service (9 replica, production group) và order-service-canary (1 replica, production,prod-v2). Tại sao canary pod active 5 profile, không phải 2? Cơ chế nào giải thích?

Canary pod active 5 profile vì group expansion:

  1. Input: SPRING_PROFILES_ACTIVE=production,prod-v2 — 2 tên.
  2. Boot tra group map: production[prod, prod-db, prod-cache, prod-tracing].
  3. Boot thêm 4 profile con vào danh sách active (không replace).
  4. Kết quả: [production, prod-v2, prod, prod-db, prod-cache, prod-tracing] — 6 entry (tên group production vẫn còn, nhưng không có file application-production.yml nên bỏ qua).
  5. Boot load: application-prod.yml, application-prod-db.yml, application-prod-cache.yml, application-prod-tracing.yml, application-prod-v2.yml.
  6. application-prod-v2.yml merge sau cùng → ghi đè các key override (pool size, sampling rate).

Main pod (group production) active 4 profile con: prod + prod-db + prod-cache + prod-tracing. Canary active thêm prod-v2 → override một số config (vd trace 100% request, pool size lớn hơn).

Điểm cốt lõi: expansion là additive, không replace. Profile prod-v2 được merge sau toàn bộ group — đảm bảo override có hiệu lực. Đây là lý do canary pattern hoạt động: base config giống main pod, chỉ override cần thiết.

Bài tiếp theo: Logging — SLF4J, levels, config

Bài này có giúp bạn hiểu bản chất không?

Hỏi đáp về bài này

Chưa có câu hỏi

Đặt câu hỏi

Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).

Đặt câu hỏi đầu tiên