Configuration, Operations, และ Security สำหรับ Deploy Spring Boot + Thymeleaf + PostgreSQL Admin App ไปยัง AWS ECS/Fargate + RDS
ระหว่างสร้าง Spring Boot + Thymeleaf admin app ให้ทำงานบน AWS ฉันจัดระเบียบว่าจะใช้ configuration แบบไหน จะป้องกันส่วนไหน และจะดำเนินการ (operate) ต่อไปอย่างไร
บทความนี้ครอบคลุมกรณีที่ deploy business app ที่สร้างด้วย Java / Spring Boot / Thymeleaf / PostgreSQL ไปยัง AWS ECS Fargate และ RDS for PostgreSQL
จุดเน้นของบทความนี้ไม่ใช่แค่ผลลัพธ์ว่าใช้งานบน AWS ได้ แต่เป็นการตัดสินใจเรื่อง configuration ที่ทำโดยคำนึงถึงการ operate admin app นี้อย่างต่อเนื่อง
สิ่งที่ให้ความสำคัญเป็นพิเศษคือ:
- จะวาง application ตัวจริงไว้ที่ไหน
- จะวาง database ไว้ตำแหน่งใด
- จะจำกัดขอบเขตการเปิดเผยสู่ภายนอกแค่ไหน
- จะใช้ขั้นตอนแบบไหนเพื่อ redeploy และตรวจสอบอย่างปลอดภัย
- จะบันทึกความรู้หลังสร้างเสร็จอย่างไรให้นำกลับมาใช้ซ้ำได้
การทบทวนเรื่อง billing กลายเป็นประเด็นสำคัญระหว่างทาง แต่ท้ายที่สุดก็เป็นเพียงหนึ่งปัจจัยในการตัดสินใจเรื่อง configuration เท่านั้น แก่นของบทความนี้อยู่ที่ design ที่ฉันเลือกใช้เพื่อให้แอพนี้ทำงานบน AWS ได้อย่างปลอดภัยและดูแลรักษาง่าย
สำหรับใครที่ต้องการ deploy Spring Boot app ไปยัง AWS ECS Fargate, ใช้งาน PostgreSQL บน RDS for PostgreSQL, หรือนำ admin app แบบ Thymeleaf ขึ้น AWS บทความนี้สรุป configuration, การ initialize, ขั้นตอนตรวจสอบ, และมุมมองด้าน operation ไว้ให้
สิ่งที่บทความนี้ครอบคลุม
- แนวคิดการวาง Spring Boot + Thymeleaf + PostgreSQL admin app บน AWS ECS/Fargate + RDS
- วิธีแยก ALB, ECS Fargate, RDS for PostgreSQL, และ NAT Gateway ออกจากกัน
- แนวคิดที่ทำให้ AWS deployment reproduce ได้ด้วย Docker และ command line
- วิธีนำ database initialization และการตรวจสอบเข้ามาอยู่ใน operation
- จุดที่มักติดขัดตอน deploy และขั้นตอนตรวจสอบ
- แนวคิดการควบคุม billing สำหรับ verification
สิ่งที่สร้างขึ้น
สิ่งที่สร้างขึ้นครั้งนี้คือ admin app ที่จำลองจากธุรกิจ DVD rental
PostgreSQL sample database ที่ใช้เป็นข้อมูลต้นทางของแอพนี้ ดูได้จากหน้านี้
วิธีประกอบตัวแอพเองสรุปไว้ในอีกบทความหนึ่ง หากต้องการดู screen structure และแนวทาง implementation ด้วย อ่านควบคู่กันจะเข้าใจง่ายขึ้น
การสร้างแอพจัดการ DVD Rental ด้วย Spring Boot + Thymeleaf บน PostgreSQL dvdrental Sample DB
ฟีเจอร์หลักมีดังนี้
- Login
- Dashboard
- การจัดการลูกค้า
- การจัดการร้านค้า
- การจัดการพนักงาน
- การจัดการสต็อก
- การจัดการการชำระเงิน
- การจัดการการเช่า
- รายงานยอดขาย
หน้าจอ configure เป็นแบบ server-rendered ด้วย Spring Boot + Thymeleaf โครงสร้างค่อนข้าง classic แบบ business app ทั่วไป มีหน้า search, detail, สร้าง, แก้ไข, และยืนยัน




Tech Stack
Tech stack หลักของครั้งนี้มีดังนี้
- Java 25
- Spring Boot
- Thymeleaf
- Spring Security
- Spring Data JPA
- PostgreSQL
- Docker
- AWS ECS Fargate
- AWS RDS for PostgreSQL
- AWS Application Load Balancer
- AWS CDK
Frontend ไม่ใช่ SPA แต่ตั้งอยู่บนพื้นฐานของ server-side rendering ดังนั้นจึงออกแบบโดยเน้น Spring MVC และการเก็บ state ฝั่ง server แทนการจัดการ state ฝั่ง client ขนาดใหญ่
ทำให้ Reproduce ได้จาก Command Line
สิ่งที่สำคัญที่สุดของการทำ AWS ครั้งนี้คือการไม่จบลงที่ configuration ที่ต้อง reproduce ได้ด้วยการคลิกหน้าจอ console ด้วยมือเท่านั้น
แอพนี้จัดวางให้ build, deploy, และตรวจสอบการ startup ทั้งหมดตรวจสอบย้อนกลับได้ผ่าน Docker และ command line หากไม่จัดการส่วนนี้ให้ดีตั้งแต่แรก ต่อให้ขึ้น AWS ได้ครั้งเดียว แต่ทุกครั้งที่ redeploy หรือแก้ไข ขั้นตอนก็จะเริ่มเบี่ยงเบนไปเรื่อยๆ
สิ่งที่ทำครั้งนี้ไม่ใช่แค่ทำให้ docker build กับ cdk deploy รันได้เท่านั้น แต่แยกไฟล์ที่ใช้งานจริงตอน execute ออกมาแล้วเขียนเนื้อหาที่จำเป็นลงในแต่ละไฟล์
ไฟล์ที่ใช้งานจริงตอน runtime หลักๆ มี 4 ไฟล์นี้
Dockerfile
ไฟล์นี้เป็นตัวหลักสำหรับสร้าง Docker image จริงๆ แล้วเป็น 2-stage build คือ image สำหรับ build กับ image สำหรับ runtime stage แรกใช้ Maven สร้าง jar ส่วน stage หลังเหลือแค่สิ่งที่จำเป็นสำหรับ execute
เนื้อหาที่เขียนไว้จริง สรุปประเด็นสำคัญได้ดังนี้
FROM maven:3.9.11-eclipse-temurin-25 AS build
RUN mvn -q -DskipTests package
FROM eclipse-temurin:25-jre-jammy
RUN apt-get install -y --no-install-recommends postgresql-client
COPY --from=build /workspace/target/dvd-rental-admin-0.0.1-SNAPSHOT.jar /app/app.jar
COPY docker/postgres/init/ /app/initdb/
COPY docker/aws-entrypoint.sh /app/aws-entrypoint.sh
ENTRYPOINT ["/app/aws-entrypoint.sh"]
กล่าวคือ ไฟล์นี้ไฟล์เดียวมีเนื้อหาต่อไปนี้อยู่
- build ด้วย
maven:3.9.11-eclipse-temurin-25 - วาง
dvd-rental-admin-0.0.1-SNAPSHOT.jarไว้ที่/app/app.jar - ใส่ชุด DB initialization SQL ทั้งหมดไว้ที่
/app/initdb/ - ให้คำสั่ง startup ผ่าน
aws-entrypoint.shแทนการเรียกjava -jarตรงๆ - ติดตั้ง
postgresql-clientใน runtime image เพื่อให้ใช้psqlและpg_isreadyได้ - เปิด port
8080
กล่าวคือ Dockerfile ไม่ใช่แค่ config สำหรับ containerize เท่านั้น แต่เป็นไฟล์ที่ประกอบ runtime image ที่ initialize DB ได้หลัง startup บน AWS
docker/aws-entrypoint.sh
ไฟล์นี้คือ process ที่รันทันทีหลัง container เริ่มทำงาน ส่วนนี้ค่อนข้างสำคัญ เพราะทำให้ RDS บน AWS อยู่ในสถานะใกล้เคียงกับ local ก่อนที่จะเริ่มแอพ
flow ภายในโดยสรุปมีดังนี้
wait_for_database
dataset_version="$({ cat /app/initdb/01-dvdrental-full.sql; cat /app/initdb/02-convert-currency-to-jpy.sql; } | sha256sum | awk '{print $1}')"
if [ "$current_version" = "$dataset_version" ]; then
log 'database already matches the development dataset version'
return
fi
run_psql <<'SQL'
DROP SCHEMA IF EXISTS public CASCADE;
SQL
run_psql -f /app/initdb/01-dvdrental-full.sql
run_psql -f /app/initdb/02-convert-currency-to-jpy.sql
exec sh -c 'java $JAVA_OPTS -jar /app/app.jar'
เมื่อจัดระเบียบเนื้อหาที่เขียนไว้จริง จะมี role ดังนี้
- รอด้วย
pg_isreadyสูงสุด 60 ครั้งจนกว่า RDS จะ ready - ดำเนินขั้นตอนใส่ dataset เฉพาะตอนที่
APP_INIT_FULL_DATASET=true - ไม่อนุญาตค่าอื่นนอกจาก
APP_DB_SCHEMA=public - จบการทำงานทันทีถ้าไม่มี
POSTGRESQL_HOST,POSTGRESQL_USER,POSTGRESQL_PASSWORD, หรือPOSTGRESQL_DATABASE - สร้าง dataset version จาก SHA-256 ของ
01-dvdrental-full.sqlและ02-convert-currency-to-jpy.sql - ข้ามการใส่ซ้ำถ้า version ที่บันทึกไว้ใน
public.app_dataset_metadataตรงกัน - ถ้า version ไม่ตรงกัน สร้างใหม่ด้วย
DROP SCHEMA IF EXISTS public CASCADEแล้วใส่ SQL ใหม่ - สุดท้ายเริ่ม Spring Boot ด้วย
java $JAVA_OPTS -jar /app/app.jar
กล่าวคือ docker/aws-entrypoint.sh เป็นไฟล์ควบคุมการ execute ที่รวม “รอ RDS” “ตรวจสอบความต่าง” “ใส่ full dataset” “เริ่มแอพ” ไว้ด้วยกัน
src/main/resources/application-aws-postgres.yml
ไฟล์นี้ใช้สำหรับรัน Spring Boot ด้วย configuration สำหรับ AWS รวมการจัดการ RDS connection, schema, cookie, และ Flyway ไว้ที่นี่
configuration หลักที่ใส่ไว้จริงมีดังนี้
spring:
config:
activate:
on-profile: aws-postgres
datasource:
url: jdbc:postgresql://${POSTGRESQL_HOST:localhost}:${POSTGRESQL_PORT:5432}/${POSTGRESQL_DATABASE:dvdrental}
username: ${POSTGRESQL_USER:postgres}
driver-class-name: org.postgresql.Driver
flyway:
enabled: ${SPRING_FLYWAY_ENABLED:true}
server:
forward-headers-strategy: framework
servlet:
session:
cookie:
secure: ${SERVER_SERVLET_SESSION_COOKIE_SECURE:true}
สิ่งที่ไฟล์นี้กำหนดไว้ชัดเจนมีดังนี้
- active profile คือ
aws-postgres - ปลายทาง RDS connection รับค่าจาก
POSTGRESQL_HOST,POSTGRESQL_PORT,POSTGRESQL_DATABASE - ใช้
org.postgresql.Driverเป็น JDBC driver - รัน HikariCP ด้วย
maximum-pool-size: 10,minimum-idle: 5,connection-timeout: 20000 - schema รับค่าจาก
APP_DB_SCHEMAค่าเริ่มต้นคือpublic - เปิด/ปิด Flyway ผ่าน environment variable
- ใช้
forward-headers-strategy: frameworkเพื่อให้ทำงานถูกต้องเมื่ออยู่หลัง ALB - อนุญาตให้ session cookie เป็น secure ได้ โดยตั้งสมมติฐานว่าอยู่บน AWS
กล่าวคือ application-aws-postgres.yml เป็นไฟล์ที่ fix ว่า “หลัง container เริ่มทำงาน Spring Boot จะทำงานด้วยปลายทาง connection และ configuration แบบไหน”
infra/cdk/lib/dvd-rental-admin-stack.ts
ไฟล์นี้คือตัวหลักที่เป็นเป้าหมายของ cdk synth และ cdk deploy เกือบทั้งหมดว่าฝั่ง AWS จะสร้างอะไรด้วย configuration แบบไหน เขียนไว้ที่นี่
ต้นไฟล์รับค่า execution จาก context
const appName = this.node.tryGetContext('appName') ?? 'dvd-rental-admin';
const databaseName = this.node.tryGetContext('databaseName') ?? 'dvdrental';
const desiredCount = Number(this.node.tryGetContext('desiredCount') ?? 1);
const cpu = Number(this.node.tryGetContext('cpu') ?? 512);
const memoryMiB = Number(this.node.tryGetContext('memoryMiB') ?? 1024);
นอกจากนี้ยังมี AWS resource definitions ต่อไปนี้อยู่จริง
- สร้าง VPC
- สร้าง subnet 3 ประเภท
public,application,database - ตั้งชื่อ ECS Cluster เป็น
${appName}-cluster - สร้าง RDS PostgreSQL 17.4 บน
t4g.micro - ใช้ Application Load Balanced Fargate Service
- ตั้ง container port เป็น
8080 - ตั้ง health check path เป็น
/login - ส่งข้อมูล DB connection จาก Secrets Manager ไปยัง ECS
Environment variables ที่ส่งให้ ECS task ก็อยู่ในไฟล์นี้โดยตรงเช่นกัน
environment: {
SERVER_PORT: '8080',
SPRING_PROFILES_ACTIVE: 'aws-postgres',
SPRING_FLYWAY_ENABLED: 'false',
SERVER_SERVLET_SESSION_COOKIE_SECURE: sessionCookieSecure,
APP_INIT_FULL_DATASET: 'true',
}
ค่าที่ส่งเป็น secrets ก็กำหนดตายตัวไว้เช่นกัน
secrets: {
POSTGRESQL_HOST: ecs.Secret.fromSecretsManager(connectionSecret, 'host'),
POSTGRESQL_PORT: ecs.Secret.fromSecretsManager(connectionSecret, 'port'),
POSTGRESQL_USER: ecs.Secret.fromSecretsManager(connectionSecret, 'username'),
POSTGRESQL_PASSWORD: ecs.Secret.fromSecretsManager(connectionSecret, 'password'),
POSTGRESQL_DATABASE: ecs.Secret.fromSecretsManager(connectionSecret, 'dbname'),
APP_DB_SCHEMA: ecs.Secret.fromSecretsManager(connectionSecret, 'schema'),
}
กล่าวคือ dvd-rental-admin-stack.ts เป็นไฟล์ที่กำหนดเงื่อนไขการ execute ฝั่ง AWS ทั้งหมด ตั้งแต่ “วิธีแบ่ง VPC” “ตำแหน่งวาง ECS กับ RDS” “env และ secret ที่ส่งให้ ECS task” ไปจนถึง “health check ของ ALB”
เวลารันคำสั่งจริง ทั้ง 4 ไฟล์นี้ทำงานเชื่อมโยงกันโดยตรง Dockerfile สร้าง container, infra/cdk/lib/dvd-rental-admin-stack.ts นำไปวางบน AWS, docker/aws-entrypoint.sh ทำงานตอน startup, และสุดท้าย Spring Boot เชื่อมต่อ RDS ด้วย configuration ใน application-aws-postgres.yml
โดยรวม flow มี 4 ขั้นตอนดังนี้
- สร้าง container ของแอพด้วย Docker
- รัน CDK จาก command line เพื่อสร้าง AWS resources
- รัน DB initialization อัตโนมัติผ่าน entrypoint ตอน container เริ่มทำงาน
- ตรวจสอบการ startup ด้วย CloudWatch Logs และ browser
ในทางปฏิบัติจะเป็นแบบนี้
docker build -t dvd-rental-admin:latest .
cd infra/cdk
npm.cmd run synth
npm.cmd run deploy
สำหรับ Windows + AWS SSO ฉัน load credential เข้า PowerShell ก่อนล่วงหน้าแล้วจึง execute
$credentialEnv = aws configure export-credentials --profile AdministratorAccess-<AWS_ACCOUNT_ID> --format powershell | Out-String
Invoke-Expression $credentialEnv
$env:AWS_REGION='ap-northeast-1'
$env:AWS_DEFAULT_REGION='ap-northeast-1'
$env:AWS_ACCOUNT_ID='<AWS_ACCOUNT_ID>'
หลังจากนั้นตรวจสอบ region ของ manifest ด้วย cdk synth ถ้าไม่มีปัญหาก็ดำเนินการ cdk deploy ต่อ
สิ่งสำคัญคือฉันไม่ได้จบแค่สร้าง container แล้ววางบน ECS เท่านั้น ใน docker/aws-entrypoint.sh รอจนกว่า RDS จะใช้งานได้ แล้ว apply 01-dvdrental-full.sql กับ 02-convert-currency-to-jpy.sql จากนั้นจึงเริ่มแอพ ทำให้ตรวจสอบบน AWS ได้ด้วยข้อมูลเริ่มต้นที่ใกล้เคียงกับ local
กล่าวคือ สิ่งที่สำคัญจริงๆ ในการทำ AWS ครั้งนี้คือการ containerize แอพด้วย Docker, การเขียน infrastructure เป็น code ด้วย CDK, และการจัดไฟล์ที่จำเป็นสำหรับ execute ทั้งหมดให้อยู่บนพื้นฐานของ command line รวมถึง DB initialization ตอน startup ด้วย
วางบน AWS ECS/Fargate + RDS for PostgreSQL อย่างไร
configuration ที่วางบน AWS ครั้งนี้ แบ่งตาม role ได้ดังนี้
กล่าวคือ ทำให้ตรวจสอบ configuration พื้นฐานของการวาง Spring Boot + PostgreSQL admin app บน AWS ECS/Fargate และ RDS for PostgreSQL ได้โดยตรง
- จุดเข้าที่รับ access จากผู้ใช้
- ตัว application ที่รัน admin screen จริง
- database ที่เก็บข้อมูลธุรกิจ
- เส้นทาง network ที่ application ใช้สื่อสารกับภายนอก
ภาพรวม configuration เป็นดังนี้
Internet ↓ Application Load Balancer ↓ Application บน ECS Fargate ↓ RDS PostgreSQL
การสื่อสารจาก application ออกสู่ภายนอก ↓ NAT Gateway ↓ Internet
เป็น configuration ที่วาง ALB ไว้ที่ทางเข้า ตามด้วย ECS Fargate application อยู่ด้านหลัง และ PostgreSQL อยู่ด้านในสุด
เหตุผลที่เลือก configuration นี้มี 3 ข้อ
- เพื่อไม่ให้ application ตัวจริงเปิดเผยสู่ internet โดยตรง
- เพื่อป้องกัน database โดยวางไว้ด้านในลึกยิ่งขึ้น
- เพื่อรันแอพด้วย container ทำให้ redeploy ง่ายขึ้น
admin app ต่างจาก service ที่เปิดให้สาธารณะทั่วไป ข้อมูลที่จัดการและสิทธิ์การใช้งานมักมีความสำคัญสูงกว่า จึงให้ความสำคัญกับ configuration ที่แยกจุดเข้า, application, และ database ออกจากกันเป็นขั้นๆ

แนวคิดการ Initialize Database สำหรับ RDS for PostgreSQL
สำหรับแอพนี้ แทนที่จะเตรียม database บน AWS ให้ว่างเปล่าเฉยๆ ฉันทำให้สามารถใส่ข้อมูลที่ใกล้เคียงกับ local development environment ได้
โดยเฉพาะ entrypoint script ก่อนที่ application container จะเริ่มทำงาน จะดำเนินการดังนี้
- รอจนกว่า PostgreSQL จะใช้งานได้
- apply full dataset SQL สำหรับ development environment
- apply SQL สำหรับแปลงสกุลเงินเยน
- จากนั้นจึงเริ่ม Spring Boot application
ด้วยวิธีนี้ ทำให้ตรวจสอบหน้า login และหน้ารายการบน AWS ได้ในเงื่อนไขที่ใกล้เคียงกับ local
จุดที่ติดขัดจริงตอน Deploy AWS ECS/Fargate + RDS
ระหว่างขึ้น AWS มีจุดที่ติดขัดชัดเจนอยู่หลายจุด
1. Spring Profile ไม่ตรงกัน
ฝั่ง ECS เริ่มด้วย aws-postgres แต่ฝั่ง config file แยกเป็น aws กับ postgres ทำให้ตกไปที่ configuration ที่ไม่ได้ตั้งใจ
เพื่อแก้ปัญหานี้ ฉันรวม configuration สำหรับ AWS ไว้ที่ application-aws-postgres.yml ให้ profile name กับเนื้อหา configuration ตรงกัน
2. ตัดสินใจว่า Startup เสร็จสมบูรณ์ยาก
แม้ CloudFormation จะเสร็จแล้ว แต่บางครั้ง task ใหม่ยังไม่เริ่มทำงานสมบูรณ์ หรือ browser ยังเห็นสถานะเก่าอยู่
ด้วยเหตุนี้ ฉันจึงตรวจสอบการเสร็จสมบูรณ์ตามลำดับนี้
- CloudFormation เสร็จสมบูรณ์
- ECS Service เข้าสู่ steady state
- ตรวจสอบ profile, JDBC URL, dataset initialization เสร็จสมบูรณ์, และ log การเริ่มแอพใน CloudWatch Logs
- สุดท้ายตรวจสอบว่า login สำเร็จบน browser
3. ตรวจสอบการแสดงผลบนมือถือไม่เพียงพอ
ถ้าดูแค่หน้า login แล้วถือว่าเสร็จ หน้าจอหลัง login ที่ใช้ layout ร่วมกันอาจพังได้
ดังนั้นตอนแก้ไข mobile ฉันจึงรวมไม่ใช่แค่หน้า login แต่รวม dashboard และหน้า admin แต่ละหน้าเข้าไปในขอบเขตการตรวจสอบด้วย
สิ่งที่ให้ความสำคัญในมุมมอง Configuration และ Operation
สิ่งที่ให้ความสำคัญที่สุดในการสร้างครั้งนี้ ไม่ใช่แค่การรันได้บน AWS แต่เป็นการสร้าง configuration ที่จัดการต่อเนื่องได้หลังจากนั้น
โดยเฉพาะให้ความสำคัญกับประเด็นต่อไปนี้
1. ไม่เปิดเผย Application ตัวจริงโดยตรง
แทนที่จะให้ access เข้า ECS task ได้โดยตรง ฉันวาง ALB ไว้ที่ทางเข้าเพื่อแยกขอบเขตการเปิดเผยให้ชัดเจน
2. วาง Database ไว้ด้านในลึกยิ่งขึ้น
ทำให้ RDS เชื่อมต่อได้เฉพาะจาก application เท่านั้น และตั้ง configuration ให้เข้าถึงจาก internet โดยตรงไม่ได้
3. นำขั้นตอนตรวจสอบหลังสร้างเข้ามาอยู่ใน Operation
ทำให้การตัดสินใจว่าเสร็จสมบูรณ์ไม่ใช่แค่ CloudFormation เสร็จ แต่รวม ECS, CloudWatch Logs, และการตรวจสอบบน browser ด้วย
4. ไม่ทำผิดพลาดซ้ำเมื่อเกิดปัญหา
บันทึกปัญหาที่เกิดขึ้น จุดที่ปรับปรุง และกฎการ operate ไว้เป็นเอกสาร เพื่อให้ใช้ได้อีกครั้งตอนสร้างใหม่ในครั้งต่อไป
สิ่งที่สังเกตเห็นจากการดู Billing
หลังจากตรวจสอบการทำงานเสร็จแล้ว พบว่า billing ของ AWS เป็นประเด็นรองในการตัดสินใจเรื่อง configuration ที่มองข้ามไม่ได้
องค์ประกอบที่ส่งผลต่อค่าใช้จ่ายจริงๆ คือ
- NAT Gateway
- Application Load Balancer
- ECS Fargate
- RDS
โดยเฉพาะ NAT Gateway กับ ALB มักสะสมใกล้เคียงกับ fixed cost แม้ปริมาณการใช้งานจะน้อย ทำให้เป็น configuration ที่หนักกว่าที่คิดไว้สำหรับ environment สำหรับ verification
สิ่งที่พบคือแค่หยุด ECS หรือ RDS ยังไม่พอ ถ้า ALB หรือ NAT Gateway ยังอยู่ billing ก็ยังคงดำเนินต่อไป
ด้วยเหตุนี้ การตัดสินใจด้าน operation จึงเปลี่ยนไปเป็น ช่วงที่ไม่ได้ใช้งานควรทำถึงขั้น “ลบ stack” ไม่ใช่แค่ “หยุด”
สิ่งที่ทำแล้วดีในครั้งนี้
สิ่งที่ดีในงานครั้งนี้คือไม่จบแค่ implementation แต่จัดระเบียบให้นำกลับมาใช้ซ้ำได้ในภายหลัง
โดยเฉพาะสร้างเอกสาร 3 ประเภทต่อไปนี้ขึ้นมา
- ภาพรวม configuration สำหรับผู้อ่านทั่วไป
- บันทึกรายละเอียดการสร้างจริงและการรับมือปัญหา
- บันทึก operation สำหรับอัปเดตต่อเนื่องเรื่อง issue, ปัญหา, จุดปรับปรุง, และผลลัพธ์
ถ้าสร้างเสร็จแล้วจบเลย ครั้งต่อไปมักจะติดขัดที่จุดเดิมอีก แต่ถ้าบันทึก configuration, ปัญหา, จุดปรับปรุง, และผลลัพธ์ไว้ การสร้างใหม่หรือเขียนเป็นบทความจะง่ายขึ้นมาก
สรุป
เมื่อลองทำให้ Spring Boot + Thymeleaf admin app รันบน AWS ECS/Fargate ได้จริง พบว่าต้องจัดระเบียบมากกว่าแค่งาน deploy รวมถึง configuration design, ขั้นตอน operation, security, และวิธีตรวจสอบด้วย
สิ่งที่ได้เรียนรู้เป็นพิเศษครั้งนี้คือ
- admin app ไม่ใช่แค่รันได้ก็พอ ต้องตัดสินใจล่วงหน้าว่าจะเปิดเผยแค่ไหน
- สำหรับ admin screen แบบ server-rendered การออกแบบการเก็บ state สำคัญมาก
- การตัดสินใจว่า AWS เสร็จสมบูรณ์ แค่ CloudFormation เสร็จอย่างเดียวไม่พอ
- การวาง database และ application แยกเป็นขั้นๆ จัดการง่ายกว่า
- แม้เป็น environment สำหรับ verification ALB กับ NAT Gateway ก็ส่งผลต่อค่าใช้จ่ายได้ง่าย
- มีบางกรณีที่ลบเหมาะสมกว่าหยุด
- การเก็บบันทึกงานและเอกสาร configuration ไว้ ทำให้ครั้งต่อๆ ไปง่ายขึ้นมาก
หวังว่าจะเป็นประโยชน์กับคนที่อยู่ในสถานการณ์เดียวกัน ไม่ว่าจะเป็นคนที่ต้องการนำ Spring Boot business app ขึ้น AWS หรือคนที่กำลังลังเลเรื่องสมดุลระหว่าง configuration กับ cost