Skip to main content

วิธีการจัดการ Resources limits ของ CPU (cores) และ Memory ใน Docker containers

Kongvut Sangkla

Intro

สวัสดีครับ บทความนี้มีเนื้อหาเกี่ยวกับ Docker คือวิธีจำกัดการใช้งาน CPU (cores) และ RAM ใน Docker containers โดยปกติ Docker containers จะมีการใช้ Resources ร่วมกัน (sharing) โดยที่บางครั้งอาจจะมี Container บางตัวใช้ CPU, RAM เกินไป

ผลจากการใช้ CPU, RAM เกินไปก็จะส่งผลทำให้ Resources และประสิทธิภาพของ Host ลดลง ดังนั้นบทความนี้จะอธิบายวิธีการจำกัด Resources เหล่านั้นเพื่อให้ส่งผลต่อประสิทธิภาพโดยรวมดีที่สุด

Docker Resouces limits

1. ทดลองสร้าง Container แบบปกติ

เริ่มด้วยแสดงข้อมูล CPU และ Memory ของฝั่งเครื่อง Host ออกมาดูก่อน

$ docker info | grep -iE "CPUs|Memory"
CPUs: 6
Total Memory: 3.773GiB

จากนั้นทดลองสร้าง Nginx container แบบวิธีปกติ ค่าปกติ (default) ของ Docker ไม่ได้กำหนดการจำกัด Resources ใด ๆ

$ docker run -d --name web-server nginx:alpine
a877ae9db70ea5e8e48b49f1c51b0147b4a948de54615ed5f28691cb7e90936c
$ docker stats web-server --no-stream --format "{{ json . }}" | jq .
{
"BlockIO": "0B / 12.3kB",
"CPUPerc": "0.00%",
"Container": "web-server",
"ID": "a877ae9db70e",
"MemPerc": "0.14%",
"MemUsage": "5.398MiB / 3.773GiB",
"Name": "web-server",
"NetIO": "0B / 0B",
"PIDs": "7"
}

จาก Output ด้านบนจะเห็น Memory limit คือ 3.773GiB มีค่าเท่ากับฝั่งเครื่อง Host

2. กำหนด Memory Limits

Hard memory limit

สำหรับการกำหนด Memory limits ใช้ Option --memory ตัวอย่าง

$ docker run -d --name demo-mem-limit --memory=256m nginx:alpine
ce927b22317885dea5cc29c154ba438c7d6a22b4904a75d8fcf1b77adce55e96
$ docker stats demo-mem-limit --no-stream --format "{{ json . }}" | jq .
{
"BlockIO": "0B / 12.3kB",
"CPUPerc": "0.00%",
"Container": "demo-mem-limit",
"ID": "ce927b223178",
"MemPerc": "2.11%",
"MemUsage": "5.398MiB / 256MiB",
"Name": "demo-mem-limit",
"NetIO": "0B / 0B",
"PIDs": "7"
}

จาก Output ด้านบนจะเรียกว่า Hard memory limit คือ 256MiB โดย --memory สามารถกำนดได้ด้วยตัวเลขเต็มบวก ตามด้วยหน่วย เช่น b, k, m, g คือ bytes, kilobytes, megabytes และ gigabytes ตามลำดับ

Soft memory limit

การกำหนด Soft memory limit โดยเป็นการอนุญาตให้ Container ใช้ Memory ขั้นต่ำตามที่ต้องการด้วยการใช้คำสั่ง --memory-reservation

$ docker run -d --name demo-soft-mem-limit --memory=256m --memory-reservation=128m nginx:alpine
6367c53d5303c1bd1866a270673ae5e79c23ccac4bc979fa117500d7c9e2d3c9
$ docker stats demo-soft-mem-limit --no-stream --format "{{ json . }}" | jq .
{
"BlockIO": "0B / 12.3kB",
"CPUPerc": "0.00%",
"Container": "demo-soft-mem-limit",
"ID": "6367c53d5303",
"MemPerc": "2.11%",
"MemUsage": "5.402MiB / 256MiB",
"Name": "demo-soft-mem-limit",
"NetIO": "0B / 0B",
"PIDs": "7"
}

จาก Output ด้านบนเห็นว่าได้กำหนด Hard memory limit = 256MiB ส่วน Soft memory limit = 128MiB

แต่คำสั่ง Docker stats ไม่สามารถแสดงค่า Soft memory limit ได้ ดังนั้นต้องใช้การแสดงว่าจาก cgroups แทน เช่น

$ docker exec -it demo-soft-mem-limit cat /sys/fs/cgroup/memory.low
134217728

จาก Output ด้านบนแสดงตัวเลขหน่วยเป็น Byte นั่นก็คือ 128MiB

Swap memory limit

การกำหนด Swap memory limit ใช้ Option --memory-swap โดยที่

  • ถ้าไม่ได้กำหนด --memory-swap แต่กำหนดแค่ --memory Container จะจำกัด Swap = Memory
  • หากกำหนด --memory-swap เองต้องมีค่ามากกว่า --memory
  • หากกำหนด --memory-swap และ --memory เอง จะไม่สามารถกำหนดเป็นค่าเดียวกันได้
  • หากกำหนด เช่น --memory=256m และ --memory-swap=512m จะทำให้ Memory = 256m และ Swap = 256m (512m - 256m)
  • รายละเอียดและเงื่อนไขอื่น ๆ สามารถอ่านเพิ่มเติมได้จาก --memory-swap details
$ docker run -d --name demo-mem-limit --memory=256m --memory-swap=512m nginx:alpine
$ docker exec -it demo-mem-limit cat /sys/fs/cgroup/memory.swap.max
268435456

จาก Output ด้านบนแสดงตัวเลขหน่วยเป็น Byte นั่นก็คือ 256MiB

3. การกำหนด CPU Limits

ตรวจสอบข้อมูล CPUs ของเครื่อง Host

ก่อนอื่นต้องมาดูว่า CPU ที่ใช้ในเครื่องมีกี่ Cores และความเร็วเท่าไหร่ด้วยคำสั่ง lscpu

$ lscpu
Architecture: aarch64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 6
On-line CPU(s) list: 0-5
Vendor ID: ARM
Model name: Cortex-A53
Model: 4
Thread(s) per core: 1
Core(s) per socket: 4
Socket(s): 1
Stepping: r0p4
CPU max MHz: 1512.0000
CPU min MHz: 408.0000
BogoMIPS: 48.00
Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
Model name: Cortex-A72
Model: 2
Thread(s) per core: 1
Core(s) per socket: 2
Socket(s): 1
Stepping: r0p2
CPU max MHz: 2016.0000
CPU min MHz: 408.0000
BogoMIPS: 48.00
Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid

จากข้อมูลด้านบนอธิบายได้ดังนี้

  • มี CPU ทั้งหมด 6 Cores (ลำดับเริ่มจาก 0-5)
  • CPU Cortex-A53 มี 4 Cores มีความเร็ว 408-1512 MHz (ลำดับ 0-3)
  • CPU Cortex-A72 มี 2 Cores มีความเร็ว 408-2016 MHz (ลำดับ 4-5)

การกำหนด CPU Limits

การกำหนด CPU Limits โดยค่า Default ของ Containers สามารถใช้ทุก CPU Cores ของ Host สำหรับการจำกัดค่าดังกล่าวทำได้ด้วยการใช้คำสั่ง --cpus และ --cpuset-cpus อธิบายดังนี้

OptionDescription
--cpusเป็นการระบุความต้องการใช้ CPU Resouces ของ Conatiner ตัวอย่างเช่น --cpus=0.5 คือการจำกัดเพื่อใช้ครึ่งหนึ่งของ Resouces หรือ --cpus=1.5 คือการใช้ประสิทธิภาพของ CPU ได้สูงสุด 150% (จาก 200%) ของ CPU 2 Cores นั่นก็หมายถึง 75% ของ 2 Cores CPU Resouces
--cpuset-cpusเป็นการจำกัดใช้ Cores ของ CPU โดยสามารถกำหนดเป็นลิสที่คั่นด้วย , หรือ - เช่น 0,3 จะหมายถึงใช้ Cores ได้แค่ลำดับ 0 และ 3
$ docker run -d --name demo-cpu-cores-limit --cpuset-cpus 0,1 nginx:alpine

หมายถึงใช้ CPU Cortex-A53 Core ที่ 1 และ 2 ได้สูงสุด Core ละ 100% รวม 200%

$ docker run -d --name demo-cpu-cores-limit --cpuset-cpus 0-3 nginx:alpine

หมายถึงใช้ CPU Cortex-A53 Core ที่ 1 ถึง 4 ได้สูงสุด Core ละ 100% รวม 400%

$ docker run -d --name demo-cpu-cores-limit --cpus=0.8 --cpuset-cpus 4,5 nginx:alpine

หมายถึงใช้ CPU Cortex-A72 Core ที่ 5 และ 6 ได้สูงสุด 80% จาก 200% คิดเป็น 40% ของ Resources

$ docker run -d --name demo-soft-mem-limit --cpus=1.5 --cpuset-cpus 3,4 nginx:alpine
ce927b22317885dea5cc29c154ba438c7d6a22b4904a75d8fcf1b77adce55e96
$ docker exec -it demo-cpu-cores-limit cat /sys/fs/cgroup/cpuset.cpus
3-4
$ docker exec -it demo-cpu-cores-limit cat /sys/fs/cgroup/cpu.max
150000 100000

หมายถึงใช้ Resources ดังนี้

  • CPU Cortex-A53 Core ที่ 4
  • CPU Cortex-A72 Core ที่ 5
  • ได้สูงสุด 150% จาก 200% คิดเป็น 75% ของ Resources

4. การกำหนด Resouces limits ผ่าน Docker compose

การกำหนดค่า Resouces limits ผ่าน Docker compose ตัวอย่างดังนี้

services:
web-server:
image: nginx:alpine
container_name: demo-web-server-limits
cpuset: "3-5"
deploy:
resources:
limits:
cpus: '2.4'
memory: 512m
pids: 1
reservations:
cpus: '1'
memory: 256M

5. Update Resouces limits บน Container ที่กำลังรันอยู่

หากต้องการ Update Resources ต่าง ๆ บน Container ที่กำลังรันอยู่สามารถใช้คำสั่ง docker update ตัวอย่างดังนี้

$ docker update --memory=512m --memory-reservation=256m --cpus=2.4 --cpuset-cpus=3-5 --memory-swap=1g demo-no-limits

สรุป

การใช้ CPU, RAM เกินไป (โดยไม่ Limits) ก็จะส่งผลทำให้ Resources และประสิทธิภาพของ Host ลดลง ดังนั้นการจำกัด Resources บน Containers เหล่านี้จึงมีความจำเป็น เพื่อให้ส่งผลต่อประสิทธิภาพโดยรวมดีที่สุด

References

Loading...