Docker cho developer: hiểu image, container, network và volume
Docker

Docker cho developer: hiểu image, container, network và volume

Nam Nguyen
5 phút đọc
0 lượt xem
#docker
#container
#compose
#devops

Docker giải quyết vấn đề gì?#

Docker giúp đóng gói ứng dụng cùng runtime, thư viện hệ thống và command chạy app vào một image có thể tái sử dụng. Thay vì mỗi máy cài Node, PHP, Python, Nginx hoặc PostgreSQL theo cách riêng, team có thể thống nhất môi trường bằng Dockerfile và Docker Compose. Điều này đặc biệt hữu ích khi dự án có nhiều service hoặc cần onboarding nhanh.

Tuy nhiên Docker không phải máy ảo nhỏ. Container dùng chung kernel với host, khởi động nhanh hơn VM và được tạo từ image. Hiểu đúng ba khái niệm image, container và volume sẽ giúp bạn debug tốt hơn rất nhiều.

Image là bản thiết kế, container là tiến trình đang chạy#

Image là artifact bất biến gồm nhiều layer. Mỗi instruction trong Dockerfile thường tạo một layer mới. Container là instance chạy từ image. Bạn có thể xóa container mà image vẫn còn; bạn có thể chạy nhiều container từ cùng một image; và dữ liệu ghi bên trong filesystem của container sẽ mất khi container bị xóa nếu không dùng volume.

Một Dockerfile tốt nên tối ưu cache layer, tránh copy thừa, không chạy app bằng root nếu không cần và tách build dependency khỏi runtime khi có thể.

Dockerfile
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "run", "start"]

Ví dụ trên còn có thể tối ưu thêm bằng multi-stage build tách riêng build output, nhưng nó đã thể hiện một nguyên tắc quan trọng: copy file dependency trước để tận dụng cache, sau đó mới copy toàn bộ source.

.dockerignore quan trọng như .gitignore#

Nếu bạn copy cả repository vào image mà không có .dockerignore, build context có thể chứa node_modules, file log, cache, file local hoặc secret. Điều này làm image nặng, build chậm và tăng rủi ro rò rỉ thông tin.

Text
node_modules
.next
.git
.env
.env.local
npm-debug.log
coverage
dist

Hãy coi Docker image như thứ có thể được chia sẻ cho môi trường khác. Bất cứ file nào không cần cho build hoặc runtime thì không nên đi vào image.

Docker Compose giúp mô tả môi trường local#

Với một ứng dụng web có database và cache, Compose giúp developer chạy cả stack bằng một command. Quan trọng nhất là nó ghi lại dependency giữa các service, port expose, volume dữ liệu và biến môi trường cơ bản.

YAML
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://app:app@db:5432/app
      REDIS_URL: redis://redis:6379
    depends_on:
      - db
      - redis

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
      POSTGRES_DB: app
    volumes:
      - db-data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine

volumes:
  db-data:

Trong network mặc định của Compose, service có thể gọi nhau bằng tên service. App không cần biết IP của database; nó chỉ cần gọi host db. Đây là lý do connection string trong container khác connection string chạy trực tiếp trên host.

Network: port mapping không phải service discovery#

Dòng 3000:3000 nghĩa là port 3000 trong container được map ra port 3000 trên host. Mapping này phục vụ truy cập từ bên ngoài Docker network. Còn giữa các container, chúng giao tiếp qua Docker network nội bộ bằng tên service và port trong container.

  • Host truy cập app qua localhost:3000.
  • Container app truy cập database qua db:5432.
  • Container database không cần publish port ra host nếu chỉ app dùng nó.

Hiểu điểm này giúp bạn tránh lỗi phổ biến: để app trong container gọi localhost:5432 và kỳ vọng đó là PostgreSQL container. Với container, localhost là chính container đó.

Volume: dữ liệu bền vững nằm ngoài vòng đời container#

Container có thể bị xóa và tạo lại bất cứ lúc nào. Database, file upload hoặc cache muốn tồn tại sau khi recreate container thì cần volume. Named volume do Docker quản lý, phù hợp cho database local. Bind mount gắn thư mục host vào container, phù hợp cho development khi muốn sửa code và thấy thay đổi ngay.

Không nên dùng container filesystem để lưu dữ liệu quan trọng. Trong production, hãy dùng managed database, object storage hoặc volume có backup rõ ràng.

Debug Docker bằng các command cơ bản#

Terminal
docker ps
docker logs app
docker exec -it app sh
docker inspect app
docker compose config
docker compose logs -f app
docker system df

docker compose config đặc biệt hữu ích vì nó cho bạn xem cấu hình Compose sau khi Docker đã merge và resolve. Khi biến môi trường hoặc file override gây lỗi, command này giúp nhìn ra cấu hình thực tế.

Checklist Dockerfile production#

  • Dùng base image rõ version, tránh tag quá mơ hồ nếu cần ổn định.
  • Không copy secret vào image.
  • Dùng .dockerignore để giảm build context.
  • Chạy build ở CI và gắn tag image theo commit SHA.
  • Không để process chính chạy nền bằng script khó kiểm soát.
  • Expose đúng port và có health check ở nền tảng deploy.
  • Giảm quyền runtime, không dùng root khi image cho phép.
  • Scan image định kỳ để phát hiện lỗ hổng dependency.

Khi nào không cần Docker?#

Nếu dự án rất nhỏ, chỉ có một runtime, team một người và nền tảng deploy đã lo phần build/runtime ổn định, Docker có thể chưa cần thiết. Nhưng khi dự án có nhiều service, nhiều developer, nhiều môi trường hoặc cần deploy nhất quán, Docker là một trong những công cụ đáng học nhất. Điều quan trọng là dùng Docker để giảm phức tạp vận hành, không biến nó thành thêm một lớp bí ẩn.

Nguồn tham khảo chính#

Chia sẻ bài viết

Giúp người khác tìm thấy bài viết này

Bình luận

Đang tải bình luận...

Đang tải bình luận...

Để lại bình luận

Email của bạn sẽ không được công khai

Tối thiểu 10 ký tự

0 / 5000