Docker 的部署方式

在使用 docker run 命令啓動 Docker 容器時,若是須要進行端口映射、目錄掛載、網絡信息等配置,整條命令將變得很是長,而且因爲是一條 shell 命令,修改和複用也不方便。咱們在大規模部署容器的時候不可能手動去輸入衆多的命令,因此須要一些工具來輔助咱們實現 docker run 命令的編寫,同時實現簡單快捷的大規模部署。node

docker-compose 部署

docker-compose 是一個讀取特定格式的 yaml 文件並將其轉換爲 docker run 命令的工具,它有效的規避了上述的問題,而且它也是 docker swarmdocker stack 等技術的基石。docker-compose 須要一份 yaml 格式的腳本,若是在使用命令時不想指定具體的腳本名稱,那就須要將腳本命名爲 docker-compose.yml。下面是一份啓動 MySQL 容器的 docker-compose 腳本。mysql

version: "3"
services:
 mysql:
 container_name: login_db
 image: mysql:5.7
 ports:
 - "3306:3306"
 environment:
 - MYSQL_ROOT_PASSWORD=123456
 volumes:
 - "mysql-data:/var/lib/mysql"
 networks:
 - my-bridge

volumes:
 mysql-data:

networks:
 my-bridge:
 driver: bridge
複製代碼

全局配置

version 指定的是 docker-compose 的版本,因爲 v2v3 在語法上存在一些不一樣,因此須要明確告訴 docker-compose 當前腳本所使用的語法版本是多少。web

services 表示服務定義。一份腳本中能夠定義多個服務,docker-compose 會一併啓動。算法

volumes 下的名稱列表就是服務啓動時要建立的全部數據卷的名稱,只有先建立了數據卷才能在下面的服務定義中的 volumes 配置中進行掛載使用。注意區分全局的 volumes 和服務定義下的 volumes 配置sql

networks 下配置的是服務啓動時要建立的網絡及其驅動類型。這裏建立了一個驅動爲 bridge、名稱爲 my-bridge 的橋接網絡。只有先建立了網絡才能在下面的服務定義中的 networks 配置中進行註冊使用。注意區分全局的 networks 和服務定義下的 networks 配置docker

服務配置

mysql 表示定義一個名叫 mysql 的服務。shell

container_name 表示服務要啓動的容器的名稱,若是這個服務要動態擴展多個容器,則不能夠指定容器名稱,不然因爲容器名稱衝突將致使沒法擴展。markdown

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 -dup 表示啓動服務,-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 來直接擴容服務。

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、Kubernates 等不一樣的集羣管理模式。

在 Docker Swarm 集羣模式下,當多個宿主機造成集羣后,咱們就能夠在管理節點(Manager Node)上經過管理命令將不一樣服務的容器部署到集羣內不一樣的宿主機上,同一個服務的多個容器也能夠分佈到集羣內不一樣的宿主機上以實現負載均衡。

建立 Swarm 集羣

建立集羣以前須要先規劃好集羣內的節點角色,選擇其中一臺宿主機做爲管理節點開始建立集羣,執行以下命令:

docker swarm init --advertise-addr=本機IP
複製代碼

--advertise-addr 用於指定管理節點所在宿主機的 eth0 網卡的 IP 地址,若是存在多個網卡,這個參數必定要指定,不然可能形成管理節點和工做節點之間沒法通訊。命令執行完畢後會輸出以下的提示信息:

Swarm initialized: current node (gmdscjfdlubanwl7i75z5cc85) is now a manager.

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

    docker swarm join \
    --token SWMTKN-1-6djatxtetutac68xd1u8v1icnyv6t0pcplhaph2irqqxqo1m2b-8w6lq2kpw6j1chqpu4vlf2cx3 \
    管理節點IP:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
複製代碼

根據輸出提示,咱們須要在其餘宿主機上執行 docker swarm join … 操做以使其加入到集羣做爲工做節點。集羣節點加入完成後在管理節點執行 docker node ls 能夠看到全部的節點狀態信息。

ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
gmdscjfdlubanwl7i75z5cc85 *  docker-1  Ready   Active        Leader
xna7a0h6a0xhct95kh7v6p9pl    docker-3  Ready   Active
複製代碼

使用標籤標記節點

Docker Swarm 會根據本身的負載均衡算法將服務分散部署到不一樣的集羣節點上,但有時候咱們也但願可以指定服務部署到指定的集羣節點上,這時候就須要經過標籤來指定具體的節點了。下面的名稱嘗試爲 HOSTNAME 是 docker-3 的節點增長一個標籤:

docker node update --label-add mytag=db xna7a0h6a0xhct95kh7v6p9pl
複製代碼

這條命令爲 ID 爲 xna7a0h6a0xhct95kh7v6p9pl 的節點增長了一個標籤,標籤名稱爲 mytag,標籤值爲 db。標籤的使用會在下文 Docker Stack 部署服務時講解。

在 Swarm 集羣中部署服務

有了集羣就能夠進行服務部署,下面嘗試在集羣中部署一個 MySQL 服務,在管理節點執行命令以下:

docker service create --name mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
複製代碼

命令的參數和 docker run 命令的參數是基本一致的,只是命令換成了 docker service create。命令 docker service ls 用於查看全部已部署的服務;命令 docker service ps 服務名稱 用於查看該服務容器的部署節點和狀態:

ID            NAME     IMAGE      NODE      ESIRED STATE  CURRENT STATE          ERROR  PORTS
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 個容器:

docker service scale mysql=3
複製代碼

再次執行 docker service ps mysql 查看容器部署狀況:

ID            NAME     IMAGE      NODE      DESIRED STATE  CURRENT STATE           ERROR  PORTS
0m5erytxi6sa  mysql.1  mysql:5.7  docker-1  Running        Running 13 minutes ago
idgvqymekwam  mysql.2  mysql:5.7  docker-3  Running        Running 3 minutes ago
fldlrega7p40  mysql.3  mysql:5.7  docker-3  Running        Running 3 minutes ago
複製代碼

能夠看到容器數量已經擴大至 3 個,其中兩個部署在 docker-3 節點上。

更新服務

在服務使用多容器部署的狀況下,可使用服務更新來發布新的版本或調整服務部署參數,這樣能夠避免先刪除服務再啓動服務形成的服務中斷。以下命令嘗試使用新版本鏡像來更新服務:

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 服務進行數據讀寫:

version: '3'
services:
 wordpress:
 image: wordpress
 ports:
 - 80:80
 environment:
 - WORDPRESS_DB_HOST=mysql
 - WORDPRESS_DB_PASSWORD=123456
 networks:
 - my-network
 depends_on:
 - mysql
 deploy:
 mode: replicated
 replicas: 3
 restart_policy:
 condition: on-failure
 delay: 5s
 max_attempts: 3
 update_config:
 parallelism: 1
 delay: 10s

 mysql:
 image: mysql:5.7
 environment:
 - MYSQL_ROOT_PASSWORD=123456
 - MYSQL_DATABASE=wordpress
 volumes:
 - mysql-data:/var/lib/mysql
 networks:
 - my-network
 deploy:
 mode: global
 placement:
 constraints: [node.labels.mytag == db]

volumes:
 mysql-data:

networks:
 my-network:
 driver: overlay
複製代碼

wordpress 服務的 environment 中配置的環境變量 WORDPRESS_DB_HOST 的值是 mysql,這個 mysql 表示的是下面的 mysql 服務。因爲 wordpress 服務和 mysql 服務都註冊到了 my-network 網絡上,因此他們彼此能夠經過服務名稱進行通訊,而不須要指定容器 IP。

depends_on 用於配置依賴關係。這裏的配置表示 wordpress 服務必須等 mysql 服務啓動後纔開始啓動,經過這個指令能夠組織服務的啓動順序。

deploy 指令下配置的是部署相關的策略信息。

  • mode 表示部署模式是多副本部署(replicated)仍是全局單節點部署(global)。
  • replicas 表示多副本部署時須要多少個副本,即該服務須要啓動多少個容器。
  • restart_policy 用於指定服務下容器的重啓策略,重啓觸發條件由 condition 定義,delay 表示每次重啓的間隔時間,max_attempts 表示最大嘗試重啓次數。
  • update_config 用於指定服務更新的策略。parallelism 表示每次更新多少個容器,delay 表示兩次更新的時間間隔。

placement 用於配置節點的部署位置。constraints 用於指定部署位置的判斷條件,上文中的 node.labels.mytag == db 表示將 mysql 服務部署到標籤 mytag 的值爲 db 的節點上。

部署使用的網絡 my-network 的驅動是 overlay,這是一種跨主機通訊的網絡,在 Swarm 模式下爲了讓分佈在集羣內不一樣節點上的容器可以互相通訊,他們就都必須註冊到 overlay 驅動的網絡上。咱們也能夠預先手動建立一個 overlay 驅動的網絡:

docker network create -d overlay my-network
複製代碼

這樣咱們在 docker-compose 腳本中聲明網絡時就須要進行以下變動:

networks:
 my-network:
	external: true
複製代碼

external: true 這裏的 my-network 網絡引用的是預先建立好的同名網絡。

部署 Stack

編寫好 docker-compose 腳本後就可使用 docker stack 命令進行服務部署了,假設上文的腳本命名爲 myweb.yml, 下面的命令使用上文的腳本進行服務部署:

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 與編寫代碼相似,都要減小相互的耦合,儘可能避免出現雪崩。

相關文章
相關標籤/搜索