1. 程式人生 > >7.2docker官網入門-Docker Swarm 叢集(下)---最重要

7.2docker官網入門-Docker Swarm 叢集(下)---最重要

Docker Swarm 叢集

(1)容器與應用: 講述 centos docker的安裝,倉庫、映象、容器、服務的概念, dockerfile,compose 檔案,容器管理圖形介面,以單機操作為主線。
(2)Docker Swarm 叢集:講述叢集(cluster)manager,worker,node 的概念與應用在叢集部署。重點講述容器網路、儲存管理、叢集管理、服務發現等知識。

1、Docker Swarm 體驗

docker swarm 是 Docker 公司的一個開源專案。自 v1.12.3 以來, docker swarm 成為 docker 引擎內建的服務。它和谷歌的 K8s 產生了直接競爭。很難說哪個好,對於熟悉 docker 容器的人來說,docker swarm 應該友好一些。

本部分內容主要來自 docker 官網 Get Started, Part 4~5

1.1 瞭解叢集(Swarm clusters)

群集是一組執行 Docker 的計算機組成,其中部分機器是叢集管理機(Swarm Manager) ,其他的是工作機(Worker)。在叢集中,在 Manager 機器上使用 Docker 命令,會在群集上執行。群集中的機器可以是物理機或虛擬機器。加入群集後,它們被統稱節點(Node)

Swarm管理機可以使用幾種策略來執行容器,例如“最空閒節點”- 容器會填充最少使用的機器。或“全域性策略”,它確保每個機器能只能獲得指定容器的一個例項。您可以將這些策略寫在 docker-compose.yml 這樣的服務組合定義檔案中,Swarm管理機會按策略部署。

Swarm Manager是群集中唯一可以執行 docker 命令的機器,或授權其他機器作為工人機(worker)加入群集。worker 只是提供能力,沒有權力指揮其他機器工作。

如果您已經熟悉單主機中使用Docker。現在,可切換到 Docker 叢集模式。啟用群組模式(swarm mode)使當前的機器成為群組管理機。這時,這臺 Docker 將執行管理這個群集的指令,而不再是在當前的機器上執行。

主要概念

  • Swarm Manager 叢集的管理者
  • worker 叢集中的執行者
  • Node 叢集中任意的 docker 機器
  • Swarm mode 叢集模式, docker 機器的狀態

1.2 配置叢集

(1) 準備機器

1) 清理 docker-master 機器

  • 清理所有的容器 docker rm -f $(docker ps -q)
  • 退出可能的叢集狀態 docker swarm leave --force
  • 刪除從倉庫下載的實驗用映象 docker rmi registry.cn-shenzhen.aliyuncs.com/pmlpml/repo:friendlyhello

2) 複製 docker-master 生成 workers

關閉 docker-master ,以它為模板,用 VBox 連結複製 workers,配置如下:

  • docker-worker1:配置 192.168.56.111/24;主機名=“docker-worker1”
  • docker-worker2:配置 192.168.56.112/24;主機名=“docker-worker2”

配置完成後,一般用無介面模式啟動,用 ssh登陸

(2)建立 docker 叢集

1) 建立第一個 Manager

ssh 連線 docker-master 機器上,啟動 docker swarm mode :

docker swarm init  --advertise-addr 192.168.56.110

# docker swarm init  --advertise-addr 192.168.56.110

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

    docker swarm join \
    --token SWMTKN-1-0o8kwg6rwcsyllo8yr4x24t304wtjvh01h1mq3jhcxi1qy5qrl-00hvxabe2qpuwyh4odii07omo \
    192.168.56.110:2377

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

這時,manager 將在埠 192.168.56.110:2377 偵聽叢集節點請求。

  • docker swarm join-token worker 顯示作為 worker 加入該叢集的指令
  • docker swarm join-token manager 顯示作為 manager 加入該叢集的指令

2) 將兩個 worker 分別加入叢集

分別用 ssh 連線兩個 worker 。貼入 manager 上 docker swarm join-token worker 顯示的指令, 格式如下:

docker swarm join \
  --token <token> \
  <ip>:<port>

This node joined a swarm as a worker.

這時,我們的第一個叢集就建完了。

提示, 如果因為防火牆,無法加入叢集,可使用以下命令關閉防火牆:

setenforce 0
systemctl disable iptables-services firewalld
systemctl stop iptables-services firewalld

3) 在 manager 上檢查結果,這時使用 docker node 指令組

# docker node ls

ID                           HOSTNAME        STATUS  AVAILABILITY  MANAGER STATUS
srm9pnuj0zum7z79xb8ptnmdi *  docker-master   Ready   Active        Leader
vhrpxjbbu3ijt84t6c9cm2t64    docker-worker2  Ready   Active
yzzt6k9rfcrti19ergdpde77u    docker-worker1  Ready   Active

在 manager 啟動 Portainer 容器

在瀏覽器中, Swarm 選單看到類似的結果。

1.3 在叢集中部署服務和使用服務

(1) 部署服務

我們在 docker-master 機器上執行同樣的部署命令

docker stack deploy -c docker-compose.yml myservice

檢查結果:

# docker stack ps myservice

ID                  NAME                IMAGE                                                         NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
w04szt4o9u9b        myservice_web.1     registry.cn-shenzhen.aliyuncs.com/pmlpml/repo:friendlyhello   docker-worker2      Running             Running 5 minutes ago
t6bhw4yoybcr        myservice_web.2     registry.cn-shenzhen.aliyuncs.com/pmlpml/repo:friendlyhello   docker-worker1      Running             Running 5 minutes ago
wzdvrjgfeyiy        myservice_web.3     registry.cn-shenzhen.aliyuncs.com/pmlpml/repo:friendlyhello   docker-worker2      Running             Running 5 minutes ago
mr3zw4q6y99n        myservice_web.4     registry.cn-shenzhen.aliyuncs.com/pmlpml/repo:friendlyhello   docker-master       Running             Running 5 minutes ago
kdu43k6ayfnz        myservice_web.5     registry.cn-shenzhen.aliyuncs.com/pmlpml/repo:friendlyhello   docker-worker1      Running             Running 5 minutes ago

果然,服務(容器)被平均分配到三臺機器上了。

(2) 訪問服務

使用叢集中任意一臺機器的 IP, 我們都能看到迴圈訪問不同容器服務的結果,體現了負載均衡。

每個IP地址都工作的原因是群集中的節點參與入口路由網格(route mesh)。這樣可以確保在群集中某個埠部署的服務始終將該埠保留給其自身,無論實際執行的是哪個節點。以下是在三節點群集my-web埠8080上釋出的服務的路由網格的示例:

route mesh

注意:如果您遇到連線故障,請注意,為了在叢集中使用入口網路,需要在啟用群組模式之時,在群集節點之間使用以下埠:

埠7946用於容器網路發現的TCP / UDP。
埠4789 UDP用於容器入口網路。

1.4 部署一個簡單應用

(1)叢集容器視覺化工具

官方文件 Part 5 介紹了官方的簡單容器狀態視覺化工具,並將它dockersamples/visualizer 新增到專案中。

(2)新增資料服務

現在我們為 web 服務新增 Redis 資料服務。

1) 新建一個 compose 檔案

cd && mkdir myapp && cd myapp
cp ../service_test/docker-compose.yml docker-compose.yml
mkdir data

注: data 目錄用來存放 redis 的資料

2) 修改服務棧配置 vi docker-compose.yml

version: "3"
services:
  web:
    image: registry.cn-shenzhen.aliyuncs.com/pmlpml/repo:friendlyhello
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "80:80"
    networks:
      - webnet
  redis:
    image: redis
    ports:
      - "6379:6379"
    volumes:
      - ./data:/data
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - webnet
networks:
  webnet:

上述配置中,添加了 redis 這個服務,redis 服務被指定到 [node.role == manager] 機器,因為它與這臺機器要共享資料卷 ./data 對映到容器 /data 資料卷

啟動這個棧:

docker stack deploy -c docker-compose.yml myservice

網站會計數了,它們共享一個 Redis 資料服務。

最後, docker stack rm myservice

(3) 什麼是“棧(stack)”

一切似乎都很完美,其實服務之間依賴、在叢集中資料遷移都是重要研究的話題。問題:

  • Redis 就必須繫結某個主機?
  • 服務啟動順序對應用有影響嗎?
  • 管理機只能一臺?
  • … …

當然,最大的麻煩還是:上午在官網讀某文件,下午網站內容變了。

2、容器與叢集技術基礎

倉庫、映象、容器、服務、服務棧、dockerfile、compose.yaml 讓我們看到容器簡單易用的一面。事實上,任何和雲相關的技術,需要你對網路、資料儲存、作業系統、應用開發等等技術的修養,俗稱“全棧”。

2.1 容器網路

(1)準備環境

前面我們建立了3臺機器的叢集。現在我們把 worker1 撤出叢集,完成以下實驗。ssh 登陸 worker1:

# docker swarm leave

Node left the swarm.

成功退出 manager 組織的叢集。

(2)容器執行的預設網路

Docker 通過使用網路驅動程式來支援容器的網路。Docker 目前提供bridgeoverlay 兩個網路驅動程式。你可以利用網路驅動外掛,建立自己的網路驅動。Docker Engine 安裝都會自動包含三個預設網路。使用 docker network 命令管理這些網路,例如:

# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
4ff847509bb3        bridge              bridge              local
68f3b3d86d97        host                host                local
690f242840f5        none                null                local

bridge是一個特殊的網路。除非您特別說明,否則Docker會在此網路中啟動容器。例如:

docker run -itd --name=networktest centos

我們在後臺啟動了一個叫 networktest 的容器,運行了 contos 容器。可以用一下命令,檢查容器網路:

# docker network inspect bridge

...
 "Containers": {
            "56d7e244d4ddcf442ddd0211c0433d11871a6bd88be3704f61ca2ece734f2a06": {
                "Name": "networktest",
                "EndpointID": "7720f7cd31f8124c5177f002628988418e6bda92d7810511f66e033a297247db",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
...

或者

# docker inspect networktest

...
          "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "79e0f4bbc9211925bc5fd08c3401a581520ccd61dac014ae75dcbf1d1c3a3fa6",
                    "EndpointID": "7720f7cd31f8124c5177f002628988418e6bda92d7810511f66e033a297247db",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02"
                }
            }
...

這時,容器網路如圖:

bridge1

使用命令 docker network disconnect bridge networktest 可以將容器與網路斷開,也可以使用 docker network connect bridge networktest 連線。

(3)建立使用者的 bridge 網路

現在我們需要定製如圖網路,怎麼做呢?

bridge3

1) 建立虛擬橋接網路 my_bridge

# docker network create -d bridge my_bridge

2)在虛擬橋接網路 my_bridge 建立名字叫 db 的容器

docker run -itd --name=db --net=my_bridge centos

檢查結果:

# docker network ls
# docker network inspect my_bridge

記錄 db 在 my_bridge 上的 ip 地址。

3) 在 bridge 上建立 web 的容器

docker run -itd --name=web centos

 達到以下效果:

 再將web容器綁到 my_bridge,即可達到目的

docker network connect my_bridge web

檢查結果, web ip 172.17.0.4;172.19.0.3db ip 172.19.0.2 。 進入容器 web

docker exec -it web /bin/bash

你可以在容器中 ping db 在容器 db 中 ping web

4) 清理

docker rm $(docker ps -q) -f
docker network rm my_bridge

小結:

  • 使用 docker network 命令可以建立、立表、刪除 使用者定義網路
  • 使用 –net 可以在特定網路上建立容器,也可以用 connect/disconnect 掛接或斷開網路
  • 在自定義網路上,自帶 dns 服務,可以用 容器名 訪問服務

官網在不醒目的地方提及:

  • * bridge 網路上沒有 dns 的支援,是為了相容*
  • 服務與容器的區別只有在機器重新啟動後你才知道,服務是自動啟動的,docker run 的容器則不會。

2.2 容器儲存管理

2.2.1 聯合檔案系統(Union FS)簡介

容器檔案系統:是容器映象檔案系統(只讀)與可讀寫層(Thin)的檔案系統聯合而成的。如圖:

一個容器檔案,是多層疊加起來的,在下載容器時就可以直觀觀察到。Thin R/W 層,是當前容器檔案讀寫層,如果你修改映象層的檔案,就會在 Thin 產生一個覆蓋。多個容器例項執行時,層次共享情形如下:

為了高效管理容器檔案,適應叢集中跨機資料遷移、多機共享等應用場景,產生了許多解決方案,它依然是容器技術熱點研究技術之一。

2.2.2 資料卷

資料卷是一個越過 Union FS 的特殊目錄。用它可以實現資料持久化、和資料共享。簡單描述,讀寫資料卷只會發生在該資料卷中,而不會訪問 Union FS 系統,而提升容器資料訪問效率。

(1)新增資料卷

例如:

docker run -itd --name web -v /webapp centos

這時,你在容器檔案系統 /webapp 的位置建立了一個卷。進入該容器 docker exec -it web /bin/bash ,使用 ls 就會看到該目錄,進入/webapp下:cd /webapp,你可以用 vi aaa.txt 在其中建立檔案。退出該容器

docker inspect web
...
        "Mounts": [
            {
                "Type": "volume",
                "Name": "8b6f417df2f99d59924276f9476a0759d73afb0d27db5d57d7d24d5b7ff3c56b",
                "Source": "/var/lib/docker/volumes/8b6f417df2f99d59924276f9476a0759d73afb0d27db5d57d7d24d5b7ff3c56b/_data",
                "Destination": "/webapp",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
...

這時,使用命令 ls <source> 就看到你剛建立的檔案了。

(2)將本機目錄作為資料卷

docker rm web -f 
docker run -itd --name web -v /root/web:/webapp centos

本命令就是將本機當前目錄下的 /root/web 目錄掛載到容器的 /webapp 目錄下。

注意

  • docker run -v 主機目錄卷僅支援全路徑。如果 -v web:/webapp 則表示命名為 web 的資料卷,通常位置: /var/lib/docker/volumes/web
  • 資料卷旨在持久保留資料,而與容器的生命週期無關。因此,Docker 在刪除容器時不會自動刪除卷,也不會自動刪除容器不再引用的卷。

(3)與主機共享檔案/將主機檔案作為卷

例如:

docker run -itd --name web -v ~/.bash_history:/root/.bash_history centos

2.2.3 建立共享資料卷

為了在容器間共享資料,需要建立共享資料卷。共享資料卷應用場景大致分為幾類:

  • 一臺主機上的多個容器共享資料卷
  • 通過 back-end 共享儲存,如 iSCSI, NFS 等,建立多主機共享資料卷
  • 在叢集中建立可在節點間遷移的資料卷

(1)建立共享資料卷

Docker 17.04 通過 local 資料卷驅動(overlay)提供卷服務,其他版本,請使用 docker info 檢視。

建立共享資料卷,非常簡單。使用 docker volume 命令建立一個命名卷。例如:

docker volume create webdata

通過命令 ls /var/lib/docker/volumes/ 就可以看到這個資料卷,使用也非常簡單,例如:

docker run -itd --name web -v webdata:/webapp centos

(2)建立共享儲存資料卷

官網資料提供了在 iSCSI 或 NFS 提供共享卷服務的案例,使用的驅動是 rancher/convoy 。

這是需要專題研究的內容,因為在不同網路和儲存環境下,需要使用不同的驅動,參見:Use Docker Engine plugins 。涉及多租戶(multi-tenant)、多主機(multi-host)、高可靠等多種裝置解決方案。

2.2.4 資料卷管理

  • 資料卷列表: docker volume ls
  • 資料卷的刪除:例如,刪除所有卷,docker volume rm $(docker volume ls -q)

備份資料卷

由於一個容器可以載入多個數據卷,通常將 backup 目錄載入到容器介面,典型的命令如下:

docker run -itd --name backup --volumes-from dbcontainer -v $(pwd):/backup centos

這樣就把 dbcontainer 資料卷載入到容器 backup 中,然後,你可以隨時進入 backup 容器, tar 到備份目錄中。

相當於在backup這個容器中,會有/backup目錄,對應掛載$PWD, 還會有dbcontainer容器所對應掛載目錄的目錄,進入不同的目錄,建立內容,會再對應的掛在目錄下出現內容。其實就相當於這個backup容器掛載了兩個目錄。

使用共享卷的重要提示

多個容器也可以共享一個或多個數據卷。但是,寫入單個共享卷的多個容器可能會導致資料損壞。確保您的應用程式旨在寫入共享資料儲存。

資料卷可以從Docker主機直接訪問。這意味著您可以使用普通的Linux工具讀寫它們。在大多數情況下,您不應該這樣做,因為如果容器和應用程式不知道您的直接訪問,它可能會導致資料損壞。

2.3 Docker 物件標籤

標籤(Label)用於分類、描述物件語義,方便指令碼過濾、選擇容器進行操作。 可標籤的物件包括:

  • 映象
  • 容器
  • 本地守護程序
  • 資料卷
  • 網路
  • 叢集節點
  • 叢集服務

標籤是一個鍵值對,通常在物件建立時用 –label 引數建立。

3、Docker Swarm 管理

Docker Swarm 特點:

  • 與引擎整合
  • 去中心化的設計
  • 宣告式的服務模型
  • 動態可伸縮服務
  • 自動狀態協調
  • 多主機(Multi-host)網路
  • 負載均衡
  • 滾動更新
  • 預設安全模式

3.1 管理叢集、節點與服務

docker swarm
docker service
docker node

三個命令組。如果你瞭解前面的概念,按文件操作是比較容易的。

3.2 叢集工作原理

一個 docker swarm 叢集的組成結構,如圖:

swarm-diagram

它分為兩類節點,manager 和 worker。

manager 節點處理叢集管理任務:

  • 維護叢集狀態(配置)
  • 排程服務

管理節點共同維護一個強一致狀態資料(你可以認為每個管理節點擁有一個同步的叢集狀態/配置資料庫),任何一個經理退出都不會導致叢集失效。

高可靠模式 是指容器叢集擁有 3 個以上 manager。一個 manager 是基數(如 3、5、7),一半以下 manager 失效都不會導致叢集狀態失效。Docker為群組建議最多七個管理器節點。

多於 7 個 manager 不會提高可靠性,反而會提高開銷

強一致狀態資料庫常見實現包括: etcd 、consul 、zookeeper 等等。

worker 節點的唯一目的就是執行容器(服務)。預設情況下,manager 同時承擔 worker 的職能,所以一個 manager 可以單節點執行,所有容器執行在一個節點中。

對於大型的容器叢集,需要設定管理器節點的可用性設定為 Drain 以阻止服務的任務執行。

docker node update 是一個很有用的命令,可以改變節點的 role,label 等

3.3 服務、任務和容器

在叢集模式下,服務(Service)部署時, manager 管理並維持服務的狀態。如果服務定義了 N 個負載均衡任務,它按策略在叢集中啟動 N 個任務(Task),每個任務執行在叢集的一個容器(Container)中。

services-diagram

任務排程策略

docker 目前提供 複製全域性 兩種策略。複製策略可指定任務的數量,它可以按資源定義,選擇合適的 host 執行任務。 全域性策略指每個主機(host)啟動一個服務,用於監控主機相關資訊。

安全策略

Docker Engine內建的群集模式公鑰基礎設施(PKI)系統使安全部署容器編排系統變得簡單。群集中的節點使用相互傳輸層安全(TLS)來認證,授權和加密他們與群集中其他節點之間的通訊。

3.4 Overlay 網路與服務發現

docker 叢集預設使用 Overlay 網路驅動,Overlay 驅動實現了跨主機叢集內部虛擬網路。它的作用:

  • 將執行的多個容器(不同主機),附加(attach to)到一個網路
  • 預設情況下,服務發現為群集中的每個服務分配虛擬IP地址(VIP)和 動態 DNS,使其可以通過服務名稱將其提供給同一網路上的容器。即在一個 Overlay 虛擬網路內,使用服務名稱訪問,將實現任務級別的負載均衡
  • 在群集中使用覆蓋網路,需要在群集節點之間開啟以下埠:
    • 埠7946 TCP / UDP用於容器網路發現。
    • 埠4789 UDP用於容器覆蓋網路。

(1) 建立 Overlay 網路

建立 Overlay 網路與建立 local 網路一樣,僅需指定 --driver overlay ,例如:

docker network create \
  --driver overlay \
  --subnet 10.0.9.0/24 \
  --opt encrypted \
  my-network

預設情況下,群集中的節點會加密自身與其他節點之間的流量。可選–opt encrypted標誌在覆蓋驅動程式中為不同節點上的容器之間的vxlan流量啟用附加的加密層。

(2)服務發現

預設情況下,建立一個連線到網路的服務時,群集將為該服務分配VIP。VIP根據服務名稱對映到DNS別名。網路上的容器使用共享服務的DNS對映,因此網路上的任何容器都可以通過其服務名稱訪問該服務。

注意:只有使用者自定義網路,才有 dns 服務和服務自動發現

最後

將 Portainer 和 Registry 作為服務部署, 為什麼?

4 、 小結

本文給出了在 centos 環境下,完成 docker 官方叢集教程(Part4-5)的要點。並給出了容器網路、儲存、叢集、服務發現管理的基礎,以及叢集的工作原理。

本文圍繞叢集、Manger、Worker、Service、Task 核心知識以及相關的操作,讀者應可以在叢集上釋出與部署簡單的 web 應用。