การออกแบบการสลับ Active Profile ของ Spring Boot ระหว่าง docker-compose และ ECS
บทนำ
เมื่อรัน Spring Boot app ในหลายสภาพแวดล้อม สิ่งสำคัญคือต้องเข้าใจอย่างแม่นยำว่า application.yml ไหนกำลังถูกใช้งานอยู่
- Local development:
application-local.yml - Docker Compose:
application-docker.yml - AWS ECS (production):
application-prod.yml
บทความนี้บันทึกการออกแบบการสลับ profile และวิธีการส่ง configuration บน ECS
พื้นฐาน Spring Boot Profile
เมื่อสร้างไฟล์ที่ชื่อ application-{profile}.yml ไฟล์นั้นจะถูก load เฉพาะเมื่อ profile นั้น active อยู่
src/main/resources/
application.yml ← ใช้ร่วมกันทุกสภาพแวดล้อม
application-local.yml ← สำหรับ local development
application-docker.yml ← สำหรับ Docker Compose
application-prod.yml ← สำหรับ production (ECS)
วิธีระบุ profile:
# ระบุตอน startup
java -jar app.jar --spring.profiles.active=prod
# ระบุผ่าน environment variable (Docker-friendly)
SPRING_PROFILES_ACTIVE=prod java -jar app.jar
Configuration Files แต่ละสภาพแวดล้อม
application.yml (ใช้ร่วมกันทุกสภาพแวดล้อม)
spring:
application:
name: dvd-rental-customer-backend
datasource:
driver-class-name: org.postgresql.Driver
jpa:
open-in-view: false
server:
port: 8082
application-local.yml
spring:
datasource:
url: jdbc:postgresql://localhost:15433/dvdrental
username: postgres
password: postgres
thymeleaf:
cache: false
logging:
level:
com.example: DEBUG
application-docker.yml
spring:
datasource:
# เชื่อมต่อ DB โดยใช้ Docker Compose service name
url: jdbc:postgresql://postgres:5432/dvdrental
username: postgres
password: postgres
application-prod.yml
spring:
datasource:
# Production DB URL รับจาก environment variables
url: ${DATABASE_URL}
username: ${DATABASE_USERNAME}
password: ${DATABASE_PASSWORD}
logging:
level:
root: WARN
com.example: INFO
สำคัญ: อย่า hard-code ข้อมูลสำคัญของ production ใน yaml ต้องส่งผ่าน environment variables เสมอ
การระบุ Profile ใน Docker Compose
# compose.yml
services:
app:
image: dvd-rental-customer-backend:latest
environment:
SPRING_PROFILES_ACTIVE: docker # ← ระบุที่นี่
TZ: Asia/Tokyo
ports:
- "8082:8082"
depends_on:
postgres:
condition: service_healthy
postgres:
image: postgres:16
environment:
POSTGRES_DB: dvdrental
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
การระบุ Profile บน ECS (AWS Fargate)
ตั้งค่า environment variables ของ container ใน ECS task definition
ตัวอย่างการตั้งค่าด้วย CDK
// cdk/lib/app-stack.ts
const taskDefinition = new ecs.FargateTaskDefinition(this, 'AppTask', {
memoryLimitMiB: 512,
cpu: 256,
});
const container = taskDefinition.addContainer('AppContainer', {
image: ecs.ContainerImage.fromEcrRepository(ecrRepo, 'latest'),
environment: {
// Environment variables (ข้อความธรรมดา)
SPRING_PROFILES_ACTIVE: 'prod',
TZ: 'Asia/Tokyo',
},
secrets: {
// ข้อมูลสำคัญรับจาก SSM Parameter Store
DATABASE_URL: ecs.Secret.fromSsmParameter(
ssm.StringParameter.fromStringParameterName(this, 'DbUrl', '/dvd-rental/db-url')
),
DATABASE_USERNAME: ecs.Secret.fromSsmParameter(
ssm.StringParameter.fromStringParameterName(this, 'DbUser', '/dvd-rental/db-username')
),
DATABASE_PASSWORD: ecs.Secret.fromSsmParameter(
ssm.StringParameter.fromStringParameterName(this, 'DbPassword', '/dvd-rental/db-password')
),
},
logging: ecs.LogDrivers.awsLogs({
streamPrefix: 'dvd-rental',
logGroup: logGroup,
}),
});
วิธีตรวจสอบ Profile บน ECS
หลัง deploy ตรวจสอบว่า profile ที่ถูกต้องถูก apply ผ่าน CloudWatch Logs
Spring Boot จะ output active profile ไปยัง logs ตอน startup:
INFO o.s.b.SpringApplication - The following 1 profile is active: "prod"
INFO o.s.b.w.embedded.tomcat.TomcatWebServer - Tomcat initialized with port 8082 (http)
ยืนยันว่าแสดง "prod" ก่อนถือว่า deployment เสร็จสมบูรณ์
# ตรวจสอบ profile ใน CloudWatch Logs
aws logs filter-log-events \
--log-group-name /dvd-rental/app \
--filter-pattern "profiles is active" \
--region ap-northeast-1
ข้อผิดพลาดที่พบบ่อย
① ลืมระบุ profile ใน Docker Compose
หากไม่ระบุ profile จะใช้ default profile
แม้ว่า application-docker.yml จะมีอยู่ก็จะไม่ถูกอ่าน
# NG (ไม่ระบุ profile)
services:
app:
environment:
TZ: Asia/Tokyo
# OK
services:
app:
environment:
SPRING_PROFILES_ACTIVE: docker # ← จำเป็น
TZ: Asia/Tokyo
② นำ application-local.yml ในเครื่องเข้าไปใน Docker image
หาก production image มีข้อมูลการเชื่อมต่อ local เช่น localhost:15433 อาจถูกอ้างอิงโดยไม่ตั้งใจ
# ยกเว้นใน .dockerignore
src/main/resources/application-local.yml
③ ใช้ตัวพิมพ์ใหญ่/เล็กผิดสำหรับ environment variables
Spring Boot รองรับทั้ง SPRING_PROFILES_ACTIVE (ตัวพิมพ์ใหญ่ทั้งหมด คั่นด้วย underscore) และ spring.profiles.active (คั่นด้วยจุด)
สำหรับ Docker environment variables ให้ใช้รูปแบบตัวพิมพ์ใหญ่ underscore
สรุป
| สภาพแวดล้อม | Profile | วิธีตั้งค่า |
|---|---|---|
| Local development | local | IDE Run config หรือ JVM args |
| Docker Compose | docker | environment: SPRING_PROFILES_ACTIVE: docker |
| ECS (production) | prod | Task definition environment |
- อย่า hard-code ข้อมูลสำคัญใน
application-prod.ymlให้ส่งผ่าน environment variables หรือ SSM - หลัง deploy ต้องตรวจสอบ “active profile” ใน CloudWatch Logs เสมอ
- รักษา profile names ให้เรียบง่าย ประมาณสามประเภท: local, Docker และ production แทนที่จะสร้างหนึ่งต่อสภาพแวดล้อม
แผนที่บทความสำหรับซีรีส์นี้
→ สร้างแอป DVD Rental สำหรับผู้ใช้ปลายทาง — โครงสร้าง Vue 3 + Spring Boot คู่กับแอปผู้ดูแลระบบ พร้อมแผนที่บทความ
→ สร้างแอปจัดการ DVD Rental ด้วย Spring Boot + Thymeleaf โดยใช้ฐานข้อมูลตัวอย่าง dvdrental