Docker từ A-Z: Cheat Sheet và mọi thứ bạn cần nhớ
Bài cuối của series Docker từ A-Z tổng kết toàn bộ kiến thức, cheat sheet đầy đủ, và những lỗi kinh điển mình đã gặp trong thực tế.
Nguyễn Nhật Long
@nguyennhatlong1303
Nếu bạn đã theo dõi series này từ đầu, xin chúc mừng bạn vừa đi qua một hành trình khá dài từ cái khái niệm container đầu tiên cho đến orchestration với Kubernetes. Bài này mình không định viết theo kiểu "recap bài 1 làm gì, bài 2 làm gì" một cách máy móc. Thay vào đó, mình muốn tổng hợp lại theo cách mà mình thực sự dùng hàng ngày cheat sheet, checklist, và những cái bẫy mà ai cũng sẽ vấp ít nhất một lần.
Cái bức tranh lớn sau 9 bài
Nhìn lại thì Docker ecosystem khá rộng, nhưng thực ra nó xoay quanh vài khái niệm cốt lõi:
- Container là process được isolated không phải VM, nhẹ hơn nhiều
- Image là template để tạo container build một lần, chạy ở đâu cũng được
- Dockerfile là recipe để build image mỗi instruction là một layer
- Docker Compose để orchestrate multi-container trên local
- Volume và Network để data persist và các container nói chuyện với nhau
- Security non-root user, scan image, giới hạn resource
- CI/CD build image trong pipeline, push lên registry, deploy tự động
- Orchestration Kubernetes/Swarm khi cần scale production
Mình thấy nhiều bạn học Docker xong vẫn bị lúng túng vì cứ nghĩ nó phức tạp. Thực ra complexity nằm ở ecosystem xung quanh, còn core concept của Docker thì khá clean. Nắm được 7 điểm trên là bạn đã cover được 80% use case thực tế rồi.
Docker CLI Cheat Sheet
Đây là phần mình pin lên màn hình suốt. Không cần nhớ hết, nhưng biết chỗ để tra là đủ.
Container Commands
| Command | Mô tả | Ví dụ |
|---|---|---|
| `docker run` | Tạo và chạy container | `docker run -d -p 8080:80 nginx` |
| `docker ps` | List container đang chạy | `docker ps -a` (kể cả stopped) |
| `docker stop` | Dừng container (graceful) | `docker stop <id hoặc name>` |
| `docker kill` | Dừng container (force) | `docker kill <id>` |
| `docker rm` | Xóa container | `docker rm -f <id>` |
| `docker logs` | Xem logs | `docker logs -f --tail 100 <id>` |
| `docker exec` | Chạy command trong container đang chạy | `docker exec -it <id> bash` |
| `docker inspect` | Xem toàn bộ metadata | `docker inspect <id>` |
| `docker stats` | Monitor resource realtime | `docker stats` |
| `docker cp` | Copy file vào/ra container | `docker cp file.txt <id>:/app/` |
Image Commands
| Command | Mô tả | Ví dụ |
|---|---|---|
| `docker build` | Build image từ Dockerfile | `docker build -t myapp:1.0 .` |
| `docker images` | List images local | `docker images` |
| `docker rmi` | Xóa image | `docker rmi myapp:1.0` |
| `docker pull` | Pull image từ registry | `docker pull node:20-alpine` |
| `docker push` | Push image lên registry | `docker push myrepo/myapp:1.0` |
| `docker tag` | Tag image | `docker tag myapp:1.0 myapp:latest` |
| `docker history` | Xem các layer của image | `docker history myapp:1.0` |
| `docker save` | Export image ra file tar | `docker save -o myapp.tar myapp:1.0` |
| `docker load` | Import image từ file tar | `docker load -i myapp.tar` |
Docker Compose Commands
| Command | Mô tả | Ghi chú |
|---|---|---|
| `docker compose up` | Khởi động services | Thêm `-d` để chạy background |
| `docker compose down` | Dừng và xóa containers | Thêm `-v` để xóa luôn volumes |
| `docker compose logs` | Xem logs | `docker compose logs -f service_name` |
| `docker compose exec` | Exec vào service | `docker compose exec web bash` |
| `docker compose build` | Build lại images | `docker compose build --no-cache` |
| `docker compose ps` | List services | |
| `docker compose restart` | Restart service | `docker compose restart web` |
| `docker compose pull` | Pull images mới nhất |
Volume và Network Commands
1# Volume2docker volume create mydata3docker volume ls4docker volume inspect mydata5docker volume rm mydata6docker volume prune # xóa tất cả volumes không dùng78# Network9docker network create mynet10docker network ls11docker network inspect mynet12docker network connect mynet <container>13docker network disconnect mynet <container>14docker network rm mynet1516# Dọn dẹp tổng thể (cẩn thận với cái này trên production!)17docker system prune -a --volumes
Dockerfile Best Practices Checklist thực chiến
Mình đã review khá nhiều Dockerfile của team và thấy lỗi lặp đi lặp lại. Đây là checklist mình dùng trước khi merge:
✅ Pin version KHÔNG dùng latest
1# Sai2FROM node:latest34# Đúng5FROM node:20.11-alpine3.19
Dùng latest là bạn đang mời bug vào nhà. Image hôm nay build được, tuần sau CI fail vì latest đã update mình đã bị cái này một lần rồi, đau lắm.
✅ Có .dockerignore
1node_modules2.git3.env4*.log5dist6coverage7.DS_Store
Thiếu cái này thì build context của bạn có thể lên đến vài GB vì copy cả node_modules vào.
✅ Sắp xếp layer hợp lý thứ ít thay đổi lên trước
1# Copy package.json trước, install dependencies2# Sau đó mới copy source code3COPY package*.json ./4RUN npm ci --only=production5COPY . .
Layer caching là một trong những thứ hay nhất của Docker. Tận dụng nó đúng cách thì build time giảm đáng kể.
✅ Multi-stage build cho production
1# Stage 1: Build2FROM node:20-alpine AS builder3WORKDIR /app4COPY package*.json ./5RUN npm ci6COPY . .7RUN npm run build89# Stage 2: Production image10FROM node:20-alpine AS production11WORKDIR /app12COPY package*.json ./13RUN npm ci --only=production14COPY --from=builder /app/dist ./dist15CMD ["node", "dist/index.js"]
Multi-stage giúp image production không chứa dev dependencies, build tools, source code gốc. Image nhỏ hơn, secure hơn.
✅ Non-root user
1RUN addgroup -S appgroup && adduser -S appuser -G appgroup2USER appuser
Chạy container với root user là anti-pattern. Nếu container bị compromise, attacker có full quyền trên container đó.
✅ HEALTHCHECK
1HEALTHCHECK --interval=30s --timeout=3s --retries=3 \2 CMD wget -qO- http://localhost:3000/health || exit 1
Không có healthcheck thì Docker/Kubernetes không biết app của bạn có thực sự ready hay không chỉ biết process đang chạy thôi.
✅ Dùng COPY thay vì ADD (trừ khi cần extract tar)
✅ Combine RUN commands để giảm layers
1RUN apt-get update && \2 apt-get install -y curl wget && \3 rm -rf /var/lib/apt/lists/*
Những lỗi kinh điển và cách fix
Theo kinh nghiệm của mình, đây là những cái bạn sẽ gặp sớm hay muộn:
Container exit ngay sau khi start
Triệu chứng: docker run myapp xong container biến mất ngay.
1# Check exit code2docker ps -a3docker logs <container_id>
Nguyên nhân phổ biến nhất: process chính trong container kết thúc. Ví dụ bạn dùng CMD ["npm", "start"] nhưng script đó chạy xong và exit. Hoặc app crash ngay khi start do thiếu env variable, không connect được database.
Port already in use
1# Tìm process đang dùng port2lsof -i :80803# hoặc4netstat -tulpn | grep 808056# Kill process đó hoặc đổi port mapping7docker run -p 8081:80 nginx
Permission denied khi mount volume
Cái này hay xảy ra trên Linux khi user trong container (ví dụ UID 1000) khác với owner của thư mục trên host.
1# Fix nhanh (không khuyến khích cho production)2docker run -v /host/data:/app/data -u $(id -u):$(id -g) myapp34# Hoặc chown trong Dockerfile5RUN mkdir -p /app/data && chown -R appuser:appgroup /app/data
Image quá lớn
Mình đã từng thấy image Node.js lên đến 1.5GB. Một số cách giảm:
- Dùng alpine base image (
node:20-alpinethay vìnode:20) - Multi-stage build để bỏ dev dependencies
- Check xem có copy nhầm thứ không cần không (
docker history myimage) - Dùng
divetool để analyze từng layer
1# Cài dive để analyze image2brew install dive3dive myapp:1.0
Data bị mất sau khi xóa container
Đây là lỗi cơ bản nhưng rất nhiều người mới mắc phải. Container là ephemeral mọi thứ ghi vào filesystem của container sẽ mất khi container bị xóa. Giải pháp là dùng volume:
1# docker-compose.yml2services:3 db:4 image: postgres:165 volumes:6 - pgdata:/var/lib/postgresql/data # named volume78volumes:9 pgdata:
Containers không connect được với nhau
Trong Docker Compose, các service tự động trong cùng một network và có thể reach nhau qua service name. Nhưng nếu bạn chạy container thủ công với docker run, bạn cần tạo network và attach vào:
1docker network create mynet2docker run --network mynet --name db postgres:163docker run --network mynet --name app myapp4# Bây giờ app có thể connect đến db qua hostname "db"
Anh em hay bị lỗi này khi connect từ app container đến database mà dùng localhost localhost trong container là container đó, không phải host machine hay container khác.
Resources mình thực sự dùng
- Docker Docs official docs của Docker khá tốt, reference đầy đủ. Mình hay dùng phần Dockerfile reference và Compose file reference.
- Docker Hub tìm official images ở đây. Luôn ưu tiên official images hoặc verified publishers.
- Play with Docker môi trường Docker free trên browser, không cần cài gì. Tuyệt vời để test nhanh hoặc demo cho người khác.
- awesome-docker curated list các tools, resources liên quan Docker. Mình tìm được
dive,ctop,lazydockertừ đây. - Hadolint linter cho Dockerfile, nên tích hợp vào CI pipeline.
1# Chạy hadolint local2docker run --rm -i hadolint/hadolint < Dockerfile
Một vài thứ mình học được sau 5 năm dùng Docker
Docker không phải silver bullet. Mình thấy nhiều team Dockerize mọi thứ một cách máy móc mà không suy nghĩ xem nó có thực sự cần thiết không. Với môi trường local development, đôi khi chạy thẳng native còn nhanh và đơn giản hơn.
Nhưng khi bạn cần consistency giữa các môi trường, khi team lớn lên, khi cần deploy lên nhiều server Docker thực sự shine. Cái câu "works on my machine" gần như biến mất khi team dùng Docker đúng cách.
Và cuối cùng: đừng sợ đọc docker logs. Phần lớn vấn đề bạn gặp với Docker đều có câu trả lời trong logs. Đó là nơi đầu tiên mình check mỗi khi có gì đó không chạy được.
Series này kết thúc ở đây, nhưng Docker ecosystem vẫn đang phát triển Compose Watch, Docker Build Cloud, hay những cải tiến liên tục trong Kubernetes integration. Mình sẽ tiếp tục viết về những thứ mới khi có dịp. Nếu bạn có câu hỏi hay muốn mình đi sâu hơn vào phần nào, cứ comment bên dưới nhé.
Nguyễn Nhật Long
@nguyennhatlong1303Nguyễn Nhật Long is a Senior Frontend Engineer and Frontend Team Leader with 7 years of experience building real-time fintech platforms. Specializing in React, Next.js, TypeScript, and React Native, shipping 10+ products across Web, Mobile, Telegram Mini-Apps, and Web3.
Thấy hay? Chia sẻ cho bạn bè!