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

Deploy Basics

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

Terminal window
# บนเซิร์ฟเวอร์ deploy
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 restart daemon
unless-stoppedเหมือน always แต่ไม่ restart หากคุณ docker stop ด้วยตัวเอง

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

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

Terminal window
# Pull image ที่อัปเดตทั้งหมดที่กำหนดใน compose.yml
docker compose pull
# Recreate container ที่มี 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 (ไม่ commit เข้า 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:
external: true

หลัง 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.27-alpine

# Run it detached with a restart policy
docker run -d \
  --name web \
  --restart unless-stopped \
  -p 8080:80 \
  nginx:1.27-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.26-alpine
docker stop web && docker rm web
docker run -d \
  --name web \
  --restart unless-stopped \
  -p 8080:80 \
  nginx:1.26-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) เป็น 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?