Lệnh docker-compose tạo và chạy các dịch vụ Docker
Phát triển một ứng dụng sẽ gồm rất nhiều container chạy trên các services khác nhau, việc khởi động và quản lý các container sẽ trở nên khó khăn. Vì vậy, Docker đã tạo ra một công cụ hữu ích giúp tăng tốc quá trình này - Docker Compose.
Docker Compose là một công cụ hỗ trợ xác định và chạy các ứng dụng multi-container . Docker Compose có thể xử lý đồng thời multi-container trong develop, staging, testing, release và cho CI/CD. Docker compose sử dụng cú pháp YAML để định nghĩa các services. Docker Compose hoạt động bằng cách áp dụng các quy tắc được xác định trong tệp docker-compose.yaml
Giả sử bạn đang phát triển một ứng dụng web có cấu trúc như sau:
- Một container chứa ứng dụng web Node.js, chạy trên cổng 3000.
- Một container chứa cơ sở dữ liệu MySQL, chạy trên cổng 3306.
Để triển khai ứng dụng này bằng Docker Compose, bạn cần tạo một tệp docker-compose.yml với các thông tin sau:
version: "3.9"
services:
web:
build: .
ports:
- "3000:3000"
depends_on:
- db
db:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD: password
ports:
- "3306:3306"
Trong đó:
- version: phiên bản của Docker Compose
- services: danh sách các dịch vụ cần triển khai
- web: định nghĩa dịch vụ web, bao gồm việc build image từ Dockerfile và ánh xạ cổng 3000 của container với cổng 3000 của máy host.
- build: lấy image từ kết quả build dockerfile tại thư mục hiện tại.
- depends_on cho biết dịch vụ này cần phụ thuộc vào dịch vụ db.
- db: định nghĩa dịch vụ cơ sở dữ liệu MySQL, bao gồm việc sử dụng image MySQL, đặt mật khẩu cho root user và ánh xạ cổng 3306 của container với cổng 3306 của máy host.
Tham khảo: Lệnh docker-compose tạo và chạy các dịch vụ Docker
Các lệnh cơ bản trong Docker Compose
- docker-compose up: Khởi động các container
- docker-compose down: Dừng và xóa các container
- docker-compose ps: Hiển thị trạng thái của các container
- docker-compose build: Tạo image từ Dockerfile trong mỗi dịch vụ
- docker-compose restart: Khởi động lại các container
- docker-compose stop: Dừng các container
- docker-compose rm: Xóa các container không sử dụng
- docker-compose logs: Hiển thị các logs của các container
- docker-compose config: Hiển thị các cấu hình của Docker Compose
- docker-compose exec: Thực thi một lệnh trên một container
- docker-compose port: Hiển thị các port của các container
- docker-compose top: Hiển thị các process đang chạy trong các container
Lưu ý: Các lệnh trên phải được thực hiện trong thư mục chứa file docker-compose.yml
Cài đặt Docker-compose
# -- Có nhiều cách cài đặt, đây là 1 trong số đó, download trực tiếp từ server cung cấp
sudo curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# -- Apply executable permissions to the binary
sudo chmod +x /usr/local/bin/docker-compose
# -- View version
docker-compose --version
# => docker-compose version 1.23.1, build b02f1306
Cấu trúc của file docker-compose.yml
File docker-compose.yml được tổ chức gồm 4 phần:
| Ý nghĩa | |
|---|---|
| version | Version của file docker-compose |
| services | chứa các container. Với mỗi service là tên của một container |
| volumes | Gắn đường dẫn trên host machine được sử dụng trên container |
| networks | Sử dụng để cấu hình network cho ứng dụng |
Với services có một số thành phần sau:
| Ý nghĩa | |
|---|---|
| image | Chỉ ra image sẽ được dùng để build container.Tên image được chỉ định khi build một image trên máy host hoặc download từ Docker Hub |
| port | Kết nối port của máy host đến port của container. Vd: 8080:80 (host_port:container_port) |
| volumes | Gắn đường dẫn trên host machine được sử dụng trên container |
| enviroment | Định nghĩa các biến môi trường được truyền vào Docker |
| depends_on | Chọn các service được dùng là dependency cho container được xác định trong service hiện tại. |
| build | Chỉ ra vị trị đường dẫn đặt Dockerfile. |
Ví dụ file docker-compose.yml, giải thích các chỉ thị
version: '3.4'
# -- SERVICES
services:
nginx:
image: nginx:1.19.2-alpine
ports:
- 80:80
- 443:443
volumes:
- ./docker/nginx/conf.d:/etc/nginx/conf.d
- .:/var/www/
links:
- app
depends_on:
- app
networks:
- backend
app:
build:
context: .
dockerfile: docker/app/Dockerfile
volumes:
- .:/var/www/
links:
- db
- redis
- minio
networks:
- backend
db:
image: mysql:5.7
command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci --skip-character-set-client-handshake
ports:
- "3389:3306"
volumes:
- mysqldata:/var/lib/mysql
- ./docker/mysql/init/init-databases.sql:/docker-entrypoint-initdb.d/init-databases.sql
environment:
MYSQL_DATABASE: laravel
MYSQL_ROOT_PASSWORD: secret
networks:
- backend
redis:
image: redis:latest
restart: always
volumes:
- ./docker/logs/redis:/var/log/redis
ports:
- "6379:6379"
networks:
- backend
command: redis-server --appendonly yes
minio:
image: minio/minio
ports:
- "9000:9000"
volumes:
- ./docker/minio:/data
tty: true
networks:
- backend
environment:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
MINIO_REGION_NAME: us-west-2
command: ["minio", "server", "/data"]
# -- VOLUMES
volumes:
mysqldata:
driver: local
# -- NETWORK
networks:
backend:
driver: bridge
1. version
# -- Version docker compose sử dụng, trong ví dụ trên mình dùng version 3.4
version: '3.4'
2. services - Khai báo các service cần dùng cho ứng dụng
# -- Khai báo các service cần dùng cho ứng dụng, mỗi một server sẽ được chạy trong 1 container
services:
nginx:
...
app:
...
2.1 image - Khai báo docker image mà service dùng để build container
# -- Service nginx được build từ docker image nginx:1.19.2-alpine
image: nginx:1.19.2-alpine
2.2 ports - Chỉ định port của máy host và container
# -- Chỉ định port của host và container (HOST:CONTAINER)
# -- Truy cập vào port 81 của máy host đồng nghĩa với truy cập vào post 80 của container
ports:
- 81:80
2.3 hostname - Khai báo hostname của container
# -- Khai báo hostname để các container khác có thể giao tiếp thông qua hostname, yêu cầu các container phải có cùng network
services:
app:
...
hostname: webserver
...
2.4 volumes - Mount data từ giữa container với máy host
# -- Mount data từ giữa container với máy host, dữ liệu được link giữa máy của bạn và container, giúp không bị mất dữ liệu mỗi lân stop container
# -- Mount code từ thư mục cùng cấp với file docker-compose, vào trong thư mục /var/www của container
volumes:
- .:/var/www/
2.5 depends_on - Phục thuộc vào service nào đó
# -- Tùy chọn này cho biết thứ tự các service sẽ được build
# -- Theo như khai báo service 'app' sẽ được khởi chạy trước service 'nginx'
services:
nginx:
...
depends_on:
- app
...
2.6 links - Cho phép từ 1 service có thể giao tiếp với 1 hoặc nhiều service khác
app:
# -- Từ service app có thể truy cập đến các service db, redis, minio
links:
- db
- redis
- minio
2.7 build - Build một server từ một dockerfile tự viết
# -- service app được build từ docker file trong thư mục docker/app/Dockerfile
# -- Nếu để cùng cấp file docker-compose.yml thì không cần dùng option 'dockerfile:'
app:
build:
context: .
dockerfile: docker/app/Dockerfile
2.8 command - Lệnh command cần thực thi, trong container khi server được chạy
# -- Lệnh này sẽ chạy ngay sao khi copy các file yêu cầu vào container và build lên được container.
db:
image: mysql:5.7
command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci --skip-character-set-client-handshake
2.9 environment - Khai báo biến môi trường dùng cho cho container của service
# -- Để biết biến môi trường nào cần cho container thì phải đọc document image của nó ở Docker Hub
db:
...
environment:
MYSQL_DATABASE: laravel
MYSQL_ROOT_PASSWORD: secret
2.10 restart - Tự động khởi động lại container
# -- 'restart' options:
# no: Containers won’t restart automatically.
# on-failure[:max-retries]: Restart the container if it exits with a non-zero exit code, and provide a maximum number of attempts for the Docker daemon to restart the container.
# always: Always restart the container if it stops.
# unless-stopped: Always restart the container unless it was stopped arbitrarily, or by the Docker daemon.
db:
...
restart: always
...
3. volumes
# -- Khai báo một thư mục dùng chung cho toàn bộ services. Khi config option này thì mỗi lần stop container data của container đó sẽ không bị mất đi.
# -- VOLUMES
volumes:
mysqldata:
driver: local # Sử dụng thư mục hiện tại, nếu muốn thay đổi thêm option 'driver_opts'
# -- KHAI BÁO VOLUME (Nâng cao)
volumes:
# volume không tạo mới, sử dụng volume đã có data1
data1:
external: true
# volume không tạo mới, sử dụng volume đã có data-abc
data2:
external:
name: data-abc
# tạo volume local
data3:
# tạo volume có ánh xạ đường dẫn
data4:
driver: local
driver_opts:
type: none
device: "/path/to/dir"
o: bind
# tạo volume mount từ NFS
data5:
driver: local
driver_opts:
type: nfs
o: addr=192.168.1.1,rw
device: ":/path/to/dir"
4. networks
# -- Khai báo network sử dụng, network này sẽ được dùng trong các container, đảm bảo các container phải dùng chung 1 network thì mới có thể truy cập được đến nhau
# -- Khai báo một network có tên là backend, loại network là bridge
networks:
backend:
driver: bridge
# -- KHAI BÁO MẠNG (Nâng cao)
networks:
# Tạo mạng cầu
network1:
driver: bridge
# Mạng lấy bên ngoài, network2 là networkxyz đã có
network2:
external:
name: networkxyz
# Tạo mạng overlay trên swam
network3:
driver: overlay
name: my-overlay
Mẫu file docker-compose.yml
# VIẾT THEO CÚ PHÁP YAML, CHÚ Ý CHÍNH XÁC KHOẢNG TRẮNG ĐẦU CÁC DÒNG
# ------------------------------------
version: "3" # chọn viết theo bản 3 docs.docker.com/compose/compose-file/
# ------------------------------------
services: # CÁC DỊCH VỤ (CONTAINER) NĂM TRONG services
pro-memcached: # (((1))) BẮT ĐẦU TẠO DỊCH VỤ THỨ NHẤT
image: "memcached:latest" # Image tạo ra dịch vụ
container_name: c-memcached01 # Tên container khi chạy
restart: always
hostname: memcached
networks:
- my-network # nối vào mạng my-network (tạo mạng này ở dưới)
command:
- "--conn-limit=2048" # Giới hạn kết nối là 2048
- "--memory-limit=2048" # Giới hạn cho phép dùng tới 4096 MB bộ nhớ làm cache
xtlab-apache: # (((2))) TẠO DỊCH VỤ HTTPD
image: "httpd:version2" # sử dụng image custome lại ở trên để tạo container
container_name: c-httpd01 # tên khi chạy container HTTPD
restart: always
hostname: httpd01
networks:
- my-network
ports:
- "8080:80" # Mở cổng 8080 public, ánh xạ vào 80
- "443:443"
volumes: # Ánh xạ thự mục vào container
- dir-site:/home/sites/ # Bind ổ đĩa - dir-site
xtlab-mysql: # (((3))) TẠO DỊCH VỤ MYSQL
image: "mysql:latest"
container_name: mysql-product
restart: always
hostname: mysql01
networks:
- my-network
environment:
MYSQL_ROOT_PASSWORD: abc123 #Thiết lập password
volumes:
- /mycode/db:/var/lib/mysql # thư mục lưu DB
- /mycode/db/my.cnf:/etc/mysql/my.cnf # ánh xạ file cấu hình
xtlab-php: # (((4))) TẠO DỊCH VỤ PHP
image: "php:version2"
container_name: php-product # tên container
hostname: php01
restart: always
networks:
- my-network
volumes:
- dir-site:/home/sites/ # Bind ổ đĩa - dir-site
# ------------------------------------
networks: # TẠO NETWORK
my-network:
driver: bridge
# ------------------------------------
volumes: # TẠO Ổ ĐĨA
dir-site: # ổ đĩa này lưu dữ liệu ở /mycode/
driver_opts:
device: /mycode/ # Hãy đảm bảo có thư mục /mycode/default
o: bind

Nhìn vào kết quả thể hiện với mô hình hóa:
- Có 4 container đang chạy (mysql-product, c-httpd01, php-product, c-memcached01), chúng được nối vào mạng my-network vậy giữa chúng có thể liên lạc với nhau qua cổng tương ứng (3304, 80, 9000, 11211). Riêng container có public cổng 8080 ánh xạ vào cổng 80 của nó, vậy bên ngoài mạng có thể kết nối tới nó qua cổng 8080.
- Có ổ đĩa dir-site dữ liệu nó lưu tại máy HOST /mycode/, ổ đĩa này cũng nối vào container c-http01 ở thư mục /home/sites. Tương tự nó cũng nối vào php-product.
- Container mysql-product cũng ánh xạ thư mục /mycode/db vào /var/lib/mysql
# -- Chạy lệnh sau để build các container
docker-compose up
# -- Nếu cần chỉnh sửa file thì down các container trước
docker-compose down
Mẫu docker-compose.yml (Với option nâng cao)
version: "3.7"
# KHAI BÁO CÁC DỊCH VỤ
services:
# TÊN DỊCH VỤ
web:
# TÊN IMAGE TẠO TẠO CONTAINER
image: busybox
## DÙNG IMAGE BUILD TỪ DOCKERFILE
# build:
# dockerfile: Dockerfile
# context: ./web
# ÁNH XẠ CỔNG MÁY HOST VÀO CỔNG CONTAINER
ports:
- 8099:80
# MỞ CỔNG, KHÔNG ÁNH XẠ HOST, DÙNG NỘI BỘ MẠNG
# expose:
# - "3000"
## CHÍNH SÁCH KHỞI ĐỘNG
restart: always
# Nối vào mạng network1
networks:
- network1
## Thêm hoặc bỏ các quyền (Capability) trong container
## http://man7.org/linux/man-pages/man7/capabilities.7.html
# cap_add:
# - ALL
# cap_drop:
# - NET_ADMIN
# - SYS_ADMIN
# cap quyen root
# privileged: true
## Ghi đè entrypoint
# entrypoint: /code/entrypoint.sh
## Ghi đè CMD mặc định nếu cần
# command: ["bash", "ls"]
## ĐẶT TÊN CONTAINER
container_name: my-container
## THÊM BIẾN MÔI TRƯỜNG
# environment:
# - TEN_BIEN1=giatri1
# - TEN_BIEN2=giatri2
## THÊM DỮ LIỆU HOST, TƯƠNG ĐƯƠNG KHAI BÁO TRONG /etc/hosts
# extra_hosts:
# - "example.com:192.168.1.55"
## GẮN Ổ ĐĨA, THƯ MỤC VÀO CONTAINER
# volumes:
# - /opt/data:/var/lib/mysql
# - data3:/var/lib/mysql
## THIẾT LẬP LOG
logging:
options:
max-size: "1m"
max-file: "2"
## CẤU HÌNH DNS
dns: 8.8.8.8
# CẤU HÌNH NẾU TRÊN SWARM
deploy:
replicas: 6 # Số lượng container cho dịch vụ
# placement:
# constraints:
# - node.role == manager # Chỉ chạy ở node manager
resources: # Thiết lập tài nguyên
limits: # Giới hạn tài nguyên
cpus: '0.50' # 50% của 1 Core
memory: 50M
reservations: # Tài nguyên tối thiểu
cpus: '0.25'
memory: 20M
restart_policy:
condition: on-failure
# ---------------------------------------------------------------------------------------
# KHAI BÁO VOLUME
volumes:
# volume không tạo mới, sử dụng volume đã có data1
data1:
external: true
# volume không tạo mới, sử dụng volume đã có data-abc
data2:
external:
name: data-abc
# tạo volume local
data3:
# tạo volume có ánh xạ đường dẫn
data4:
driver: local
driver_opts:
type: none
device: "/path/to/dir"
o: bind
# tạo volume mount từ NFS
data5:
driver: local
driver_opts:
type: nfs
o: addr=192.168.1.1,rw
device: ":/path/to/dir"
# ---------------------------------------------------------------------------------------
# KHAI BÁO MẠNG
networks:
# Tạo mạng cầu
network1:
driver: bridge
# Mạng lấy bên ngoài, network2 là networkxyz đã có
network2:
external:
name: networkxyz
# Tạo mạng overlay trên swam
network3:
driver: overlay
name: my-overlay