摘要:docker@manager:~$ docker service create --replicas 3 -p 80:80 --name nginx nginx:1.17.4-alpine # 創建服務,三個副本,服務監聽在80端口 pydkv5ffwfqiv1aua1ylmwhum overall progress: 3 out of 3 tasks 1/3: running [==================================================>] 2/3: running [==================================================>] 3/3: running [==================================================>] verify: Service converged docker@manager:~$ docker service ls # 查看當前Swarm集羣運行的服務 ID NAME MODE REPLICAS IMAGE PORTS pydkv5ffwfqi nginx replicated 3/3 nginx:1.17.4-alpine *:80->80/tcp # 現在我們使用瀏覽器,輸入任意節點IP(如管理節點的192.168.99.104),都能看到nginx默認頁面 docker@manager:~$ docker service logs nginx # 查看Nginx服務的日誌 ... # 省略輸出 docker@manager:~$ docker service scale nginx=5 # 業務高峯期時,擴展服務運行的容器數量 nginx scaled to 5 overall progress: 5 out of 5 tasks 1/5: running [==================================================>] 2/5: running [==================================================>] 3/5: running [==================================================>] 4/5: running [==================================================>] 5/5: running [==================================================>] verify: Service converged docker@manager:~$ docker service ps nginx # 查看服務詳情 i6xkgnneqbbq nginx.1 nginx:1.17.4-alpine worker2 Running Running 4 minutes ago f517ogp705ne nginx.2 nginx:1.17.4-alpine manager Running Running 5 minutes ago ... # 省略輸出 docker@manager:~$ docker service scale nginx=2 # 業務平穩期時,減少服務運行的容器數量。❯ eval "$(docker-machine env manager)" # 本機切換到管理主機 ❯ git clone https://github.com/dongweiming/lyanna # 下載lyanna項目源碼,如果原來已經clone了不用再做 ❯ cd lyanna ❯ docker service create --name registry --publish published=5000,target=5000 registry:2 # 創建註冊服務(名字叫registry),啓動在5000端口上 ❯ docker-compose -f docker-compose.swarm.yml build # 用Compose的方式啓動,這個過程會構建lyanna-app鏡像 ❯ docker-compose -f docker-compose.swarm.yml push # 把lyanna-app推送給本地的註冊服務 ❯ docker stack deploy -c docker-compose.swarm.yml lyanna # 部署服務 Ignoring unsupported options: build Creating network lyanna_default Creating service lyanna_web Creating service lyanna_visualizer Creating service lyanna_db Creating service lyanna_redis Creating service lyanna_memcached。

前言

這篇文章介紹 Docker 生態中的常被提到的 Engine、Machine 和 Swarm,大家以瞭解爲主,工作需要再深入。

Engine

Docker Engine 其實就是我們常說的「Docker」,它是一個 C/S 模型 (Client/Server) 的應用,包含如下組件:

dockerd
docker

客戶端訪問服務端的方式有三種:

  • 使用命令行工具,如 docker rundocker ps 等等
  • 直接通過調用 REST API,如發送一個 curl 請求
  • 通過腳本直接和 Daemon 交互

用戶通過 Docker CLI 向 Docker Daemon 發送 REST API 請求。Daemon 創建和管理 Docker objects (對象),如:

  • images。鏡像
  • containers。容器
  • networks。網絡
  • volumes。數據卷

Machine

在沒有 Machine 之前,Docker 的安裝流程非常複雜,首先需要登錄到相應的主機上,根據官方的安裝和配置指南來安裝 Docker,而且不同的操作系統的安裝步驟也不同。

Machine 是一個簡化 Docker Engine 安裝和管理的命令行工具,這樣通過一個簡單的命令即可在相應的平臺上安裝 Docker,如本地 (macOS、Linux 和 Windows)、虛擬化平臺 (VirtualBox、macOS xhyve 等),公有云 (AWS、Azure、Digital Ocean 等) 等。使用 Machine 可以啓動、審查、停止和重新啓動託管的宿主機、升級 Docker 客戶端和守護程序、並配置 Docker 客戶端與宿主機通信。

通過圖示可以看出來,Machine 是管理本地 / 遠程帶有 Docker Engine 的主機的工具, docker-machine create 創建的「machine」包含了 Daemon 和 REST API 這 2 部分,Machine 自己包含 CLI。

我大概演示一下使用 Machine 的方法:

  • 創建 machine。 docker-machine create --driver virtualbox default ,這就會可以創建一個叫做 default 的「機器」,它是 Virtualbox 類型的,所以可以在 Virtualbox 管理器裏面看到這個虛擬機。
  • 連接到 machine。 eval "$(docker-machine env default)" ,其實就是做了對應的環境變量設置
  • 使用 Docker CLI。之後就可以使用 docker ps 等命令查看和管理這個主機裏面的鏡像 / 容器等內容了

Swarm Mode

Docker Swarm 是 Docker 官方的集羣管理和編排工具,可以將多個 Docker 主機封裝爲單個大型的虛擬 Docker 主機,成爲一個容器平臺。從 Docker 1.12.0+ 開始 Swarm Mode 已經內嵌入 Docker Engine,成爲子命令 docker swarm 可以直接使用。

Swarm Mode 主要特性如下:

  • 具有容錯能力的去中心化設計
  • 服務發現。可以做到 Docker 集羣中節點的動態加入和退出的感知,支持主流的 etcd、consul 和 zookeeper。
  • 負載均衡。讓資源分配負載,以達到最優化資源使用、最大化吞吐率、最小化響應時間、同時避免過載。
  • 動態伸縮。服務在判斷監測指標超出所設定的上下限時,會按照你的設置觸發擴容或縮容。
  • 滾動更新 (Rolling updates)。可以實現「零停機時間部署」,下節我們還會再說。
  • 安全傳輸。集羣中的每個節點都執行 TLS 的相互認證和加密,以確保自己與所有其他節點之間的通信安全。
  • 確保期望狀態。Swarm 會在後臺進行輪訓檢查,確保實際狀態能夠滿足期望狀態的要求。

Swarm 是使用 SwarmKit 構建的 Docker 引擎內置(原生)的集羣管理和編排工具。它包含如下三個重要概念:節點、服務和任務,我們挨個看。

節點 (Node)

運行 Docker 的主機可以主動初始化一個 Swarm 集羣或者加入一個已存在的 Swarm 集羣,這樣這個運行 Docker 的主機就成爲一個 Swarm 集羣的節點。節點分爲管理 (manager) 節點和工作 (worker) 節點。

管理節點用於 Swarm 集羣的管理,管理節點分發工作單元 (稱爲 Task「任務」) 到工作節點。 docker swarm 命令基本只能在管理節點執行(節點退出集羣命令 docker swarm leave 可以在工作節點執行)。一個 Swarm 集羣可以有多個管理節點,但只有一個管理節點可以成爲領導 (leader, 通過 Raft 協議實現)。管理節點還要通過 leader 執行維護集羣所需狀態所需的編排和集羣管理任務。

工作節點接收並執行從管理節點分派的任務。默認情況下,管理器節點也作爲工作節點運行服務 (Service),但是你可以將它們配置爲專門運行管理器任務,並且只運行管理器節點。代理在每個工作節點上運行,並報告分配給它的任務。工作節點通知管理節點其分配任務的當前狀態,以便管理器可以維護每個工作的所需狀態。

任務 (Task)

任務是 Swarm 中的最小的調度單位,任務攜帶 Docker 容器和在容器中運行的命令。管理節點根據服務中設置的副本 (Replicas) 數量將任務分配給工作節點。一旦任務被分配給一個節點,它就不能移動到另一個節點。它只能在指定的節點上運行或失敗

任務時這麼調度的:

服務 (Service)

服務是指一組任務的集合,它定義了任務的屬性,是 Swarm 系統的中心結構:

服務有兩種模式:

  • Replicated services。按照一定規則在各個工作節點上運行指定個數的任務
  • Global services。每個可用節點上運行一個任務

PS: 兩種模式通過 docker service create--mode 參數指定。

基本用法

我們創建一個最小的 Swarm 集羣,包含一個管理節點和兩個工作節點。創建 Docker 主機使用 Docker Machine:

# 管理節點
❯ docker-machine create -d virtualbox manager # 創建管理節點,名字爲manager
❯ docker-machine ssh manager  # 登錄到管理節點
docker@manager:~$ /sbin/ifconfig eth1 | grep 'inet addr' | cut -d: -f2 | awk '{print $1}'
192.168.99.104  # 獲得IP
docker@manager:~$ docker swarm init --advertise-addr 192.168.99.104  # 在管理節點初始化一個Swarm集羣,另外Docker主機有多個網卡,所以有多個IP,必須使用 --advertise-addr 指定IP
Swarm initialized: current node (k8cdrnrylrkxpsk4qoyybwpca) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-2gfzia6yrk172e8352jxpolevjr9gx1a9xu95hg0ibkhqat52p-d6j79273adew38s5mzmewgwoo 192.168.99.104:2377  # 記住這句命令

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
❯ docker-machine create -d virtualbox worker1 # 創建工作節點,名字worker1
❯ docker-machine ssh worker1
docker@worker1:~$ docker swarm join --token SWMTKN-1-2gfzia6yrk172e8352jxpolevjr9gx1a9xu95hg0ibkhqat52p-d6j79273adew38s5mzmewgwoo 192.168.99.104:2377  # 從上面直接粘貼來
This node joined a swarm as a worker.
❯ docker-machine create -d virtualbox worker2 # 創建工作節點,名字worker2
❯ docker-machine ssh worker2
docker@worker2:~$ docker swarm join --token SWMTKN-1-2gfzia6yrk172e8352jxpolevjr9gx1a9xu95hg0ibkhqat52p-d6j79273adew38s5mzmewgwoo 192.168.99.104:2377
This node joined a swarm as a worker.

這樣集羣就做好了,在管理節點看一下狀態:

❯ docker-machine ssh manager
docker@manager:~$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
k8cdrnrylrkxpsk4qoyybwpca *   manager             Ready               Active              Leader              18.09.9
puzrum9ixbt6holgfk5d8aokl     worker1             Ready               Active                                  18.09.9
sqwpb00zh5fp9z2o6r7vnebbt     worker2             Ready               Active                                  18.09.9

然後部署 Nginx (只能在管理節點運行):

docker@manager:~$ docker service create --replicas 3 -p 80:80 --name nginx nginx:1.17.4-alpine  # 創建服務,三個副本,服務監聽在80端口
pydkv5ffwfqiv1aua1ylmwhum
overall progress: 3 out of 3 tasks
1/3: running   [==================================================>]
2/3: running   [==================================================>]
3/3: running   [==================================================>]
verify: Service converged
docker@manager:~$ docker service ls # 查看當前Swarm集羣運行的服務
ID                  NAME                MODE                REPLICAS            IMAGE                 PORTS
pydkv5ffwfqi        nginx               replicated          3/3                 nginx:1.17.4-alpine   *:80->80/tcp
# 現在我們使用瀏覽器,輸入任意節點IP(如管理節點的192.168.99.104),都能看到nginx默認頁面
docker@manager:~$ docker service logs nginx # 查看Nginx服務的日誌
... # 省略輸出
docker@manager:~$ docker service scale nginx=5 # 業務高峯期時,擴展服務運行的容器數量
nginx scaled to 5
overall progress: 5 out of 5 tasks
1/5: running   [==================================================>]
2/5: running   [==================================================>]
3/5: running   [==================================================>]
4/5: running   [==================================================>]
5/5: running   [==================================================>]
verify: Service converged
docker@manager:~$ docker service ps nginx # 查看服務詳情
i6xkgnneqbbq        nginx.1             nginx:1.17.4-alpine   worker2             Running             Running 4 minutes ago
f517ogp705ne        nginx.2             nginx:1.17.4-alpine   manager             Running             Running 5 minutes ago
... # 省略輸出
docker@manager:~$ docker service scale nginx=2 # 業務平穩期時,減少服務運行的容器數量

在 Swarm 集羣中使用 Compose 文件

在第一篇中我使用 docker-compose.yml 一次配置、啓動多個容器,在 Swarm 集羣中也可以使用 compose 文件來配置、啓動多個服務。在上一小節中,使用 docker service create 一次只能部署一個服務 (Nginx),使用 docker-compose.yml 可以一次啓動多個關聯的服務。還是拿 lyanna 項目的 docker-compose.yml 體驗一下,不過需要修改配置項,添加 deploy (如 mode 和副本數等項),也要去掉一些 stack 不支持的項 (如 build、restart 等):

version: '3'
services:
  db:
    image: mysql
    environment:
      MYSQL_DATABASE: 'test'
      MYSQL_USER: 'root'
      MYSQL_PASSWORD: ''
      MYSQL_ROOT_PASSWORD: ''
      MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
    volumes:
      - my-datavolume:/var/lib/mysql
    deploy:
      placement:
        constraints: [node.role == manager]
  redis:
    image: redis:alpine
    deploy:
       mode: replicated
       replicas: 3
  memcached:
    image: memcached:1.5-alpine
    deploy:
       mode: replicated
       replicas: 3
  web:
    image: 127.0.0.1:5000/lyanna-app
    build: .
    ports:
      - '8000:8000'
    volumes:
      - .:/app
      - ./local_settings.py.tmpl:/app/local_settings.py
    depends_on:
      - db
      - redis
      - memcached
    environment:
      PYTHONPATH: $PYTHONPATH:/usr/local/src/aiomcache:/usr/local/src/tortoise:/usr/local/src/arq:/usr/local/src
    command: sh -c './setup.sh && python app.py'
  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    stop_grace_period: 1m30s
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
volumes:
  my-datavolume:

其中有 3 個需要着重說明的點:

  • visualizer 服務提供一個可視化頁面,可以從瀏覽器中很直觀的查看集羣中各個服務的運行節點,一會會感受到
  • db/redis/memcached/visualizer 這幾項都添加了 deploy 項, mode 指服務模式, replicas 指副本數, placement 可以限定滿足條件的 Node,而避免在不合適的 Node 進行部署,這裏限制 db/visualizer 都要在管理節點上
  • web 加了 image 項,是一個註冊服務的 API 地址,下面會看到如何註冊和推送鏡像上去

接着部署:

❯ eval "$(docker-machine env manager)"  # 本機切換到管理主機
❯ git clone https://github.com/dongweiming/lyanna  # 下載lyanna項目源碼,如果原來已經clone了不用再做
❯ cd lyanna
❯ docker service create --name registry --publish published=5000,target=5000 registry:2  # 創建註冊服務(名字叫registry),啓動在5000端口上
❯ docker-compose -f docker-compose.swarm.yml build  # 用Compose的方式啓動,這個過程會構建lyanna-app鏡像
❯ docker-compose -f docker-compose.swarm.yml push  # 把lyanna-app推送給本地的註冊服務
❯ docker stack deploy -c docker-compose.swarm.yml lyanna # 部署服務
Ignoring unsupported options: build

Creating network lyanna_default
Creating service lyanna_web
Creating service lyanna_visualizer
Creating service lyanna_db
Creating service lyanna_redis
Creating service lyanna_memcached

現在在瀏覽器輸入 任一節點IP:8080 即可看到各節點運行狀態,類似如下效果:

可以看到:

  • db、visualizer 限定在管理節點 manager
  • redis/memcached 由於副本數和節點數一致,所以每個節點都有一個
  • web 和 registry 由於負載平衡的作用分配到了 2 個工作節點上,讓服務整體看起來比較均衡

在瀏覽器新的標籤頁輸入 任一節點IP:8000 即可看到 lyanna 博客效果!

延伸閱讀

相關文章