Skip to content

14.3 Deploy เวอร์ชันใหม่

บทนี้อธิบายขั้นตอนการ deploy สำหรับทั้ง 5 services รวมถึง rollback

ภาพรวมกระบวนการ deploy

Servicepipeline auto?มี image ใน GCRวิธี deploy จริง
vtrc-api✅ push imagemanual docker pull + docker-compose up -d
vtrc-web✅ push imagemanual docker pull + docker-compose up -d
vtrc-rc-backofficebuild image ใน host + docker-compose up -d
centralize-apibuild image ใน host + docker-compose up -d prod
cu-central-api✅ (มีใน compose)manual docker pull + docker-compose up -d

สรุป: pipeline push image จบ — การ deploy ไป server ทำด้วยมือทุกครั้ง

ขั้นตอนก่อน deploy

1. สำรองข้อมูล (ถ้าเกี่ยวข้อง)

bash
# backup database (รายละเอียดบท 13.5)
mysqldump -h <db-host> -u root -p vtrc > /backup/vtrc-$(date +%Y%m%d-%H%M).sql

2. แจ้งผู้ใช้ล่วงหน้า

  • ระบุเวลาที่จะ deploy และ downtime ที่คาดไว้
  • แจ้งช่องทางที่จะแจ้งสถานะ (อีเมล, LINE, etc.)

3. ตรวจสอบ image tag ที่จะ deploy

bash
# ดู tag ล่าสุดใน GCR (ต้องลงชื่อเข้า gcloud)
gcloud container images list-tags gcr.io/vtrc-nonprod/vtrc-api--prod

จด tag ปัจจุบันไว้สำหรับ rollback

Deploy vtrc-api

ขั้นตอน

bash
cd /home/dev/vtrc-api/

# 1. ดึง image ใหม่
docker pull gcr.io/vtrc-nonprod/vtrc-api--prod:latest

# 2. ตรวจสอบว่า image มาถึง
docker images | grep vtrc-api

# 3. deploy ทีละ replica เพื่อรักษา uptime

# replica 1
docker-compose up -d --no-deps vtrc-api
sleep 15
docker logs --tail 30 vtrc-api-nodejs
# รอจนกว่าจะเห็น "Server ready"

# ทดสอบ
curl -I https://vtrcapi.redcross.or.th/api/graphql

# replica 2
docker-compose up -d --no-deps vtrc-api-2
sleep 15
docker logs --tail 30 vtrc-api-nodejs-2

# replica 3
docker-compose up -d --no-deps vtrc-api-3
sleep 15
docker logs --tail 30 vtrc-api-nodejs-3

# replica 5
docker-compose up -d --no-deps vtrc-api-5
sleep 15
docker logs --tail 30 vtrc-api-nodejs-5

Rollback vtrc-api

bash
# 1. หา tag ก่อนหน้า
gcloud container images list-tags gcr.io/vtrc-nonprod/vtrc-api--prod

# 2. แก้ docker-compose.yml เพื่อระบุ tag ก่อนหน้า
#    image: gcr.io/vtrc-nonprod/vtrc-api--prod:<previous-tag>

# 3. pull และ restart ทีละ replica
docker pull gcr.io/vtrc-nonprod/vtrc-api--prod:<previous-tag>
docker-compose up -d --no-deps vtrc-api
# ... ทำซ้ำกับทุก replica

Deploy vtrc-web

vtrc-web เป็น static file ที่ nginx serve จาก volume ./build

ขั้นตอน

bash
cd /home/dev/vtrc-web/

# 1. pull image ใหม่
docker pull gcr.io/vtrc-nonprod/vtrc-web--prod:latest

# 2. สร้าง container ชั่วคราวเพื่อคัดลอก build
docker create --name vtrc-web-tmp gcr.io/vtrc-nonprod/vtrc-web--prod:latest
docker cp vtrc-web-tmp:/usr/share/nginx/html/build ./build-new

# 3. สำรอง build เดิม
mv /home/dev/vtrc-web/build /home/dev/vtrc-web/build-backup-$(date +%Y%m%d-%H%M)

# 4. ย้าย build ใหม่เข้าที่
mv ./build-new /home/dev/vtrc-web/build

# 5. ลบ container ชั่วคราว
docker rm vtrc-web-tmp

# 6. ทดสอบ
curl -I https://vtrc.redcross.or.th/

หมายเหตุ: วิธีนี้อาจไม่ตรงกับที่ทีมทำจริง — บางทีอาจ build ใน host โดยตรง ต้องสอบถามทีม

Rollback vtrc-web

bash
# คืน build สำรอง
rm -rf /home/dev/vtrc-web/build
mv /home/dev/vtrc-web/build-backup-<timestamp> /home/dev/vtrc-web/build

Deploy vtrc-rc-backoffice

ขั้นตอน

bash
cd /home/dev/vtrc-rc-backoffice/

# 1. pull source ใหม่ (หรือ git pull)
git pull origin prod

# 2. build (ต้องใช้ host ที่มี Node 16 และ npm)
CI=false GENERATE_SOURCEMAP=false NODE_OPTIONS=--max-old-space-size=4096 npm run build

# 3. สำรอง build เดิม
mv build build-backup-$(date +%Y%m%d-%H%M)

# 4. ย้าย build ใหม่
# build ถูกสร้างใน ./build/ โดย react-scripts

# 5. restart nginx container
docker-compose restart web-server

# 6. ทดสอบ
curl -I https://vtrcbackoffice.redcross.or.th/

Rollback

bash
rm -rf build
mv build-backup-<timestamp> build
docker-compose restart web-server

Deploy centralize-api

ขั้นตอน

bash
cd /home/dev/centralize-api/

# 1. pull source ใหม่
git pull origin main

# 2. build image ในเครื่อง (ไม่มี CI สำหรับ service นี้)
docker-compose build prod

# 3. deploy
docker-compose up -d prod

# 4. ตรวจสอบ log
docker-compose logs --tail 50 prod

# 5. ทดสอบ — Swagger UI ควรเข้าได้
curl -I http://localhost:3000/api

Rollback

bash
# กลับไป commit ก่อนหน้า
git checkout <previous-commit>
docker-compose build prod
docker-compose up -d prod

Deploy cu-central-api

ขั้นตอน

bash
cd /home/dev/cu-central-api/

# 1. ดึง image ใหม่
docker pull gcr.io/vtrc-nonprod/cu-centralize-api:latest

# 2. deploy ทีละ replica
docker-compose up -d --no-deps cu-cen-api
sleep 15
docker logs --tail 30 cu-central-api

docker-compose up -d --no-deps cu-cen-api_2
sleep 15
docker logs --tail 30 cu-central-api_2

docker-compose up -d --no-deps cu-cen-api_3
sleep 15
docker logs --tail 30 cu-central-api_3

Rollback

เช่นเดียวกับ vtrc-api — ระบุ tag ก่อนหน้าใน docker-compose.yml

สิ่งที่ต้องทอดสอบหลัง deploy

แม้จะไม่มี automated test, ควรทดสอบด้วยมือตาม checklist:

vtrc-api

  • [ ] GraphQL playground เข้าได้ที่ /api/graphql
  • [ ] login ผ่านด้วยบัญชีทดสอบ
  • [ ] ดึงข้อมูล profile สำเร็จ
  • [ ] สร้าง leave request สำเร็จ (จะไม่ submit จริง แค่ draft)
  • [ ] download payslip PDF สำเร็จ

vtrc-web

  • [ ] หน้า login โหลด
  • [ ] login สำเร็จ
  • [ ] นำทางไปหน้าหลักสำเร็จ
  • [ ] ตรวจสอบ browser console ไม่มี error

vtrc-rc-backoffice

  • [ ] หน้า login โหลด
  • [ ] login ด้วยบัญชี admin สำเร็จ
  • [ ] ดู report สำเร็จ

centralize-api

  • [ ] Swagger UI ที่ /docs โหลด
  • [ ] เรียก endpoint /api/... สำเร็จ

cu-central-api

  • [ ] เรียก GraphQL endpoint ผ่าน vtrc-api สำเร็จ (login ผ่าน vtrc-web แล้ว profile กลับมา)

ปัญหาที่พบบ่อยตอน deploy

1. image pull ไม่สำเร็จ

bash
Error response from daemon: pull access denied

สาเหตุ: ไม่ได้ลงชื่อเข้า gcloud Docker registry

แก้:

bash
gcloud auth configure-docker
docker pull ...

2. database schema เปลี่ยนระหว่าง deploy

อาการ: หลัง deploy service รัน แต่ query บางอย่าง fail

สาเหตุ: syncModelToTable() รันตอน Node start และอัปเดต schema ตาม code ใหม่

แก้: ดู log ของ vtrc-api ว่ามีการ alter table หรือไม่ ถ้า rollback ต้อง rollback schema ด้วย

3. cron job รันซ้อน

ถ้า deploy ทั้งหมดในเวลาใกล้เคียงกัน และ APP_NO=1 กลับมา online พร้อมกับ replica อื่น ๆ อาจมีกรณี cron รันซ้อน (edge case)

แก้: deploy APP_NO=1 เป็นตัวสุดท้าย และรอให้ replica อื่น stable ก่อน

4. nginx ส่งไป replica ที่ยัง boot อยู่

อาการ: ผู้ใช้ได้รับ 502 หรือ connection refused หลัง deploy

สาเหตุ: nginx upstream ส่ง traffic ไป port ที่ Node ยังไม่ฟัง

แก้: รอ docker logs แสดง "Server ready" ก่อน restart replica ถัดไป

แนวทางที่ดีขึ้น

การ deploy ด้วยมือเป็นแหล่งของความผิดพลาด — แนะนำให้:

  1. เขียน deploy script ที่ automate ขั้นตอนข้างต้น
  2. ใช้ Watchtower สำหรับ auto-update container เมื่อ image ใหม่มาถึง
  3. สร้าง pipeline สำหรับทุก repo ไม่ใช่แค่ 2 แรก
  4. เพิ่ม health check และใช้ depends_on: condition: service_healthy ใน compose
  5. ใช้ blue-green deploy แทน rolling ถ้าเป็นไปได้

รายละเอียดเพิ่มเติมอยู่ใน Volume 15 (Modernization Plan)