docker compose cho người mới: dựng cả cụm app kèm database bằng một lệnh

docker compose cho người mới: dựng cả cụm app kèm database bằng một lệnh

Ở các bài trước, chúng ta đóng gói một app vào một container. Nhưng phần mềm thật gần như không bao giờ chỉ có một mảnh. App cần một cơ sở dữ liệu, có khi thêm một bộ nhớ đệm, một hàng đợi. Chạy tay từng lệnh docker run cho từng thứ, rồi tự nối chúng với nhau, vừa dài dòng vừa dễ sai. docker compose sinh ra để giải quyết việc này.

docker compose là gì

docker compose cho phép bạn mô tả toàn bộ cụm ứng dụng, nhiều container cùng cấu hình của chúng, trong một tập tin duy nhất. Sau đó chỉ cần một lệnh để dựng tất cả lên, và một lệnh để dọn tất cả đi.

Một lưu ý nhỏ về tên gọi: hiện nay lệnh chuẩn là docker compose, viết rời hai chữ, tích hợp sẵn trong Docker. Bạn có thể còn thấy kiểu cũ viết dính docker-compose trong các bài viết xưa, nhưng cách viết rời là bản hiện đại nên dùng.

Tập tin compose trông ra sao

Bạn tạo một tập tin tên compose.yaml. Đây là ví dụ dựng một app cùng một cơ sở dữ liệu PostgreSQL:

services:
  app:
    build: .
    ports:
      - "8080:3000"
    environment:
      DATABASE_URL: postgres://postgres:secret@db:5432/appdb
    depends_on:
      - db

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

volumes:
  db-data:

Đọc qua từng phần cho dễ hiểu:

  • services liệt kê các thành phần. Ở đây có hai: app và db.
  • build: . nghĩa là dựng app từ Dockerfile trong thư mục hiện tại. Còn db thì dùng thẳng một image có sẵn qua image:.
  • ports nối cổng máy bạn vào cổng trong container, giống lệnh chạy tay ở bài trước.
  • environment truyền các biến cấu hình, ví dụ mật khẩu database, tên database.
  • depends_on nói cho compose biết app cần db khởi động trước.
  • volumes là phần giữ dữ liệu, sẽ nói ngay dưới đây.

Một điều rất tiện: các service tự thấy nhau qua tên. Trong chuỗi kết nối database ở trên, chữ db chính là tên service, app cứ gọi db là tới đúng container database, không cần biết địa chỉ mạng cụ thể.

Volume: để dữ liệu không bốc hơi

Theo mặc định, khi bạn xoá một container, dữ liệu bên trong nó mất theo. Với một database thì đó là thảm hoạ. Volume giải quyết bằng cách lưu dữ liệu ra một nơi bền vững nằm ngoài vòng đời của container. Trong ví dụ trên, dòng db-data:/var/lib/postgresql/data gắn một volume vào đúng thư mục Postgres cất dữ liệu. Bạn tắt rồi bật lại cụm, dữ liệu vẫn còn nguyên.

Những lệnh bạn sẽ dùng hằng ngày

Dựng cả cụm lên và chạy nền:

docker compose up -d

Xem nhật ký của cả cụm:

docker compose logs -f

Xem các service đang chạy:

docker compose ps

Dọn cả cụm đi:

docker compose down

Chỉ một lệnh up là toàn bộ app cùng database dựng lên, tự nối vào nhau. Đây là điều làm nên sức mạnh thật sự của compose với người làm sản phẩm một mình.

Vì sao điều này quan trọng cho cả nhóm

Giá trị lớn nhất của compose lộ ra khi có người mới. Thay vì một trang hướng dẫn cài đặt dài lê thê “cài cái này phiên bản kia, dựng database thế nọ”, giờ họ chỉ cần tải mã nguồn về và gõ một lệnh up. Vài phút sau, toàn bộ hệ thống chạy y hệt máy của bạn. Môi trường phát triển trở nên nhất quán cho tất cả mọi người.

Định nghĩa xong

Bạn coi như nắm được bài này khi:

  • Một lệnh docker compose up dựng lên cả app lẫn database, và chúng nói chuyện được với nhau.
  • Một người mới tải mã nguồn về, gõ đúng một lệnh, là chạy được toàn bộ hệ thống ngay.
  • Bạn hiểu volume dùng để làm gì, và vì sao thiếu nó thì dữ liệu database sẽ mất khi xoá container.

Giờ app đã chạy gọn trên máy bạn. Nhưng để chia sẻ image cho máy khác hay cho cả nhóm, bạn cần một nơi để cất và lấy image. Bài cuối của tuần sẽ nói về registry, với Docker Hub và Harbor.