Docker cho người mới: Hiểu đúng, dùng đúng từ ngày đầu
Tất cả những gì bạn cần biết về Docker để bắt đầu — không lý thuyết suông, có ví dụ thực tế và góc nhìn từ người đã dùng Docker hàng ngày.
Nguyen Nhat Long
@longnn

Bạn đã bao giờ nghe câu "Ở máy tao chạy ngon mà" chưa? Mình cá là ai làm dev cũng từng nghe ít nhất một lần. Đó chính xác là vấn đề mà Docker sinh ra để giải quyết. Và nếu bạn đang bắt đầu tìm hiểu Docker, thì đây là bài viết mình ước mình có từ hồi mới học.
Mình đã dùng Docker gần như mỗi ngày trong suốt 4 năm qua — từ side project nhỏ đến hệ thống production phục vụ hàng triệu request. Điều mình nhận ra là: Docker không khó, nhưng nhiều người hiểu sai ngay từ đầu rồi loay hoay mãi. Bài này mình sẽ đi thẳng vào những thứ thực sự quan trọng.
Vấn đề thực tế Docker giải quyết
Hình dung thế này: bạn code một app bằng Node.js 18, dùng PostgreSQL 15, cần Redis, cần cài thêm vài thư viện hệ thống. Mọi thứ chạy ngon trên máy bạn. Rồi đến lúc deploy lên server, hoặc đơn giản hơn — đồng nghiệp mới vào team clone repo về.
Chuyện gì xảy ra? Máy người ta dùng Node 16. PostgreSQL thì version khác. Redis chưa cài. Thư viện hệ thống thiếu. Mất nửa ngày chỉ để setup môi trường.
Docker giải quyết chuyện này bằng cách đóng gói toàn bộ application cùng với môi trường của nó vào một cái gọi là container. Container này chạy giống hệt nhau trên mọi máy — laptop của bạn, máy đồng nghiệp, hay server production.

Docker khác máy ảo (VM) ở chỗ nào?
Nhiều người mới hay nhầm Docker với máy ảo. Khác biệt lớn nhất: VM ảo hóa cả hệ điều hành, còn Docker chỉ ảo hóa ở tầng application. VM cần vài phút để boot, tốn vài GB RAM. Container Docker start trong vài giây, tốn vài chục MB.
Theo kinh nghiệm của mình, đây là lý do Docker thắng trong hầu hết use case phát triển phần mềm hiện đại. Bạn có thể chạy 10-20 container trên một laptop bình thường, trong khi chạy 10 VM thì máy đã muốn nổ rồi.

Những khái niệm cốt lõi bạn cần nắm
Docker có khá nhiều thuật ngữ, nhưng bạn chỉ cần hiểu rõ 4 thứ này trước:
Image
Image là bản "blueprint" — một template chứa mọi thứ cần thiết để chạy application: code, runtime, thư viện, biến môi trường. Image là read-only, không thay đổi được.
Container
Container là một instance đang chạy của image. Một image có thể tạo ra nhiều container. Nghĩ đơn giản: image là class, container là object.
Dockerfile
Đây là file config để Docker biết cách build ra image. Mình sẽ nói kỹ hơn ở phần dưới.
Docker Hub / Registry
Nơi lưu trữ và chia sẻ image. Docker Hub là registry công khai lớn nhất — giống GitHub nhưng cho Docker image. Bạn cũng có thể dùng registry riêng trên AWS ECR, Google Container Registry, hay tự host.

Dockerfile — Trái tim của mọi thứ
Điều mình thấy hay là Dockerfile cực kỳ dễ đọc, gần như đọc là hiểu. Đây là ví dụ thực tế:
1FROM golang:1.11 AS builder2WORKDIR /go/src/docker-demo/3COPY . .4RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o docker-demo .56FROM alpine:latest7WORKDIR /root/8COPY --from=builder /go/src/docker-demo .9CMD ["./docker-demo"]
Đây là một multi-stage build — kỹ thuật mà mình khuyên bạn nên dùng từ đầu. Stage đầu dùng image golang nặng để build binary. Stage sau chỉ dùng alpine (siêu nhẹ, ~5MB) để chạy binary đó. Kết quả: image cuối cùng nhỏ gọn hơn rất nhiều.
Những instruction quan trọng nhất:
- FROM — image gốc để bắt đầu (bắt buộc, luôn là dòng đầu tiên)
- WORKDIR — set thư mục làm việc trong container
- COPY / ADD — copy file từ máy host vào container
- RUN — chạy lệnh khi build image (cài package, compile code...)
- CMD — lệnh mặc định khi container start
- EXPOSE — khai báo port container lắng nghe
- ENV — set biến môi trường
Một tip từ kinh nghiệm thực tế: thứ tự các instruction rất quan trọng. Docker cache từng layer, nên bạn nên đặt những thứ ít thay đổi (như COPY package.json và RUN npm install) lên trước, còn source code hay thay đổi thì COPY sau. Build sẽ nhanh hơn đáng kể.
Các lệnh Docker bạn sẽ dùng hàng ngày
Không cần nhớ hết, nhưng đây là những lệnh mình dùng nhiều nhất:
1# Build image từ Dockerfile2docker build -t my-app .34# Chạy container5docker run -d -p 8080:8080 --name my-app my-app67# Xem container đang chạy8docker ps910# Xem log11docker logs my-app1213# Dừng và xóa container14docker stop my-app15docker rm my-app1617# Xóa tất cả container đã dừng18docker container prune1920# Xóa tất cả image không dùng21docker image prune -a
Mẹo: lệnh docker container prune và docker system prune là bạn thân của bạn. Mình đã từng bị đầy ổ cứng vì quên dọn image và container cũ — đừng lặp lại sai lầm đó.
Docker Compose — Khi app cần nhiều service
Thực tế hiếm khi app chỉ chạy một container. Bạn cần database, cache, message queue... Docker Compose cho phép bạn define tất cả trong một file docker-compose.yml:
1version: '3.8'2services:3 app:4 build: .5 ports:6 - "8080:8080"7 depends_on:8 - db9 - redis10 db:11 image: postgres:1512 environment:13 POSTGRES_PASSWORD: secret14 redis:15 image: redis:7-alpine
Một lệnh docker compose up là toàn bộ stack chạy. Đồng nghiệp mới vào team? Clone repo, chạy docker compose up, xong. Không cần cài PostgreSQL, không cần cài Redis, không cần đọc wiki setup dài 3 trang.

Những điều mình học được sau nhiều năm dùng Docker
Đừng chạy container với quyền root. Thêm USER instruction trong Dockerfile để chạy với user không có quyền root. Đây là security basic nhưng nhiều người bỏ qua.
Dùng .dockerignore. Giống .gitignore, file này giúp bạn loại bỏ node_modules, .git, file log... khỏi build context. Image nhẹ hơn, build nhanh hơn.
Không lưu data quan trọng trong container. Container là ephemeral — nó có thể bị xóa bất cứ lúc nào. Dùng Docker Volume để persist data, đặc biệt là database.
Pin version cụ thể cho base image. Đừng dùng FROM node:latest. Dùng FROM node:18.19-alpine. "Latest" hôm nay khác "latest" ngày mai, và bạn sẽ không muốn production build bị break vì chuyện này.

Bắt đầu từ đâu?
Nếu bạn đọc đến đây và chưa từng dùng Docker, đây là lộ trình mình gợi ý:
- Cài Docker Desktop (Windows/Mac) hoặc Docker Engine (Linux)
- Chạy
docker run hello-worldđể verify - Viết Dockerfile cho project hiện tại của bạn
- Thêm
docker-compose.ymlnếu project cần database - Thử deploy container lên một VPS nhỏ
Đừng cố học hết Docker Swarm, Kubernetes, hay orchestration phức tạp ngay. Nắm vững Dockerfile và Docker Compose trước đã — hai thứ đó cover 90% nhu cầu hàng ngày của một developer.
Docker không phải silver bullet, nhưng nó là một trong những công cụ có ROI cao nhất mà mình từng học. Đầu tư vài ngày để hiểu rõ, và bạn sẽ tiết kiệm được hàng trăm giờ về sau. Chúc bạn setup ngon lành từ lần đầu tiên — hoặc ít nhất là từ lần thứ hai. 😄
Nguyen Nhat Long
@longnnThấy hay? Chia sẻ cho bạn bè!
Bài viết liên quan
Có thể bạn cũng thích

30 khái niệm Frontend mà bạn phải nắm trước khi đi phỏng vấn
Frameworks thay đổi, tools tiến hóa, nhưng 30 concepts này cứ xuất hiện hoài trong mọi buổi phỏng vấn frontend. Nắm chắc chúng, bạn sẽ khác biệt.

TanStack Start — Khi Next.js không còn là lựa chọn mặc định
Next.js đã thống trị 5 năm qua, nhưng sự phức tạp ngày càng tăng khiến nhiều dev tìm kiếm lựa chọn khác. TanStack Start có phải là câu trả lời?
Setup NGINX + Next.js Standalone: Hướng dẫn từ thực chiến
Hướng dẫn chi tiết cách setup NGINX làm reverse proxy cho Next.js standalone mode, kèm tips từ kinh nghiệm deploy thực tế.