คู่มือ Docker Compose บน DigitalOcean Droplet 2026
A practical guide to running multi-container Docker Compose stacks on a DigitalOcean Droplet, from installation and configuration to reverse proxy setup and backup best practices.
Docker Compose เป็นเครื่องมือมาตรฐานสำหรับรัน multi-container application บน DigitalOcean Droplet เดียว โดยไม่ต้องพึ่งพา orchestration ที่ซับซ้อนอย่าง Kubernetes บทความนี้พาไล่เรียงตั้งแต่ติดตั้ง Docker Engine บน Droplet ไปจนถึงเขียน docker-compose.yml จริง เชื่อม Volume เก็บข้อมูลถาวร ตั้ง Reverse Proxy ด้วย Nginx และแนวทางแก้ปัญหาที่พบบ่อยในการใช้งานจริง
สารบัญ
ติดตั้ง Docker + Docker Compose
DigitalOcean Droplet ที่รัน Ubuntu 24.04 LTS เป็นตัวเลือกที่ใช้กันมากที่สุดสำหรับวาง Docker เพราะมี kernel และ package ที่เข้ากันได้ดีกับ Docker Engine เวอร์ชันล่าสุด สำหรับ stack ขนาดเล็กถึงกลาง (เว็บแอป + ฐานข้อมูล + cache) Droplet ระดับ Basic 2 GiB RAM / 2 vCPU ราคา $18/เดือน มักเพียงพอ ส่วนโปรเจกต์ทดสอบเดี่ยวๆ ใช้ 1 GiB RAM ที่ $6/เดือน ได้เช่นกัน (ข้อมูลราคา ณ กรกฎาคม 2026 ตรวจสอบราคาล่าสุดที่เว็บผู้ให้บริการ) วิธีติดตั้งที่แนะนำที่สุดคือใช้ convenience script ของ Docker เอง เพราะจะดึง Docker Engine, CLI และ Compose plugin มาในคำสั่งเดียว: curl -fsSL https://get.docker.com -o get-docker.sh && sudo sh get-docker.sh หลังติดตั้งเสร็จ ให้เพิ่มผู้ใช้ปัจจุบันเข้ากลุ่ม docker เพื่อไม่ต้องพิมพ์ sudo ทุกครั้ง: sudo usermod -aG docker $USER แล้ว logout/login ใหม่หนึ่งรอบให้สิทธิ์มีผล
ข้อควรรู้คือ Docker Compose เวอร์ชันปัจจุบันไม่ใช่โปรแกรมแยกต่างหากชื่อ docker-compose (มีขีด) อีกต่อไป แต่ถูกรวมเป็น plugin ของ Docker CLI เรียกผ่านคำสั่ง docker compose (มีช่องว่างแทนขีด) หากติดตั้งผ่าน convenience script หรือ apt repository ทางการ plugin นี้จะมาให้อัตโนมัติ ตรวจสอบว่าใช้งานได้ด้วย docker compose version ควบคู่กับ docker --version หากใช้ distro อื่นที่ไม่ใช่ Ubuntu/Debian เช่น CentOS หรือ Alpine ต้องเพิ่ม repository ของ Docker เองตามคู่มือทางการ เพราะ package ในคลังเริ่มต้นของหลาย distro มักเป็นเวอร์ชันเก่าหรือเป็น fork อื่นที่ syntax ต่างออกไปเล็กน้อย
สุดท้ายอย่าลืมเปิดใช้งาน service ให้ Docker เริ่มทำงานอัตโนมัติทุกครั้งที่ Droplet reboot: sudo systemctl enable --now docker และเปิด Cloud Firewall ของ DigitalOcean (ฟรี ไม่มีค่าใช้จ่ายเพิ่ม) อนุญาตเฉพาะพอร์ตที่จำเป็น เช่น 22 (SSH), 80/443 (HTTP/HTTPS) ก่อนเริ่มรัน container ที่เปิดพอร์ตออกสู่อินเทอร์เน็ต
DigitalOcean Droplets running Ubuntu 24.04 LTS are the most popular choice for Docker because the kernel and packages work seamlessly with the latest Docker Engine versions. For small-to-medium stacks (web app + database + cache), a Basic 2 GiB RAM / 2 vCPU Droplet at $18/month is usually sufficient; single test containers can use 1 GiB RAM at $6/month (pricing as of July 2026—verify current rates on the provider's website). The recommended installation method is Docker's convenience script, which pulls Docker Engine, CLI, and the Compose plugin in a single command: curl -fsSL https://get.docker.com -o get-docker.sh && sudo sh get-docker.sh After installation completes, add your current user to the docker group to avoid typing sudo every time: sudo usermod -aG docker $USER Then log out and back in once to activate the permissions.
One important detail: the current version of Docker Compose is no longer a standalone program called docker-compose (with hyphen). Instead, it's a plugin built into Docker CLI and invoked via docker compose (with space). If you install via the convenience script or official apt repository, this plugin comes automatically. Verify it works with docker compose version alongside docker --version. If you're using a different distribution like CentOS or Alpine, add Docker's own repository according to their official guide because many distros' default package collections ship older or forked versions with slightly different syntax.
Finally, enable the Docker service to start automatically whenever the Droplet reboots: sudo systemctl enable --now docker and configure DigitalOcean's Cloud Firewall (free—no extra cost) to allow only necessary ports such as 22 (SSH), 80/443 (HTTP/HTTPS) before running containers that expose services to the internet.
- แนะนำ Ubuntu 24.04 LTS + Docker convenience script ติดตั้งเร็วและได้ Compose plugin มาด้วยในคำสั่งเดียว
- Droplet Basic 2 GiB RAM / 2 vCPU ($18/เดือน) เหมาะกับ stack เว็บ+DB+cache ทั่วไป; 1 GiB ($6/เดือน) พอสำหรับทดสอบเดี่ยว
- เพิ่ม user เข้ากลุ่ม docker ด้วย usermod -aG docker $USER แล้ว login ใหม่เพื่อเลิกพึ่ง sudo
เขียน docker-compose.yml ตัวอย่างหลาย container
ที่พบบ่อยในทางปฏิบัติ — compose Specification เวอร์ชันปัจจุบันไม่บังคับให้ใส่ key version: ที่หัวไฟล์อีกต่อไป เพราะรวม syntax ของ 2.x/3.x เดิมไว้เป็นมาตรฐานเดียวแล้ว โครงไฟล์หลักประกอบด้วย key services: ที่ระบุ container แต่ละตัว, volumes: สำหรับพื้นที่เก็บข้อมูลถาวร และ networks: ถ้าต้องการแยกเครือข่ายภายในเพิ่มเติมนอกจาก network เริ่มต้นที่ Compose สร้างให้อัตโนมัติต่อโปรเจกต์อยู่แล้ว ตัวอย่าง stack เว็บแอปคู่กับฐานข้อมูล PostgreSQL: services:
web:
build: .
ports:
- 3000:3000
depends_on:
- db
env_file: .env
restart: unless-stopped
db:
image: postgres:16
volumes:
- db_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
restart: unless-stopped
volumes:
db_data:
สังเกตว่า service web ใช้ build: . เพื่อ build image จาก Dockerfile ในโฟลเดอร์ปัจจุบันเอง ส่วน service db ใช้ image: postgres:16 ดึง image สำเร็จรูปจาก registry มาใช้ตรงๆ โดยระบุเลขเวอร์ชันชัดเจนแทนการปล่อยให้เป็น latest ค่า ports: คือการ map พอร์ต host:container ส่วน environment: ใช้ตั้งค่าตัวแปรที่ container อ่านตอน start ได้ ถ้าไม่อยากใส่ค่าลับตรงไฟล์ที่ commit เข้า git ให้แยกไปไว้ใน .env แล้วอ้างผ่าน env_file: .env หรือใช้ syntax ${DB_PASSWORD} แทนค่าตรงๆ ในไฟล์
จุดที่มักเข้าใจผิดคือ depends_on ควบคุมแค่ลำดับการ start container เท่านั้น ไม่ได้รอให้แอปพลิเคชันข้างในพร้อมรับ connection จริง เช่น db container อาจ start เสร็จแต่ PostgreSQL process ยังไม่ ready รับ query หากต้องการรอจริงต้องเสริม healthcheck: ใน service db แล้วใช้ depends_on.condition: service_healthy ใน service web ท้ายไฟล์ยังมี key volumes: db_data: ประกาศ named volume ไว้ให้ Docker จัดการพื้นที่เก็บข้อมูลถาวรแยกจาก lifecycle ของ container
- ไม่ต้องใส่ version: ที่หัวไฟล์อีกต่อไป Compose Specification ปัจจุบันรวมทุก syntax ไว้ในมาตรฐานเดียว
- build: . ใช้ตอน build image เองจาก Dockerfile ในโฟลเดอร์ปัจจุบัน ส่วน image: ใช้ pull image สำเร็จรูปจาก registry
- depends_on บอกลำดับการ start container เท่านั้น ไม่รอแอปข้างในพร้อมใช้งานจริง ต้องเสริม healthcheck ถ้าต้องการรอ
- env_file: .env แยกค่าลับอย่างรหัสผ่านออกจากไฟล์ compose ที่ commit เข้า git
- ประกาศ named volume เช่น db_data: ไว้ท้ายไฟล์ในบล็อก volumes: เพื่อให้ข้อมูลอยู่ถาวรแม้ container ถูกลบ
รัน/หยุด/อัปเดต container
หลังเขียน docker-compose.yml เสร็จ คำสั่งเริ่มต้น stack คือ docker compose up -d ซึ่งจะ build (ถ้ามี build:), pull image ที่ยังไม่มีในเครื่อง และรันทุก service แบบ detached (พื้นหลัง) ตรวจสถานะ container ทั้งหมดในโปรเจกต์ด้วย docker compose ps และดู log แบบ real-time ของ service ใดก็ได้ด้วย docker compose logs -f web ซึ่งมีประโยชน์มากตอน debug ปัญหาที่แอปไม่ตอบสนองหรือ crash หลัง start
เวลาต้องการอัปเดต image เป็นเวอร์ชันใหม่ ลำดับที่ปลอดภัยคือ docker compose pull ดึง image ใหม่ทุก service ที่มี image: ระบุไว้ก่อน แล้วตามด้วย docker compose up -d --build ซึ่งจะ recreate เฉพาะ container ที่ config หรือ image เปลี่ยนไปจริงๆ ส่วน service ที่ไม่เปลี่ยนจะไม่ถูกแตะต้อง ลด downtime โดยรวม หากแก้เฉพาะ Dockerfile ของ service ที่ build เองใหม่ ใช้ docker compose build --no-cache web && docker compose up -d web เพื่อบังคับ build ใหม่ทั้งหมดไม่ให้ cache layer เก่าตกค้าง
การหยุด stack มีสองแบบที่ผลต่างกันมาก docker compose down จะหยุดและลบ container กับ network ของโปรเจกต์ แต่ named volume ยังอยู่ครบ ข้อมูลไม่หาย ส่วน docker compose down -v จะลบ volume ไปด้วย เหมาะเฉพาะตอนต้องการล้างทุกอย่างจริงๆ เช่น environment ทดสอบ ต้องระวังไม่ใช้คำสั่งนี้ผิดที่ผิดทางกับฐานข้อมูล production เด็ดขาด สำหรับงานบำรุงรักษาย่อย เช่น restart service เดียวโดยไม่ recreate ใช้ docker compose restart web และเข้าไปตรวจสอบภายใน container ที่กำลังรันอยู่ด้วย docker compose exec web sh ส่วนการล้าง image, layer และ network เก่าที่ไม่ใช้แล้วซึ่งสะสมจนกิน SSD ของ Droplet ควรรัน docker system prune -f เป็นระยะ
- docker compose up -d รันทุก service แบบ background (detached mode)
- docker compose ps และ docker compose logs -f web ใช้ตรวจสถานะและอ่าน log แบบ real-time
- docker compose pull && docker compose up -d --build ดึง image ใหม่แล้ว recreate เฉพาะ container ที่เปลี่ยน
- docker compose down เก็บ volume ไว้ ต่างจาก docker compose down -v ที่ลบ volume ด้วย ระวังข้อมูลหาย
- docker system prune -f ล้าง image/layer ที่ไม่ใช้แล้วเป็นระยะ ป้องกัน SSD ของ Droplet เต็ม
เชื่อมกับ Volumes สำหรับข้อมูลถาวร
container ตามธรรมชาติเป็น stateless — เมื่อลบ container ข้อมูลภายใน filesystem ของมันหายไปด้วย ฐานข้อมูลหรือไฟล์อัปโหลดที่ต้องอยู่ถาวรจึงต้องผูกกับ volume เสมอ Docker เสนอสองแบบหลัก คือ named volume เช่น db_data:/var/lib/postgresql/data ที่ให้ Docker จัดการพื้นที่เก็บเองใน /var/lib/docker/volumes และ bind mount เช่น ./data:/var/lib/mysql ที่ผูกกับ path จริงบน host โดยตรง เหมาะกับตอนต้องการเปิดไฟล์ดูหรือแก้จากฝั่ง host ได้ทันทีโดยไม่ต้องเข้าไปใน container
ถ้าพื้นที่ SSD หลักของ Droplet เริ่มไม่พอ (เช่น Droplet ขนาด 2 GiB มี SSD 60 GB) DigitalOcean มี Block Storage Volumes แยกต่างหากให้แนบเพิ่มได้โดยไม่ต้อง resize Droplet ทั้งลูก ราคา $0.10/GiB/เดือน เช่น 100 GiB คิด $10/เดือน ขั้นตอนคือสร้าง Volume จาก control panel หรือ doctl แนบเข้า Droplet แล้ว format และ mount เป็น path เช่น /mnt/volume_sgp1_01 ผ่าน fstab ให้ mount อัตโนมัติทุกครั้งที่ reboot จากนั้นใช้ path นั้นเป็นฝั่ง host ของ bind mount ในไฟล์ compose ได้ทันที เช่น /mnt/volume_sgp1_01/pgdata:/var/lib/postgresql/data วิธีนี้แยกข้อมูลออกจาก disk หลักของ Droplet ทำให้ backup, resize หรือย้าย Droplet ในอนาคตง่ายขึ้นเพราะ volume ย้ายข้าม Droplet ได้อิสระ
ไม่ว่าจะใช้ named volume หรือ Block Storage Volume ควรมีกระบวนการสำรองข้อมูลแยกต่างหากเสมอ อย่าพึ่ง volume เดียวเป็นสำเนาเดียวของข้อมูลสำคัญ วิธีง่ายที่สุดคือใช้ container ชั่วคราวมา tar ข้อมูลออกมาเก็บนอก volume: docker run --rm -v db_data:/data -v $(pwd):/backup busybox tar czf /backup/db_data.tar.gz /data แล้วค่อยย้ายไฟล์ backup ไปเก็บที่อื่น เช่น Spaces Object Storage
- Named volume (เช่น db_data:) ให้ Docker จัดการพื้นที่เก็บเองใน /var/lib/docker/volumes ง่ายต่อการย้ายด้วย docker เท่านั้น
- Bind mount (./data:/var/lib/mysql) เหมาะกับตอนต้องการเห็นหรือแก้ไฟล์จากฝั่ง host โดยตรง
- DO Block Storage Volumes ราคา $0.10/GiB/เดือน แนบเพิ่มพื้นที่แยกจาก SSD หลักได้โดยไม่ต้อง resize Droplet
- Mount Volume ไว้ที่ /mnt/volume_xxx ผ่าน fstab แล้วใช้ path นั้นเป็นปลายทาง bind mount ใน compose ได้ทันที
- สำรองข้อมูลด้วย docker run --rm -v ผูก tar ไปเก็บนอก container เป็นประจำ อย่าพึ่ง volume เดียวเป็นสำเนาเดียว
Reverse Proxy หน้า container ด้วย Nginx
ตรงนี้สำคัญ — แทนที่จะ publish พอร์ตของแต่ละแอปออกสู่อินเทอร์เน็ตตรงๆ วิธีที่ปลอดภัยและจัดการง่ายกว่าคือวาง Nginx เป็นทางเข้าเดียว (reverse proxy) แล้วให้ container อื่นอยู่บนเครือข่ายภายในที่ Compose สร้างให้อัตโนมัติ วิธีที่ง่ายที่สุดคือเพิ่ม service nginx:alpine เข้าไปใน compose file แล้ว mount ไฟล์ config ของตัวเองเข้าไปแทนที่ default: nginx:
image: nginx:alpine
ports:
- 80:80
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- web ภายใน nginx.conf ใช้ proxy_pass http://web:3000; ได้ตรงๆ เพราะ container ในเครือข่ายเดียวกันของ Compose ระบุ hostname กันด้วยชื่อ service ได้เองโดยไม่ต้องรู้ IP address
ข้อดีของแนวทางนี้คือ service อย่าง web หรือ db ไม่จำเป็นต้อง publish พอร์ตออกสู่ host เลย (ตัด ports: ออกจาก service เหล่านั้น) เพราะมีแค่ nginx ตัวเดียวที่เปิดพอร์ต 80/443 ออกสู่อินเทอร์เน็ต ลดพื้นผิวโจมตีลงอย่างมีนัยสำคัญ ฝั่ง DigitalOcean ให้เปิด Cloud Firewall (ฟรี ไม่มีค่าใช้จ่ายเพิ่ม) อนุญาตเฉพาะ 80/443 เข้า Droplet เท่านั้น ปิดพอร์ตภายในของ container อื่นทั้งหมดไม่ให้เข้าถึงจากภายนอกโดยตรง
สำหรับ HTTPS ทางเลือกที่ใช้กันมากคือรัน Certbot คู่กับ Nginx เพื่อออก certificate ฟรีจาก Let's Encrypt แล้วตั้ง cron ต่ออายุอัตโนมัติทุก 90 วัน หรือถ้าต้องการให้ทุกอย่างอยู่ใน compose file เดียวจบ สามารถใช้ image สำเร็จรูปอย่าง nginx-proxy คู่กับ acme-companion ที่จะออกและต่ออายุ certificate ให้อัตโนมัติตาม environment variable ของแต่ละ container โดยไม่ต้องเขียน nginx.conf เอง ไม่ว่าจะเลือกทางไหนควรทดสอบ config ด้วย nginx -t ก่อน reload จริงทุกครั้ง เพื่อกัน syntax error ทำให้เว็บล่มโดยไม่ตั้งใจ
- ใช้ nginx เป็นอีก service ใน compose แล้ว proxy_pass ไปยังชื่อ service อื่น (เช่น http://web:3000) เพราะ container resolve ชื่อกันเองได้ในเครือข่ายเดียวกัน
- ไม่ต้อง publish พอร์ตของ app service ออกสู่ host ถ้ามีแค่ nginx เป็นทางเข้าเดียว ลดพื้นผิวโจมตี
- ใช้ Certbot คู่ Nginx หรือ image สำเร็จรูปอย่าง nginx-proxy + acme-companion สำหรับออก TLS certificate อัตโนมัติจาก Let's Encrypt
- เปิด Cloud Firewall ฟรีเฉพาะพอร์ต 80/443 ปิดพอร์ตภายในของ container อื่นไม่ให้เข้าถึงจากอินเทอร์เน็ตโดยตรง
- ทดสอบ config ด้วย nginx -t ก่อน reload ทุกครั้ง ป้องกัน downtime จาก syntax error
เมื่อไหร่ควรใช้ฟีเจอร์นี้ (Use Case จริง)
Docker Compose บน Droplet เดียวเหมาะที่สุดกับ side project, staging environment, internal tool หรือ MVP ที่มีจำนวน service ไม่มากและทีมพัฒนายังเล็ก เพราะตั้งค่าเร็ว ควบคุมได้ตรงไปตรงมา ไม่ต้องเรียนรู้แนวคิด orchestration ที่ซับซ้อนอย่าง pod, service mesh หรือ ingress controller ของ Kubernetes ค่าใช้จ่ายก็จำกัดอยู่ที่ Droplet ตัวเดียวบวกกับ Volume หรือ Load Balancer ที่เพิ่มเข้ามาตามจริง ไม่มีค่า control plane เหมือนบางแพลตฟอร์ม แต่ข้อจำกัดสำคัญคือ Docker Compose รันอยู่บนเครื่องเดียว ถ้า Droplet นั้นล่มหรือ reboot กะทันหัน ทุก service ในไฟล์ compose หยุดพร้อมกันหมด ไม่มี failover ข้าม node แบบอัตโนมัติ จึงไม่เหมาะกับระบบที่ต้องการ high availability จริงจังหรือ traffic สูงจนต้อง scale แนวนอนหลาย instance เมื่อธุรกิจโตถึงจุดนั้น ทางเลือกที่ควรพิจารณาคือย้ายไป Managed Kubernetes (DOKS) ที่ control plane ฟรีและเริ่มจ่ายค่า node pool ที่ราคา Droplet ปกติ (เริ่ม $12/เดือนต่อ node) หรือถ้าไม่อยากดูแล infrastructure เองเลยก็ใช้ App Platform ที่จัดการ deploy และ scale ให้อัตโนมัติแทน กรณีมีหลาย Droplet ที่ต้องคุยกันภายใน เช่น app แยกจาก db คนละเครื่อง ก็ยังใช้ VPC (private networking) ของ DigitalOcean ได้ฟรีไม่จำกัดจำนวนต่อบัญชี โดยไม่ต้องเสียค่าใช้จ่ายเพิ่ม สำหรับคนที่ยังไม่เคยมีบัญชี DigitalOcean และอยากลองทำตามคู่มือนี้จริงก่อนตัดสินใจใช้งานต่อเนื่อง ผู้สมัครใหม่ (ที่ไม่เคยใช้ trial มาก่อน) จะได้เครดิตทดลองใช้ $200 ใช้ได้ 60 วันหลังสมัคร (ต้องผูกบัตรเครดิตหรือ PayPal ตามเงื่อนไข ณ กรกฎาคม 2026) สมัครผ่านลิงก์ รับ $200 Free Credit เพียงพอสำหรับสร้าง Droplet ทดสอบ deploy stack ตามตัวอย่างในบทความนี้ได้สบายๆ หลายสัปดาห์
- เหมาะกับ side project, staging environment, internal tool ที่มีไม่กี่ service และทีมพัฒนาเล็ก
- เหมาะกับ MVP/SaaS ระยะเริ่มต้นที่ยังไม่ต้องการ auto-scaling ข้ามหลาย node
- ไม่เหมาะกับระบบที่ต้องการ high availability ข้ามหลาย Droplet เพราะรันบนเครื่องเดียว ถ้า Droplet ล่มระบบหยุดทั้งหมด
- เมื่อ traffic โตจนต้อง scale หลาย node ค่อยพิจารณาย้ายไป Managed Kubernetes (DOKS) หรือ App Platform
ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข
Error ที่เจอบ่อยที่สุดตอนเริ่มใช้ Docker Compose คือ Error: port is already allocated เกิดจากพอร์ตฝั่ง host ที่ระบุใน ports: ถูก service อื่นบน Droplet ใช้อยู่ก่อนแล้ว (เช่น Nginx ที่ติดตั้งไว้เดิมนอก container ใช้พอร์ต 80 อยู่) ตรวจสอบว่าพอร์ตไหนถูกใช้อยู่ด้วย ss -tulpn แล้วเปลี่ยน mapping ฝั่ง host ในไฟล์ compose หรือหยุด service ที่ชนกันก่อน
อีกปัญหาที่พบตั้งแต่ขั้นตอนติดตั้งคือ permission denied while trying to connect to the Docker daemon socket ซึ่งมักเกิดจาก user ยังไม่ถูกเพิ่มเข้ากลุ่ม docker จริง หรือเพิ่มแล้วแต่ session SSH เดิมยังไม่รับสิทธิ์ใหม่ ต้อง logout แล้ว login เข้ามาใหม่ (หรือรัน newgrp docker ชั่วคราว) ปัญหาถัดมาที่เจอหลังใช้งานไปนานคือ no space left on device ซึ่งเกิดจาก image เก่า, build cache และ layer ที่ไม่ใช้แล้วสะสมจนกิน SSD ของ Droplet จนเต็ม แก้ด้วย docker system prune -a ล้างของที่ไม่ใช้ทั้งหมด หรือถ้าข้อมูลจริงเยอะจนต้องการพื้นที่เพิ่มถาวร ให้แนบ Block Storage Volume เข้ามาแทนการลบทิ้งเรื่อยๆ
กรณี container วนรีสตาร์ทไม่หยุด (restart loop) อย่าเพิ่งสั่ง restart ซ้ำเฉยๆ ให้เปิดอ่าน docker compose logs -f service_name หา error message จริงก่อนเสมอ ส่วนปัญหาตัวแปรใน .env ไม่ถูกอ่านเข้า container มักเกิดจากไฟล์ .env ไม่ได้อยู่โฟลเดอร์เดียวกับ docker-compose.yml หรือสะกดชื่อตัวแปรไม่ตรงกับที่ compose ใช้ อีกเคสที่พบไม่บ่อยแต่แก้ยากคือ container เข้าถึงอินเทอร์เน็ตไม่ได้ทั้งที่ network ดูปกติ ซึ่งบางครั้งเกิดจาก Docker แก้ iptables ของตัวเองไปขัดกับ rule ของ UFW ที่ตั้งไว้บน host กรณีนี้ต้องเพิ่ม rule ให้ตรงกับ chain DOCKER-USER ของ Docker แทนที่จะพึ่ง UFW เพียงอย่างเดียว
- Error "port is already allocated": พอร์ตซ้ำกับ service อื่นบน host ตรวจด้วย ss -tulpn แล้วเปลี่ยน mapping ฝั่ง host
- "permission denied ... docker.sock": user ยังไม่อยู่กลุ่ม docker หรือ session ค้างสิทธิ์เก่า ต้อง logout/login ใหม่
- "no space left on device": SSD เต็มจาก image/layer เก่าสะสม รัน docker system prune -a หรือแนบ Block Storage Volume เพิ่ม
แนวทางปฏิบัติที่ดีที่สุด (Best Practices)
Pin เวอร์ชัน image ให้ชัดเจนเสมอ เช่น postgres:16 หรือ nginx:1.27-alpine แทน tag latest เพราะ latest อาจถูกอัปเดตเป็นเวอร์ชันใหม่ที่มี breaking change แบบไม่ทันตั้งตัวตอน pull image รอบถัดไป ทุก service ที่ต้องรันตลอดเวลาควรตั้ง restart: unless-stopped เพื่อให้ Docker เริ่ม container ให้เองอัตโนมัติหาก Droplet reboot หรือ container crash โดยไม่ตั้งใจ และเสริม healthcheck: ให้ Compose รู้สถานะจริงของแต่ละ service ไม่ใช่แค่ "container กำลังรัน" แต่ยัง "พร้อมรับ request" ด้วยหรือไม่
ด้านความปลอดภัย ควรรัน process ภายใน container ด้วย non-root user เสมอโดยระบุ USER ใน Dockerfile ไม่ปล่อยให้รันเป็น root ตาม default ของหลาย base image ลดผลกระทบหาก container ถูกเจาะ และแยกความลับอย่าง API key กับรหัสผ่านฐานข้อมูลไว้ใน .env ที่ไม่ commit เข้า git repository เด็ดขาด ฝั่งข้อมูล ควรสำรอง Droplet ด้วย Snapshot เป็นระยะ (ราคา $0.06/GiB/เดือน) ควบคู่กับการสำรอง volume ข้อมูลจริงแยกต่างหากด้วยวิธี tar ที่กล่าวไปก่อนหน้า อย่าพึ่งแค่ Snapshot อย่างเดียวเพราะ Snapshot จับภาพทั้ง Droplet ไม่เหมาะกับการกู้คืนเฉพาะข้อมูลชุดใดชุดหนึ่งอย่างรวดเร็ว
ด้าน monitoring ควรเปิดใช้ Monitoring ฟรีของ DigitalOcean ที่มากับทุก Droplet เพื่อดูกราฟ CPU, RAM และ Disk usage ช่วยจับสัญญาณ container กิน memory จนใกล้ OOM หรือ SSD ใกล้เต็มได้ล่วงหน้าก่อนระบบล่มจริง สุดท้ายควรทำความสะอาด environment เป็นกิจวัตร ใช้ docker compose down --remove-orphans เวลาลบ service ออกจากไฟล์ compose เพื่อกัน container ค้างที่ไม่มีใน config แล้ว และรัน docker system prune เป็นระยะเพื่อไม่ให้ Droplet สะสมขยะ image, network และ build cache เก่าจนกระทบพื้นที่ใช้งานจริง
- Pin เวอร์ชัน image ชัดเจน (postgres:16 ไม่ใช่ postgres:latest) ป้องกัน breaking change แบบไม่ทันตั้งตัว
- ตั้ง restart: unless-stopped ทุก service ที่ต้องรันตลอด และเสริม healthcheck ให้รู้สถานะจริงไม่ใช่แค่กำลังรัน
- รัน process ในทุก container ด้วย non-root user ผ่าน USER ใน Dockerfile ลดผลกระทบหาก container ถูกเจาะ
- สำรอง Droplet ด้วย Snapshot ($0.06/GiB/เดือน) เป็นระยะ ควบคู่กับสำรอง volume ข้อมูลจริงแยกต่างหาก