Câu giải thích quen thuộc nhất về Docker — "container là một máy ảo nhẹ" — cũng là câu sai nhất, và hiểu sai điểm này khiến bạn không lý giải được vì sao container khởi động trong mili giây, vì sao container Linux không chạy được trên kernel Windows, hay vì sao container "thấy" ít tiến trình hơn host. Sự thật đơn giản và mạnh mẽ hơn: container chỉ là một tiến trình bình thường trên host, được kernel cô lập và giới hạn bằng hai tính năng có sẵn. Bài này (phần 1 loạt "Docker và container: nhìn từ bên trong") chứng minh điều đó bằng demo chạy thật — kể cả tự dựng "container" mini không cần Docker.
VM và container khác nhau ở tầng nào
- Máy ảo (VM): hypervisor ảo hoá phần cứng, mỗi VM chạy một kernel riêng và cả một hệ điều hành đầy đủ. Cô lập rất mạnh, nhưng nặng: tốn RAM cho mỗi kernel, khởi động phải boot cả OS (tính bằng giây tới phút).
- Container: không ảo hoá phần cứng, không có kernel riêng. Nó là một tiến trình chạy trực tiếp trên kernel host, chỉ được kernel cô lập tầm nhìn (namespace) và giới hạn tài nguyên (cgroup). Nhẹ, nhanh, nhưng cô lập ở mức tiến trình chứ không phải máy.
Nói cách khác: Docker không "chạy" container theo nghĩa máy ảo. Nó cấu hình các tính năng kernel để một tiến trình tưởng rằng nó có cả hệ thống cho riêng mình.

Hình 1: VM có kernel riêng qua hypervisor; container là tiến trình host cô lập bằng namespace (tầm nhìn) + cgroup (tài nguyên), chung kernel. Có thể tự dựng cô lập bằng unshare — chính là thứ Docker làm bên dưới.
Đo thật: ba bằng chứng container không phải VM

Hình 2: Chạy thật — alpine và ubuntu cùng trả kernel 7.0.12-linuxkit (kernel host); trong PID namespace mới tạo bằng unshare, shell thành PID 1 và chỉ thấy tiến trình của chính nó; docker run alpine true mất 164 ms.
- Chung kernel host:
docker run alpine uname -rvàdocker run ubuntu uname -rtrả về cùng một phiên bản kernel (7.0.12-linuxkit) — dù alpine và ubuntu là hai distro khác hẳn. Nếu là VM, mỗi cái sẽ có kernel riêng. Chúng dùng chung kernel vì đó là kernel của host. (Lưu ý:linuxkitlà kernel của VM Linux nhẹ mà Docker Desktop dùng trên macOS/Windows — xem phần đánh đổi.) - Cô lập bằng namespace, không cần Docker: chạy
unshare --pid --fork --mount-proc shtạo một PID namespace mới; shell trở thành PID 1 vàpschỉ thấy tiến trình của chính nó. Đây chính xác là cơ chế Docker dùng — bạn vừa tự tạo phần lõi của một "container" bằng một lệnh. - Khởi động mili giây:
docker run --rm alpine truemất 164 ms cho cả tạo + chạy + xoá container. Không có kernel nào được boot — chỉ là fork một tiến trình rồi gắn namespace/cgroup. VM cần boot cả OS nên tính bằng giây.
Đánh đổi cần cân nhắc
Cô lập của container yếu hơn VM — vì chung kernel. Mọi container chia sẻ kernel host, nên một lỗ hổng leo thang đặc quyền ở tầng kernel có thể ảnh hưởng cả host và các container khác. VM cô lập mạnh hơn (ranh giới phần cứng ảo). Với workload cần cô lập bảo mật cao (chạy code không tin cậy của nhiều khách hàng), người ta dùng VM hoặc sandbox kiểu gVisor/Kata (container chạy trong micro-VM). Container mặc định đánh đổi cô lập lấy hiệu năng.
Container Linux cần kernel Linux. Vì chung kernel host, container Linux không chạy trực tiếp trên kernel Windows hay macOS. Docker Desktop trên hai OS đó thật ra chạy một VM Linux nhẹ ẩn bên dưới (chính là linuxkit thấy ở demo), rồi container chạy trong VM đó. Đây là lý do file I/O qua bind mount trên Mac/Windows chậm hơn Linux gốc — nó đi qua ranh giới VM.
"Nhẹ" không có nghĩa "miễn phí". Container không boot OS, nhưng vẫn tốn RAM/CPU cho tiến trình bên trong, và một image cồng kềnh vẫn chiếm nhiều đĩa. "Nhẹ" là so với VM về overhead cô lập, không phải lời hứa ứng dụng của bạn sẽ nhẹ. Các phần sau của loạt sẽ đo image layer và cách giảm kích thước.
Ba ý mang về
- Container là tiến trình host bị cô lập, không phải VM: đo thật, alpine và ubuntu cùng thấy kernel
7.0.12-linuxkitcủa host — không có kernel riêng như VM. Docker chỉ cấu hình hai tính năng kernel: namespace + cgroup. - Cô lập là tính năng kernel, tự dựng được: đo thật
unshare --pidcho shell thành PID 1 chỉ thấy tiến trình của chính nó — không cần Docker; Docker chỉ dựng sẵn và quản lý image trên nền đó. - Nhẹ nhờ không boot kernel, nhưng cô lập yếu hơn VM: đo thật
docker runmất 164 ms (VM tính bằng giây); đổi lại chung kernel nên cô lập bảo mật kém hơn — workload không tin cậy nên cân nhắc VM/micro-VM.
Nguồn
- man7.org — namespaces(7): https://man7.org/linux/man-pages/man7/namespaces.7.html
- man7.org — cgroups(7): https://man7.org/linux/man-pages/man7/cgroups.7.html
- Docker docs — Docker overview / architecture: https://docs.docker.com/get-started/docker-overview/
Phần sau ta đào sâu vào PID namespace: vì sao tiến trình trong container thấy mình là PID 1, điều gì đặc biệt ở PID 1 (xử lý tín hiệu, tiến trình mồ côi), và vì sao ứng dụng container hay cần một "init" nhỏ.