Swarm: Overlay Network và Routing Mesh

K
Kai··5 min read

Ở Bài 11, service chạy nhiều task rải trên nhiều node. Hai câu hỏi tự nhiên: các task trên những máy khác nhau nói chuyện với nhau thế nào? Và khi publish một cổng, làm sao request tới được task dù nó nằm ở node nào? Bài này trả lời — bằng overlay network và routing mesh.

Bridge không đủ cho nhiều máy

Nhớ Bài 7: bridge network (docker0) là mạng nội bộ một máy. Container trên hai host khác nhau không cùng bridge, nên không thấy nhau qua đó. Swarm cần một loại mạng trải xuyên nhiều host — đó là overlay.

Khi bạn swarm init (Bài 10), Docker tạo sẵn hai mạng đặc biệt:

docker network ls
NAME              DRIVER    SCOPE
docker_gwbridge   bridge    local      ← nối overlay ra mạng ngoài của từng host
ingress           overlay   swarm      ← mạng routing mesh (nói ở dưới)

Để ý ingress có driver overlay và scope swarm (toàn cụm), khác với bridge scope local (một máy).

Overlay network: một mạng phẳng trên nhiều host

Theo tài liệu Docker, overlay network "nối nhiều Docker daemon lại với nhau". Về mặt sử dụng, container trên các node khác nhau nhưng cùng một overlay sẽ thấy nhau như đang ở chung một mạng LAN — dù thực tế chúng ở các máy vật lý cách xa.

Bên dưới, overlay dùng kỹ thuật VXLAN: gói tin giữa hai container được "bọc" (encapsulate) trong một gói UDP rồi gửi qua mạng vật lý giữa hai host, tới nơi thì được "mở" ra. Container không hề biết có lớp bọc này — với nó, mạng cứ phẳng.

   Node A                         Node B
   ┌──────────────┐               ┌──────────────┐
   │ [ctn api.1]  │   VXLAN bọc    │ [ctn api.2]  │
   │   10.0.1.2 ──┼─ qua mạng vật ─┼─► 10.0.1.3   │
   │              │  lý (UDP)      │              │
   └──────┬───────┘               └───────┬──────┘
          └────── overlay "appoverlay" ────┘
              (cùng một mạng logic 10.0.1.0/24)

Tạo một overlay network:

docker network create -d overlay appoverlay
appoverlay  overlay  swarm

Rồi gắn service vào nó:

docker service create --name api --network appoverlay --replicas 2 nginx:alpine
docker service create --name worker --network appoverlay alpine sleep 600

Giờ workerapi ở chung overlay, kể cả khi task của chúng nằm trên các node khác nhau.

Service discovery: gọi bằng tên, qua VIP

Giống user-defined bridge ở Bài 7, overlay có DNS nội bộ: gọi service bằng tên. Nhưng Swarm thêm một lớp: mỗi service có một virtual IP (VIP). DNS phân giải tên service thành VIP, và Swarm tự cân bằng tải VIP đó qua tất cả task của service.

Thử từ trong worker, phân giải tên api:

# (chạy bên trong một task của worker)
nslookup api
Name:    api
Address: 10.0.1.2

10.0.1.2 không phải IP của một container cụ thể — nó là VIP của service api. Khi worker gửi request tới api, Swarm phân phối request đó tới một trong các task api.1, api.2... Bạn chỉ gọi api, không cần biết có mấy bản hay chúng ở đâu.

   worker  ── gọi "api" ──►  VIP 10.0.1.2 (service api)
                                  │ Swarm cân bằng tải
                       ┌──────────┼──────────┐
                       ▼                      ▼
                  task api.1              task api.2
                  (node A)                (node B)

Đây là service discovery + load balancing có sẵn, không cần dựng thêm gì. Trong code, worker chỉ cần trỏ tới host api.

Routing mesh: publish cổng trên mọi node

Câu hỏi khó hơn: bạn publish service web ở cổng 80, nhưng task của nó chỉ nằm trên vài node. Nếu request tới một node không có task thì sao? Câu trả lời là routing mesh.

Khi bạn publish một cổng cho service, Swarm mở cổng đó trên mọi node trong cụm (qua mạng ingress). Request tới bất-kỳ-node:cổng đều được routing mesh chuyển tới một task đang chạy của service, kể cả task nằm ở node khác.

docker service create --name pub -p 9091:80 nginx:alpine
curl http://localhost:9091
HTTP 200

Trên cụm nhiều node, bạn gọi curl http://<bất kỳ node nào>:9091 đều ra trang web — dù node đó có hay không có task của pub.

   Request tới node BẤT KỲ:9091
        │ (mọi node đều nghe 9091 nhờ ingress)
        ▼
   routing mesh ──► chuyển tới một task "pub" còn sống
        ├──► task trên node A
        └──► task trên node B

Lợi ích thực tế: bạn đặt một load balancer phía trước và cho nó trỏ tới tất cả node ở cùng một cổng, không cần biết task nằm đâu. Node nào cũng là "cửa vào" hợp lệ.

Có chế độ publish khác: --publish mode=host để publish thẳng trên node chạy task (bỏ routing mesh), dùng khi bạn muốn kiểm soát chính xác hoặc cần hiệu năng. Mặc định là mode=ingress (routing mesh) như trên.

docker_gwbridge là gì

Mạng docker_gwbridge (scope local, có trên mỗi node) là cầu nối để container trong overlay đi ra ngoài — tới Internet hoặc nhận lưu lượng từ routing mesh. Bạn hiếm khi đụng trực tiếp tới nó, nhưng biết để khỏi bỡ ngỡ khi thấy nó trong docker network ls.

🧹 Dọn dẹp

docker service rm api worker pub
docker network rm appoverlay

Xóa service trước, vì không xóa được overlay đang có service dùng. (Vẫn giữ swarm cho Bài 13.)

Tổng kết

Overlay network tạo một mạng phẳng trải trên nhiều host (dùng VXLAN bọc gói tin qua mạng vật lý), cho container ở các node khác nhau nói chuyện như cùng một LAN. Trên đó, mỗi service có một VIP: gọi service bằng tên, Swarm cân bằng tải qua các task. Routing mesh publish cổng trên mọi node và định tuyến request tới task còn sống ở bất kỳ đâu — nên node nào cũng làm cửa vào được.

Bài cuối (13) ghép tất cả: dùng docker stack deploy để triển khai cả một ứng dụng nhiều service từ một compose file lên cụm, quản lý secret an toàn, rồi dọn dẹp toàn bộ và rời swarm.