+2

7 mẹo Docker Compose để nâng cấp quy trình phát triển của bạn

Docker Compose là một công cụ thay đổi cuộc chơi dành cho các nhà phát triển đang làm việc với ứng dụng đa container. Nó đơn giản hóa việc khởi chạy các dịch vụ, mạng và volume chỉ với một tệp YAML duy nhất. Nhưng ngoài lệnh docker-compose up cơ bản, còn rất nhiều mẹo khác giúp bạn sử dụng Docker Compose mượt mà, nhanh chóng và mạnh mẽ hơn. Dưới đây là 7 mẹo ít được biết đến mà bạn có thể áp dụng ngay.

1. Sử dụng Profiles để bật/tắt dịch vụ theo điều kiện

Profiles trong Docker Compose cho phép bạn chỉ chạy những dịch vụ cần thiết, giúp môi trường phát triển gọn nhẹ hơn. Thay vì phải quản lý nhiều tệp YAML hoặc ghi chú/xóa dịch vụ, bạn có thể nhóm các dịch vụ vào một profile và kích hoạt chúng bằng một lệnh đơn giản.

Cách hoạt động

Định nghĩa profile trong docker-compose.yml bằng khóa profiles trong từng service. Sau đó, dùng cờ --profile để kích hoạt. Những service không có profile sẽ luôn chạy mặc định, còn các service có profile chỉ khởi động khi được gọi cụ thể.

Ví dụ

Hãy tưởng tượng một dự án có ứng dụng web, cơ sở dữ liệu và công cụ gỡ lỗi như Adminer. Bạn không phải lúc nào cũng cần Adminer, vì vậy hãy đưa nó vào hồ sơ.

version: '3.8'
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"
  db:
    image: postgres:13
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
  adminer:
    image: adminer:latest
    profiles:
      - debug
    ports:
      - "8081:8080"

Chạy dịch vụ mặc định (web và db):

docker-compose up

Chạy kèm với Adminer:

docker-compose --profile debug up

Tại sao nó lại hữu ích?

  • Tiết kiệm tài nguyên: Bỏ qua những dịch vụ nặng khi không cần thiết.
  • Tệp YAML gọn gàng: Không cần xóa hoặc ghi chú dịch vụ thủ công.

2. Ghi đè biến môi trường với tệp .env

Sử dụng .env là cách sạch sẽ để cấu hình dịch vụ mà không cần hardcode giá trị. Bạn có thể tùy biến theo từng môi trường hoặc từng lần chạy.

Cách hoạt động

Docker Compose tự động đọc tệp .env từ thư mục gốc của dự án. Bạn có thể sử dụng biến đó trong docker-compose.yml với cú pháp ${TEN_BIEN}. Để ghi đè, tạo một tệp .env khác và truyền vào với --env-file.

Ví dụ

Sau đây là thiết lập với ứng dụng Node.js và cổng có thể cấu hình.

.env

APP_PORT=3000
NODE_ENV=development

docker-compose.yml

version: '3.8'
services:
  app:
    image: node:16
    command: npm start
    ports:
      - "${APP_PORT}:3000"
    environment:
      - NODE_ENV=${NODE_ENV}
    volumes:
      - ./app:/usr/src/app
    working_dir: /usr/src/app

app/index.js

const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Hello, Docker!'));
app.listen(3000, () => console.log('Server running on port 3000'));

Chạy nó:

docker-compose up

Ghi đè cho môi trường production: Tạo một tệp prod.env:

APP_PORT=4000
NODE_ENV=production

Chạy với:

docker-compose --env-file prod.env up

Output: Ứng dụng chạy trên cổng 3000 với .env, hoặc 4000 với prod.env; NODE_ENV thay đổi tương ứng.

Tại sao nó lại hữu ích?

  • Linh hoạt: Chuyển đổi môi trường mà không sửa file YAML.
  • Bảo mật: Không cần đẩy thông tin nhạy cảm lên Git.

3. Tối ưu hóa build bằng cache và context

Docker Compose hỗ trợ cấu hình build để tận dụng cache và context, giúp giảm thời gian build hình ảnh (image).

Cách hoạt động

Dùng khóa build với context và cache_from để xác định nơi lấy file và reuse các layer đã cache.

Ví dụ

Dockerfile

FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]

docker-compose.yml

version: '3.8'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      cache_from:
        - myapp:latest
    image: myapp:latest
    ports:
      - "8000:8000"

app.py

from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
    return "Hello from Docker!"
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

requirements.txt

flask==2.0.1

Build:

docker-compose build --pull

Tại sao nó lại hữu ích?

  • Nhanh hơn: Tận dụng cache từ các lần build trước.
  • Chính xác: Xác định rõ vùng context cần thiết.

4. Quản lý phụ thuộc với healthcheck

healthcheck đảm bảo một service chỉ khởi động khi các service phụ thuộc đã sẵn sàng.

Cách hoạt động

Dùng healthcheck cho service phụ thuộc, kết hợp với depends_on và điều kiện service_healthy.

Ví dụ

Một ứng dụng web cần có cơ sở dữ liệu MySQL khỏe mạnh.

docker-compose.yml

version: '3.8'
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"
    depends_on:
      db:
        condition: service_healthy
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: mydb
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

Chạy nó:

docker-compose up

Output: Dịch vụ web chờ cho đến khi MySQL hoạt động hoàn toàn và phản hồi mysqladmin ping.

Tại sao nó lại hữu ích?

  • Ổn định hơn: Tránh lỗi do kết nối quá sớm.
  • Tùy chỉnh: Ghi đè healthcheck theo nhu cầu.

5. Đơn giản hóa log nhiều container bằng tên tùy chỉnh

Quản lý log từ nhiều container rất dễ rối. Docker Compose cho phép đặt container_name và cấu hình driver log để dễ đọc hơn.

Cách hoạt động

Dùng container_name để đặt tên, cấu hình logging để định dạng đầu ra.

Ví dụ

Thiết lập với ứng dụng web và Redis, có tên rõ ràng và nhật ký JSON.

docker-compose.yml

version: '3.8'
services:
  web:
    image: nginx:latest
    container_name: myapp-web
    ports:
      - "8080:80"
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
  cache:
    image: redis:latest
    container_name: myapp-redis
    logging:
      driver: json-file
      options:
        max-size: "5m"
        max-file: "2"

Chạy và kiểm tra nhật ký:

docker-compose up -d
docker-compose logs

Tại sao nó lại hữu ích?

  • Dễ đọc: Tên rõ ràng giúp scan log nhanh hơn.
  • Kiểm soát: Giới hạn kích thước log, tránh đầy đĩa.

6. Sử dụng named volumes để lưu dữ liệu bền vững

Named volumes cho phép lưu dữ liệu giữa các lần restart container và chia sẻ giữa các dịch vụ.

Cách hoạt động

Khai báo ở phần volumes cấp cao và sử dụng trong services.

Ví dụ

version: '3.8'
services:
  db:
    image: postgres:13
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - db-data:/var/lib/postgresql/data
volumes:
  db-data:

Chạy nó:

docker-compose up

Tại sao nó lại hữu ích?

  • Dễ di chuyển: Không phụ thuộc đường dẫn máy chủ.
  • Tái sử dụng: Dùng chung volume giữa các dự án.

7. Mở rộng file Compose để dễ quản lý

Tách nhiều tệp Compose giúp modular hóa và quản lý dự án lớn dễ hơn.

Cách hoạt động

Tạo tệp docker-compose.base.yml và tệp mở rộng theo môi trường dùng extends.

Ví dụ

Một tệp cơ sở cho ứng dụng web và ghi đè phát triển.

docker-compose.base.yml

version: '3.8'
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"

docker-compose.dev.yml

version: '3.8'
services:
  web:
    extends:
      file: docker-compose.base.yml
      service: web
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf

nginx.conf

events {}
http {
    server {
        listen 80;
        server_name localhost;
        location / {
            root /usr/share/nginx/html;
            index index.html;
        }
    }
}

Chạy nó:

docker-compose -f docker-compose.dev.yml up

Tại sao nó lại hữu ích?

  • Tái sử dụng: Chia sẻ cấu hình chung giữa các môi trường.
  • Dễ bảo trì: Giữ riêng phần cấu hình đặc thù cho từng môi trường.

Bước tiếp theo cho hành trình Docker Compose của bạn

Những mẹo như profile, biến môi trường, caching, healthcheck, logging, named volumes và file mở rộng có thể biến cách bạn dùng Docker Compose. Chúng tiết kiệm thời gian, giảm lỗi và làm quy trình làm việc linh hoạt hơn. Hãy thử áp dụng một vài mẹo trong dự án tiếp theo — bắt đầu với profile hoặc healthcheck để thấy hiệu quả ngay lập tức. Truy cập tài liệu chính thức của Docker Compose để khám phá thêm!

Cảm ơn các bạn đã theo dõi!


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.