ข้ามไปยังเนื้อหา

Deploy Basics

การ deploy ที่ตรงไปตรงมาที่สุด: SSH ไปยัง server, pull image ใหม่, แล้วเริ่ม container

Terminal window
# On the deployment server
docker pull acme/api-server:2.1.0
docker stop api-server || true
docker rm api-server || true
docker run -d \
--name api-server \
--restart unless-stopped \
-p 3000:3000 \
-e DATABASE_URL="$DATABASE_URL" \
acme/api-server:2.1.0

|| true ป้องกัน pipeline ล้มเหลวหาก container ยังไม่มีอยู่ใน deploy ครั้งแรก

flag --restart บอก Docker ว่าต้องทำอะไรหาก container หยุดทำงาน:

Policyพฤติกรรม
no (ค่าเริ่มต้น)ไม่ restart เลย
on-failureRestart เฉพาะเมื่อ exit code ไม่ใช่ศูนย์
alwaysRestart เสมอ รวมถึงหลัง Docker daemon restart (หลัง docker stop ด้วยตนเองจะยังหยุดอยู่จนถึงตอนนั้น)
unless-stoppedเหมือน always แต่ไม่ restart หากคุณ docker stop ด้วยตัวเอง

สำหรับ production service ใช้ unless-stopped เพราะรอดทั้งการ reboot host และการ restart daemon แต่ยังเคารพการสั่งหยุดด้วยตัวคุณเอง

หาก server รัน service ด้วย Compose v2 อยู่แล้ว การอัปเดตทำได้ด้วยสองคำสั่ง:

Terminal window
# Pull all updated images defined in compose.yml
docker compose pull
# Recreate containers that have a newer image
docker compose up -d

Compose จะ recreate เฉพาะ service ที่ image digest เปลี่ยนแปลง โดยปล่อย service ที่ไม่เปลี่ยนแปลงให้รันต่อ หากคุณใช้ compose.yml ที่ pin image tag:

services:
api:
image: acme/api-server:2.1.0
restart: unless-stopped
ports:
- "3000:3000"
env_file:
- .env

เปลี่ยน tag ใน compose.yml แล้วรัน docker compose up -d — Compose จะตรวจพบการเปลี่ยน tag และ recreate service

ห้ามฝัง secrets ไว้ใน image ให้ส่งผ่านตอน runtime แทน

สามแนวทาง เรียงจากง่ายไปถึงปลอดภัยที่สุด:

Terminal window
docker run -d \
-e DATABASE_URL="postgres://user:pass@db:5432/app" \
-e SECRET_KEY="abc123" \
acme/api-server:2.1.0

ง่าย แต่ค่าจะปรากฏใน docker inspect output และ shell history

Terminal window
# .env (not committed to git)
DATABASE_URL=postgres://user:pass@db:5432/app
SECRET_KEY=abc123
Terminal window
docker run -d --env-file .env acme/api-server:2.1.0

สะอาดกว่า -e flags เก็บไฟล์ .env ใน secrets manager หรือ vault บน server

สำหรับทีมที่รัน Docker Swarm หรือ Compose กับ block secrets: นั้น secrets จะถูก mount เป็นไฟล์ที่ /run/secrets/<name> ภายใน container นี่คือตัวเลือกที่ปลอดภัยที่สุด — secrets ไม่ถูกเปิดเผยเป็น environment variables

services:
api:
image: acme/api-server:2.1.0
secrets:
- db_password
secrets:
db_password:
file: ./db_password.txt

หลัง pull และ restart ยืนยันว่า version ใหม่กำลังรัน:

Terminal window
docker ps
docker logs api-server --tail 20
docker inspect api-server | grep Image

Snippet ด้านล่างแสดงการ docker pull, docker run -d --restart unless-stopped, และการตรวจสอบ log — ใช้ public image ดังนั้นไม่ต้องใช้ credentials

# Pull a versioned nginx image
docker pull nginx:1.31-alpine

# Run it detached with a restart policy
docker run -d \
  --name web \
  --restart unless-stopped \
  -p 8080:80 \
  nginx:1.31-alpine

# Verify it is running
docker ps

# Check logs
docker logs web --tail 5

# Simulate an update: pull a different tag and recreate
docker pull nginx:1.30-alpine
docker stop web && docker rm web
docker run -d \
  --name web \
  --restart unless-stopped \
  -p 8080:80 \
  nginx:1.30-alpine

docker ps
ตัวเลือกBenefitCost
Deploy ด้วย docker run ตรง ๆเข้าใจง่าย ควบคุมทุกขั้นตอนได้ตรงไปตรงมาไม่มี rollback อัตโนมัติ ต้อง script การเช็คและย้อนกลับเอง
Deploy ด้วย docker compose up -dDeclarative รองรับหลาย service พร้อมกัน recreate เฉพาะที่ image เปลี่ยนยังไม่ใช่ full orchestration ไม่มี health-based rollback แบบ Kubernetes
  • Deploy image เวอร์ชันใหม่ขึ้น production โดยไม่เคยรัน vulnerability scan ก่อนเลย
  • Pull image แล้ว restart ทันทีโดยไม่ทดสอบว่า container รันขึ้นจริงก่อน promote ไปสภาพแวดล้อมถัดไป
  • Push และ deploy เฉพาะ latest tag ทำให้ไม่มี version ที่ pin ไว้ให้ rollback กลับไปได้เมื่อ deploy มีปัญหา

💡 ตัวอย่างจากของจริง

หลายทีมใช้ Trivy (open-source scanner จาก Aqua Security, github.com/aquasecurity/trivy) เป็น gate ใน pipeline ก่อนขั้นตอน deploy — หากพบ critical CVE ใน image จะ block การ deploy โดยอัตโนมัติ แทนที่จะปล่อยให้ image ที่มีช่องโหว่หลุดไปถึง production

Restart policy ใดที่ restart container เมื่อ host reboot แต่ไม่ restart หากคุณ docker stop ด้วยตั้งใจ?
docker compose up -d ทำอะไรเมื่อคุณอัปเดต image tag ใน compose.yml?
เหตุใดจึงไม่ควรฝัง secrets ไว้ใน Docker image?
flag ใดทำให้ container ที่รัง survive การ restart ของ Docker daemon หรือ host?