歡迎光臨
每天分享高質量文章

Docker 的部署方式

在使用 docker run 命令啟動 Docker 容器時,如果需要進行端口映射、目錄掛載、網絡信息等配置,整條命令將變得非常長,並且由於是一條 shell 命令,修改和復用也不方便。我們在大規模部署容器的時候不可能手動去輸入眾多的命令,所以需要一些工具來輔助我們實現 docker run 命令的編寫,同時實現簡單快捷的大規模部署。
Docker Compose 部署

 

docker-compose 是一個讀取特定格式的 yaml 檔案並將其轉換為 docker run 命令的工具,它有效的規避了上述的問題,並且它也是 Docker Swarm、Docker Stack 等技術的基石。docker-compose 需要一份 yaml 格式的腳本,如果在使用命令時不想指定具體的腳本名稱,那就需要將腳本命名為 docker-compose.yml。下麵是一份啟動 MySQL 容器的 docker-compose 腳本。
  1. version: "3"
  2. services:
  3. mysql:
  4. container_name: login_db
  5. image: mysql:5.7
  6. ports:
  7. - "3306:3306"
  8. environment:
  9. - MYSQL_ROOT_PASSWORD=123456
  10. volumes:
  11. - "mysql-data:/var/lib/mysql"
  12. networks:
  13. - my-bridge
  14. volumes:
  15. mysql-data:
  16. networks:
  17. my-bridge:
  18. driver: bridge
全域性配置
version 指定的是 docker-compose 的版本,由於 v2 和 v3 在語法上存在一些不同,所以需要明確告訴 docker-compose 當前腳本所使用的語法版本是多少。
services 表示服務定義。一份腳本中可以定義多個服務,docker-compose 會一併啟動。
volumes 下的名稱串列就是服務啟動時要創建的所有資料捲的名稱,只有先創建了資料捲才能在下麵的服務定義中的 volumes 配置中進行掛載使用。註意區分全域性的 volumes 和服務定義下的 volumes 配置。
networks 下配置的是服務啟動時要創建的網絡及其驅動型別。這裡創建了一個驅動為 bridge、名稱為 my-bridge 的橋接網絡。只有先創建了網絡才能在下麵的服務定義中的 networks 配置中進行註冊使用。註意區分全域性的 networks 和服務定義下的 networks 配置。
服務配置
MySQL 表示定義一個名叫 MySQL 的服務。
container_name 表示服務要啟動的容器的名稱,如果這個服務要動態擴展多個容器,則不可以指定容器名稱,否則由於容器名稱衝突將導致無法擴展。
image 表示服務要使用的鏡像。
ports 表示容器與宿主機的端口映射關係。凡是指定了端口映射關係的服務都不能動態擴展容器數量,因為會導致端口衝突。
environment 表示要設置到容器中的環境變數。這裡設置的環境變數將被放置到容器的全域性環境變數中,你可以在容器中讀取並操作。
volumes 表示要掛載的目錄或者資料捲。這裡和 docker run 命令中的 -v 引數作用是一致的,即可以掛載資料捲,也可以掛載目錄。這裡使用到的資料捲必須在全域性配置中先指定,如果是掛載目錄則需要先手動創建。
networks 表示這個服務要註冊到哪些網絡上去,這裡使用到的網絡必須在全域性配置中先指定。註冊到同一個網絡上的容器之間可以使用服務名進行通信。
使用 docker-compose
通過 docker-compose 可以對服務進行啟動、停止、刪除、擴容等操作。docker-compose 的操作必須依賴腳本,如果腳本存在於當前目錄下且名為 docker-compose.yml 則不需要額外指定,否則需要使用 -f 引數進行指定。
 
啟動服務
啟動服務使用命令 docker-compose -f /path/to/script.yml up -d,up 表示啟動服務,-d 表示後臺運行。這個命令會讀取腳本檔案並首先創建申明的資料捲和網絡,然後再啟動服務。
 
停止服務
停止服務使用命令 docker-compose -f /path/to/script.yml stop。這個命令會將腳本中的所有服務的所有容器都停止,但不會刪除容器。
 
刪除服務
刪除服務使用命令 docker-compose -f /path/to/script.yml rm。這個命令會要求二次確認刪除,並且無法刪除未停止的服務。刪除服務時不會關聯刪除服務啟動時創建的網絡和資料捲。
 
強行刪除服務
強行刪除服務使用命令 docker-compose -f /path/to/script.yml down。這個命令會將所有服務的所有容器都停止並刪除,同時刪除服務啟動時創建的網絡,但不會刪除資料捲。
擴容服務隨著業務量的上升,我們可能需要將服務從一個容器擴展到多個容器以提高服務能力,這時候就可以使用 docker-compose 來直接擴容服務。
  1. docker-compose -f /path/to/script.yml up --scale orderService=3 -d
這個命令表示將名為 orderService 的服務擴容至三個容器並後臺啟動。如果原本的容器數量大於 3 個,那麼這個命令就是縮減容器數量操作。需要註意的是,支持服務擴容的要求是非常苛刻的,需要滿足以下三點要求:
  1. 不能夠指定 container_name,即容器名;

  2. 不能夠指定端口映射關係;

  3. 不能夠指定掛載資料捲或目錄。

如果在腳本中指定了要掛在的目錄或者資料捲,那麼擴容後多個容器將共用一個資料捲和目錄,這樣就會導致資料出現混亂。解決方法是不指定任何資料捲和目錄進行掛載,由 Docker 自行創建隨機名稱的資料捲。
Docker Swarm 部署

 

上文講到的 docker-compose 部署方式還停留在單機部署上,但在實際生產環境中不同系統的 Docker 容器都是垮宿主機部署,這時候就需要將這些宿主機形成集群統一管理,Docker Swarm 就是 Docker 原生提供的一種集群管理樣式。除了 Docker Swarm 外,還有 Mesos、Kubernetes 等不同的集群管理樣式。
在 Docker Swarm 集群樣式下,當多個宿主機形成集群後,我們就可以在管理節點(Manager Node)上通過管理命令將不同服務的容器部署到集群內不同的宿主機上,同一個服務的多個容器也可以分佈到集群內不同的宿主機上以實現負載均衡。
創建 Swarm 集群
創建集群之前需要先規劃好集群內的節點角色,選擇其中一臺宿主機作為管理節點開始創建集群,執行如下命令:
  1. docker swarm init --advertise-addr=本機IP
–advertise-addr 用於指定管理節點所在宿主機的 eth0 網卡的 IP 地址,如果存在多個網卡,這個引數一定要指定,否則可能造成管理節點和工作節點之間無法通信。命令執行完畢後會輸出如下的提示信息:
  1. Swarm initialized: current node (gmdscjfdlubanwl7i75z5cc85) is now a manager.
  2. To add a worker to this swarm, run the following command:
  3. docker swarm join \
  4. --token SWMTKN-1-6djatxtetutac68xd1u8v1icnyv6t0pcplhaph2irqqxqo1m2b-8w6lq2kpw6j1chqpu4vlf2cx3 \
  5. 管理節點IP:2377
  6. To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
根據輸出提示,我們需要在其他宿主機上執行 docker swarm join … 操作以使其加入到集群作為工作節點。集群節點加入完成後在管理節點執行 docker node ls 可以看到所有的節點狀態信息。
  1. ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
  2. gmdscjfdlubanwl7i75z5cc85 * docker-1 Ready Active Leader
  3. xna7a0h6a0xhct95kh7v6p9pl docker-3 Ready Active
 
使用標簽標記節點
Docker Swarm 會根據自己的負載均衡演算法將服務分散部署到不同的集群節點上,但有時候我們也希望能夠指定服務部署到指定的集群節點上,這時候就需要通過標簽來指定具體的節點了。下麵的名稱嘗試為 HOSTNAME 是 docker-3 的節點增加一個標簽:
  1. docker node update --label-add mytag=db xna7a0h6a0xhct95kh7v6p9pl
這條命令為 ID 為 xna7a0h6a0xhct95kh7v6p9pl 的節點增加了一個標簽,標簽名稱為 mytag,標簽值為 db。標簽的使用會在下文 Docker Stack 部署服務時講解。
在 Swarm 集群中部署服務
有了集群就可以進行服務部署,下麵嘗試在集群中部署一個 MySQL 服務,在管理節點執行命令如下:
  1. docker service create --name mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
命令的引數和 docker run 命令的引數是基本一致的,只是命令換成了 docker service create。命令 docker service ls 用於查看所有已部署的服務;命令 docker service ps 服務名稱 用於查看該服務容器的部署節點和狀態:
  1. ID NAME IMAGE NODE ESIRED STATE CURRENT STATE ERROR PORTS
  2. 0m5erytxi6sa mysql.1 mysql:5.7 docker-1 Running Running 3 minutes ago
上面的信息表示 MySQL 服務下共啟動了 1 個容器,其部署在名為 docker-1 的節點上,容器ID 為 0m5erytxi6sa,當前狀態是正在運行,並且與期望的狀態一致。
 
擴容服務
與使用 docker-compose 部署服務類似,docker service 命令也可以讓指定的服務進行容量增減,下麵的命令嘗試將 MySQL 服務擴容至 3 個容器:
  1. docker service scale mysql=3
再次執行 docker service ps mysql 查看容器部署情況:
  1. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  2. 0m5erytxi6sa mysql.1 mysql:5.7 docker-1 Running Running 13 minutes ago
  3. idgvqymekwam mysql.2 mysql:5.7 docker-3 Running Running 3 minutes ago
  4. fldlrega7p40 mysql.3 mysql:5.7 docker-3 Running Running 3 minutes ago
可以看到容器數量已經擴大至 3 個,其中兩個部署在 docker-3 節點上。
 
更新服務
在服務使用多容器部署的情況下,可以使用服務更新來發佈新的版本或調整服務部署引數,這樣可以避免先刪除服務再啟動服務造成的服務中斷。如下命令嘗試使用新版本鏡像來更新服務:
  1. docker service update --image mysql:5.8 mysql
這個命令表示對名為 MySQL 的服務使用使用 mysql:5.8 版本的鏡像進行更新。需要註意的是,如果服務只部署了一個容器,那麼更新過程中,對外服務是肯定會中斷的。
 
刪除服務
使用命令 docker service rm 服務名稱 可以將已部署的服務刪除。刪除服務時服務下所有的容器都會被刪除且不可恢復。
使用 Docker Stack 管理多個服務
 
Stack
在 Swarm 樣式下,使用 docker service create 命令可以創建服務進行部署,當多個服務組合到一起時,我們就把它們看作是一個 Stack。簡單來說,**Stack 就是多個 Service 的組合。在 Swarm 樣式下可以使用 Docker Stack 可以實現服務的批量部署。
 
Docker Stack 腳本
Docker Stack 並不是新的技術點,它同樣是使用 docker-compose 腳本來管理服務創建腳本,並且語法沒有任何區別。下麵的示例展示了怎麼使用 Docker Stack 來部署一個 WordPress 和 MySQL 服務,其中 WordPress 服務需要取用 MySQL 服務進行資料讀寫:
  1. version: '3'
  2. services:
  3. wordpress:
  4. image: wordpress
  5. ports:
  6. - 80:80
  7. environment:
  8. - WORDPRESS_DB_HOST=mysql
  9. - WORDPRESS_DB_PASSWORD=123456
  10. networks:
  11. - my-network
  12. depends_on:
  13. - mysql
  14. deploy:
  15. mode: replicated
  16. replicas: 3
  17. restart_policy:
  18. condition: on-failure
  19. delay: 5s
  20. max_attempts: 3
  21. update_config:
  22. parallelism: 1
  23. delay: 10s
  24. mysql:
  25. image: mysql:5.7
  26. environment:
  27. - MYSQL_ROOT_PASSWORD=123456
  28. - MYSQL_DATABASE=wordpress
  29. volumes:
  30. - mysql-data:/var/lib/mysql
  31. networks:
  32. - my-network
  33. deploy:
  34. mode: global
  35. placement:
  36. constraints: [node.labels.mytag == db]
  37. volumes:
  38. mysql-data:
  39. networks:
  40. my-network:
  41. driver: overlay
在 WordPress 服務的 environment 中配置的環境變數 WORDPRESSDBHOST 的值是 MySQL,這個 MySQL 表示的是下麵的 MySQL 服務。由於 WordPress 服務和 MySQL 服務都註冊到了 my-network 網絡上,所以他們彼此可以通過服務名稱進行通信,而不需要指定容器 IP。
depends_on 用於配置依賴關係。這裡的配置表示 wordpress 服務必須等 mysql 服務啟動後才開始啟動,通過這個指令可以組織服務的啟動順序。
deploy 指令下配置的是部署相關的策略信息。
mode 表示部署樣式是多副本部署(replicated)還是全域性單節點部署(global)。
replicas 表示多副本部署時需要多少個副本,即該服務需要啟動多少個容器。
restartpolicy 用於指定服務下容器的重啟策略,重啟觸發條件由 condition 定義,delay 表示每次重啟的間隔時間,maxattempts 表示最大嘗試重啟次數。
update_config 用於指定服務更新的策略。parallelism 表示每次更新多少個容器,delay 表示兩次更新的時間間隔。
placement 用於配置節點的部署位置。constraints 用於指定部署位置的判斷條件,上文中的 node.labels.mytag == db 表示將 MySQL 服務部署到標簽 mytag 的值為 db 的節點上。
部署使用的網絡 my-network 的驅動是 overlay,這是一種跨主機通信的網絡,在 Swarm 樣式下為了讓分佈在集群內不同節點上的容器能夠互相通信,他們就都必須註冊到 overlay 驅動的網絡上。我們也可以預先手動創建一個 overlay 驅動的網絡:
  1. docker network create -d overlay my-network
這樣我們在 docker-compose 腳本中宣告網絡時就需要進行如下變更:
  1. networks:
  2. my-network:
  3. external: true
external: true 這裡的 my-network 網絡取用的是預先創建好的同名網絡。
 
部署 Stack
編寫好 docker-compose 腳本後就可以使用 docker stack 命令進行服務部署了,假設上文的腳本命名為 myweb.yml, 下麵的命令使用上文的腳本進行服務部署:
  1. docker stack deploy -c myweb.yml myweb
-c 引數是 –compose-file 的縮寫,用於指定部署腳本的位置,最後的 myweb 是這個 Stack 的名字,可以任意設置,通常建議和腳本名稱保持一致,便於管理。命令 docker stack ls 可以查看部署的所有 Stack;命令 docker stack ps Stack名稱 可以查看該 Stack 下所有服務的容器部署情況;命令 docker stack services Stack 名稱 可以查看該 Stack 下所有服務的部署情況,如部署樣式、副本數量等信息。
 
刪除 Stack
命令 docker stack rm Stack名稱 可以刪除一個指定的 Stack。這個命令會刪除該 Stack 下所有的服務及其所有的容器,無法恢復。
 
規劃 Stack
上文提到刪除 Stack 時,其下所有服務都會被刪除,那麼規劃 Stack 就變得尤為重要。如果在規劃時將所有服務都放到一個 Stack 下,那麼當需要重新部署某個服務時就不得不將其他所有服務也全部重新部署。通常建議將高耦合的服務放到一個 Stack中,每個中間件集群作為一個 Stack,這樣可以避免重新部署時發生雪崩。總之,規劃 Stack 與編寫代碼類似,都要減少相互的耦合,儘量避免出現雪崩。
原文鏈接:https://www.ganpengyu.com/archives/docker_deploy.html

赞(0)

分享創造快樂