

Linux Cgroups v2: พื้นฐานและความสำคัญสำหรับการจัดการระบบในยุค 2026
ในโลกของการประมวลผลแบบคลาวด์และคอนเทนเนอร์ที่พัฒนาอย่างไม่หยุดนิ่ง กลไกการควบคุมและแยกทรัพยากรระบบกลายเป็นหัวใจสำคัญของการรักษาเสถียรภาพและความปลอดภัย Linux Control Groups หรือที่รู้จักกันในชื่อ Cgroups เป็นฟีเจอร์เคอร์เนลที่ทรงพลังซึ่งทำหน้าที่นี้มาตั้งแต่ปี 2007 สำหรับ Cgroups เวอร์ชัน 2 (cgroup v2) ซึ่งถูกนำมาใช้อย่างเต็มที่ในยุคปัจจุบัน ได้กลายเป็นมาตรฐานใหม่ที่แก้ไขข้อจำกัดและความซับซ้อนของเวอร์ชัน 1 โดยนำเสนอ hierarchical unified model ที่จัดการทรัพยากรทั้งหมด (CPU, Memory, I/O, เป็นต้น) ภายใต้โครงสร้างต้นไม้เดียวที่สอดคล้องกับตรรกะมากขึ้น
ในปี 2026 การใช้งาน cgroup v2 ไม่ใช่แค่ตัวเลือกอีกต่อไป แต่เป็นพื้นฐานของระบบ Linux รุ่นใหม่ส่วนใหญ่ และเป็นหัวใจของ container runtime อย่าง systemd, Docker, และ Kubernetes ด้วยความซับซ้อนและความสำคัญของระบบที่ใช้ cgroup v2 การมี ยุทธศาสตร์การแบ็กอัพและกู้คืน (Backup & Recovery Strategy) ที่รอบคอบจึงเป็นสิ่งจำเป็นอย่างยิ่ง เพื่อป้องกันไม่ให้การกำหนดค่าที่ละเอียดอ่อน สิทธิ์ (permissions) และนโยบายการจำกัดทรัพยากรสูญหายไป ซึ่งอาจนำไปสู่การหยุดทำงานของบริการ การแย่งชิงทรัพยากร (noisy neighbor) หรือแม้แต่ช่องโหว่ด้านความปลอดภัย
บทความฉบับสมบูรณ์นี้จะพาคุณเจาะลึกทุกแง่มุมของการแบ็กอัพและกู้คืน cgroup v2 ตั้งแต่พื้นฐานการทำงาน โครงสร้างไฟล์ระบบ ไปจนถึงกลยุทธ์ขั้นสูงและกรณีศึกษาในโลกจริง พร้อมด้วยสคริปต์และคำสั่งที่พร้อมใช้งานได้ทันที
การเข้าใจโครงสร้างและจุดเก็บข้อมูลของ Cgroups v2
ก่อนจะออกแบบยุทธศาสตร์การแบ็กอัพได้อย่างมีประสิทธิภาพ เราต้องเข้าใจว่า cgroup v2 จัดเก็บข้อมูลการกำหนดค่าของมันไว้ที่ใดและในรูปแบบใด ข้อมูลหลักของ cgroup v2 แบ่งออกเป็นสองส่วนใหญ่ๆ ได้แก่ โครงสร้างลำดับชั้น (Hierarchy) และ พารามิเตอร์ควบคุม (Controller Parameters)
ระบบไฟล์ cgroup2 และจุด mount
โดยปกติแล้ว cgroup v2 จะถูก mount ที่ /sys/fs/cgroup/ (หรือบางครั้งที่ /sys/fs/cgroup/unified ในระบบที่รองรับทั้ง v1 และ v2 พร้อมกัน) เมื่อเราเปลี่ยนไดเรกทอรีไปยังจุดนี้ เราจะเห็นโครงสร้างต้นไม้ของ cgroup ที่สร้างขึ้นโดยระบบ (เช่น โดย systemd) หรือโดยผู้ดูแลระบบและซอฟต์แวร์ (เช่น container runtime)
$ ls -la /sys/fs/cgroup/
total 0
dr-xr-xr-x 15 root root 0 Aug 20 10:00 .
drwxr-xr-x 9 root root 0 Aug 20 10:00 ..
-r--r--r-- 1 root root 0 Aug 20 10:00 cgroup.controllers
-r--r--r-- 1 root root 0 Aug 20 10:00 cgroup.subtree_control
drwxr-xr-x 2 root root 0 Aug 20 10:00 init.scope
drwxr-xr-x 105 root root 0 Aug 20 10:00 system.slice
drwxr-xr-x 3 root root 0 Aug 20 10:00 user.slice
แต่ละไดเรกทอรีภายในนี้คือ一個 cgroup ซึ่งสามารถมีไฟล์ควบคุมเฉพาะตัวได้ ไฟล์สำคัญที่ต้องรู้จักสำหรับการแบ็กอัพ ได้แก่:
cgroup.procs: บันทึก Process IDs (PIDs) ที่อยู่ใน cgroup นี้cgroup.controllers&cgroup.subtree_control: ควบคุมว่า controller ใด (cpu, memory, io) ถูกเปิดใช้งาน*.max,*.weight(เช่นcpu.max,memory.max,io.weight): เป็นไฟล์ที่กำหนดขีดจำกัดและน้ำหนักของทรัพยากรcgroup.freeze: สำหรับแช่แข็ง (freeze) กระบวนการทั้งหมดใน cgroup
ประเภทของข้อมูลที่ต้องแบ็กอัพ
เราสามารถจำแนกข้อมูล cgroup v2 ที่ต้องการปกป้องออกเป็น 3 ประเภทหลัก:
- โครงสร้างลำดับชั้น (Hierarchy Structure): ลำดับและความสัมพันธ์ของ cgroup ย่อยต่างๆ ภายใต้ root cgroup (เช่น system.slice, docker-, kubepods-)
- พารามิเตอร์การควบคุมทรัพยากร (Controller Parameters): ค่าต่างๆ ในไฟล์เช่น
memory.max,cpu.weightซึ่งเป็นหัวใจของการจัดการทรัพยากร - การแมปกระบวนการ (Process Membership): PID ที่ถูกกำหนดให้อยู่ใน cgroup ใด cgroup หนึ่ง (เก็บใน
cgroup.procsและcgroup.threads)
การแบ็กอัพที่สมบูรณ์ต้องครอบคลุมทั้งสามส่วนนี้ โดยต้องคำนึงถึงความสัมพันธ์ระหว่าง cgroup กับกระบวนการที่กำลังทำงานอยู่ ซึ่งอาจเปลี่ยนแปลงได้ตลอดเวลา
ยุทธศาสตร์การแบ็กอัพ Cgroups v2 แบบครอบคลุม
การออกแบบยุทธศาสตร์การแบ็กอัพควรคำนึงถึงความถี่ ความสมบูรณ์ของข้อมูล และผลกระทบต่อระบบที่กำลังทำงานอยู่ เราเสนอสามระดับของการแบ็กอัพ ดังนี้
ระดับที่ 1: การแบ็กอัพแบบสแนปชอตด้วยสคริปต์ (Snapshot Backup)
เหมาะสำหรับการกู้คืนด่วนหรือการย้ายการกำหนดค่าไปยังระบบอื่นในลักษณะ stateless วิธีนี้จะบันทึกสถานะของโครงสร้าง cgroup และพารามิเตอร์ทั้งหมด ณ ช่วงเวลาหนึ่ง โดยไม่สนใจกระบวนการที่กำลังทำงานอยู่
#!/bin/bash
# Script: backup_cgroupv2_snapshot.sh
BACKUP_DIR="/backup/cgroupv2/$(date +%Y%m%d_%H%M%S)"
CGROUP_ROOT="/sys/fs/cgroup"
mkdir -p "$BACKUP_DIR"
# 1. Backup the hierarchy structure (find all cgroup directories)
find "$CGROUP_ROOT" -type d -name "*.slice" -o -name "*.service" -o -name "*.scope" | while read -r CGROUP_PATH; do
REL_PATH="${CGROUP_PATH#$CGROUP_ROOT/}"
BACKUP_PATH="$BACKUP_DIR/$REL_PATH"
mkdir -p "$(dirname "$BACKUP_PATH")"
# 2. Backup all readable control files
find "$CGROUP_PATH" -maxdepth 1 -type f -readable | while read -r FILE; do
FILENAME=$(basename "$FILE")
# Avoid backing up pseudo-files with dynamic content
if [[ "$FILENAME" =~ ^(cgroup.procs|cgroup.threads|tasks)$ ]]; then
echo "# Skipping $FILE" > "$BACKUP_PATH/$FILENAME.skip"
else
cp "$FILE" "$BACKUP_PATH/$FILENAME" 2>/dev/null || echo "# Error copying $FILE" > "$BACKUP_PATH/$FILENAME.error"
fi
done
echo "Backed up: $REL_PATH"
done
# 3. Backup the overall controller configuration at root
cp "$CGROUP_ROOT/cgroup.controllers" "$BACKUP_DIR/"
cp "$CGROUP_ROOT/cgroup.subtree_control" "$BACKUP_DIR/"
echo "Snapshot backup completed to: $BACKUP_DIR"
tar -czf "$BACKUP_DIR.tar.gz" -C "$BACKUP_DIR" .
echo "Archive created: $BACKUP_DIR.tar.gz"
สคริปต์นี้จะสร้างสำเนาของไดเรกทอรี cgroup และไฟล์ควบคุมทั้งหมด (ยกเว้นไฟล์ที่มี PID) เก็บไว้ในรูปแบบที่สามารถกู้คืนได้ในภายหลัง
ระดับที่ 2: การแบ็กอัพแบบประกาศด้วย systemd (Declarative Backup)
สำหรับระบบที่ใช้ systemd ในการจัดการ cgroup (ซึ่งเป็นมาตรฐานในระบบ Linux สมัยใหม่) วิธีที่มีประสิทธิภาพที่สุดคือการแบ็กอัพ หน่วยงาน systemd (unit files) และ การกำหนดค่า drop-in files เนื่องจาก systemd จะสร้างและจัดการ cgroup ตามการกำหนดค่าเหล่านี้โดยอัตโนมัติเมื่อบูตระบบหรือรีสตาร์ทบริการ
- แบ็กอัพ unit files:
/etc/systemd/system/,/usr/lib/systemd/system/ - แบ็กอัพ drop-in directories:
/etc/systemd/system/*.service.d/,/etc/systemd/system/*.slice.d/ - แบ็กอัพการกำหนดค่า cgroup เฉพาะของ systemd: ไฟล์เช่น
/etc/systemd/system.conf,/etc/systemd/system.control/*
การกู้คืนด้วยวิธีนี้คือการคืนค่าไฟล์การกำหนดค่าเหล่านี้และรัน systemctl daemon-reload ตามด้วยการรีสตาร์ทหน่วยงานที่เกี่ยวข้อง
ระดับที่ 3: การแบ็กอัพแบบเรียลไทม์และแบบไฮบริด (Hybrid Real-time Backup)
ในสภาพแวดล้อมการผลิตที่สำคัญ เช่น Kubernetes cluster หรือระบบคลาวด์ที่ต้องมีระยะเวลา downtime ต่ำสุด จำเป็นต้องมีกลยุทธ์ที่ซับซ้อนขึ้น ซึ่งอาจรวมถึง:
- การใช้เครื่องมือเฉพาะ: เช่น
criu (Checkpoint/Restore In Userspace)ซึ่งสามารถ checkpoint สถานะของกระบวนการทั้ง cgroup ได้ (เหมาะสำหรับการย้าย container) - การซิงค์การกำหนดค่าไปยังระบบคอนฟิกูเรชันภายนอก: เช่น Git, Consul, หรือฐานข้อมูล ซึ่งช่วยให้ติดตามการเปลี่ยนแปลง (version control) และนำไปใช้กับโหนดหลายตัวได้
- การผสานกับระบบตรวจสอบ (Monitoring): ส่งค่าพารามิเตอร์ cgroup ไปยังระบบเช่น Prometheus (ผ่าน cAdvisor หรือ node-exporter) เพื่อเก็บประวัติการเปลี่ยนแปลงของขีดจำกัดทรัพยากร
ขั้นตอนการกู้คืน Cgroups v2 อย่างปลอดภัย
การกู้คืนเป็นขั้นตอนที่ต้องทำอย่างระมัดระวัง เพื่อไม่ให้เกิดการขัดข้องของบริการหรือการกำหนดค่าที่ขัดแย้งกัน เราขอเสนอขั้นตอนการกู้คืนแบบเป็นลำดับ
การกู้คืนจากสแนปชอต (Snapshot Recovery)
สมมติว่าคุณมีแบ็กอัพจากสคริปต์ระดับที่ 1 ขั้นตอนการกู้คืนมีดังนี้:
#!/bin/bash
# Script: restore_cgroupv2_snapshot.sh
RESTORE_ARCHIVE="/backup/cgroupv2/20260820_143000.tar.gz"
RESTORE_DIR="/tmp/cgroup_restore"
CGROUP_ROOT="/sys/fs/cgroup"
# 1. Extract the backup
mkdir -p "$RESTORE_DIR"
tar -xzf "$RESTORE_ARCHIVE" -C "$RESTORE_DIR"
# 2. Recreate the cgroup hierarchy and set parameters
find "$RESTORE_DIR" -type d | tail -n +2 | while read -r BACKUP_CGROUP_DIR; do
REL_PATH="${BACKUP_CGROUP_DIR#$RESTORE_DIR/}"
TARGET_CGROUP_PATH="$CGROUP_ROOT/$REL_PATH"
# Create the cgroup directory if it doesn't exist
if [ ! -d "$TARGET_CGROUP_PATH" ]; then
mkdir -p "$TARGET_CGROUP_PATH"
echo "Created cgroup: $TARGET_CGROUP_PATH"
fi
# Restore control file values
find "$BACKUP_CGROUP_DIR" -maxdepth 1 -type f ! -name "*.skip" ! -name "*.error" | while read -r BACKUP_FILE; do
FILENAME=$(basename "$BACKUP_FILE")
TARGET_FILE="$TARGET_CGROUP_PATH/$FILENAME"
# Only write to writable interface files
if [ -f "$TARGET_FILE" ] && [ -w "$TARGET_FILE" ]; then
# For critical files like memory.max, we use cat to avoid shell interpretation
cat "$BACKUP_FILE" > "$TARGET_FILE" 2>/dev/null && echo " Restored: $FILENAME"
fi
done
done
echo "Snapshot restoration process finished. Note: Process membership (PIDs) is NOT restored."
echo "You may need to manually move processes into their appropriate cgroups."
คำเตือนสำคัญ: การกู้คืนแบบสแนปชอตอาจเขียนทับการกำหนดค่าปัจจุบันที่อาจมีการเปลี่ยนแปลงหลังจากการแบ็กอัพ ควรทำในสภาพแวดล้อมที่ทดสอบแล้วหรือในช่วงเวลาที่ระบบไม่繁忙
การกู้คืนในระบบที่ใช้ systemd
หากการกำหนดค่า cgroup มาจาก systemd unit files การกู้คืนจะตรงไปตรงมาและปลอดภัยกว่า:
- คืนค่า unit files และ drop-in directories ไปยังตำแหน่งเดิม
- รันคำสั่ง
sudo systemctl daemon-reloadเพื่อให้ systemd อ่านการกำหนดค่าใหม่ - สำหรับ slice หรือ scope ที่ไม่ใช่บริการที่ทำงานอยู่ตลอดเวลา อาจต้องรีสตาร์ทหน่วยงานที่เกี่ยวข้อง:
sudo systemctl restart <unit-name> - ตรวจสอบสถานะ cgroup ที่สร้างขึ้น:
sudo systemd-cglsหรือsudo cat /sys/fs/cgroup/<path>/cgroup.procs
การเปรียบเทียบยุทธศาสตร์และเครื่องมือที่เกี่ยวข้อง
การเลือกยุทธศาสตร์ที่เหมาะสมขึ้นอยู่กับสภาพแวดล้อมและความต้องการ ลองเปรียบเทียบกันในตารางต่อไปนี้
| ยุทธศาสตร์ | ข้อดี | ข้อเสีย | เหมาะสำหรับ |
|---|---|---|---|
| สแนปชอตด้วยสคริปต์ | – ง่ายและรวดเร็ว – ไม่ขึ้นกับระบบ init – กู้คืนได้แม้ systemd ล้มเหลว |
– ไม่บันทึกสถานะกระบวนการ – อาจขัดแย้งกับระบบที่จัดการ cgroup อัตโนมัติ – ไม่มี version control |
– ระบบที่กำหนดค่า cgroup ด้วยมือ – การย้ายระบบด่วน – การทดลองและพัฒนา |
| ประกาศด้วย systemd | – สอดคล้องกับระบบมาตรฐาน – กู้คืนได้อย่างเป็นระเบียบเมื่อบูตระบบใหม่ – รองรับ version control ผ่าน Git |
– ใช้ได้เฉพาะกับ cgroup ที่ systemd จัดการ – ต้องรีโหลด/รีสตาร์ทหน่วยงาน |
– เซิร์ฟเวอร์ Linux ทั่วไปที่ใช้ systemd – บริการและ container ที่ systemd จัดการ |
| ไฮบริดกับเครื่องมือภายนอก (Criu, GitOps) | – กู้คืนได้ทั้งโครงสร้างและสถานะกระบวนการ – เหมาะสำหรับการย้าย container แบบ live – ติดตามการเปลี่ยนแปลงได้ |
– ซับซ้อนในการตั้งค่าและดูแล – อาจต้องการ downtime สั้นๆ – โอเวอร์เฮดบางส่วน |
– Container orchestration (K8s) – การย้ายเวิร์กโหลดระหว่างโหนด – สภาพแวดล้อมการผลิตที่ต้องการความต่อเนื่องสูง |
เครื่องมือเสริมสำหรับการจัดการแบ็กอัพ
- rsync / tar: สำหรับการคัดลอกโครงสร้างไดเรกทอรีจาก
/sys/fs/cgroup(ระวังไฟล์ pseudo) - Git: สำหรับจัดการ version ของ systemd unit files และสคริปต์กำหนดค่า
- Ansible / Puppet / Chef: สำหรับกำหนดค่า cgroup แบบ declarative บนเซิร์ฟเวอร์หลายตัวและสามารถทำเป็นโค้ด (Infrastructure as Code)
- cAdvisor + Prometheus + Grafana: สำหรับติดตามและแสดงภาพการใช้ทรัพยากรและขีดจำกัดของ cgroup แบบเรียลไทม์ ซึ่งช่วยในการตัดสินใจกู้คืนค่าที่เหมาะสม
กรณีศึกษาและแนวปฏิบัติที่ดีที่สุด (Best Practices) ปี 2026
กรณีศึกษา 1: การกู้คืนบริการฐานข้อมูลหลังจากการกำหนดค่า memory.max ผิดพลาด
สถานการณ์: ผู้ดูแลระบบกำหนดค่า memory.max สำหรับ cgroup ของ MySQL ต่ำเกินไปโดยไม่ได้ตั้งใจ ทำให้บริการหยุดทำงานกะทันหัน
การแก้ไข:
1. ใช้แบ็กอัพแบบประกาศของ systemd: ค้นหา drop-in file ของบริการ mysql (/etc/systemd/system/mysql.service.d/memory.conf) จากแบ็กอัพ Git
2. คืนค่าไฟล์และรัน systemctl daemon-reload
3. รีสตาร์ทบริการ: systemctl restart mysql
4. ระบบจะสร้าง cgroup ใหม่ด้วยขีดจำกัด memory ที่ถูกต้อง และบริการจะเริ่มทำงานได้ปกติ
บทเรียน: ควรเก็บการกำหนดค่า cgroup ที่สำคัญเป็นไฟล์ภายนอก (เช่น systemd drop-in) และใช้ระบบ version control ในการจัดการ
กรณีศึกษา 2: การย้ายกลุ่ม container ทั้งชุดไปยังโหนดใหม่ใน Kubernetes
สถานการณ์: ต้องการอพยพ Pod ทั้งหมดจาก Kubernetes Node A ไปยัง Node B เนื่องจากปัญหาฮาร์ดแวร์
การแก้ไข:
1. Kubernetes scheduler จะจัดการสร้าง Pod ใหม่บน Node B โดยอัตโนมัติตามการกำหนดค่าใน Manifest (YAML)
2. การกำหนดค่า cgroup (requests/limits) ที่ระบุใน Manifest จะถูกส่งผ่าน container runtime (containerd/CRI-O) ไปยังระบบเพื่อสร้าง cgroup ใหม่บน Node B
3. แนวปฏิบัติสำคัญ: ต้องมั่นใจว่าแบ็กอัพของ Kubernetes etcd (ซึ่งเก็บสถานะของ cluster) มีความสมบูรณ์และล่าสุด เพราะนี่คือแหล่งความจริงของการกำหนดค่าทรัพยากรทั้งหมด
4. การกู้คืนในกรณีนี้คือการทำให้โหนดใหม่รับ workload ได้ ซึ่งขึ้นกับความสมบูรณ์ของ etcd backup และการกำหนดค่า Network/Storage
แนวปฏิบัติที่ดีที่สุดสรุป
- ใช้ Declarative Configuration เสมอ: กำหนด cgroup ผ่าน systemd units, Kubernetes manifests, หรือเครื่องมือ IaC อย่าแก้ไขด้วยมือโดยตรงที่
/sys/fs/cgroupเป็นประจำ - แบ็กอัพเป็นโค้ด (Backup as Code): เก็บการกำหนดค่าทั้งหมดใน repository (Git) พร้อมบันทึกประวัติการเปลี่ยนแปลง
- ทดสอบการกู้คืนเป็นประจำ: สร้างสภาพแวดล้อมทดสอบเพื่อรันกระบวนการกู้คืนทั้งหมดอย่างน้อยทุกไตรมาส
- แบ็กอัพแบบหลายชั้น: ใช้ทั้งสแนปชอต (สำหรับกู้ด่วน) และการแบ็กอัพแบบประกาศ (สำหรับกู้คืนอย่างเป็นระบบ)
- ตรวจสอบและแจ้งเตือน: ตั้งค่า monitoring เพื่อตรวจจับการเปลี่ยนแปลงของไฟล์ cgroup ที่สำคัญนอกเหนือจากกระบวนการที่กำหนด
- บันทึกกระบวนการ (Process Membership) แยกต่างหาก (ถ้าจำเป็น): สำหรับระบบพิเศษที่ต้องการกู้คืน PID ที่แน่นอน ให้พิจารณาใช้
criuแต่ต้องเข้าใจข้อจำกัดอย่างลึกซึ้ง
Summary
ในยุคที่ระบบไอทีมีความซับซ้อนและกระจายตัวมากขึ้น การจัดการทรัพยากรผ่าน Linux Cgroups v2 ได้กลายเป็นทักษะพื้นฐานที่ผู้ดูแลระบบและวิศวกรแพลตฟอร์มต้องเข้าใจอย่างลึกซึ้ง ยุทธศาสตร์การแบ็กอัพและกู้คืนสำหรับ cgroup v2 นั้นไม่ใช่แค่การคัดลอกไฟล์จาก /sys/fs/cgroup แต่เป็นกระบวนการที่ต้องออกแบบโดยคำนึงถึงสถาปัตยกรรมของระบบ (systemd-based, containerized), ความสมบูรณ์ของข้อมูล (โครงสร้าง, พารามิเตอร์, กระบวนการ) และความเร็วในการกู้คืน การเลือกใช้เครื่องมือที่เหมาะสม ตั้งแต่สคริปต์ Bash ง่ายๆ ไปจนถึงระบบ GitOps และเครื่องมือ checkpoint อย่าง criu จะช่วยสร้างเกราะป้องกันที่มั่นคงให้กับระบบการผลิตของคุณ อย่าลืมว่า แบ็กอัพที่ไม่มีค่าหากไม่เคยผ่านการทดสอบการกู้คืน ดังนั้นให้กำหนดเวลาและทรัพยากรสำหรับการฝึกซ้อมการกู้คืน cgroup เป็นประจำ เพื่อให้มั่นใจว่าเมื่อเกิดเหตุการณ์ไม่คาดคิดขึ้นจริงๆ ทีมงานจะสามารถฟื้นฟูระบบกลับมาได้อย่างรวดเร็วและมีประสิทธิภาพสูงสุด