Container không phải máy ảo thu nhỏ. Phần lớn container Linux vẫn dùng chung kernel của máy chủ, nhưng mỗi nhóm tiến trình nhìn thấy một phạm vi tài nguyên được giới hạn và chỉ được tiêu thụ lượng tài nguyên đã cấp. Hai cơ chế kernel tạo nên phần cốt lõi của mô hình này là namespaces và cgroups.
Namespaces thay đổi những gì một tiến trình có thể nhìn thấy: PID, mount, mạng, hostname, IPC, user ID và một số tài nguyên khác. cgroups tổ chức tiến trình theo cây để đo, ưu tiên và giới hạn CPU, bộ nhớ hoặc I/O. Chúng bổ sung cho nhau nhưng không đồng nghĩa với một ranh giới bảo mật hoàn chỉnh.
1. Tách “góc nhìn” và “ngân sách”
| Cơ chế | Câu hỏi chính | Ví dụ |
|---|---|---|
| Namespace | Tiến trình nhìn thấy tài nguyên nào? | Danh sách PID, interface mạng, mount point |
| cgroup | Nhóm tiến trình được dùng bao nhiêu? | Giới hạn memory, trọng số CPU, băng thông I/O |
| Capabilities/LSM/seccomp | Tiến trình được phép thực hiện hành động nào? | Drop đặc quyền, lọc syscall, policy truy cập |
Cô lập tên và giới hạn tài nguyên là hai bài toán khác nhau. Có namespace mà không có cgroup, một workload vẫn có thể làm cạn RAM hoặc tranh CPU với phần còn lại của host.
2. Namespace hoạt động như thế nào?
Một namespace bọc tài nguyên toàn cục trong một lớp trừu tượng. Tiến trình bên trong tưởng rằng nó có phiên bản riêng của tài nguyên đó. Kernel theo dõi tiến trình thuộc namespace nào và trả về góc nhìn tương ứng khi tiến trình gọi system call hoặc đọc giao diện trong /proc.
Namespace được tạo hoặc tham gia thông qua các API như clone(), unshare() và setns(). Trong vận hành, quản trị viên thường dùng unshare, nsenter, lsns và các runtime container thay vì gọi API trực tiếp.
| Loại | Cô lập | Ý nghĩa với container |
|---|---|---|
| PID | Không gian process ID | Tiến trình có thể thấy PID 1 riêng |
| Mount | Danh sách mount point | Root filesystem và volume khác host |
| Network | Interface, routing, port, firewall | Mỗi container có network stack riêng |
| UTS | Hostname và domain name | Hostname độc lập |
| IPC | System V IPC, POSIX message queue | Giảm giao tiếp ngoài ý muốn |
| User | UID, GID và capabilities | UID 0 bên trong có thể ánh xạ sang user thường bên ngoài |
| Cgroup | Góc nhìn cây cgroup | Ẩn phần cây quản lý không liên quan |
| Time | Một số clock hệ thống | Điều chỉnh offset thời gian cho workload phù hợp |
3. PID namespace và vai trò đặc biệt của PID 1
PID namespace cho phép cùng một tiến trình có PID khác nhau khi được quan sát từ các namespace lồng nhau. Tiến trình đầu tiên trong PID namespace mới mang PID 1 ở góc nhìn bên trong. Nó có trách nhiệm quan trọng trong việc thu gom tiến trình con kết thúc và xử lý signal.
Nếu ứng dụng chính không xử lý đúng vai trò init, zombie process có thể tích tụ hoặc tín hiệu dừng không được chuyển tiếp như mong đợi. Vì vậy runtime có thể dùng một init nhỏ, hoặc ứng dụng phải được thiết kế để reap child process và phản ứng đúng với SIGTERM.
4. Mount và network namespace
Mount namespace tách danh sách mount mà tiến trình nhìn thấy. Đây là nền tảng để container có root filesystem riêng, bind mount cấu hình và gắn volume dữ liệu. Tuy nhiên mount không tự làm dữ liệu “an toàn”: quyền file, chế độ read-only, propagation và đường dẫn được bind vẫn phải cấu hình đúng.
Network namespace cung cấp network device, routing table, firewall rule và không gian port riêng. Một cặp veth thường nối namespace của container với bridge hoặc namespace của host. Việc một service lắng nghe cổng 8080 bên trong không có nghĩa nó tự động được truy cập từ bên ngoài; runtime phải cấu hình đường đi và policy phù hợp.
5. User namespace không biến root thành root của host
User namespace cho phép ánh xạ UID/GID giữa bên trong và bên ngoài. Một tiến trình có thể là UID 0 trong namespace nhưng tương ứng với một UID không đặc quyền trên host. Capabilities cũng được đánh giá trong phạm vi user namespace liên quan.
Đây là lớp giảm đặc quyền hữu ích, nhưng không phải lời bảo đảm tuyệt đối. Kernel vẫn là tài nguyên dùng chung; syscall, thiết bị, filesystem mount và cấu hình runtime quyết định bề mặt tấn công. Khi có thể, hãy chạy ứng dụng bằng non-root, drop capabilities không cần thiết và tránh chế độ privileged.
6. cgroup v2: một cây quản lý thống nhất
cgroup v2 tổ chức tiến trình trong một hierarchy duy nhất. Core quản lý cấu trúc cây và membership; các controller đảm nhiệm từng loại tài nguyên. Một controller được bật ở node cha sẽ phân phối hoặc giới hạn tài nguyên cho cây con, và giới hạn ở cấp dưới không thể vượt qua giới hạn cấp trên.
Các file phổ biến gồm:
cgroup.controllers: controller có thể bật cho cây con.cgroup.subtree_control: bật controller cho các cgroup con.cgroup.procs: PID của tiến trình thuộc cgroup.cpu.maxvàcpu.weight: quota và trọng số CPU.memory.max,memory.high,memory.current: giới hạn cứng, ngưỡng pressure và mức dùng hiện tại.io.maxvàio.stat: giới hạn và số liệu I/O theo thiết bị.pids.max: giới hạn số tiến trình để giảm nguy cơ fork bomb.
7. Quan sát an toàn trên máy Linux
# Namespace của tiến trình hiện tại
ls -l /proc/self/ns
lsns
# Loại filesystem cgroup và controller khả dụng
stat -fc %T /sys/fs/cgroup
cat /sys/fs/cgroup/cgroup.controllers
# Cgroup của tiến trình hiện tại
cat /proc/self/cgroup
# Áp lực tài nguyên toàn hệ thống nếu kernel hỗ trợ PSI
cat /proc/pressure/cpu
cat /proc/pressure/memory
Các lệnh trên chủ yếu đọc trạng thái. Đừng ghi trực tiếp vào cây cgroup của máy production nếu systemd hoặc container runtime đang quản lý nó. Thay đổi ngoài bộ điều phối có thể bị ghi đè, làm sai accounting hoặc khiến service bị dừng.
8. Limit, reservation và pressure không giống nhau
Giới hạn cứng trả lời “không được vượt quá”, còn trọng số hoặc reservation trả lời “được ưu tiên thế nào khi tranh chấp”. Đặt mọi container ở limit rất thấp có thể gây OOM hoặc throttling dù host còn tài nguyên; không đặt limit nào lại khiến một workload lỗi ảnh hưởng toàn máy.
Quan sát memory.current cùng event OOM, CPU throttling, I/O latency và Pressure Stall Information giúp phân biệt thiếu capacity với cấu hình limit sai. Metric bên trong container cũng cần đối chiếu với metric ở host, vì góc nhìn namespace có thể khác góc nhìn của node.
9. Container không phải sandbox hoàn chỉnh
Namespaces và cgroups không lọc toàn bộ syscall, không tự loại capabilities, không kiểm soát mọi đường dẫn file và không vá lỗ hổng kernel. Một cấu hình an toàn thường kết hợp nhiều lớp:
- Image tối giản, cập nhật và không chứa secret.
- User không đặc quyền; user namespace hoặc rootless mode khi phù hợp.
- Drop capability, tránh
CAP_SYS_ADMINvà tránh privileged container. - Filesystem read-only, mount rõ ràng, không đưa socket quản trị của host vào container.
- seccomp để giảm syscall; SELinux hoặc AppArmor để áp policy bắt buộc.
- Resource limit và health check phù hợp với hành vi thật.
- Tách workload có mức tin cậy khác nhau bằng VM hoặc node riêng khi rủi ro yêu cầu.
10. Những hiểu lầm phổ biến
- “Container có kernel riêng”: container Linux thông thường dùng chung kernel host.
- “Root trong container luôn là root host”: điều này phụ thuộc user mapping và capabilities, nhưng root trong container vẫn cần được coi là nhạy cảm.
- “Có memory limit là hết OOM”: workload vẫn có thể bị OOM trong cgroup dù host chưa cạn RAM.
- “CPU limit bảo đảm hiệu năng”: quota chỉ đặt trần; latency còn phụ thuộc contention, scheduling và I/O.
- “Không publish port thì mạng tuyệt đối kín”: còn phụ thuộc bridge, route, firewall và policy của nền tảng.
11. Checklist vận hành
- Xác định host đang dùng cgroup v2 hay mô hình legacy/hybrid.
- Đặt request/weight và limit dựa trên đo đạc, không sao chép máy móc.
- Giới hạn PID, kiểm tra OOM event và theo dõi throttling.
- Chạy non-root; drop toàn bộ capability rồi thêm lại tối thiểu khi cần.
- Không mount Docker socket,
/proc,/syshoặc thiết bị host tùy tiện. - Kiểm thử shutdown để ứng dụng xử lý
SIGTERMvà thoát đúng thời hạn. - Dùng runtime/orchestrator hoặc systemd quản lý cgroup thay vì chỉnh tay trên production.
- Đánh giá VM hoặc sandbox chuyên dụng cho code không tin cậy.
Tài liệu tham khảo
- Linux manual: namespaces(7)
- Linux kernel documentation: Control Group v2
- Linux manual: capabilities(7)
Kết luận
Namespaces tạo ra góc nhìn tài nguyên riêng; cgroups đặt ngân sách và thu thập số liệu cho nhóm tiến trình. Container runtime kết hợp hai cơ chế đó với filesystem, networking và nhiều lớp policy khác để tạo môi trường chạy ứng dụng. Hiểu ranh giới từng lớp giúp quản trị viên đặt limit đúng, điều tra sự cố chính xác và không nhầm sự tiện lợi của container với một sandbox tuyệt đối.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.