根據我以前的幾篇「Django 系列」文章,後端架構中我使用了 Django + Celery + RabbitMQ 三個框架/服務。如今有幾個問題:前端
在我以往的實踐中,容器的編排使用了 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
,由於最開始我把 Stack
和 Swarm
視爲同一級了。Swarm
更可能是提供集羣環境,協調各類服務組件,而Stack
更像是一個命令行工具,調用 Swarm
的各類命令啓動不一樣服務等。服務器
Swarm
能夠是一個 Docker 集羣,在單宿主機上,Swarm 集羣中運行着各類應用(App
),每一個應用由一個或多個服務(Service
)組成,例如前端、後端、數據庫三個服務能夠組成一個應用。網絡
每一個服務由任務(Task
)的複製集組成,一個任務就是一個容器(Container
)。例如一個後端服務,咱們能夠經過啓動 3 個複製任務來提升性能。服務是程序的出入口,雖然啓動了 3 個任務,咱們訪問這個服務時候仍是用服務名便可,請求會在幾個任務之間按 RR(輪詢) 機制被處理。架構
介紹了 Docker Swarm 的幾個概念以後,咱們來實際實現標題「用 Docker 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
配置文件
先按個人服務架構,寫一份 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…