Tạo network dùng chung trong docker-compose

Đây chỉ là một ghi chú nhanh do việc này cũng rất đơn giản, mình ngộ ra từ một project thực tế nên ghi lại cho nhớ.

Vấn đề

Có lẽ thường thì chúng ta chỉ hay làm việc với những app độc lập khi dùng Docker. Ví dụ mỗi app dùng riêng một docker-compose.yml với các containers độc lập chẳng hạn, app nào biết app đó. Nhưng có trường hợp thế này: bạn đang phát triển một project bao gồm phần API và phần Admin tách riêng, nhưng lại dùng chung database. Nếu như bạn tự build trên máy local thì quá đơn giản, ở mỗi app chỉ cần trỏ chung đến cùng một database là xong. Nhưng khi dùng docker thì sao?
Nếu như ở phần Admin bạn điền DATABASE HOST cho giống với API thì sẽ không thể nào chạy được, vì đơn giản là mỗi khi bạn build từ docker-compose, nó sẽ tự tạo cho mỗi project một network mặc định khác nhau, khác network thì không thể liên lạc với nhau được.

$ docker network ls
NETWORK ID      NAME                     DRIVER       SCOPE
e186de001b4b    my-demo-api_default      bridge       local
7dc9746e3ad0    my-demo-admin_default    bridge       local

Ví dụ như trên khi mình list ra các networks đang có, mỗi bên app của mình có một network riêng với suffix _default

Network dùng chung

Vấn đề sẽ được giải quyết khi ta chỉ cần tạo 1 network thôi, và ở đâu muốn dùng thì ta khai báo là được. Cụ thể, ta sẽ khai báo network dùng chung ở bên API chẳng hạn, sau đó bên Admin sẽ dùng lại network đó.

Cài đặt trong docker-compose.yml

Bên API

Trong docker-compose.yml, thêm phần khai báo network:

# services declarations...

networks:
  my-network:
    driver: bridge

Nếu bạn docker-compose up với config này, nó sẽ báo:

WARNING: Some networks were defined but are not used by any service: my-network

Nghĩa là các services trong docker-compose.yml chưa khai báo để sử dụng network này, cho nên docker sẽ chỉ tạo network mặc định như đầu bài viết có nói. Ta phải định nghĩa thêm cho các services:

version: '2'
services:
  my_api:
    build: .
    working_dir: /app
    ports:
      - '3000:3000'
    networks:
      - my-network
  my_db:
    image: mysql:5.7
    ports:
      - 33066:3306
    networks:
      - my-network
  
  # other servies...
  
networks:
  my-network:
    driver: bridge

Khi up với nội dung config này, docker sẽ tạo ra network có tên theo định dạng <directory_name>_<network_name>, với <directory_name> là tên của folder đang chứa app hiện tại, <network_name> là tên chúng ta vừa khai báo. Cụ thể, network sẽ có tên là my-demo-api_my-network. Đây chính là tên sẽ khai báo ở bên Admin.

Bên Admin

Không giống như bên "chủ nhà" tạo ra network, ở bên sử dụng, chỉ cần khai báo networks là xong, không cần khai báo đến từng service:

# admin services...

networks:
  default:
    external:
      name: my-demo-api_my-network

Chỉ cần như vậy, khi up project Admin lên, nó sẽ kết nối tới network của bên API, và khi đó bạn có thể dùng chung các thứ khác, ví dụ database.

Chỉ có một lưu ý nho nhỏ là để các app chạy được, bạn phải bật app "chủ nhà" tạo network trước, rồi mới đến các app khác.

Chúc Mừng Năm Mới 2020!