SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-28

รัน Docker บน VPS ต้องระวังอะไรบ้าง? ปัญหาที่พบบ่อย

การใช้งาน Docker บน VPS ต่างจากการรันในเครื่องส่วนตัว ทั้งเรื่อง RAM ที่จำกัด การทะลุผ่าน UFW ของพอร์ตที่เปิดไว้ ปัญหาคอนเทนเนอร์ไม่รีสตาร์ท และดิสก์เต็มจากไฟล์ขยะที่สะสม

สิ่งที่เปลี่ยนไปเมื่อรัน Docker บน VPS

Docker บน VPS ใช้เอนจินและอิมเมจชุดเดียวกับที่รันบนแล็ปท็อปของคุณ ดังนั้นทุกคำสั่งที่คุณคุ้นเคยจึงยังคงใช้งานได้เหมือนเดิม สิ่งที่เปลี่ยนไปคือสภาพแวดล้อมโดยรอบ แล็ปท็อปมีหน่วยความจำเหลือเฟือ มีไฟร์วอลล์ที่ไม่มีใครสแกน และมีดิสก์ขนาดใหญ่จนคุณแทบไม่ต้องกังวล แต่เซิร์ฟเวอร์เช่ามีขีดจำกัดของหน่วยความจำที่แน่นอน มี IP สาธารณะที่ถูกสแกนภายในไม่กี่นาทีหลังจากบูตเครื่อง และมี root filesystem ที่ Docker จะเขียนข้อมูลลงไปจนเต็มโดยไม่แจ้งเตือน

ความแตกต่าง 4 ประการต่อไปนี้เป็นสาเหตุของปัญหาที่พบบ่อยที่สุดบนเซิร์ฟเวอร์ขนาดเล็ก:

  • หน่วยความจำมีจำกัด และเคอร์เนลจะแก้ไขปัญหาการขาดแคลนหน่วยความจำด้วยการสั่ง kill กระบวนการทำงาน
  • พอร์ตที่เปิดใช้งาน (published port) จะทะลุผ่าน UFW (uncomplicated firewall) ไปโดยตรง เนื่องจาก Docker เขียนกฎไฟร์วอลล์ของตัวเอง
  • คอนเทนเนอร์จะไม่กลับมาทำงานใหม่หลังจากการรีบูต เว้นแต่คุณจะกำหนดค่าไว้ล่วงหน้า
  • อิมเมจ, คอนเทนเนอร์, วอลุ่ม และ build cache จะเพิ่มขนาดขึ้นเรื่อยๆ จนกว่าดิสก์จะเต็ม

แต่ละหัวข้อด้านล่างจะระบุถึงความล้มเหลว, ข้อความแจ้งเตือนที่คุณจะพบจริง และคำแนะนำในการแก้ไขปัญหาอย่างละเอียด หากคุณยังไม่ได้เขียนไฟล์ compose ให้ศึกษา พื้นฐาน Docker Compose บน VPS ก่อนแล้วจึงกลับมาหน้านี้ หน้าเว็บนี้ตั้งสมมติฐานว่าคุณรู้วิธีการรัน stack ขึ้นมาใช้งานได้แล้ว

Docker container ใช้ RAM เท่าไหร่?

น้อยกว่าที่คนส่วนใหญ่คาดไว้ Container เป็นเพียง process หนึ่งที่อยู่ภายใน cgroup (control group) ไม่ใช่ virtual machine จึงไม่มี guest kernel และไม่มีการจัดสรรทรัพยากรแบบคงที่ ต้นทุนการใช้หน่วยความจำขึ้นอยู่กับสิ่งที่ process ภายในเรียกใช้งานจริง นี่คือเหตุผลที่ full stack สามารถทำงานได้ใน 2 GB ในขณะที่ stack เดียวกันหากสร้างด้วย virtual machine จะไม่สามารถทำได้

ตัวเลขด้านล่างนี้เป็นค่าเฉลี่ยขณะ idle ของ stock image บน Ubuntu 24.04 ที่ใช้การตั้งค่าเริ่มต้น โดยอ่านค่าจาก docker stats หลังจากเริ่มทำงานไปแล้วไม่กี่นาที ตัวเลขเหล่านี้เป็นเพียงจุดเริ่มต้นสำหรับการวางแผน ไม่ใช่เกณฑ์มาตรฐานสำหรับ workload ของคุณ ให้รัน docker stats --no-stream บนเครื่องของคุณเองก่อนที่จะเชื่อถือตัวเลขใดๆ รวมถึงตัวเลขเหล่านี้ด้วย

ChartTypical idle container memory, stock images, megabytes
The data behind this chart
[
  {
    "label": "nginx",
    "idle_mb": 8,
    "budget_mb": 64
  },
  {
    "label": "Redis 7",
    "idle_mb": 12,
    "budget_mb": 128
  },
  {
    "label": "Traefik v3",
    "idle_mb": 40,
    "budget_mb": 128
  },
  {
    "label": "PostgreSQL 16",
    "idle_mb": 45,
    "budget_mb": 512
  },
  {
    "label": "Uptime Kuma",
    "idle_mb": 95,
    "budget_mb": 256
  },
  {
    "label": "MariaDB 11",
    "idle_mb": 190,
    "budget_mb": 512
  },
  {
    "label": "Nextcloud (Apache)",
    "idle_mb": 210,
    "budget_mb": 768
  }
]

ทั้งสองคอลัมน์มีหน้าที่ต่างกัน idle_mb คือปริมาณที่ container ใช้ในขณะที่ไม่มีการทำงานใดๆ ส่วน budget_mb คือปริมาณที่ควรสำรองไว้เมื่อคุณวางแผน เพราะการใช้งานจริงไม่ได้หยุดนิ่ง PostgreSQL มีค่า idle อยู่ที่ประมาณ 45 MB และต้องการ 512 MB เมื่อมีการเชื่อมต่อ การเรียงลำดับข้อมูล และการใช้ cache เกิดขึ้นจริง ให้วางแผนโดยใช้คอลัมน์ budget และใช้คอลัมน์ idle สำหรับการ debug

สังเกตลักษณะของแถว 7 เหล่านั้น nginx มีค่า idle อยู่ที่ 8 MB และ Nextcloud อยู่ที่ 210 MB ตัว proxy ที่อยู่หน้าแอปพลิเคชันของคุณแทบจะไม่กินทรัพยากรเลย ส่วนฐานข้อมูลและแอปพลิเคชัน PHP คือสิ่งที่คุณต้องใช้กำหนดขนาดของเครื่อง

ข้อควรระวังเกี่ยวกับ docker stats: ตัวเลขหน่วยความจำนี้รวมถึง page cache ที่เกิดจากการอ่านไฟล์ของตัว container เองด้วย ดังนั้นค่าจะค่อยๆ เพิ่มขึ้นหลังจากเริ่มทำงานและจะคงที่ในเวลาต่อมา ให้เฝ้าสังเกตค่านี้เป็นเวลาหนึ่งชั่วโมงก่อนที่จะตัดสินว่ามีส่วนใดของระบบที่หน่วยความจำรั่วไหล (leaking)

การเลือกขนาด VPS: สิ่งที่รองรับได้ใน 2 GB, 4 GB และ 8 GB

ให้หักส่วนที่โฮสต์ต้องใช้ทิ้งไปก่อน Kernel, systemd, journald, sshd และ Docker daemon ล้วนใช้ RAM ชุดเดียวกับคอนเทนเนอร์ของคุณ และ dockerd ร่วมกับ containerd จะใช้ RAM ไปประมาณ 100 MB คุณยังจำเป็นต้องเหลือหน่วยความจำไว้สำหรับ page cache และรองรับช่วงที่มีการใช้งานสูง เช่น ขณะ build image หรือทำ database dump

ChartRAM budget by plan size, megabytes
The data behind this chart
[
  {
    "plan": "2 GB VPS",
    "total_mb": 2048,
    "host_reserve_mb": 768,
    "container_mb": 1280
  },
  {
    "plan": "4 GB VPS",
    "total_mb": 4096,
    "host_reserve_mb": 1024,
    "container_mb": 3072
  },
  {
    "plan": "8 GB VPS",
    "total_mb": 8192,
    "host_reserve_mb": 1536,
    "container_mb": 6656
  }
]

host_reserve_mb ครอบคลุมถึงระบบปฏิบัติการ, Docker daemon และพื้นที่สำรองเพื่อให้เซิร์ฟเวอร์ยังคงตอบสนองได้ดีภายใต้ภาระงาน ส่วนที่เหลือคือ container_mb ซึ่งเป็นตัวเลขเดียวที่คุณสามารถนำไปใช้งานได้จริง พื้นที่สำรองนี้จะเพิ่มขึ้นตามแผนบริการ ตั้งแต่ 768 MB ในเครื่องขนาดเล็กที่สุด ไปจนถึง 1536 MB ในเครื่องขนาดใหญ่ที่สุด เนื่องจากเครื่องที่ใหญ่กว่าจะรันคอนเทนเนอร์จำนวนมากกว่า, เขียน log มากกว่า และต้องการ page cache มากกว่า

แผน 2 GB จะเหลือพื้นที่สำหรับคอนเทนเนอร์ 1280 MB หากคุณจัดสรร 512 MB ให้กับ PostgreSQL และ 128 MB ให้กับ Traefik พื้นที่ครึ่งหนึ่งก็จะถูกใช้ไปทันที ส่วนที่เหลือจะรองรับแอปพลิเคชันขนาดเล็กได้อีกสองตัวที่ประมาณ 256 MB ต่อตัว นี่ถือเป็นเซิร์ฟเวอร์ที่ใช้งานได้จริง แต่ไม่ใช่พื้นที่สำหรับ Nextcloud และ search cluster รวมกัน

แผน 4 GB จะเหลือพื้นที่ 3072 MB ซึ่งเพียงพอสำหรับฐานข้อมูล, reverse proxy, แอปพลิเคชันสามตัว และคอนเทนเนอร์สำหรับ monitoring พร้อมกัน นี่คือขนาดที่เล็กที่สุดที่คุ้มค่าสำหรับการใช้งานจริงที่คุณให้ความสำคัญ เพราะหน่วยความจำที่เหลือจะช่วยรองรับกรณีการ deploy ที่มีปัญหาได้

แผน 8 GB จะเหลือพื้นที่ 6656 MB จากทั้งหมด 8192 MB ซึ่งโดยปกติแล้วข้อจำกัดจะเปลี่ยนจากหน่วยความจำไปเป็น CPU หรืออัตราการรับส่งข้อมูลของดิสก์แทน คอนเทนเนอร์บางประเภทจะกำหนดขนาดตัวเองจากค่าคอนฟิกมากกว่าภาระงานจริง เช่น local model server จะจอง KV cache ตามขนาดของ context window ดังนั้น การเพิ่ม num_ctx ของ Ollama อาจทำให้ต้องใช้หน่วยความจำเพิ่มขึ้นหลาย GB ก่อนที่จะมีคำขอเข้ามาแม้แต่รายการเดียว หากการคำนวณระบุว่า stack ของคุณไม่สามารถรันได้ ให้เลือกแผนที่ใหญ่ขึ้นแทนการพยายามปรับแต่งเพื่อเลี่ยงปัญหา: ต้นทุนที่แท้จริงของ VPS จะอธิบายว่าการเพิ่มหน่วยความจำแต่ละ GB นั้นคุ้มค่าเพียงใดต่อเดือน

กฎสองข้อที่จะช่วยให้การคำนวณของคุณแม่นยำคือ กำหนด memory limit ให้กับทุกบริการ เพื่อไม่ให้กระบวนการที่ทำงานผิดปกติเพียงตัวเดียวดึงทรัพยากรไปจนหมดทั้งเครื่อง และควรเหลือพื้นที่หน่วยความจำไว้โดยไม่ใช้งาน เพราะ docker compose build และ pg_dump มักต้องการหน่วยความจำในช่วงเวลาที่วิกฤตที่สุด การจำกัดหน่วยความจำใน Docker Compose มีรายละเอียดเกี่ยวกับไวยากรณ์และข้อควรระวังที่คุณต้องทราบ

เหตุใดคอนเทนเนอร์ของฉันจึงหยุดทำงานด้วยรหัส 137?

เป็นเพราะ kernel สั่งยุติการทำงานของคอนเทนเนอร์นั้น รหัส 137 เกิดจาก 128 บวก 9 ซึ่งสัญญาณที่ 9 คือ SIGKILL คอนเทนเนอร์ใช้หน่วยความจำเกินกว่าที่ได้รับอนุญาต ทำให้ out of memory (OOM) killer เข้ามาจัดการ

CONTAINER ID   IMAGE         STATUS
9f2c1a4d7b3e   postgres:16   Exited (137) 4 minutes ago

ยืนยันสาเหตุแทนการคาดเดา:

docker inspect my-db | grep -i oomkilled
sudo journalctl -k | grep -i "out of memory"

"OOMKilled": true หมายความว่าคอนเทนเนอร์ใช้งานเกินขีดจำกัด cgroup ของตนเอง และ log ของ kernel จะระบุชื่อกระบวนการที่ถูกเลือกให้ยุติการทำงาน:

Memory cgroup out of memory: Killed process 2417 (postgres) total-vm:1284416kB

นี่เป็นกรณีที่ดีเพราะความเสียหายจำกัดอยู่เพียงคอนเทนเนอร์เดียว กรณีที่แย่คือคอนเทนเนอร์ที่ไม่มีการกำหนดขีดจำกัดไว้เลย หากไม่มีขีดจำกัด เพดานการใช้งานของคอนเทนเนอร์จะเท่ากับทรัพยากรทั้งหมดของเครื่อง ดังนั้นหากบริการหนึ่งมีการรั่วไหลของหน่วยความจำ (memory leak) จะทำให้โฮสต์ขาดแคลนทรัพยากร และ kernel จะเลือกยุติกระบวนการใดกระบวนการหนึ่งในระบบโดยพิจารณาจากขนาดของหน่วยความจำที่ใช้ บรรทัดใน log จะไม่มีคำนำหน้า Memory cgroup และจะแสดงเป็น Out of memory: Killed process 2417 (postgres) แทน กระบวนการที่ถูกเลือกมักจะเป็นฐานข้อมูลของคุณ ในขณะที่คอนเทนเนอร์ที่เป็นต้นเหตุของการรั่วไหลยังคงทำงานต่อไป นี่คือเหตุผลว่าทำไมการกำหนดขีดจำกัดให้กับทุกบริการจึงมีความสำคัญมากกว่าค่าที่แม่นยำของขีดจำกัดใดขีดจำกัดหนึ่ง

Swap เปลี่ยนแปลงจังหวะเวลาแต่ไม่ได้เปลี่ยนหลักการคำนวณ VPS ส่วนใหญ่ที่ติดตั้งมาไม่มีการตั้งค่า swap ให้ตรวจสอบด้วย swapon --show ซึ่งจะไม่แสดงผลลัพธ์ใดๆ หากไม่มีการตั้งค่า swap ไว้ การสร้าง swap file ช่วยให้ kernel มีพื้นที่สำหรับพักข้อมูลที่ไม่ได้ใช้งาน (cold pages) ซึ่งช่วยซื้อเวลาให้คุณได้ตรวจสอบปัญหา

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -h

free -h ควรแสดงค่ารวมที่ไม่ใช่ศูนย์ในแถว Swap ทั้งนี้ swap ไม่ได้เป็นการเพิ่ม RAM เครื่องที่อยู่ภายใต้แรงกดดันด้านหน่วยความจำตลอดเวลาจะทำงานช้าลงจนคุณไม่สามารถ SSH เข้าไปแก้ไขได้ ดังนั้นให้มองว่า swap เป็นบัฟเฟอร์สำหรับแจ้งเตือนและเร่งแก้ไขการจัดสรรทรัพยากรให้เหมาะสม

เหตุใด UFW จึงไม่บล็อกพอร์ต Docker ที่ฉันเปิดใช้งาน?

เนื่องจากทราฟฟิกไม่เคยเดินทางไปถึง chain ที่ UFW ดูแลอยู่ เมื่อคุณเปิดพอร์ตด้วย -p 5432:5432 หรือรายการ ports: ใน compose ตัว daemon จะเขียนกฎ DNAT (destination network address translation) ลงในตาราง nat และกฎ accept ลงใน chain DOCKER ของตัวมันเอง แพ็กเก็ตที่มุ่งหน้าไปยังคอนเทนเนอร์จะถูกส่งต่อไปยังคอนเทนเนอร์นั้นแทนที่จะส่งมอบให้โฮสต์ ดังนั้นมันจึงถูกจัดการในเส้นทาง FORWARD และไม่เคยผ่านกฎ INPUT ที่ UFW เขียนไว้

คุณสามารถตรวจสอบเหตุการณ์นี้ได้บนเซิร์ฟเวอร์:

sudo ufw status | grep 5432
sudo iptables -t nat -L DOCKER -n | grep 5432

UFW อาจแสดงสถานะ 5432 DENY IN Anywhere ในขณะที่ตาราง nat ยังคงมีกฎ DNAT tcp ... to:172.18.0.2:5432 สำหรับพอร์ตเดียวกันอยู่ จากเครื่องอื่น nc -vz your.server.ip 5432 ยังคงเชื่อมต่อได้ ฐานข้อมูลจึงอยู่บนอินเทอร์เน็ตสาธารณะทั้งที่ไฟร์วอลล์ระบุว่าไม่ได้เปิดไว้

วิธีแก้ไขคือการเปิดพอร์ตให้น้อยลง คอนเทนเนอร์ในโปรเจกต์ compose เดียวกันจะใช้เครือข่ายร่วมกันและเข้าถึงกันได้ผ่านชื่อบริการ ดังนั้นฐานข้อมูลที่ให้บริการเฉพาะแอปพลิเคชันที่อยู่ข้างๆ จึงไม่จำเป็นต้องมีรายการ ports: เลย หากคุณต้องการการเข้าถึงภายในเครื่อง ให้ผูกการเปิดพอร์ตไว้กับ loopback:

services:
  db:
    image: postgres:16
    ports:
      - "127.0.0.1:5432:5432"

หลังจาก docker compose up -d แล้ว nc -vz your.server.ip 5432 จากภายนอกจะล้มเหลว แต่ psql -h 127.0.0.1 -p 5432 บนเครื่องยังคงใช้งานได้ ใน stack ขนาดเล็กที่จัดการอย่างถูกต้อง ควรมีเพียง reverse proxy เท่านั้นที่เปิดพอร์ต 80 และ 443 เหตุใดพอร์ตที่ Docker เปิดใช้งานจึงข้าม UFW ครอบคลุมถึง chain DOCKER-USER สำหรับกรณีที่คุณจำเป็นต้องเปิดพอร์ตแต่ยังต้องการกรองทราฟฟิก และ พื้นฐานไฟร์วอลล์ UFW ครอบคลุมถึงกฎของโฮสต์ที่อยู่เบื้องล่าง

ทำไมคอนเทนเนอร์ของฉันถึงหายไปหลังจากรีบูต?

เพราะไม่มีคำสั่งใดระบุให้คอนเทนเนอร์เหล่านั้นกลับมาทำงานใหม่ คอนเทนเนอร์จะถูกสร้างขึ้นโดยมีนโยบายการรีสตาร์ทเป็น no หากคุณไม่ได้กำหนดค่าไว้ ดังนั้นเมื่อรีบูตเครื่อง คอนเทนเนอร์จะยังคงอยู่ในสถานะหยุดทำงานและ daemon จะไม่ดำเนินการใดๆ การรีบูตบน VPS เกิดขึ้นได้บ่อยครั้ง ไม่ว่าจะเป็นการอัปเดต kernel จาก unattended upgrades, การบำรุงรักษาของผู้ให้บริการ หรือลำดับเหตุการณ์ OOM ที่กล่าวถึงข้างต้น ซึ่งทั้งหมดล้วนส่งผลให้เกิดการรีบูต

เงื่อนไขสองประการต้องเป็นจริง ประการแรก daemon ต้องเริ่มทำงานเมื่อบูตเครื่อง:

systemctl is-enabled docker

คำสั่งนี้จะแสดงผล enabled บนการติดตั้ง Ubuntu มาตรฐาน จากนั้นแต่ละบริการจำเป็นต้องมีนโยบาย:

services:
  app:
    image: ghcr.io/example/app:1.4
    restart: unless-stopped

unless-stopped จะทำให้คอนเทนเนอร์กลับมาทำงานหลังจากรีบูตและเคารพสถานะของคอนเทนเนอร์ที่คุณหยุดทำงานด้วยความตั้งใจ ส่วน always จะรีสตาร์ทคอนเทนเนอร์ที่คุณหยุดไว้ด้วยความตั้งใจทุกครั้งที่ daemon เริ่มทำงานใหม่ ซึ่งอาจสร้างความประหลาดใจในระหว่างการแก้ไขปัญหา การแก้ไขไฟล์เพียงอย่างเดียวไม่เพียงพอ เนื่องจากนโยบายการรีสตาร์ทจะถูกกำหนดไว้ตั้งแต่ตอนสร้างคอนเทนเนอร์ ให้รัน docker compose up -d เพื่อสร้างคอนเทนเนอร์ขึ้นใหม่ จากนั้นตรวจสอบค่าที่ใช้งานจริง:

docker inspect my-app | grep -A3 RestartPolicy

จากนั้นให้รีบูตเครื่องด้วยความตั้งใจและรัน docker compose ps ในไดเรกทอรีของโปรเจกต์ stack ที่สามารถกลับมาทำงานได้หลังจากการรีบูตที่วางแผนไว้ ย่อมสามารถกลับมาทำงานได้หลังจากการรีบูตที่ไม่ได้วางแผนไว้เช่นกัน หาก stack ของคุณต้องการการรับประกันลำดับการทำงานหรือต้องการงานแบบ one-shot เมื่อบูตเครื่อง การใช้ systemd unit จะเป็นเครื่องมือที่เหมาะสมกว่า: การเริ่ม Docker Compose เมื่อบูตเครื่อง มีไฟล์ unit ให้ใช้งาน หากต้องการทราบว่าคอนเทนเนอร์ที่กลับมาทำงานนั้นให้บริการได้จริงหรือไม่ ให้เพิ่ม Compose healthchecks

ทำไมดิสก์ VPS ของฉันถึงเต็ม?

เพราะ Docker จะเก็บทุกอย่างไว้จนกว่าคุณจะสั่งให้ลบออก ทุก image tag ที่คุณเคยดึงมา, container ที่หยุดทำงานแล้ว, anonymous volume ที่ค้างอยู่จากการสร้างใหม่ และทุก layer ของ build cache จะยังคงอยู่บนดิสก์ บน root filesystem ขนาด 40 GB หรือ 80 GB ซึ่งเป็นขนาดปกติของแพ็กเกจเหล่านี้ พื้นที่ดังกล่าวจะเต็มจนระบบล่มในเวลาเพียงไม่กี่เดือน

เมื่อดิสก์เต็ม อาการจะไม่เหมือนกับระบบล่ม (crash) คุณจะได้รับ no space left on device จาก container, จาก apt, จาก journald และจาก docker pull ภายในชั่วโมงเดียวกัน PostgreSQL จะหยุดรับข้อมูลเขียนใหม่ เซิร์ฟเวอร์ยังคงทำงานอยู่ ซึ่งทำให้สังเกตเห็นได้ยากกว่าอาการ reboot วนลูป

ตรวจสอบก่อนลบ:

docker system df
df -h /

docker system df จะแบ่งพื้นที่ทั้งหมดออกเป็น images, containers, local volumes และ build cache พร้อมคอลัมน์ RECLAIMABLE แสดงข้างๆ ในเซิร์ฟเวอร์ที่มีการ build images เอง build cache มักจะเป็นส่วนที่กินพื้นที่มากที่สุด

docker image prune -a
docker builder prune
docker system df

docker image prune -a จะลบทุก image ที่ไม่มี container ใดใช้งานอยู่ docker builder prune จะล้าง build cache ทั้งสองคำสั่งนี้ปลอดภัยในขณะที่บริการต่างๆ กำลังทำงานอยู่ เพราะระบบจะข้ามสิ่งที่กำลังถูกใช้งานไป สิ่งที่ไม่ปลอดภัยคือ docker system prune --volumes ซึ่งจะลบทุก volume ที่ไม่มี container ใดอ้างอิงอยู่ในขณะนั้น stack ที่คุณหยุดทำงานไว้ในช่วงสุดสัปดาห์จะมีสถานะเป็นเช่นนั้น และ volume ของฐานข้อมูลก็จะถูกลบไปด้วย โปรดอ่าน bind mounts เทียบกับ named volumes ก่อนใช้ flag ดังกล่าว และสำรองข้อมูลไว้ก่อนเสมอ

Log ของ container เป็นส่วนที่เพิ่มขึ้นอย่างเงียบเชียบ Driver เริ่มต้นอย่าง json-file ไม่มีข้อจำกัดเรื่องขนาด ดังนั้น container ที่มีการเขียน log จำนวนมากอาจเขียนข้อมูลหลาย GB ลงใน /var/lib/docker/containers ให้จำกัดขนาดสำหรับทุก container ใน /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

นำไปใช้ด้วย sudo systemctl restart docker ซึ่งจะทำการ restart container ของคุณ ดังนั้นควรเลือกช่วงเวลาที่เหมาะสม ข้อจำกัดนี้จะมีผลกับ container ที่สร้างขึ้นหลังจากเปลี่ยนค่าเท่านั้น ดังนั้นให้สร้าง container ที่กำลังทำงานอยู่ขึ้นใหม่ด้วย docker compose up -d --force-recreate และตรวจสอบ:

docker inspect my-app | grep -A5 LogConfig
sudo du -sh /var/lib/docker/containers

ผลลัพธ์จากคำสั่ง inspect ควรแสดงค่า max-size ที่ตั้งไว้ หากค่าว่างเปล่า แสดงว่า container นั้นถูกสร้างก่อนการเปลี่ยนแปลงและยังคงเขียน log โดยไม่มีการจำกัดขนาด

นิสัยที่ช่วยให้ Docker box ขนาดเล็กทำงานได้อย่างราบรื่น

สิ่งเหล่านี้ไม่จำเป็นต้องใช้แดชบอร์ดหรือเครื่องมือที่คุณต้องเสียเวลาเรียนรู้

  • รัน docker system df และ df -h / ในวันที่ 1 ของทุกเดือน เพียงสองคำสั่งใช้เวลาสามสิบวินาที คุณก็จะเห็นแนวโน้มการใช้งานก่อนที่ปัญหาจะลุกลามจนระบบล่ม
  • กำหนดขีดจำกัดหน่วยความจำ (memory limit) ให้กับทุกบริการ รวมถึงบริการที่คุณมั่นใจว่าใช้ทรัพยากรน้อย ขีดจำกัดนี้จะช่วยเปลี่ยนเหตุการณ์ที่ระบบล่มทั้งโฮสต์ให้กลายเป็นการรีสตาร์ทเพียงคอนเทนเนอร์เดียวเท่านั้น
  • ตรวจสอบสถานะของเซิร์ฟเวอร์จากภายนอก เพื่อให้คุณได้รับแจ้งเตือนเกี่ยวกับปัญหาหน่วยความจำหรือพื้นที่ดิสก์ก่อนที่ kernel จะเข้ามาจัดการ Uptime Kuma สามารถรันในคอนเทนเนอร์และใช้หน่วยความจำขณะว่างอยู่ที่ประมาณ 95 MB
  • สำรองข้อมูลเฉพาะ volume ไม่ใช่คอนเทนเนอร์ คอนเทนเนอร์เป็นสิ่งที่ทิ้งได้แต่ volume ไม่ใช่ การสำรองข้อมูลด้วย restic บน VPS ครอบคลุมทั้งการตั้งเวลาและการทดสอบการกู้คืนข้อมูล
  • ระบุ image tag ให้ชัดเจนในไฟล์ compose และอัปเดตในวันที่คุณกำหนดเอง หากใช้ latest เวอร์ชันที่คุณได้รับจากการรัน docker compose pull ครั้งถัดไปจะเป็นเวอร์ชันล่าสุดที่เพิ่งปล่อยออกมาในเช้าวันนั้น

VPS ขนาดเล็กที่รัน Docker จะทำงานได้อย่างราบรื่นนานหลายปีหากคุณควบคุมตัวเลขสี่ค่านี้ให้อยู่ในเกณฑ์ที่เหมาะสม ได้แก่ งบประมาณหน่วยความจำ, รายการพอร์ตที่เปิดใช้งาน, นโยบายการรีสตาร์ทของแต่ละบริการ และพื้นที่ดิสก์ที่เหลืออยู่ ส่วนองค์ประกอบอื่นๆ ก็คือ Docker แบบเดียวกับที่คุณใช้งานอยู่ที่บ้านตามปกติ

FAQ

ฉันต้องใช้ RAM เท่าไรในการรัน Docker บน VPS?

ตัว Docker เองใช้ทรัพยากรน้อย โดย daemon และ containerd รวมกันใช้พื้นที่ประมาณ 100 MB ส่วนที่เหลือขึ้นอยู่กับ container ของคุณ ให้จัดสรรส่วนของ host ไว้ก่อน: 768 MB บนเครื่องขนาด 2048 MB สำหรับระบบปฏิบัติการ, daemon และพื้นที่สำรอง ซึ่งจะเหลือ 1280 MB สำหรับใช้งานจริง ฐานข้อมูลที่ใช้ 512 MB, reverse proxy ที่ใช้ 128 MB และแอปพลิเคชันขนาดเล็กอีกสองตัวสามารถรันได้ในพื้นที่นี้ ให้วัดค่าจาก stack ของคุณเองด้วย docker stats --no-stream แทนการเชื่อตัวเลขที่เผยแพร่ทั่วไป

ฉันสามารถรัน Docker บน VPS ขนาด 1 GB ได้หรือไม่?

ได้ สำหรับ container ขนาดเล็กหนึ่งหรือสองตัว แต่ควรเพิ่ม swap file ก่อนเริ่มใช้งาน พื้นที่ประมาณครึ่งหนึ่งของเครื่องขนาด 1 GB จะถูกใช้ไปทันทีเมื่อระบบปฏิบัติการและ Docker daemon ทำงาน ซึ่งจะเหลือพื้นที่สำหรับแอปพลิเคชันขนาดเล็กและ reverse proxy แต่ไม่เพียงพอสำหรับฐานข้อมูลที่มีภาระงานจริง การ build image บนเครื่องขนาดนี้อาจล้มเหลวหรือทำให้กระบวนการอื่นถูกสั่ง kill ดังนั้นควร build ที่อื่นแล้วค่อย pull image ที่เสร็จแล้วมาใช้งาน

UFW ป้องกัน Docker container ได้หรือไม่?

ไม่ได้สำหรับพอร์ตที่คุณเปิดใช้งาน (publish) Docker จะเขียนกฎ DNAT และ forward ของตัวเอง ดังนั้นแพ็กเก็ตที่มุ่งหน้าไปยังพอร์ตของ container ที่เปิดไว้จะถูกส่งต่อไปยัง container โดยตรงแทนที่จะส่งมาที่ host และกฎ INPUT ที่ UFW จัดการจะไม่เห็นแพ็กเก็ตเหล่านั้น ufw deny 5432 สามารถทำงานอยู่ได้ในขณะที่พอร์ตนั้นยังคงตอบสนองจากอินเทอร์เน็ต ให้เปิดพอร์ตเฉพาะ loopback ด้วย 127.0.0.1:5432:5432, ไม่ต้องเปิดพอร์ตสำหรับบริการภายใน หรือกรองทราฟฟิกใน chain DOCKER-USER แทน

container ของฉันจะเริ่มทำงานใหม่หลังจากรีบูต VPS หรือไม่?

จะเริ่มใหม่ก็ต่อเมื่อถูกสร้างด้วย restart policy เท่านั้น ให้ตั้งค่า restart: unless-stopped ในแต่ละ service, รัน docker compose up -d เพื่อให้ container ถูกสร้างใหม่ด้วยค่าดังกล่าว และตรวจสอบว่า systemctl is-enabled docker แสดงผลเป็น enabled จากนั้นให้ลองรีบูตเครื่องเพื่อทดสอบและตรวจสอบด้วย docker compose ps restart policy ที่คุณไม่เคยทดสอบถือว่าไม่ใช่ restart policy ที่ใช้งานได้จริง

ฉันควรลบ Docker image ที่ไม่ได้ใช้ (prune) บ่อยแค่ไหน?

รายเดือนเพียงพอสำหรับเซิร์ฟเวอร์ขนาดเล็กส่วนใหญ่ หรือเมื่อใดก็ตามที่ docker system df รายงานว่ามีพื้นที่ที่สามารถกู้คืนได้ซึ่งคุณต้องการใช้งาน docker image prune -a และ docker builder prune ปลอดภัยที่จะใช้งานในขณะที่ service กำลังรันอยู่ เนื่องจาก image และ cache ที่กำลังใช้งานอยู่จะถูกข้ามไป หลีกเลี่ยงการใช้ docker system prune --volumes เว้นแต่คุณจะทราบแน่ชัดว่า volume ใดไม่มีการอ้างอิงแล้ว เพราะคำสั่งนี้จะลบข้อมูลของ stack ใดก็ตามที่หยุดทำงานอยู่ในขณะนั้น