Docker Images và Containers: Giải Thích Từ Đầu

Bạn đã nghe câu này cả trăm lần: "Dùng Docker đi." Nhưng nếu chưa từng đụng vào, các concept cứ mờ mờ ảo ảo. Docker image là gì? Container là gì? Và tại sao mọi người cứ ca bài "it works on my machine"?
Bài này sẽ giải thích hết — kèm ví dụ thực hành chạy được ngay bây giờ.
Docker là gì?
Docker là platform cho phép bạn đóng gói app cùng tất cả những thứ nó cần (runtime, libraries, config) vào một unit duy nhất, portable — và chạy nó nhất quán ở bất kỳ đâu.
Problem kinh điển mà nó giải quyết:
Developer: "Trên máy mình chạy ngon!"
Server: "Trên server thì không."Tại sao? Vì máy developer dùng Node 20, server dùng Node 16. Hoặc developer cài một library global mà server không có. Hoặc environment variables khác nhau.
Docker fix điều này bằng cách đóng gói tất cả mọi thứ app cần vào một bundle duy nhất, chạy giống nhau ở mọi nơi:
- Laptop của bạn
- Máy của teammate
- CI/CD pipeline
- Staging server
- Production
Không còn "works on my machine" nữa.
Lợi ích khác
Onboard teammate mới nhanh hơn:
Thay vì hướng dẫn setup 2 tiếng, họ chỉ cần chạy docker compose up là bắt đầu code được. Không cần cài MySQL, Redis, Node, Java — tất cả đã có sẵn trong project.
Giữ máy sạch:
Không muốn cài PostgreSQL, Redis hay Java thẳng lên laptop? Chạy chúng trong Docker container. Khi xong project, docker compose down -v --rmi all là dọn sạch hết.
Cài đặt Docker
macOS
Download Docker Desktop từ trang Docker.
Windows
Download Docker Desktop từ trang Docker.
Ubuntu / Linux
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Kiểm tra hoạt động
docker infoSau khi cài xong, chạy smoke test kinh điển:
docker run hello-worldNếu thấy "Hello from Docker!" — OK rồi đó.
Docker Image là gì?
Image là một package read-only chứa tất cả mọi thứ cần để chạy app:
- Layer OS (ví dụ Ubuntu, Alpine Linux)
- Runtime (Node.js, Python, Java,...)
- Libraries và dependencies
- Code của app
- Configuration
Hình dung nó như một bản thiết kế — bạn không chạy trực tiếp image; bạn tạo ra container từ image đó.
Image được tạo từ các Layer
Mỗi image được build lên từ nhiều layer chồng nhau:
Tại sao layer lại quan trọng:
- Caching — layer không thay đổi sẽ được reuse. Nếu chỉ sửa code app, Docker không cần re-download Node.js hay re-install dependencies.
- Sharing — nếu hai image dùng cùng base layer (ví dụ
ubuntu:22.04), Docker chỉ lưu một bản trên disk. - Immutable — không thể sửa image đang tồn tại. Bạn chỉ có thể build image mới hoặc thêm layer mới lên trên.
Docker Hub: Registry chứa Image
Docker Hub là registry công khai nơi hàng nghìn image sẵn có. Cần PostgreSQL? Chạy thôi:
docker pull postgres:15Docker tải image PostgreSQL 15 chính thức từ Docker Hub. Bạn cũng tìm được image của Nginx, Redis, Node.js, Python, MySQL và hầu hết mọi tool cần thiết.
Liệt kê và xóa Image
# Xem tất cả image trên máy
docker images
# Xóa một image
docker rmi nginx:1.25
# Xóa tất cả image không dùng
docker image pruneDocker Container là gì?
Container là một instance đang chạy của image. Mối quan hệ là:
Image (bản thiết kế) → Container (app đang chạy)Bạn có thể tạo nhiều container từ cùng một image:
image nginx:1.25 → container: web-1 (đang chạy)
→ container: web-2 (đang chạy)
→ container: web-test (đã dừng)Container độc lập với nhau và với host. Chúng có filesystem, process space và network interface riêng. Nhưng nhẹ hơn VM rất nhiều — khởi động trong vài giây, không phải vài phút, và chỉ dùng vài MB RAM thay vì vài GB.
Container vs Virtual Machine
| Feature | Container | Virtual Machine |
|---|---|---|
| Kích thước | MB | GB (full OS) |
| Khởi động | Vài giây | Vài phút |
| Isolation | Process-level | Hardware-level |
| Performance | Gần native | ~5–10% overhead |
| Mật độ | Hàng trăm trên một host | Vài chục trên một host |
Container chia sẻ kernel của host OS, đó là lý do chúng nhẹ đến vậy. VM phải chạy toàn bộ guest OS trên hypervisor.
Chạy Container Đầu Tiên
Hello World
docker run hello-worldCâu này pull image hello-world (nếu chưa có) và chạy container từ nó.
Nginx Web Server
# Chạy Nginx, map port 8080 trên host vào port 80 trong container
docker run -p 8080:80 nginxMở http://localhost:8080 trên trình duyệt — bạn thấy trang welcome của Nginx.
Flag -p 8080:80 nghĩa là: "forward traffic từ port 8080 của host vào port 80 của container."
Chạy ngầm (Detached Mode)
docker run -d --name my-nginx -p 8080:80 nginx-d chạy container ngầm. --name my-nginx đặt tên dễ nhớ.
Xem các Container đang chạy
docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a3f1b2c4d5e6 nginx ... 2 phút trước Up 2 phút 0.0.0.0:8080->80/tcp my-nginxDừng và Xóa
docker stop my-nginx
docker rm my-nginxHoặc force-remove container đang chạy:
docker rm -f my-nginxTự Build Image (Dockerfile)
Đến giờ ta chỉ dùng image từ Docker Hub. Nhưng làm sao để đóng gói app của chính mình?
Bạn viết một Dockerfile — script nói cho Docker biết cách build image.
Đây là ví dụ Node.js đơn giản:
index.js:
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from Docker!\n');
});
server.listen(3000, () => {
console.log('Server đang chạy trên port 3000');
});Dockerfile:
FROM node:24
WORKDIR /app
COPY index.js .
EXPOSE 3000
CMD ["node", "index.js"]Build và chạy:
# Build image (đặt tên là "my-app")
docker build -t my-app .
# Chạy container từ image đó
docker run -p 3000:3000 my-appVào http://localhost:3000 — bạn thấy "Hello from Docker!"
Mỗi Instruction Trong Dockerfile Làm Gì
| Instruction | Mục đích |
|---|---|
FROM node:24 | Bắt đầu từ image Node.js 24 chính thức |
WORKDIR /app | Đặt thư mục làm việc bên trong container |
COPY index.js . | Copy file của bạn vào container |
EXPOSE 3000 | Khai báo app lắng nghe trên port 3000 |
CMD [...] | Lệnh chạy khi container khởi động |
Cheat Sheet Các Lệnh Cần Biết
Image
docker pull nginx:1.25 # Tải image
docker images # Liệt kê image local
docker rmi nginx:1.25 # Xóa image
docker build -t my-app . # Build từ Dockerfile
docker image prune # Xóa image không dùngContainer
docker run -d --name web -p 8080:80 nginx # Chạy container
docker ps # Liệt kê container đang chạy
docker ps -a # Liệt kê tất cả container
docker stop web # Dừng container
docker start web # Start container đã dừng
docker rm web # Xóa container
docker rm -f web # Force-remove container đang chạy
docker logs web # Xem log
docker logs -f web # Follow log
docker exec -it web bash # Mở shell bên trong container
docker container prune # Xóa tất cả container đã dừngDọn dẹp hệ thống
docker system df # Kiểm tra dung lượng
docker system prune # Xóa resource không dùng
docker system prune --volumes # Bao gồm cả volumeLỗi Hay Gặp
Dùng :latest trong Production
# Rủi ro — "latest" thay đổi mà không báo trước
docker run nginx:latest
# An toàn — pin vào version cụ thể
docker run nginx:1.25.3Lưu Data Bên Trong Container
Container là ephemeral — khi docker rm một container, toàn bộ data bên trong mất hết. Với database, luôn dùng volume:
# Nguy hiểm — data mất khi container bị xóa
docker run postgres:15
# Đúng cách — data tồn tại trong named volume
docker run -v pgdata:/var/lib/postgresql/data postgres:15Không Dọn Dẹp
Container, image và volume tích lũy nhanh lắm. Chạy lệnh này định kỳ:
docker system prune --volumesTóm Lại
✅ Docker đóng gói app và dependencies vào container portable
✅ Image là bản thiết kế read-only; container là instance đang chạy
✅ Image được build từ nhiều layer — layer không đổi được cache để build nhanh
✅ Container nhẹ hơn VM rất nhiều (MB vs GB, vài giây vs vài phút)
✅ Dùng docker run để start container, -p để map port, -d để chạy ngầm
✅ Viết Dockerfile để đóng gói app của mình thành image
✅ Dùng volume cho data persistent; đừng bao giờ trông cậy vào filesystem của container
Series: Docker & Kubernetes Learning Roadmap
Next: Docker Fundamentals: Hướng Dẫn Toàn Diện Cho Người Mới
Muốn đào sâu hơn? Bài tiếp theo cover Docker đầy đủ — networking, volumes, Docker Compose và best practices cho production.
📬 Đăng ký nhận bản tin
Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.
Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.
💬 Comments
Đăng nhập để bình luận
Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.