用Docker Swarm實現容器服務高可用

背景與技術選擇

根據我以前的幾篇「Django 系列」文章,後端架構中我使用了 Django + Celery + RabbitMQ 三個框架/服務。如今有幾個問題:前端

  1. 如何用容器快速部署這三個應用?
  2. 如何提升性能?
  3. 如何保障後端可用性?

Docker Compose vs Swarm vs K8s

在我以往的實踐中,容器的編排使用了 docker-compose 實現,問題一就已經解決。但 docker-compose 也只是用於編排,能夠各啓動三個服務的一個容器,性能與高可用性就可能不能知足要求。python

對於性能與高可用,若是是大型項目,目前不二的選擇就是 Kubernetes(K8s) ,可是個人項目不足以稱之爲「大型項目」,所以我考慮的是,如何在單宿主機上提升性能與高可用。web

Docker Swarm 是官方集成至 Docker CLI 中的集羣服務(雖然被 K8s 後來居上,可是其設計理念與功能也是十分紅熟完善,架構上與 K8s 有不少共通點)。Swarm 能夠鏈接多個宿主機做爲集羣節點,固然也是支持單機容器集羣的部署。Swarm 的集羣部署須要建立 services, secret 等,也是較爲繁瑣,所以有 Stack 工具可以解析 compose 文件,讓建立各類服務的過程描述於 YAML 腳本中,更方便管理。docker

固然,Stack 解析的 compose 文件語法與 docker-compose 所支持的略微有不一樣,但大可能是通用的,具體後面提到。數據庫

綜上能夠總結一下幾個工具的關係與區別:後端

優點/劣勢僅針對個人後端架構而言bash

工具/服務 優點 劣勢 是否知足
docker-compose 容器編排 不支持高可用
Kubernetes 容器編排,高可用,適合大型項目
Swarm 容器編排,高可用 成熟度略差於K8s
Stack 屬於Swarm的命令,用於應用Compose文件 N/A N/A

表格中特地加上了 Stack,由於最開始我把 StackSwarm 視爲同一級了。Swarm 更可能是提供集羣環境,協調各類服務組件,而Stack 更像是一個命令行工具,調用 Swarm 的各類命令啓動不一樣服務等。服務器

Swarm 架構簡介

(圖片來源: Docker文檔)

Swarm 能夠是一個 Docker 集羣,在單宿主機上,Swarm 集羣中運行着各類應用(App),每一個應用由一個或多個服務(Service)組成,例如前端、後端、數據庫三個服務能夠組成一個應用。網絡

每一個服務由任務(Task)的複製集組成,一個任務就是一個容器(Container)。例如一個後端服務,咱們能夠經過啓動 3 個複製任務來提升性能。服務是程序的出入口,雖然啓動了 3 個任務,咱們訪問這個服務時候仍是用服務名便可,請求會在幾個任務之間按 RR(輪詢) 機制被處理。架構

實現

介紹了 Docker Swarm 的幾個概念以後,咱們來實際實現標題「用 Docker Swarm 實現容器服務高可用」吧!

Swarm 集羣初始化

由於我在單機上部署個人應用,擴展 Swarm 節點的操做就不贅述了。

首先初始一個Swarm集羣:

docker swarm init
複製代碼

集羣初始化成功後,docker network ls 會看到新建立了兩個網絡:

  • 一個名爲 ingress 的 overlay 網絡,用於處理與 swarm 服務相關的控制命令和數據交互。
  • 一個名爲 docker_gwbridge 的網橋,用於打通 swarm 集羣中的每一個獨立的容器之間的網絡。

異常解決

在調試 swarm 部署應用時,我在 3 臺機器執行了同樣的操做,奇怪的是其中一臺服務器在初始化 swarm 集羣后,只建立了 ingress,致使應用部署後任務沒法啓動。

經過執行:

docker service ps --no-trunc {serviceName}
複製代碼

查看到部分報錯信息以下:

ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network
複製代碼

發現是 docker 網絡出了問題,經過對比幾臺服務器的網絡找到是 docker_gwbridge 的缺失。

手動建立該網橋解決問題:

docker network create \
--subnet 172.20.0.0/20 \
--gateway 172.20.0.1 \
-o com.docker.network.bridge.enable_icc=false \
-o com.docker.network.bridge.name=docker_gwbridge \
docker_gwbridge
複製代碼

應用部署

應用能夠經過手動一個個建立服務的方式部署,經過引用同一個 docker 網絡來保證服務間的通訊可達。

可是 docker 提供了更方便的方式來部署、擴展一個應用———— docker-compose.yml 配置文件

Compose 文件

先按個人服務架構,寫一份 docker-compose.yml 文件:

version: '3'

services:
 rabbit:
 image: rabbitmq:3
 ports:
 - "5672:5672"
 networks:
 - webnet

 web:
 image: myweb:latest
 command: python manage.py runserver 0.0.0.0:8000
 environment:
 - DJANGO_SETTINGS_MODULE=bd_annotation_proj.settings.staging
 deploy:
 replicas: 3
 depends_on:
 - rabbit
 - worker
 ports:
 - "8000:8000"
 networks:
 - webnet

 celery-worker:
 image: myweb:latest
 command: celery -A bd_annotation_proj worker -l info
 environment:
 - DJANGO_SETTINGS_MODULE=bd_annotation_proj.settings.staging
 deploy:
 replicas: 2
 depends_on:
 - rabbit
 networks:
 - webnet

networks:
 webnet:
複製代碼

重要字段含義以下:

  • version: docker-compose 文件的版本,docker stack 只支持版本 "3"
  • service: 服務列表
  • image: 指定運行的鏡像
  • command: 容器啓動的運行命令
  • environment: 容器內的環境變量,此處配置了 Django 的配置文件指向 staging
  • deploy: 指定部署限制,例如能夠限制複製集(replicas)大小、CPU 上限等
  • depends_on: 指明服務間的依賴關係,應用部署時會以依賴關係按順序啓動服務
  • network: 指明應用中的各服務所接入的網絡,指定後服務間經過服務名進行通訊

建立應用與服務

有了 docker-compose.yml 文件,建立應用以及服務就簡單了。假設應用名爲 myapp ,直接執行:

docker stack deploy -c docker-compose.yml myapp
複製代碼

服務查看

# 查看全部服務
docker service ls
# 查看與 myapp 相關的服務
docker stack services myapp
複製代碼

服務中運行的任務能夠直接經過 docker ps 查看容器 ID 等信息。

應用擴容

修改 docker-compose.yml 中的 replicas 配置來擴展複製集:

...
delopy:
 replicas: 5
複製代碼

修改後應用新配置:

docker stack deploy -c docker-compose.yml myapp
複製代碼

鏡像更新

若是鏡像發生了更新,此時須要針對性地更新服務:

docker service update myapp_web --image myweb:latest --force
複製代碼

會有進度條顯示當前服務中任務的更新進度。

結束應用

經過執行:

docker stack rm myapp
複製代碼

結束應用的生命週期,應用相關的任務、服務與網絡都會被刪除。

總結

經過 Docker Swarm 部署完成個人應用後,我經過刪除容器查看重啓狀況實際測試了一下高可用性,徹底符合個人預期。Swarm 中的 ingress 相似 Nginx,已經替咱們完成了負載均衡,咱們只要享受這種便利就好。

性能上,因爲啓動了 3 個容器,相比以前在一個容器中使用 uWSGI 的方式運行服務,部分請求響應時間提高 10 倍,至關滿意。

容器是開發者的福音,不管是先後端仍是測試運維都有必要學習與應用它。雖然容器編排的戰役能夠說是 K8s 拿下,可是 Swarm 在不少場景也是可以勝任。仍是那句話:技術沒有對錯,只有合適不合適!

參考

docs.docker.com/compose/com… docs.docker.com/get-started… blog.51cto.com/wutengfei/2…

相關文章
相關標籤/搜索