SSD Nodes Learn 🎉 VPS เริ่ม $5.50/เดือน
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-13

รัน Docker บน VPS ต้องระวังอะไรบ้าง ข้อควรทราบก่อนใช้งาน

การรัน Docker บน VPS มีความเสี่ยงที่ต่างจากเครื่องส่วนตัว ทั้งปัญหา RAM เต็มจนถูก kill process พอร์ตทะลุ UFW และดิสก์เต็มจาก cache ที่สะสมโดยไม่แจ้งเตือนล่วงหน้า

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

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

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

  • หน่วยความจำมีจำกัด และ kernel จะแก้ไขปัญหาการขาดแคลนหน่วยความจำด้วยการสั่ง kill process นั้นทิ้ง
  • พอร์ตที่เปิดใช้งาน (published port) จะทะลุผ่าน UFW (uncomplicated firewall) ไปโดยตรง เพราะ Docker เขียนกฎไฟร์วอลล์ของตัวเองขึ้นมา
  • คอนเทนเนอร์จะไม่กลับมาทำงานใหม่หลังจากการรีบูต เว้นแต่คุณจะตั้งค่าไว้ล่วงหน้า
  • image, คอนเทนเนอร์, volume และ 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 คือสิ่งที่ควรสำรองไว้เมื่อคุณวางแผน เพราะการใช้งานจริงไม่ได้ idle ตลอดเวลา PostgreSQL มีค่า idle อยู่ที่ประมาณ 45 MB และต้องการ 512 MB เมื่อมีการเชื่อมต่อ การเรียงลำดับข้อมูล และ cache เริ่มทำงาน ให้วางแผนโดยใช้คอลัมน์ budget และใช้คอลัมน์ idle สำหรับการ debug

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

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

การกำหนดขนาด 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 หรืออัตราการรับส่งข้อมูลของดิสก์แทน หากการคำนวณระบุว่า stack ของคุณไม่สามารถรันได้ ให้เลือกแผนบริการที่ใหญ่ขึ้นแทนการพยายามปรับแต่งเพื่อเลี่ยงปัญหา: ต้นทุนที่แท้จริงของ VPS จะอธิบายว่าการเพิ่ม RAM อีกไม่กี่ GB นั้นคุ้มค่าเพียงใดต่อเดือน

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

ทำไม container ของฉันถึงหยุดทำงานด้วย exit code 137?

เพราะ kernel สั่งยุติการทำงานของมัน เลข 137 เกิดจาก 128 บวก 9 ซึ่งสัญญาณที่ 9 คือ SIGKILL สาเหตุคือ container ใช้หน่วยความจำเกินกว่าที่ได้รับอนุญาต และตัว 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 หมายความว่า container ทำงานเกินขีดจำกัด cgroup ของตัวเอง และ log ของ kernel จะระบุชื่อ process ที่ถูกเลือกให้ยุติการทำงาน:

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

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

Swap เปลี่ยนแปลงจังหวะเวลา แต่ไม่ได้เปลี่ยนหลักการคำนวณ VPS ส่วนใหญ่ที่ติดตั้งมาไม่มี swap ให้ตรวจสอบด้วย swapon --show ซึ่งจะไม่แสดงผลลัพธ์ใดๆ หากไม่มี swap ไฟล์ swap ช่วยให้ 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 project เดียวกันจะใช้เครือข่ายร่วมกันและเข้าถึงกันได้ผ่านชื่อบริการ ดังนั้นฐานข้อมูลที่ให้บริการเฉพาะแอปพลิเคชันที่อยู่ข้างๆ จึงไม่จำเป็นต้องมีรายการ 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 ของคุณต้องการการรับประกันลำดับการทำงานหรือต้องการรันงานแบบครั้งเดียวเมื่อบูตเครื่อง การใช้ systemd unit จะเป็นเครื่องมือที่เหมาะสมกว่า โดยสามารถดูไฟล์ unit ได้ที่ การเริ่ม Docker Compose เมื่อบูตเครื่อง และหากต้องการทราบว่าคอนเทนเนอร์ที่กลับมาทำงานนั้นให้บริการได้จริงหรือไม่ ให้เพิ่ม Compose healthchecks เข้าไป

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

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

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

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

FAQ

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

ตัว Docker เองใช้ทรัพยากรน้อย โดย daemon และ containerd รวมกันใช้พื้นที่ประมาณ 100 MB ส่วนที่เหลือขึ้นอยู่กับ container ของคุณ ให้จัดสรรส่วนของโฮสต์ไว้ก่อน โดยใช้ 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 บนเครื่องขนาดนี้อาจล้มเหลวหรือทำให้กระบวนการอื่นถูกสั่งหยุดทำงาน (OOM kill) ดังนั้นควร build ที่อื่นแล้วค่อย pull image ที่เสร็จสมบูรณ์มาใช้งาน

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

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

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

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

ฉันควรล้าง Docker image บ่อยแค่ไหน?

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