Part 11 · Docker · 11.1.04

Namespaces, cgroups và Linux security boundary

Container cô lập process view và kiểm soát resource usage bằng các primitive của Linux kernel. Điểm quan trọng nhất: container không có guest kernel riêng như VM — các container trên cùng host vẫn chia sẻ host kernel.

Mental model: namespace trả lời “process này nhìn thấy gì?”, cgroup trả lời “process này được dùng bao nhiêu?”, còn capabilities + seccomp + LSM trả lời “process này được phép làm gì?”. Các lớp này bổ sung cho nhau; không lớp nào đơn độc tạo thành security boundary hoàn chỉnh.

1. Isolation: boundary thật nằm ở đâu?

Khi Docker chạy một container, runtime tạo namespace và cgroup cho các process của container, sau đó áp dụng các giới hạn quyền như Linux capabilities, seccomp và LSM policy nếu host hỗ trợ. Vì kernel vẫn được chia sẻ, một kernel vulnerability hoặc cấu hình đặc quyền quá rộng có thể làm blast radius vượt qua boundary của container.

Do đó không nên mô tả container như “một VM nhẹ”. Container là một nhóm process được cô lập và giới hạn bằng kernel primitives. Mức an toàn thực tế phụ thuộc vào kernel, runtime, daemon, mount/device exposure, network policy và cấu hình của workload.

2. Namespaces

Các namespace thường gặp gồm PID, mount, network, IPC, UTS, user và cgroup. Chúng tạo ra các “view” riêng: process list riêng, mount tree riêng, network stack riêng, hostname riêng hoặc mapping UID/GID riêng.

NamespaceCô lập điều gì?Ví dụ failure / escape surface
PIDProcess IDs và process visibility.Dùng host PID namespace làm mất phần lớn process isolation.
MountMount points và filesystem view.Bind-mount host path nhạy cảm có thể làm dữ liệu host lộ trực tiếp vào container.
NetworkInterfaces, routes, ports, network stack.Host networking làm container dùng trực tiếp network namespace của host.
IPCSystem V IPC / POSIX message queues, shared IPC objects.Chia sẻ IPC namespace làm tăng coupling và blast radius giữa workloads.
UTSHostname/domain name.Chủ yếu là isolation về identity/view, không phải authorization.
UserUID/GID mapping giữa container và host.Container UID 0 có thể map sang UID ít quyền hơn trên host; nhưng mapping không thay thế hardening khác.
cgroupView về cgroup hierarchy.Giúp che/giới hạn view quản lý resource, không tự tạo authorization boundary đầy đủ.

User namespace đặc biệt hữu ích khi workload cần chạy UID 0 bên trong container: có thể remap UID đó sang một UID không đặc quyền trên host. Dù vậy, nguyên tắc ưu tiên vẫn là chạy application bằng user không đặc quyền khi có thể.

Namespace ≠ authorization. Namespace làm thay đổi những gì process nhìn thấy, nhưng process vẫn gọi vào cùng Linux kernel. Không nên xem namespace là cơ chế duy nhất để chống privilege escalation.

3. Cgroups: giới hạn và accounting tài nguyên

Cgroups dùng để account và phân phối CPU, memory, PIDs và I/O. Nếu không đặt giới hạn, container có thể dùng tài nguyên theo mức host scheduler cho phép. Đây là lý do resource isolation cũng là một phần của availability/security: một container misbehave có thể gây denial-of-service cho workload khác.

3.1 CPU

--cpus / CPU quota đặt ceiling; CPU weight/shares điều chỉnh mức ưu tiên tương đối khi có contention. Khi quota bị dùng hết trong một period, workload sẽ bị throttled. Kết quả thường là p95/p99 latency tăng dù host vẫn chưa trông giống “100% CPU” ở dashboard tổng.

Với cgroup v2, cpu.stat cung cấp các counter như nr_throttledthrottled_usec. Khi latency tăng, cần nhìn các counter này cùng application latency, run queue và CPU saturation thay vì chỉ nhìn host CPU average.

3.2 Memory

Memory limit không chỉ có Java heap. Footprint của process/container còn có native allocations, thread stacks, mmap, kernel-accounted memory và file/page cache tùy workload và kernel accounting. Nếu vượt giới hạn hoặc host rơi vào memory pressure, kernel có thể OOM-kill process; với container một-process, process đó thường chính là PID 1 và container sẽ exit/restart.

Với cgroup v2, memory.current, memory.statmemory.events giúp phân biệt footprint, pressure và OOM-related events. Không nên “fix” bằng cách vô hiệu OOM killer mà không hiểu failure mode; điều đó có thể chuyển rủi ro từ một container sang cả host.

3.3 PIDs và I/O

--pids-limit bảo vệ host khỏi process/thread explosion như fork bomb. Trong cgroup v2, pids.currentpids.events cho biết mức sử dụng và số lần đụng giới hạn. I/O controller có thể dùng để điều phối bandwidth/weight; các signal như io.stat hỗ trợ chẩn đoán khi disk contention làm latency kéo dài.

Failure windowTriệu chứngSignal nên xemRecovery / rollback
CPU quota quá thấpLatency tăng, timeout, throughput tụt.cpu.stat, app latency, request queue.Tăng quota/replica tạm thời; sau đó right-size bằng load test production-like.
Memory limit quá thấpOOM kill, restart loop, cache churn.memory.current, memory.events, container exit reason.Rollback limit hoặc release; giảm heap/native footprint; giữ headroom.
PIDs limit quá thấpKhông tạo được process/thread mới.pids.current, pids.events, application errors.Tăng limit có kiểm soát; tìm leak/fork storm trước khi bỏ limit.
I/O contentionRequest stall, fsync/read/write chậm.io.stat, device latency/utilization.Giảm concurrency/ingress; tách noisy neighbor hoặc điều chỉnh I/O policy.

4. Capabilities, seccomp và LSM

Linux capabilities tách quyền của root thành các quyền nhỏ hơn. Docker mặc định chạy container với một tập capability bị giới hạn; khi cần quyền bổ sung, ưu tiên --cap-add tối thiểu và cân nhắc --cap-drop ALL rồi add lại đúng capability cần thiết.

Seccomp lọc system calls. Docker có default seccomp profile và khuyến nghị không tắt profile này một cách tùy tiện. AppArmor/SELinux là Linux Security Modules (LSM) cung cấp policy confinement bổ sung. Đây là defense in depth: capabilities giới hạn quyền, seccomp giảm syscall attack surface, LSM kiểm soát hành vi theo policy.

Tránh --privileged. Chế độ privileged cấp tất cả Linux capabilities, mở rộng device access và gỡ/giảm nhiều confinement mặc định. Nếu workload chỉ cần một quyền hoặc device cụ thể, cấp đúng capability/device thay vì privileged toàn phần.

4.1 Baseline hardening thực tế

5. Container vs VM

Khía cạnhContainerVM
KernelChia sẻ host kernel.Có guest kernel riêng.
Isolation boundaryNamespace/cgroup/capability/seccomp/LSM + runtime/kernel hardening.Hardware virtualization + hypervisor + guest kernel tạo boundary mạnh hơn cho nhiều threat model.
Startup & densityThường nhanh và mật độ cao vì không boot guest OS.Overhead lớn hơn nhưng boundary độc lập hơn.
Multi-tenancyCần hardening cao, policy chặt và đôi khi sandbox/runtime bổ sung.Thường phù hợp hơn khi tenant không tin cậy lẫn nhau và yêu cầu kernel boundary riêng.
Chọn khi nào?Workload tin cậy tương đối, cần density/deploy speed, có platform controls tốt.Threat model cần isolation mạnh hơn, OS/kernel khác nhau hoặc compliance yêu cầu boundary riêng.

Quyết định nên dựa trên threat model, mức độ multi-tenancy, blast radius chấp nhận được và operational model, không dựa trên slogan “container = lightweight VM”. Trong hệ thống nhạy cảm, container vẫn có thể chạy bên trong VM để kết hợp deployment density với một boundary host/tenant rõ hơn.

6. Kiểm tra nhanh trên host

Các lệnh dưới đây giúp xác minh cấu hình runtime; đường dẫn/counter cụ thể có thể khác giữa cgroup v1/v2, rootless mode và distribution.

# Xem Docker đang dùng cgroup / security options gì
docker info

# Xem limits / security config đã apply lên container
docker inspect <container>

# Quan sát usage ở mức Docker
docker stats <container>

# Ví dụ chạy với resource/security baseline
docker run --rm \
  --memory=512m \
  --cpus=1.0 \
  --pids-limit=256 \
  --cap-drop=ALL \
  --security-opt=no-new-privileges=true \
  IMAGE
Verification rule: đừng chỉ kiểm tra “container start được”. Hãy load test, inject memory/CPU pressure, xác minh exit/restart behavior, alerting, downstream timeout và recovery khi giới hạn thực sự bị chạm.

7. Production checklist

Tài liệu tham khảo (official / primary): Docker Engine Security · Docker Resource Constraints · Docker Seccomp · Docker AppArmor · Docker User Namespace Remap · docker container run reference · Linux cgroup v2 · Linux namespaces