fbpx

用 Docker Swarm 部署你的雲服務 (實作篇)

docker compose for swarm

安裝 Docker Engine 與 Docker Swarm

DevOps 又要進化了,在前一篇文章已經介紹過 Docker Swarm 的基本架構,今天要介紹如何把玩 Docker Swarm。新版的 Docker Swarm 已經內建在 Docker Engine 中,只要將 Docker 裝好就可以使用了,我們先裝一下官方最新版 Docker Engine,以下為 Ubuntu 測試環境,安裝方式如下:

sudo apt-get remove docker docker-engine docker.io

sudo apt-get update

sudo apt-get install apt-transport-https ca-certificates curl software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt-get update

sudo apt-get install docker-ce

安裝 Docker Compose

由於 Docker Swarm 部署時會用到 Docker Compose,Docker Compose 是一個可以同時管理多個 Container 設定的套件,包含複雜的網路設定、磁碟掛載、資源配置等等,省得啟動 Container 還要輸入一堆命令與參數,使用起來真的方便很多,真的超好用 der。Docker Compose 安裝方式如下:

sudo apt-get install python3-setuptools

sudo easy_install3 pip

sudo pip install -U docker-compose

不想裝 python 也可以直接安裝 binary 如下:

sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

建立你的 Docker Swarm 群集

由於 Docker Swarm 在我們前面安裝 Docker Engine 的時候已經安裝好了,現在可以直接開始設定,如果你有多台 VM 要組合為 Docker Cluster,記得全部都先安裝好 Docker Engine 與 Docker Compose 囉。今天的操作會使用一個線上的 Docker 模擬環境叫做「Play With Docker」只要有 Docker Hub 帳號就可以使用,可以建立很多 Host 進行 Cluster 模擬操作,是免費的、是免費的、是免費的!如果想要自行安裝 Docker Machine 也是一種建立模擬環境的方法。

先使用瀏覽器連線到 https://labs.play-with-docker.com/ 網頁,進入後先按下「ADD NEW INSTANCE」新增三個 Node,如下:

player-with-docker

我們預設第一台 Node 作為 Manager Node,另外兩台作為 Worker Node,接著在第一台 Console 輸入以下命令啟動 Swarm Mode:

docker swarm init

結果噴出以下 Error Message

Error response from daemon: could not choose an IP address to advertise since this system has multiple addresses on different interfaces (10.0.9.3 on eth0 and 172.18.0.77 on eth1) - specify one with --advertise-addr

由於 Docker Swarm 偵測到系統有多個 Network Interface,要請您確認 Cluster 要依附在哪一個 eth 上,因此重新行 init 如下:

docker swarm init --advertise-addr 10.0.9.3

第一台 Manager Node 成功建立後會顯示其他 Worker Node 加入這個 Cluster 的命令,如下:

swarm init

然後我們直接在其他兩個 Worker Node 輸入上述給我們的命令,如下:

docker swarm join --token SWMTKN-1-0wbfsgvk7dzda847tu8y3zkajwc4cnttztn4rw8u28t003ocjz-09u6npdo8qd21apj27nqjtjvp 10.0.9.3:2377

如果日後忘記 Token 的話可以在 Leader Node 輸入以下命令重新顯示 Token:

docker swarm join-token -q worker

然後在第一台 Manager Node 可以輸入以下命令查看 Cluster Node 狀態,如下:

docker node ls

show-docker-node-cluster

通常我只要看到 Ready 或 Active 就 High 了,整個群集貌似運作正常。上圖中的 ID 欄位是自動產生的 UID,未來設定與管理都是透過這個 ID 進行操作。

先說明一下我們今天的規劃,假設我們有三個 Node,分別是資料庫與兩台 Server,我們期望 Server 可以透過 Swarm Network 實現 Load Balance,並且在部署時透過我們預先設定的 Node Label 指定 Container Run 在我們規劃好的 Node 上。Docker Worker Node 可以指定一些自訂的 Label,好讓我們彈性的調配資源,比如記憶體比較高的 Node 執行資料庫,運算能力比較高的負責 App 等等架構。首先我們先設定 Node Label,命令如下:

docker node update 3p3yi8ptuc6q8kiqkm5fow5v3 --label-add mysql=true

docker node update wmcp142469s1p8qo5jkivw368 --label-add server=true

docker node update k46wnmivx68qxydvrwqwpz5wg --label-add server=true

Label 是一種 Key/Value 的型態,上述的命令將第一台 Worker Node 加上 mysql=true,另外兩台加上 server=true,設定好之後可以透過「docker node inspect」顯示 Node 的詳細資訊,如下:

docker node inspect 3p3yi8ptuc6q8kiqkm5fow5v3 --pretty

make-node-labels

上圖執行 docker node inspect 之後可以看到被我們設定進去的 Labels。接著我們建立要部署的 Docker Compose File,詳細的 Compose 定義方法請參考官方網站。今天的教學規劃配置一台 MySQL 與一台 WordPress,今天我們練習的 Compose File (完整範例在 GitHub) 如下:

vim docker-compose.yml

version: '3.2'
services:
  server:
    image: samejack/php5-fpm-nginx:latest
    hostname: server
    restart: always
    depends_on:
      - mysql
    ports:
      - "80:80"
    volumes:
      - /root/wordpress:/usr/share/nginx/html
    deploy:
      placement:
        constraints: [node.labels.server == true]
  mysql:
    image: samejack/mysql:latest
    hostname: mysql
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=1234
      - MYSQL_USER_NAME=wordpress
      - MYSQL_USER_PASSWORD=5678
    volumes:
      - /root/mysql-data:/var/lib/mysql
    deploy:
      placement:
        constraints: [node.labels.mysql == true]

docker-compose-file

上述的 Compose File 我們透過 deploy.placement.constraints 定義 Container 要執行的 Node Labels, 接著我們在第一台預計要配置 MySQL 的 Node 建立要掛載出來的資料夾:

mkdir /root/mysql-data

然後再另外兩台節點下載 WordPress 並指定 MySQL 連線位置,這裡直接指定 Compose File 中的 hostname 即可在 Docker Swarm 中自動反查對應的 IP Address,如下:

wget https://tw.wordpress.org/wordpress-4.8.2-zh_TW.zip

unzip wordpress-4.8.2-zh_TW.zip

mv wordpress/wp-config-sample.php wordpress/wp-config.php

vim wordpress/wp-config.php

wordpress-app-config

接著我們就可以在這一群 Worker Node 中啟動我們定義好的 Docker Cluster,透過以下 docker deploy 命令:

docker deploy --compose-file docker-compose.yml MY_STACK

如果您是自己安裝 Docker Engine 在執行的時候可能會碰到以下錯誤訊息:

docker deploy is only supported on a Docker daemon with experimental features enabled

解決方法如下:

echo '{"experimental":true}' > /etc/docker/daemon.json && service docker restart

前面的 docker deploy 命令,最後的定義的 MY_STACK 表示我們的 Stack Name,啟動後可以用來查詢與監控,像是列出 Docker Swarm 中所有執行中的 Stack:

docker stack ls

顯示目前在執行的 Service:

docker service ls

顯示某一個指定的 Stack 中所有管理執行 Container:

docker stack ps MY_STACK | grep Running

docker-swarm-deploy

我們測試一下啟動的 Server 有沒有正常,由於在 Docker Ingress Network 的環境下,Compose File 指定導出的 Port 在每一個 Node 都會被開啟,就算是 Port 所屬的 Container 沒有執行在這個 Node,一樣會看到 Port 被開啟,可以透過 netstat 查看。因此我們直接在第一台 Node 1 透過 CURL 127.0.0.1 就可以測試位於 Node 2 的 Nginx Server,如下:

docker container test

Docker Swarm Load Balance 自動拓展機制 (Scale-out)

接著我們測試一下如何動態拓展 Service,假設我們的網站忽然需要應付大流量,那麼我們可以直接修改 Docker Compose File 加上 service.server.deploy.replicas = 2 來實例化更多的 Container (範例 GitHub),修改好以後只要重新執行 docker deploy,不需要停止原本的 Docker 就可以直接進行拓展,執行後 Container 會排程進行更新,很快地我們就可以透過 docker stack ps 查詢到另一個 Node 也跑起來新的 Container,如下:

當 Service 有兩個以上的 Container 在服務時,預設 Docker Ingress Network 會平均派送連線封包到不同的 Container 中以達到 Load Balance 的作用,底層是透過 iptables 實現 NAT 網路封包轉遞。測試一下,如果我們連續發送好幾個連線到 80 Port,如下:

curl http://127.0.0.1

load-balance-test

可以看到兩台 Server 的 Nginx Log 分別收到了連線,如下:

docker-log-1docker-log-2

看起來貌似成功了,其實這只是 Docker  Swarm 一個很簡單的示範。Docker 還有很多實務的應用,比如進行灰度升級、Image 更新。但把服務全面 Docker 化也不是那麼容易,通常為了能夠快速地進行版本發佈與還原,會在 LAN 架設自己專用的 Deploy Registry Server,這樣一來速度比較快。此外,由於預設的 Insgress Network Load Balance 是屬於 L4,因此 HTTP Server 會取不到使用者真正的 IP Address,要錢的 UCP External L7 Load Balancing 可以設定 HTTP L7 Load Balance,不然也可以自己架一個 HAProxy 在外層,透過 x-forwarded-for HTTP Header 傳遞使用者 IP Address。

其實內建的 Load Balance 不太夠用,常常需要搭配 etcdconfd 等等第三方套件實現動態擴展。雖然 Docker Swarm 貌似還在發展中,但是實際上已經有很多案例在 Production 環境中,大量透過 Docker Swarm 進行部署工作,好讓整個 DevOps 能夠能順暢,我自己也還在努力中,加油了....... 終於寫完了,今天先介紹到這裡,Bye!