今天要為應用程式新增其他服務,使其功能更為完整。在 Get Started 中這是第三層,稱為堆疊 (stack)。堆疊是一組彼此相關的服務,共享相依性,並且可以一起被編配 (orchestrated)  及擴展 (scaled)。大部分的概念及工具前兩天都介紹過了,那就直接開始吧。因為這個服務還是要部署在 swarm cluster 中,請先將昨天的虛擬機啟動,並組成具有一 manager 及一 worker 的 swarm cluster。
首先編輯 docker-compose.yml,內容如下,主要是加上一個服務稱為 visualizer,它會在網頁介面上顯示 swarm 如何安排這些容器。
version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: username/repo:tag
    deploy:
      replicas: 5
      restart_policy:
        condition: on-failure
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
    ports:
      - "80:80"
    networks:
      - webnet
  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - webnet
networks:
  webnet:
請將第 5 行的 username/repo:tag 置換成上傳至 Docker Hub 的映像檔位置,而原本 web 服務的 ports 設定的值改為 "80:80",表示服務的 80 port 會對應本機的 80 port,之後可以直接以 80 port 而不是先前的 4000 port 來連接 web 服務。在 visualizer 中有兩個新的設定之前沒看過,第一個是 volumes,讓容器可以存取本機的 socket 檔案,第二個是 placement 的 constraints,確保 visualizer 這個服務只會運行在 manager 節點,這是因為 swarm manager 才能知道這個 swarm 中各個節點的狀況。visualizer 服務使用的映像檔可直接由 Docker Hub 取得。
接下來設定 shell 讓它可直接與 swarm manager 溝通,指令是 eval $(docker-machine env myvm1),並部署新的應用程式,指令是 docker stack deploy -c docker-composer.yml getstartedlab。用 docker stack ls 及 docker service ls 分別列出目前的堆疊和服務項目:
$ docker stack ls
NAME                SERVICES            ORCHESTRATOR
getstartedlab       2                   Swarm
$ docker service ls
ID                  NAME                       MODE                REPLICAS            IMAGE                             PORTS
o2yy2v16xzsq        getstartedlab_visualizer   replicated          1/1                 dockersamples/visualizer:stable   *:8080->8080/tcp
wea9mjlcdhw1        getstartedlab_web          replicated          5/5                 odie1111/get-started:part2        *:80->80/tcp
可看到這個應用程式目前有兩個服務及它們的 ID、名稱、replica 數量等資訊。接下來以瀏覽器連至任一節點的 8080 port,看看新添加的服務頁面是如何呈現的。
可看出 swarm 有兩個節點,各有三個 task。其中 getstartedlab_visualizer 是新加入的服務,只有一個 task,位於 swarm manager 上,正如在 docker-composer.yml 中設置的一樣。而這個服務雖然只部署於 swarm manager 上,但透過兩個節點的 IP 都可以連接至它。
visualizer 這個服務和 web 並不具相依性,現在要再加入一個服務,它和 web 服務具相依性,是 web 後端的資料庫,用來提供計數,同時也透過這個資料庫服務,示範如何在 Docker 中留存資料。
首先在 docker-compose.yml 中加入新的服務 redis,設定檔片段如下:
  redis:
    image: redis
    ports:
      - "6379:6379"
    volumes:
      - "/home/docker/data:/data"
    deploy:
      placement:
        constraints: [node.role == manager]
    command: redis-server --appendonly yes
    networks:
      - webnet
將以上片段放在 services 段落中,visualizer 的後面,請留意縮排。文件中指出 Redis 的官方映像檔有被授權可以使用 redis 這個名稱,因此不需使用 username/repository 這樣的格式,和之前使用過的 hello-world 映像檔情況類似。接下來關於如何留存 redis 服務中的資料,有幾個重要的關鍵,第一個是讓 redis 只在同一台機器上運作,以存取相同的檔案系統,第二個是讓 redis 能存取主機中的某一目錄,並將它對應到容器中的 /data 目錄,這是 Redis 儲存資料的地方。command 是指容器運行後要執行的指令,這裡會啟動 Redis server。
接下來準備部署應用程式,先在 myvm1 中建立 /home/docker/data 目錄,以作為 Redis 儲存資料之用。雖然已經設定過 shell 讓 docker 可以直接和 myvm1 溝通,但建立目錄並非 docker 指令,所以要用 docker-machine ssh 連到 myvm1 來做,登入後的工作目錄即是 /home/docker,因此直接使用指令 docker-machine ssh myvm1 "mkdir data" 來建立 myvm1 中的目錄。
現在可以用指令 docker stack deploy -c docker-compose.yml getstartedlab 來部署或更新應用程式,如果原本應用程式就已經在執行,docker stack deploy 會直接把 redis 服務加入應用程式,不會感受到應用程式的 downtime。(但如果是更新 docker-compose.yml,刪除 redis 服務,docker stack deploy 並不會將 redis 服務停止。)
以瀏覽器連接節點的 80 port,會發現頁面上的計數 Visits 欄位開始更新;連接節點 8080 port 可看見目前的 swarm 服務的狀況,visualizer 和 redis 兩個服務都只在 manager 上運行。
要確認 Redis 資料是否留存,可將應用程式卸除後再重新部署,並確認是否延續上次的計數,或者可試驗將 volumes 設定刪除,此時計數應該會重新開始。
以上就是 Get Started 關於服務堆疊的部分,這裡示範了在 swarm 節點部署具多個服務且有相依性的應用程式,並以 volumes 來留存 docker 中的資料。Get Started 還有一個部署到雲端環境的教學,這裡暫時先跳過,有興趣的夥伴再自己參考文件操作看看吧。