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

วิธีจำกัด Memory และ CPU ใน Docker Compose ป้องกัน VPS ล่ม

เรียนรู้วิธีตั้งค่า deploy.resources เพื่อจำกัดการใช้ RAM และ CPU ป้องกันคอนเทนเนอร์กินทรัพยากรจนเกิด error 137 และช่วยให้ VPS ของคุณทำงานได้อย่างเสถียรและปลอดภัยยิ่งขึ้น

ขีดจำกัดหน่วยความจำของ Docker Compose ทำหน้าที่อะไร

ขีดจำกัดหน่วยความจำของ Docker Compose คือเพดานสูงสุดที่ Linux kernel บังคับใช้กับ cgroup (control group ซึ่งเป็นฟีเจอร์ของ kernel ที่ใช้ควบคุมทรัพยากรสำหรับกลุ่มกระบวนการ) ของคอนเทนเนอร์หนึ่งๆ เมื่อคุณตั้งค่า deploy.resources.limits.memory ไว้ใน service คอนเทนเนอร์นั้นจะไม่สามารถใช้หน่วยความจำเกินกว่าจำนวนที่กำหนดได้ หากพยายามใช้เกิน kernel จะสั่งยุติกระบวนการภายในคอนเทนเนอร์นั้น และคอนเทนเนอร์มักจะหยุดทำงานด้วย exit code 137

เรื่องนี้มีความสำคัญอย่างยิ่งบน VPS ซึ่งมี RAM จำกัดและไม่มีหน่วยความจำสำรองจากโฮสต์ให้ดึงมาใช้ หากคอนเทนเนอร์ใดมีปัญหา memory leak หรือมีการประมวลผลคำสั่งที่ผิดพลาด มันอาจดึงหน่วยความจำว่างทั้งหมดบนเซิร์ฟเวอร์ขนาด 8GB ไปใช้จนหมด จากนั้น kernel จะสั่งยุติกระบวนการที่มันประเมินว่า "แย่ที่สุด" ซึ่งบ่อยครั้งมักจะเป็นฐานข้อมูลหรือเซสชัน SSH ของคุณ แทนที่จะเป็นคอนเทนเนอร์ที่เป็นต้นเหตุ การกำหนดขีดจำกัดจึงช่วยเปลี่ยนจากเหตุการณ์เซิร์ฟเวอร์ล่มทั้งระบบ ให้เหลือเพียงบริการเดียวที่รีสตาร์ทตัวเองแทน

services:
  app:
    image: ghcr.io/example/app:1.4
    deploy:
      resources:
        limits:
          cpus: "1.5"
          memory: 1g
        reservations:
          memory: 256m

นำไปใช้และตรวจสอบว่าขีดจำกัดมีผลจริง:

docker compose up -d
docker stats --no-stream

คอลัมน์ MEM USAGE / LIMIT ควรแสดงค่าประมาณ 142MiB / 1GiB หากคอลัมน์ขีดจำกัดแสดงค่า RAM ทั้งหมดของโฮสต์ แสดงว่าการตั้งค่าไม่มีผล และคำแนะนำที่เหลือในบทความนี้จะใช้งานไม่ได้จนกว่าจะแก้ไขให้ถูกต้อง หากคุณยังไม่คุ้นเคยกับไฟล์ compose สามารถดู พื้นฐาน Docker Compose สำหรับ VPS เพื่อศึกษาโครงสร้างไฟล์ที่ใช้เป็นรากฐานในที่นี้ได้

deploy.resources.limits หรือ mem_limit: ควรใช้ตัวไหน

การสะกดสองแบบสำหรับแนวคิดเดียวกันทำให้เกิดความสับสน

mem_limit, mem_reservation, memswap_limit, cpus และ cpu_shares เป็นคีย์ระดับบนสุดของ service ที่สืบทอดมาจากรูปแบบไฟล์ Compose รุ่นเก่า ส่วน deploy.resources มาจาก schema ของ Swarm และปัจจุบันเป็นส่วนหนึ่งของ Compose Specification ซึ่งเป็นรูปแบบที่ docker compose อ่านในปัจจุบัน

ทั้งสองแบบใช้งานได้บนโฮสต์เดียว Docker Compose ซึ่งเป็นปลั๊กอิน docker compose จะนำ deploy.resources.limits และ deploy.resources.reservations ไปใช้เมื่อคุณรัน docker compose up โดยไม่จำเป็นต้องมีคลัสเตอร์ Swarm ปัจจุบันปลั๊กอินอยู่ในสายการพัฒนา v5 (v5.6.0 คือรุ่นเสถียรล่าสุดเมื่อตรวจสอบ ณ วันที่ 2026-10-10) โดยข้ามจาก v2 ไป v5 ทันทีเพื่อหลีกเลี่ยงความสับสนกับเวอร์ชันของไฟล์ Compose แบบเก่า และไม่มีรุ่น v5 ใดที่เปลี่ยนแปลงวิธีการจัดการขีดจำกัดทรัพยากร ส่วนประกอบที่เน้น Swarm ของบล็อก deploy คือคีย์อื่นๆ เช่น placement, update_config และ endpoint_mode ซึ่งอธิบายการจัดตารางเวลาและการ rollout ข้ามคลัสเตอร์ของโหนดสำหรับ docker stack deploy ดังนั้นคำแนะนำทั่วไปที่ว่า "deploy ต้องใช้ Swarm" จึงไม่ถูกต้องสำหรับส่วนย่อย resources และการทำตามคำแนะนำนั้นจะทำให้ service ของคุณไม่มีการจำกัดทรัพยากรเลย

ให้เลือกใช้การสะกดแบบใดแบบหนึ่งต่อหนึ่งโปรเจกต์ การเขียนทั้ง mem_limit: 512m และ deploy.resources.limits.memory: 1g ใน service เดียวกันนั้นอ่านยากเกินไป อีกทั้ง Compose Specification ยังระบุว่าเมื่อมีการตั้งค่า mem_limit จะต้องสอดคล้องกับ limits.memory และไม่ได้ระบุว่าค่าใดจะมีผลหากทั้งสองค่าไม่ตรงกัน ไม่ว่าคุณจะใช้การสะกดแบบใด ให้ยืนยันสิ่งที่ daemon นำไปใช้จริงด้วยคำสั่งต่อไปนี้:

docker inspect --format '{{.HostConfig.Memory}} {{.HostConfig.MemoryReservation}} {{.HostConfig.NanoCpus}}' app-1

ค่าหน่วยความจำเป็นไบต์ ดังนั้น 1g จะแสดงผลเป็น 1073741824 ส่วน CPU จะอยู่ในหน่วย nano CPUs ดังนั้น 1.5 จะแสดงผลเป็น 1500000000 ค่า 0 ในฟิลด์ใดก็ตามหมายความว่าไม่มีการตั้งค่าขีดจำกัดไว้ ขีดจำกัดหน่วยความจำต่ำสุดที่ Docker ยอมรับคือ 6m หากต่ำกว่านั้น container จะปฏิเสธการเริ่มทำงาน

เกิดอะไรขึ้นเมื่อคอนเทนเนอร์ถึงขีดจำกัด

คอนเทนเนอร์จะไม่ทำงานช้าลง แต่จะหยุดทำงานทันที

เมื่อกระบวนการร้องขอหน่วยความจำและ cgroup ถึงขีดจำกัด memory.max แล้ว เคอร์เนลจะพยายามเรียกคืนหน่วยความจำภายใน cgroup นั้นก่อน โดยเริ่มจาก clean page cache ตามด้วยหน้าหน่วยความจำที่สามารถ swap ได้ หากการเรียกคืนหน่วยความจำไม่เพียงพอ ตัว OOM (out of memory) killer ของ cgroup จะเลือกกระบวนการหนึ่งภายในคอนเทนเนอร์และส่งสัญญาณ SIGKILL ให้ การสั่งยุติ PID 1 ของคอนเทนเนอร์จะทำให้คอนเทนเนอร์นั้นหยุดทำงาน รหัสสถานะ 137 เกิดจาก 128 บวกกับสัญญาณหมายเลข 9 ดังนั้น 137 จึงเป็นเพียงร่องรอยของ SIGKILL เท่านั้น ไม่ใช่หลักฐานยืนยันว่าเกิด OOM ด้วยตัวมันเอง

docker compose ps -a
docker inspect --format '{{.State.OOMKilled}} {{.State.ExitCode}}' app-1

true 137 คือการถูกสั่งยุติเนื่องจาก OOM ส่วน false 137 มักหมายความว่ามีสิ่งอื่นส่งสัญญาณ SIGKILL มาให้ (โปรแกรมอาจสั่ง exit ด้วยรหัส 137 เองได้ แต่พบได้น้อย) ซึ่งสาเหตุทั่วไปคือ docker compose stop ทำงานเกินระยะเวลาผ่อนผัน 10 วินาที เนื่องจากแอปพลิเคชันเพิกเฉยต่อสัญญาณ SIGTERM การแยกแยะความแตกต่างนี้ช่วยประหยัดเวลาได้มาก เพราะปัญหาทั้งสองอย่างไม่มีส่วนเกี่ยวข้องกันเลย

มีอีกสองแหล่งที่บันทึกเหตุการณ์นี้ไว้ ให้ตรวจสอบ daemon แบบเรียลไทม์:

docker events --filter event=oom

จากนั้นให้อ่าน log ของเคอร์เนล ซึ่งเป็นบันทึกที่ยังคงอยู่แม้หลังจากรีสตาร์ทเครื่อง:

sudo dmesg -T | grep -i -E 'memory cgroup out of memory|killed process'

การสั่งยุติโดย cgroup จะแสดงบรรทัดที่ขึ้นต้นด้วย Memory cgroup out of memory: Killed process 24713 (node) บรรทัดนั้นหมายความว่าคอนเทนเนอร์หนึ่งตัวถึงขีดจำกัดของตัวเอง และอาจปรากฏขึ้นในขณะที่โฮสต์ยังมี RAM เหลือเฟือ บรรทัดที่ไม่มีคำนำหน้า Memory cgroup คือเหตุการณ์โฮสต์ OOM ซึ่งหมายความว่าเครื่องแม่ข่ายเองที่ RAM หมด นี่คือความล้มเหลวที่ขีดจำกัดควรจะป้องกันไว้ ดังนั้นหากพบเหตุการณ์นี้ มักหมายความว่าผลรวมของขีดจำกัดที่คุณตั้งไว้สูงเกินไป, มีบริการบางอย่างไม่ได้ตั้งขีดจำกัดไว้เลย หรือมีบางอย่างภายนอก Docker กำลังใช้ RAM มากกว่าพื้นที่ว่างที่คุณเหลือไว้

เมื่อใช้ restart: unless-stopped ลูปการเกิด OOM จะถูกซ่อนไว้ได้ง่าย เพราะบริการจะดูเหมือนทำงานปกติใน docker compose ps เพียงหนึ่งวินาทีหลังจากที่มันตายไปแล้ว ให้ตรวจสอบคอลัมน์ uptime และจำนวนครั้งที่รีสตาร์ท และจับคู่ขีดจำกัดเข้ากับ healthcheck ที่รายงานว่าแอปอยู่ในสถานะไม่สมบูรณ์ เพื่อให้คอนเทนเนอร์ที่ตายซ้ำซากปรากฏให้เห็นโดยที่คุณไม่ต้องคอยเฝ้าดูตลอดเวลา

Reservation เป็นเพียงคำแนะนำ แต่ limit คือกฎเกณฑ์

reservations.memory (หรือ mem_reservation ในเวอร์ชันเก่า) เป็นค่าขั้นต่ำแบบยืดหยุ่น Docker อธิบายว่าเป็น soft limit ที่จะทำงานเมื่อ daemon ตรวจพบการแย่งชิงทรัพยากรหรือหน่วยความจำบนโฮสต์เหลือน้อย ค่านี้ไม่เคยหยุดยั้งไม่ให้ container ใช้หน่วยความจำเกินกว่าที่กำหนด และไม่รับประกันว่าจะมีหน่วยความจำว่างเมื่อ container ร้องขอ มันเพียงแค่ส่งผลให้ kernel เลือกดึงหน่วยความจำคืนจาก container ที่ใช้เกินค่า reservation ก่อนเป็นอันดับแรก

ดังนั้น reservation จึงไม่ได้ปกป้องสิ่งใดด้วยตัวมันเอง ให้ใช้มันเพื่อระบุบริการที่คุณต้องการให้ได้รับการปฏิบัติเป็นพิเศษเมื่อระบบอยู่ภายใต้ภาระงานหนัก และใช้ limit เพื่อความปลอดภัย ให้ตั้งค่า reservation ไว้ต่ำกว่า limit เสมอ มิฉะนั้น container จะไม่เริ่มทำงาน โดย Docker จะปฏิเสธการตั้งค่าดังกล่าวด้วยข้อผิดพลาด Minimum memory limit can not be less than memory reservation limit

ความจริงเกี่ยวกับ Swap accounting

VPS ส่วนใหญ่ที่ติดตั้งมามักไม่มี swap file ให้ใช้งาน ให้รันคำสั่ง swapon --show และ free -h หากค่ารวมของ swap เป็นศูนย์ การตั้งค่าที่เกี่ยวข้องกับ swap ทั้งหมดด้านล่างนี้จะไม่มีผล และขีดจำกัดหน่วยความจำของคุณจะเป็นเพียงการจำกัด RAM เท่านั้น

memswap_limit ไม่ใช่ปริมาณของ swap แต่เป็นผลรวมของหน่วยความจำและ swap หากใช้ mem_limit: 1g และ memswap_limit: 2g คอนเทนเนอร์จะได้ RAM 1GB และ swap 1GB การตั้งค่าทั้งสองค่าให้เท่ากันจะทำให้คอนเทนเนอร์ไม่มี swap เลย การตั้งค่า mem_limit โดยปล่อยให้ memswap_limit ว่างไว้ จะทำให้คอนเทนเนอร์สามารถใช้ swap ได้สูงสุดเท่ากับขนาดของขีดจำกัดหน่วยความจำเดิม

Ubuntu 24.04 และ Debian 13 ใช้ cgroup v2 เป็นค่าเริ่มต้น ซึ่ง swap จะถูกนับเป็นตัวนับแยกต่างหาก (memory.swap.max) และทำงานได้โดยไม่ต้องตั้งค่าเพิ่มเติม ข้อความแจ้งเตือนเก่าๆ อย่าง Your kernel does not support swap limit capabilities มาจากโฮสต์ที่ใช้ cgroup v1 ซึ่งไม่ได้บูตด้วยพารามิเตอร์ swapaccount=1 ในกรณีเหล่านั้น ขีดจำกัดหน่วยความจำยังคงมีผล แต่ส่วนของ swap จะถูกละเว้น

ควรพิจารณาตามความเป็นจริงว่า swap มีประโยชน์อย่างไร มันเพียงแค่ทำให้การเกิด OOM kill ช้าลงเท่านั้น ไม่ได้ทำให้โอกาสเกิดน้อยลง เพราะกระบวนการที่หน่วยความจำรั่วไหลจะเติม swap ได้รวดเร็วพอๆ กับการเติม RAM ในขณะเดียวกัน หากคอนเทนเนอร์มีการทำ thrashing บน swap ของพื้นที่จัดเก็บข้อมูล VPS ที่ใช้ร่วมกัน จะทำให้บริการอื่นๆ ทั้งหมดบนเครื่องทำงานช้าลง สำหรับงานที่ไวต่อความหน่วง (latency sensitive) การกำหนดขีดจำกัดที่ถูกต้องโดยไม่มี swap จะทำให้ระบบล้มเหลวได้เร็วกว่าและคาดการณ์ได้มากกว่า

เหตุใดการใช้หน่วยความจำจึงดูสูงกว่าความเป็นจริง

บน Linux ค่า MEM USAGE ใน docker stats จะหักออกเฉพาะ page cache ที่ไม่ได้ใช้งาน (inactive_file บน cgroup v2) เท่านั้น ดังนั้น cache ที่เพิ่งถูกใช้งานไปจะยังคงถูกนับรวมอยู่ ส่งผลให้คอนเทนเนอร์ที่อ่านไฟล์ขนาดใหญ่มีตัวเลขการใช้หน่วยความจำพุ่งสูงขึ้นจนเกือบถึงขีดจำกัดและค้างอยู่ที่ระดับนั้น นี่เป็นพฤติกรรมปกติและไม่ใช่การรั่วไหลของหน่วยความจำ เนื่องจาก clean cache จะถูกเรียกคืนก่อนที่ OOM killer จะทำงานเสมอ บริการอย่าง Jellyfin media server ที่โฮสต์เอง จึงมักแสดงตัวเลขการใช้หน่วยความจำใกล้เพดานสูงสุดอยู่ตลอดเวลาด้วยเหตุผลนี้

ให้แยกตัวเลขระหว่าง cache และ working set จริงจากภายในคอนเทนเนอร์:

docker compose exec app grep -E '^(anon|file) ' /sys/fs/cgroup/memory.stat
docker compose exec app cat /sys/fs/cgroup/memory.events

anon คือหน่วยความจำแบบ anonymous ซึ่งเป็น working set ที่ไม่สามารถลบออกได้ ส่วน file คือ page cache ซึ่งสามารถลบออกได้ ให้กำหนดขีดจำกัดโดยอิงจาก anon บวกกับส่วนเผื่อ ไม่ใช่อิงจากยอดรวมทั้งหมด ไฟล์ memory.events จะช่วยตัดสินปัญหาได้อย่างชัดเจน หากตัวนับ oom_kill มีค่ามากกว่าศูนย์ แสดงว่าเคอร์เนลได้สั่งยุติกระบวนการบางอย่างในคอนเทนเนอร์นี้ไปแล้วนับตั้งแต่เริ่มทำงาน และหากตัวนับ max มีค่าเพิ่มขึ้นเรื่อยๆ แสดงว่าคอนเทนเนอร์กำลังถูกจำกัดอยู่ที่เพดานสูงสุดในขณะนี้ คำสั่งทั้งสองจำเป็นต้องใช้ shell และ coreutils ภายในอิมเมจ ดังนั้นคำสั่งเหล่านี้จะใช้งานไม่ได้บนอิมเมจแบบ distroless หรือ scratch

การกำหนดขีดจำกัดทรัพยากรบน VPS ขนาด 8GB

ให้เริ่มพิจารณาจากโฮสต์ ไม่ใช่จากแอปพลิเคชัน บน VPS ขนาด 8GB ควรเผื่อหน่วยความจำไว้ประมาณ 1GB สำหรับเคอร์เนล, Docker daemon, sshd, journald และเชลล์สำหรับล็อกอินของคุณ ซึ่งจะเหลือพื้นที่ประมาณ 7GB ให้จัดสรร และผลรวมของขีดจำกัดคอนเทนเนอร์ทั้งหมดควรอยู่ภายใต้ค่านี้ การจัดสรรเกิน (Overcommitting) อาจใช้งานได้จนถึงวันที่บริการสองอย่างทำงานหนักพร้อมกัน

ตัวอย่างการแบ่งทรัพยากรที่ใช้งานได้บนเครื่อง 8GB:

  • Reverse proxy: จำกัดที่ 128m เนื่องจากเป็นโปรเซสขนาดเล็ก การจำกัดที่เข้มงวดเช่นนี้จะช่วยตรวจจับกรณีการโหลด config ที่ผิดพลาดได้ทันที
  • PostgreSQL: จำกัดที่ 2g โดยตั้งค่า shared_buffers ไว้ที่ประมาณ 512MB ในไฟล์คอนฟิกของฐานข้อมูล
  • Application container: จำกัดที่ 1g
  • Background worker: จำกัดที่ 512m
  • Media หรือ file service: จำกัดที่ 2g ซึ่งส่วนใหญ่จะถูกใช้เป็น page cache

อย่าคัดลอกตัวเลขเหล่านี้ไปใช้กับ stack ของคุณโดยตรง ให้รันบริการภายใต้โหลดจริงเป็นเวลาหนึ่งวัน ตรวจสอบ docker stats นำค่า anon สูงสุดของแต่ละคอนเทนเนอร์มาคำนวณ แล้วบวกเพิ่มอีกประมาณครึ่งหนึ่งเพื่อเป็นพื้นที่สำรอง การตั้งขีดจำกัดที่เข้มงวดเกินไปนั้นแย่กว่าการไม่ตั้งเลย เพราะมันจะทำให้บริการที่ทำงานปกติถูกสั่งหยุดทำงานในช่วงที่มีปริมาณการใช้งานสูง

มีกับดักหนึ่งอย่างที่ควรระวังเป็นพิเศษ รันไทม์บางตัวจะเพิกเฉยต่อขีดจำกัดหากคุณไม่ได้ระบุให้มันทราบ และตัวที่อ่านค่าได้ก็อาจไม่ได้ปรับขนาดตัวเองในแบบที่คุณคาดหวัง PostgreSQL จะปรับขนาด shared_buffers และ work_mem เกินขีดจำกัดของคอนเทนเนอร์และถูกสั่งหยุดทำงานในที่สุด JVM (Java virtual machine) สมัยใหม่จะตรวจจับขีดจำกัด cgroup โดยอัตโนมัติ แต่ HotSpot build เช่น OpenJDK จะจัดสรร heap ให้เพียง 25 เปอร์เซ็นต์ของขีดจำกัดนั้น ดังนั้น -XX:MaxRAMPercentage=75 จึงเป็นวิธีปกติในการอนุญาตให้ heap ใช้พื้นที่ได้มากขึ้นโดยยังเหลือพื้นที่สำหรับหน่วยความจำนอก heap Node.js ได้ปรับขนาด heap เริ่มต้นตามขีดจำกัด cgroup มาตั้งแต่เวอร์ชัน 12 โดยอยู่ที่ประมาณครึ่งหนึ่งของขีดจำกัดคอนเทนเนอร์และสูงสุดที่ประมาณ 2GB ดังนั้นให้ตั้งค่า --max-old-space-size เป็นเมกะไบต์เฉพาะเมื่อคุณต้องการเพดานที่ต่างออกไป และควรตั้งให้ต่ำกว่าขีดจำกัดของคอนเทนเนอร์เพื่อให้ garbage collector ทำงานก่อนที่เคอร์เนลจะเข้ามาแทรกแซง Ollama ก็เป็นกรณีเดียวกันแต่ใช้ตัวแปรควบคุมที่ต่างออกไป เพราะ การเพิ่ม num_ctx จะทำให้ KV cache ขยายตัว ขึ้นหลายร้อยเมกะไบต์จนคอนเทนเนอร์ถูกสั่งหยุดทำงานระหว่างการประมวลผล prompt ที่ยาว cgroup ไม่มีการเจรจาต่อรอง มันจะสั่งหยุดทำงานทันที

การจำกัด CPU มีพฤติกรรมที่แตกต่างออกไปโดยสิ้นเชิง

cpus: "1.5" หมายถึง 150% ของหนึ่งคอร์ โดยบังคับใช้ผ่านโควตาของ CFS (completely fair scheduler) คอนเทนเนอร์จะได้รับเวลา CPU 150ms ในทุกๆ รอบเวลา 100ms ซึ่งจะถูกแบ่งใช้โดยทุกเธรดภายในคอนเทนเนอร์ เมื่อใช้เวลาจนครบ Kernel จะทำให้คอนเทนเนอร์ต้องรอจนกว่าจะถึงรอบเวลาถัดไป

นี่คือข้อแตกต่างที่สำคัญ คอนเทนเนอร์ที่ใช้หน่วยความจำเกินขีดจำกัดจะถูกสั่ง kill แต่คอนเทนเนอร์ที่ใช้ CPU เกินขีดจำกัดจะถูก throttled และทำงานต่อไปได้เพียงแต่ช้าลง ดังนั้นการตั้งค่า CPU limit จึงสามารถทำได้อย่างเข้มงวด ในขณะที่ memory limit จำเป็นต้องเผื่อพื้นที่ไว้

cpu_shares เป็นเครื่องมือที่แตกต่างออกไป คือการกำหนดน้ำหนักสัมพัทธ์ซึ่งจะมีผลก็ต่อเมื่อ CPU ทำงานเต็มประสิทธิภาพเท่านั้น คอนเทนเนอร์สองตัวที่มีค่า shares เป็น 1024 และ 512 จะแบ่งการใช้งานคอร์ที่กำลังยุ่งในสัดส่วนประมาณสองต่อหนึ่ง แต่หากเครื่องว่างอยู่ ทั้งสองตัวจะไม่ถูกจำกัดการใช้งาน ให้ใช้ shares เพื่อจัดลำดับความสำคัญของบริการ และใช้ cpus เมื่อคุณต้องการกำหนดเพดานการใช้งานจริง ตัวอย่างเช่น เพื่อป้องกันไม่ให้งาน transcode ที่รันในตอนกลางคืนแย่งทรัพยากรจนเว็บเซิร์ฟเวอร์ของคุณทำงานไม่ได้

FAQ

deploy.resources.limits ทำงานโดยไม่มี Docker Swarm ได้หรือไม่

ได้ Docker Compose ซึ่งใช้ปลั๊กอิน docker compose (ปัจจุบันอยู่ในเวอร์ชัน v5) จะนำ deploy.resources.limits และ deploy.resources.reservations ไปใช้งานเมื่อคุณรัน docker compose up บนโฮสต์เดียว คุณสามารถตรวจสอบได้ด้วย docker inspect --format '{{.HostConfig.Memory}}' <container> ซึ่งจะแสดงค่าขีดจำกัดเป็นไบต์ และแสดง 0 หากไม่มีการกำหนดขีดจำกัดไว้ คีย์ภายใน deploy ที่ออกแบบมาสำหรับ Swarm จะเป็นคีย์ระดับคลัสเตอร์ เช่น placement, update_config และ endpoint_mode

exit code 137 ใน Docker Compose หมายความว่าอย่างไร

โดยส่วนใหญ่หมายความว่ากระบวนการหลักได้รับสัญญาณ SIGKILL เนื่องจาก 137 คือ 128 บวกกับสัญญาณที่ 9 (โปรแกรมอาจ exit ด้วย 137 โดยเจตนาได้เช่นกัน แต่พบได้น้อย) สาเหตุที่พบบ่อยคือ OOM killer ของ kernel แต่การหมดเวลาในการปิดระบบ (shutdown timeout) ก็ทำให้เกิดรหัสนี้ได้เช่นกันหากแอปพลิเคชันเพิกเฉยต่อ SIGTERM ให้รัน docker inspect --format '{{.State.OOMKilled}} {{.State.ExitCode}}' <container> เพื่อแยกแยะสาเหตุ โดย true 137 คือการถูกสั่งหยุดเนื่องจากหน่วยความจำเต็ม และ false 137 ไม่ใช่

ควรตั้งค่า mem_limit หรือ deploy.resources.limits.memory

ใช้ได้ทั้งสองแบบกับ docker compose โดย deploy.resources.limits.memory เป็นรูปแบบมาตรฐานของ Compose Specification ในปัจจุบันและเป็นตัวเลือกที่ดีกว่าสำหรับไฟล์ใหม่ ให้ใช้ mem_limit ต่อไปหากไฟล์ส่วนที่เหลือของคุณใช้คีย์ระดับบนสุดแบบเก่าอยู่ Compose Specification กำหนดให้ทั้งสองค่าต้องสอดคล้องกันหากมีการตั้งค่าไว้ทั้งคู่ ดังนั้นให้เลือกใช้อย่างใดอย่างหนึ่งและตรวจสอบผลลัพธ์ด้วย docker inspect

ทำไมคอนเทนเนอร์ของฉันถึงใช้หน่วยความจำเต็มขีดจำกัดโดยไม่ถูกสั่งหยุด

ตัวเลขการใช้งานใน docker stats ยังคงนับรวม page cache ที่เพิ่งใช้งานไป ซึ่ง kernel จะล้างออกเมื่อเกิดแรงกดดันแทนที่จะสั่ง OOM kill ให้รัน docker compose exec <service> grep -E '^(anon|file) ' /sys/fs/cgroup/memory.stat และอ่านค่า anon ซึ่งเป็น working set ที่ไม่สามารถเรียกคืนได้ ค่า file ที่สูงควบคู่กับค่า anon ที่ต่ำ หมายถึงคอนเทนเนอร์กำลังทำ disk input และ output ไม่ใช่คอนเทนเนอร์ที่กำลังจะหยุดทำงาน

ควรเหลือ RAM ที่ไม่ได้จัดสรรไว้เท่าใดบน VPS ขนาด 8GB

ควรเหลือไว้ประมาณ 1GB สำหรับ kernel, Docker daemon, sshd, journald และ shell ของคุณ จากนั้นให้ผลรวมของขีดจำกัดคอนเทนเนอร์ทั้งหมดอยู่ภายใต้ 7GB ที่เหลือ ให้เฝ้าดูค่าสูงสุดของ anon ต่อคอนเทนเนอร์ภายใต้ภาระงานจริงเป็นเวลาหนึ่งวันก่อนที่จะกำหนดตัวเลข และให้ถือว่าผลรวมทั้งหมดเป็นงบประมาณ ไม่ใช่เป้าหมายที่ต้องใช้ให้เต็ม

บทความนี้มีประโยชน์หรือไม่