จาก Source Code สู่มือผู้ใช้งาน: กระบวนการส่งมอบซอฟต์แวร์อย่างต่อเนื่องและกลยุทธ์การ Deploy ที่ปลอดภัย
ก่อนจะส่งมอบ (Deliver) เราต้องมั่นใจว่าการรวมโค้ด (Integrate) สมบูรณ์แล้ว
คอมไพล์โค้ด หรือสร้าง Docker Image
Unit Test และ Integration Test ผ่านทั้งหมด
ได้ชิ้นงาน (เช่น Docker Image) ที่พร้อมนำไปใช้งาน
แนวปฏิบัติในการพัฒนาซอฟต์แวร์ที่ทำให้โค้ดของเรา "พร้อมที่จะ Deploy" ไปยัง Production ได้ตลอดเวลา อย่างปลอดภัยและรวดเร็ว
✅ Automated Build & Test
✅ Deploy to Staging อัตโนมัติ
✋ Manual Approval เพื่อไป Production
"ซอฟต์แวร์พร้อมเสมอ แต่เราเลือกเวลาปล่อยเอง"
✅ Automated Build & Test
✅ Deploy to Staging อัตโนมัติ
🚀 Automated Deploy ไป Production ทันที
"ถ้า Test ผ่าน ลูกค้าจะได้ใช้ฟีเจอร์ใหม่ทันที"
เส้นทางของโค้ดจากเครื่อง Developer สู่ Production Server
Reference: DevOps Pipeline
ส่งมอบฟีเจอร์ใหม่ถึงมือลูกค้าได้เร็วขึ้น ไม่ต้องรอนานเป็นเดือน
การปล่อยทีละนิด (Small Batches) ทำให้ความเสี่ยงต่ำ และแก้ปัญหาได้ง่ายกว่าการปล่อยก้อนใหญ่
ได้รับฟีดแบ็คจากผู้ใช้จริงเร็วขึ้น เพื่อนำมาปรับปรุงผลิตภัณฑ์
กระบวนการเป็นอัตโนมัติ ลด Human Error จากการ Deploy ด้วยมือ
ก่อนจะ Deploy แอปฯ เราต้องมีโครงสร้างพื้นฐานที่พร้อมและเหมือนกันทุก Environment
การกดสร้าง Server ผ่านหน้าเว็บ Console
การเขียน Code เพื่อกำหนดโครงสร้างระบบ (เช่น Terraform, Ansible)
ในยุค Container เราจะไม่ SSH เข้าไปอัปเดตแพทช์หรือแก้โค้ดใน Server ที่รันอยู่
*Docker Image คือตัวอย่างที่ดีที่สุดของ Immutable Artifact
Artifact คือ "ของ" ที่ได้จากการ Build และพร้อมส่งมอบ (เช่น Docker Image, JAR file, Binary)
เราควร Build Artifact แค่ครั้งเดียว ในขั้นตอน CI แล้วใช้ตัวเดิม Deploy ไปยังทุก Environment (Dev, QA, Prod)
ถ้าเกิดปัญหาที่ Production เราต้องมั่นใจได้ว่า Image นั้นคือตัวเดียวกับที่ผ่านการเทสมาแล้ว
เปรียบเสมือน "โกดัง" เก็บสินค้าที่รอส่งออก
Docker Hub
Public/Private
การตั้งชื่อ Tag ของ Docker Image มีผลต่อการทำ CD อย่างมาก
เพราะเราจะไม่รู้เลยว่า 'latest' ตอนนี้คือเวอร์ชันไหนกันแน่ ทำให้ Rollback ยาก
myapp:v1.0.2 (ชัดเจน, สื่อความหมาย) myapp:git-a1b2c3d (ผูกกับ Source Code commit ได้แม่นยำ)"Code เดียวกัน แต่ Config ต่างกันตาม Environment"
เราไม่ควร Hardcode ค่า Database หรือ API Key ลงใน Docker Image แต่ควรส่งเข้าไปตอน Deploy ผ่าน Environment Variables
# Docker Compose Example
services:
web:
image: myapp:v1.0.0
environment:
- DB_HOST=${DB_HOST}
- API_KEY=${API_KEY}
ใน Enterprise CD ความปลอดภัยและการตรวจสอบย้อนกลับเป็นเรื่องสำคัญ
รู้ว่า Artifact นี้มาจาก Commit ไหน, ใครเป็นคนเขียน, และผ่านการ Test อะไรมาบ้าง
การเซ็น Digital Signature ให้กับ Image เพื่อยืนยันว่าไม่ได้ถูกแก้ไขระหว่างทาง (Supply Chain Security)
Release ไม่ใช่แค่การ Copy ไฟล์ แต่คือกระบวนการ
"จะเปลี่ยนของเก่าเป็นของใหม่ยังไง ให้ระบบไม่ล่ม และผู้ใช้ไม่บ่น?"
ค่อยๆ เปลี่ยนทีละตัว
สลับขั้วทันที (Instant Switch)
ปล่อยให้กลุ่มเล็กๆ ลองก่อน
วิธีทำงาน: หยุดระบบเก่าทั้งหมด (Downtime) -> ลงของใหม่ -> เริ่มระบบใหม่
ค่อยๆ แทนที่ Instance เก่าด้วยของใหม่ ทีละส่วน (Incrementally)
Step 1
Step 2
Complete
✅ Zero Downtime: ผู้ใช้ยังใช้งานได้ตลอด
⚠️ Risk: จะมีช่วงเวลาที่ v1 และ v2 ทำงานพร้อมกัน (ต้องระวังเรื่อง Database/API compatibility)
สร้าง Environment ใหม่ (Green) ให้สมบูรณ์ แล้วสลับ Traffic ไปทีเดียว
User Traffic ❌
User Traffic ✅
✅ Instant Switch & Rollback: สลับไปมาได้ทันที ถ้ามีปัญหาก็สลับกลับ Blue ง่ายมาก
⚠️ Cost: เปลืองทรัพยากร 2 เท่า (ต้องมี Server รองรับทั้ง 2 environments)
"นกขมิ้นในเหมืองถ่านหิน" - ปล่อยให้ผู้ใช้กลุ่มเล็กๆ ลองก่อน
1. ปล่อย v2 ให้ User 10%
2. Monitor Error Rate / Performance
3. ถ้าดี -> ขยายเป็น 50% -> 100%
4. ถ้าพัง -> Rollback ทันที (ผู้ใช้ส่วนใหญ่ไม่ได้รับผลกระทบ)
Deploy โค้ดไปแล้ว แต่ "ปิด" ฟีเจอร์ไว้ก่อน แล้วค่อย "เปิด" เมื่อพร้อม
if (features.isEnabled('new-checkout-ui')) {
return <NewCheckout />;
} else {
return <OldCheckout />;
}
หัวใจสำคัญคือ Load Balancer และ Health Checks
1. Health Check: ระบบต้องรู้ว่า Container ตัวใหม่ "พร้อม" (Healthy) หรือยัง ก่อนจะส่ง Traffic ไปหา
2. Graceful Shutdown: Container ตัวเก่าต้องเคลียร์ Request ที่ค้างอยู่ให้จบก่อนจะดับไป
3. Database Migrations: ต้องระวังการแก้ Database ที่ทำให้เวอร์ชันเก่าพัง (Backward Compatibility)
| Strategy | Zero Downtime | Real User Testing | Cost | Rollback Duration |
|---|---|---|---|---|
| Recreate | ❌ No | ❌ No | Lowest | Slow |
| Rolling | ✅ Yes | ❌ No | Low | Slow |
| Blue/Green | ✅ Yes | ❌ No | High (x2) | Instant ⚡ |
| Canary | ✅ Yes | ✅ Yes | Low | Fast |
ใช้ Git เป็น "Single Source of Truth" สำหรับ Infrastructure และ Application
Git Repo
(Manifests)
ArgoCD / Flux
(Controller)
Kubernetes
(Cluster)
แทนที่จะรันคำสั่ง kubectl apply เอง เราแค่แก้ไฟล์ใน Git แล้วระบบจะ Sync ให้เองอัตโนมัติ
GitOps tool สำหรับ Kubernetes ยอดนิยม
Classic tool ปรับแต่งได้เยอะ แต่ต้องดูแลเอง
Platform as a Service (PaaS) ที่รวม CD มาให้ในตัว ใช้ง่าย
ใช้ทำได้ทั้ง CI และ CD (Push Docker, Deploy to Cloud)
ความปลอดภัยต้องอยู่ในทุกขั้นตอน ไม่ใช่แค่ตอนจบ
สแกนหาช่องโหว่ (CVEs) ใน Docker Image ก่อนขึ้น Production (เช่นใช้ Trivy, Snyk)
ห้ามฝัง Password ใน Code/Image ให้ใช้ Vault หรือ Secret Manager ของ Cloud
CD Tool ควรมีสิทธิ์เท่าที่จำเป็นในการ Deploy เท่านั้น
NO! เราต้องเฝ้าระวัง (Monitor) ทันที
CPU, RAM, Error Rate (Prometheus)
บันทึกเหตุการณ์ (ELK, Loki)
แจ้งเตือนเมื่อมีปัญหา (PagerDuty)
*ถ้า Deploy แล้ว Error Rate พุ่งสูง -> ต้อง Auto-Rollback ทันที
มีคำถามเกี่ยวกับ Continuous Delivery หรือ Deployment Strategies ไหมครับ?
ใน Lab ถัดไป เราจะนำโปรเจกต์ Django + React ที่ทำ CI ไว้แล้ว มาทำ CD (Continuous Deployment) ขึ้น Cloud จริงๆ
See you in the Lab!
เรียนรู้วิธีการนำ Django Application ขึ้นสู่ระบบ Production จริงบนคลาวด์ของ Render.com
เราจะใช้โค้ดจาก Branch wk07 เป็นจุดเริ่มต้นในการ Deploy
# 1. ไปที่ GitHub และทำการ Fork Repository ต่อไปนี้ไปยังบัญชีของคุณ:
https://github.com/wichitpaulsombat/djrepo
# 2. ในเครื่องของคุณ ให้ Clone repo ที่เพิ่ง Fork มา (สลับไปที่ branch wk07)
$ git clone -b wk07 https://github.com/YOUR_GITHUB_USER/djrepo.git
$ cd djrepo
requirements.txt
Render ต้องการคำสั่งในการ "Build" โปรเจกต์ เราจึงมักสร้างไฟล์ build.sh แยกไว้
# build.sh (ตรวจสอบว่ามีไฟล์นี้อยู่ในโปรเจกต์)
#!/usr/bin/env bash
# Exit on error
set -o errexit
# ติดตั้ง Dependencies
pip install -r requirements.txt
# รวบรวม Static Files (CSS, JS, Images)
python manage.py collectstatic --no-input
# อัปเดตโครงสร้างฐานข้อมูล
python manage.py migrate
gunicorn : Web Server สำหรับรัน Django บน Productionpsycopg2-binary : ตัวเชื่อมต่อฐานข้อมูล PostgreSQLdj-database-url : ตัวแปลง String URL เป็นการตั้งค่า Databasewhitenoise : ตัวช่วยเสิร์ฟ Static files1. เข้าไปที่ dashboard.render.com และ Sign in ด้วยบัญชี GitHub
2. กดปุ่ม New + และเลือก PostgreSQL
3. ตั้งค่าฐานข้อมูลดังนี้:
4. กดปุ่ม Create Database
🔑 สำคัญ: เมื่อสร้างเสร็จแล้ว ให้คัดลอก Internal Database URL เก็บไว้ (เราจะใช้เชื่อมต่อกับ Web Service)
ตอนนี้เราจะนำโค้ดจาก GitHub มาวางบนเซิร์ฟเวอร์
1. กลับมาที่หน้า Dashboard หลัก กด New + แล้วเลือก Web Service
2. เลือก Build and deploy from a Git repository แล้วกด Next
3. กด Connect ที่ Repository djrepo ของคุณ
4. ตั้งค่า Web Service เบื้องต้น:
บอกให้ Render รู้ว่าต้องรันคำสั่งอะไรเพื่อเตรียมและเปิดใช้งานแอป
ใส่คำสั่งเพื่อเรียกใช้สคริปต์ที่เราเตรียมไว้
./build.sh
ใช้ Gunicorn เสิร์ฟแอปแทนรันเซิร์ฟเวอร์ของ Django
gunicorn mysite.wsgi:application
mysite ใน Start Command ต้องตรงกับโฟลเดอร์ที่มีไฟล์ wsgi.py ในโปรเจกต์ของคุณ (ให้เช็คชื่อโปรเจกต์ในโค้ดอีกครั้ง หากตั้งชื่ออื่นให้เปลี่ยนตามนั้น)
เลื่อนลงมาที่หมวด Environment Variables และเพิ่มค่าต่างๆ ดังนี้ (กด Add Environment Variable):
เมื่อกรอกครบแล้ว ให้เลื่อนลงไปล่างสุดและกดปุ่ม Create Web Service
เมื่อกด Create แล้ว ระบบจะเริ่มกระบวนการ CI/CD ทันที
wk07./build.shpip install ทำงานสำเร็จหรือไม่https://djrepo-app.onrender.com) เพื่อดูเว็บไซต์ของคุณได้เลย!
ฐานข้อมูลบน Production เริ่มต้นจะว่างเปล่า เราต้องสร้าง Admin เพื่อเข้าหลังบ้าน
# พิมพ์คำสั่งนี้ในหน้า Shell
$ python manage.py createsuperuser
Username: admin
Email address: admin@example.com
Password:
Password (again):
Superuser created successfully.
สาเหตุ: พิมพ์ชื่อ Library ใน requirements.txt ผิด หรือเวอร์ชัน Python ไม่ตรงกัน
แก้: เช็ค Logs ให้ดีว่าตัวไหน Error และระบุ PYTHON_VERSION ให้ตรง
สาเหตุ: คัดลอก DATABASE_URL ผิด หรือใส่ External URL แทน Internal
แก้: กลับไปเช็คที่แท็บ Environment ให้แน่ใจว่าใช้ postgres://... ที่ถูกต้อง
สาเหตุ: โค้ดมีบั๊ก หรือลืมตั้ง ALLOWED_HOSTS ใน Django settings
แก้: ถ้าในโปรเจกต์ตั้ง ALLOWED_HOSTS = ['*'] ไว้แล้ว ให้ไปเช็คหน้า Logs เพื่อดู Error จริงๆ ของ Django
Render ได้เชื่อมต่อกับ GitHub Repository ของคุณเรียบร้อยแล้ว
ทุกครั้งที่คุณมีการ git push การอัปเดตโค้ดขึ้นไปยัง Branch wk07 บน GitHub ของคุณ:
https://djrepo-app.onrender.com)
/admin ที่เข้าสู่ระบบด้วย Superuser แล้ว