日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

如果了解Docker Compose,就會(huì)發(fā)現(xiàn)Docker Stack非常簡(jiǎn)單。事實(shí)上在許多方面,Stack一直是期望的Compose——完全集成到Docker中,并能夠管理應(yīng)用的整個(gè)生命周期。

從體系結(jié)構(gòu)上來(lái)講,Stack位于Docker應(yīng)用層級(jí)的最頂端。Stack基于服務(wù)進(jìn)行構(gòu)建,而服務(wù)又基于容器,如圖14.1所示。

使用Docker Stack部署應(yīng)用

 

圖14.1 AtSea商店架構(gòu)圖

接下來(lái)的章節(jié)分為如下幾部分。

  • 簡(jiǎn)單應(yīng)用。
  • 深入分析Stack文件。
  • 部署應(yīng)用。
  • 管理應(yīng)用。

14.2.1 簡(jiǎn)單應(yīng)用

本章后續(xù)的內(nèi)容會(huì)一直使用示例應(yīng)用AtSea Shop。該示例托管在Github的dockersamples/atsea-sample-shop-App庫(kù)中,基于Apache 2.0許可證開(kāi)源。

使用該應(yīng)用是因?yàn)槠鋸?fù)雜度適中,不會(huì)因?yàn)樘珡?fù)雜而難以完整解釋。除此之外,該應(yīng)用還是個(gè)多服務(wù)應(yīng)用,并且利用了認(rèn)證和安全相關(guān)的技術(shù)。應(yīng)用架構(gòu)如圖14.2所示。

如圖所示,該應(yīng)用由5個(gè)服務(wù)、3個(gè)網(wǎng)絡(luò)、4個(gè)密鑰以及3組端口映射構(gòu)成。具體細(xì)節(jié)將會(huì)結(jié)合Stack文件進(jìn)行分析。

注:

 

在本章中用到服務(wù)一詞時(shí),指的是Docker服務(wù)(由若干容器組成的集合,作為一個(gè)整體進(jìn)行統(tǒng)一管理,并且在Docker API中存在對(duì)應(yīng)的服務(wù)對(duì)象)。

使用Docker Stack部署應(yīng)用

 

圖14.2 AtSea商店架構(gòu)圖

復(fù)制Github倉(cāng)庫(kù),以獲取全部源代碼文件。

$ git clone https://github.com/dockersamples/atsea-sample-shop-app.git Cloning
into 'atsea-sample-shop-app'...
remote: Counting objects: 636, done.
remote: Total 636 (delta 0), reused 0 (delta 0), pack-reused 636
Receiving objects: 100% (636/636), 7.23 MiB | 28.25 MiB/s, done.
Resolving deltas: 100% (197/197), done.

該應(yīng)用的代碼由若干目錄和源碼文件組成。讀者可以隨意瀏覽這些文件。但是接下來(lái),重點(diǎn)關(guān)注的文件是docker-stack.yml。該文件通常被稱為Stack文件,在該文件中定義了應(yīng)用及其依賴。

在該文件整體結(jié)構(gòu)中,定義了4種頂級(jí)關(guān)鍵字。

version:
services:
networks:
secrets:

version代表了Compose文件格式的版本號(hào)。為了應(yīng)用于Stack,需要3.0或者更高的版本。services中定義了組成當(dāng)前應(yīng)用的服務(wù)都有哪些。networks列出了必需的網(wǎng)絡(luò),secrets定義了應(yīng)用用到的密鑰。

如果展開(kāi)頂級(jí)的關(guān)鍵字,可以看到類似圖14.2中的結(jié)構(gòu)。Stack文件由5個(gè)服務(wù)構(gòu)成,分別為“reverse_proxy”“database”“appserver”“visualizer”“payment_gateway”。Stack文件中包含3個(gè)網(wǎng)絡(luò),分別為“front-tier”“back-tier”“payment”。最后,Stack文件中有4個(gè)密鑰,分別為“postgres_password”“staging_token”“revprox_key”“revprox_cert”。

version: "3.2"
services:
    reverse_proxy:
    database:
    appserver:
    visualizer:
    payment_gateway:
networks:
    front-tier:
    back-tier:
    payment:
secrets:
    postgres_password:
    staging_token:
    revprox_key:
    revprox_cert:

Stack文件定義了應(yīng)用的很多依賴要素,理解這一點(diǎn)很重要。因此,Stack文件是應(yīng)用的一個(gè)自描述文件,并且作為一個(gè)很好的工具彌合了開(kāi)發(fā)和運(yùn)維之間的隔閡。

接下來(lái)一起深入分析Stack文件的細(xì)節(jié)。

14.2.2 深入分析Stack文件

Stack文件就是Docker Compose文件。唯一的要求就是version:一項(xiàng)需要是“3.0”或者更高的值。具體可以關(guān)注Docker文檔中關(guān)于Compose文件的最新版本信息。

在Docker根據(jù)某個(gè)Stack文件部署應(yīng)用的時(shí)候,首先會(huì)檢查并創(chuàng)建networks:關(guān)鍵字對(duì)應(yīng)的網(wǎng)絡(luò)。如果對(duì)應(yīng)網(wǎng)絡(luò)不存在,Docker會(huì)進(jìn)行創(chuàng)建。

一起看一下Stack文件中的網(wǎng)絡(luò)定義。

1.網(wǎng)絡(luò)

networks:
  front-tier:
  back-tier:
  payment:
    driver: overlay
    driver_opts:
      encrypted: 'yes'

該文件中定義了3個(gè)網(wǎng)絡(luò):front-tier、back-tier以及payment。默認(rèn)情況下,這些網(wǎng)絡(luò)都會(huì)采用overlay驅(qū)動(dòng),新建對(duì)應(yīng)的覆蓋類型的網(wǎng)絡(luò)。但是payment網(wǎng)絡(luò)比較特殊,需要數(shù)據(jù)層加密。

默認(rèn)情況下,覆蓋網(wǎng)絡(luò)的所有控制層都是加密的。如果需要加密數(shù)據(jù)層,有兩種選擇。

  • 在docker network create命令中指定-o encrypted參數(shù)。
  • 在Stack文件中的driver_opts之下指定encrypted:'yes'。

數(shù)據(jù)層加密會(huì)導(dǎo)致額外開(kāi)銷,而影響額外開(kāi)銷大小的因素有很多,比如流量的類型和流量的多少。但是,通常額外開(kāi)銷會(huì)在10%的范圍之內(nèi)。

正如前面提到的,全部的3個(gè)網(wǎng)絡(luò)均會(huì)先于密鑰和服務(wù)被創(chuàng)建。

2.密鑰

密鑰屬于頂級(jí)對(duì)象,在當(dāng)前Stack文件中定義了4個(gè)。

secrets:
  postgres_password:
    external: true
  staging_token:
    external: true
  revprox_key:
    external: true
  revprox_cert:
    external: true

注意,4個(gè)密鑰都被定義為external。這意味著在Stack部署之前,這些密鑰必須存在。

當(dāng)然在應(yīng)用部署時(shí)按需創(chuàng)建密鑰也是可以的,只需要將file: <filename>替換為external: true。但該方式生效的前提是,需要在主機(jī)文件系統(tǒng)的對(duì)應(yīng)路徑下有一個(gè)文本文件,其中包含密鑰所需的值,并且是未加密的。這種方式存在明顯的安全隱患。

稍后會(huì)展示在部署的時(shí)候究竟是如何創(chuàng)建這些密鑰的?,F(xiàn)在,讀者只需知道應(yīng)用定義了4個(gè)密鑰,并且需要提前創(chuàng)建即可。

下面對(duì)服務(wù)逐一進(jìn)行分析。

3.服務(wù)

部署中的主要操作都在服務(wù)這個(gè)環(huán)節(jié)。

每個(gè)服務(wù)都是一個(gè)JSON集合(字典),其中包含了一系列關(guān)鍵字。本書會(huì)依次介紹每個(gè)關(guān)鍵字,并解釋操作的具體內(nèi)容。

(1)reverse_proxy服務(wù)

正如讀者所見(jiàn),reverse_proxy服務(wù)定義了鏡像、端口、密鑰以及網(wǎng)絡(luò)。

reverse_proxy:
  image: dockersamples/atseasampleshopapp_reverse_proxy
  ports:
    - "80:80"
    - "443:443"
  secrets:
    - source: revprox_cert
      target: revprox_cert
    - source: revprox_key
      target: revprox_key
networks:
  - front-tier

image關(guān)鍵字是服務(wù)對(duì)象中唯一的必填項(xiàng)。顧名思義,該關(guān)鍵字定義了將要用于構(gòu)建服務(wù)副本的Docker鏡像。

Docker是可選項(xiàng),除非指定其他值,否則鏡像會(huì)從Docker Hub拉取。讀者可以通過(guò)在鏡像前添加對(duì)應(yīng)第三方鏡像倉(cāng)庫(kù)服務(wù)API的DNS名稱的方式,來(lái)指定某個(gè)鏡像從第三方服務(wù)拉取。例如google的容器服務(wù)的DNS名稱為gcr.io。

Docker Stack和Docker Compose的一個(gè)區(qū)別是,Stack不支持構(gòu)建。這意味著在部署Stack之前,所有鏡像必須提前構(gòu)建完成。

ports關(guān)鍵字定義了兩個(gè)映射。

  • 80:80將Swarm節(jié)點(diǎn)的80端口映射到每個(gè)服務(wù)副本的80端口。
  • 443:443將Swarm節(jié)點(diǎn)的443端口映射到每個(gè)服務(wù)副本的443端口。

默認(rèn)情況下,所有端口映射都采用Ingress模式。這意味著Swarm集群中每個(gè)節(jié)點(diǎn)的對(duì)應(yīng)端口都會(huì)映射并且是可訪問(wèn)的,即使是那些沒(méi)有運(yùn)行副本的節(jié)點(diǎn)。另一種方式是Host模式,端口只映射到了運(yùn)行副本的Swarm節(jié)點(diǎn)上。但是,Host模式需要使用完整格式的配置。例如,在Host模式下將端口映射到80端口的語(yǔ)法如下所示。

ports:
  - target: 80
    published: 80
    mode: host

推薦使用完整語(yǔ)法格式,這樣可以提高易讀性,并且更靈活(完整語(yǔ)法格式支持Ingress模式和Host模式)。但是,完整格式要求Compose文件格式的版本至少是3.2。

secret關(guān)鍵字中定義了兩個(gè)密鑰:revprox_cert以及revprox_key。這兩個(gè)密鑰必須在頂級(jí)關(guān)鍵字secrets下定義,并且必須在系統(tǒng)上已經(jīng)存在。

密鑰以普通文件的形式被掛載到服務(wù)副本當(dāng)中。文件的名稱就是stack文件中定義的target屬性的值,其在linux下的路徑為/run/secrets,在windows下的路徑為C:ProgramDataDockersecrets。Linux將/run/secrets作為內(nèi)存文件系統(tǒng)掛載,但是Windows并不會(huì)這樣。

本服務(wù)密鑰中定義的內(nèi)容會(huì)在每個(gè)服務(wù)副本中被掛載,具體路徑為/run/secrets/revprox_cert和/run/secrets/revprox_key。若將其中之一掛載為/run/secrets/uber_secret,需要在stack文件中定義如下內(nèi)容。

secrets:
  - source: revprox_cert
    target: uber_secret

networks關(guān)鍵字確保服務(wù)所有副本都會(huì)連接到front-tier網(wǎng)絡(luò)。網(wǎng)絡(luò)相關(guān)定義必須位于頂級(jí)關(guān)鍵字networks之下,如果定義的網(wǎng)絡(luò)不存在,Docker會(huì)以O(shè)verlay網(wǎng)絡(luò)方式新建一個(gè)網(wǎng)絡(luò)。

(2)database服務(wù)

數(shù)據(jù)庫(kù)服務(wù)也在Stack文件中定義了,包括鏡像、網(wǎng)絡(luò)以及密鑰。除上述內(nèi)容之外,數(shù)據(jù)庫(kù)服務(wù)還引入了環(huán)境變量和部署約束。

database:
  image: dockersamples/atsea_db
  environment:
    POSTGRES_USER: gordonuser
    POSTGRES_DB_PASSWORD_FILE: /run/secrets/postgres_password
    POSTGRES_DB: atsea
  networks:
    - back-tier
  secrets:
    - postgres_password
  deploy:
    placement:
      constraints:
        - 'node.role == worker'

environment關(guān)鍵字允許在服務(wù)副本中注入環(huán)境變量。在該服務(wù)中,使用了3個(gè)環(huán)境變量來(lái)定義數(shù)據(jù)庫(kù)用戶、數(shù)據(jù)庫(kù)密碼的位置(掛載到每個(gè)服務(wù)副本中的密鑰)以及數(shù)據(jù)庫(kù)服務(wù)的名稱。

environment:
  POSTGRES_USER: gordonuser
  POSTGRES_DB_PASSWORD_FILE: /run/secrets/postgres_password
  POSTGRES_DB: atsea

注:

 

將三者作為密鑰傳遞會(huì)更安全,因?yàn)檫@樣可以避免將數(shù)據(jù)庫(kù)名稱和數(shù)據(jù)庫(kù)用戶以明文變量的方式記錄在文件當(dāng)中。

該服務(wù)還在deploy關(guān)鍵字下定義了部署約束。這樣保證了當(dāng)前服務(wù)只會(huì)運(yùn)行在Swarm集群的worker節(jié)點(diǎn)之上。

deploy:
  placement:
    constraints:
      - 'node.role == worker'

部署約束是一種拓?fù)涓兄〞r(shí)任務(wù),是一種很好的優(yōu)化調(diào)度選擇的方式。Swarm目前允許通過(guò)如下幾種方式進(jìn)行調(diào)度。

  • 節(jié)點(diǎn)ID,如node.id==o2p4kw2uuw2a。
  • 節(jié)點(diǎn)名稱,如node.hostname==wrk-12。
  • 節(jié)點(diǎn)角色,如node.role!=manager。
  • 節(jié)點(diǎn)引擎標(biāo)簽,如engine.labels.operatingsystem==ubuntu16.04。
  • 節(jié)點(diǎn)自定義標(biāo)簽,如node.labels.zone==prod1。

注意==和!=操作符均支持。

(3)appserver服務(wù)

appserver服務(wù)使用了一個(gè)鏡像,連接到3個(gè)網(wǎng)絡(luò),并且掛載了一個(gè)密鑰。此外appserver服務(wù)還在deploy關(guān)鍵字下引入了一些額外的特性。

appserver:
  image: dockersamples/atsea_app
  networks:
    - front-tier
    - back-tier
    - payment
  deploy:
    replicas: 2
    update_config:
      parallelism: 2
    failure_action: rollback
    placement:
      constraints:
      - 'node.role == worker'
  restart_policy:
    condition: on-failure
    delay: 5s
    max_attempts: 3
    window: 120s
secrets:
  - postgres_password

接下來(lái)進(jìn)一步了解deploy關(guān)鍵字中新增的內(nèi)容。

首先,services.appserver.deploy.replicas = 2設(shè)置期望服務(wù)的副本數(shù)量為2。缺省情況下,默認(rèn)值為1。如果服務(wù)正在運(yùn)行,并且需要修改副本數(shù),則讀者需要顯示聲明該值。這意味著需要更新stack文件中的services.appserver.deploy.replicas,設(shè)置一個(gè)新值,然后重新部署當(dāng)前stack。后面會(huì)進(jìn)行具體展示,但是重新部署stack并不會(huì)影響那些沒(méi)有改動(dòng)的服務(wù)。

services.appserver.deploy.update_config定義了Docker在服務(wù)滾動(dòng)升級(jí)的時(shí)候具體如何操作。對(duì)于當(dāng)前服務(wù),Docker每次會(huì)更新兩個(gè)副本(parallelism),并且在升級(jí)失敗后自動(dòng)回滾?;貪L會(huì)基于之前的服務(wù)定義啟動(dòng)新的副本。failure_action的默認(rèn)操作是pause,會(huì)在服務(wù)升級(jí)失敗后阻止其他副本的升級(jí)。failure_action還支持continue。

update_config:
  parallelism: 2
  failure_action: rollback

services.appserver.deploy.restart-policy定義了Swarm針對(duì)容器異常退出的重啟策略。當(dāng)前服務(wù)的重啟策略是,如果某個(gè)副本以非0返回值退出(condition: onfailure),會(huì)立即重啟當(dāng)前副本。重啟最多重試3次,每次都會(huì)等待至多120s來(lái)檢測(cè)是否啟動(dòng)成功。每次重啟的間隔是5s。

restart_policy:
  condition: on-failure
  delay: 5s
  max_attempts: 3
  window: 120s

(4)visualizer服務(wù)

visualizer服務(wù)中指定了鏡像,定義了端口映射規(guī)則、更新配置以及部署約束。此外還掛載了一個(gè)指定卷,并且定義了容器的優(yōu)雅停止方式。

visualizer:
  image: dockersamples/visualizer:stable
  ports:
    - "8001:8080"
  stop_grace_period: 1m30s
  volumes:
    - "/var/run/docker.sock:/var/run/docker.sock"
  deploy:
    update_config:
      failure_action: rollback
    placement:
      constraints:
        - 'node.role == manager'

當(dāng)Docker停止某個(gè)容器的時(shí)候,會(huì)給容器內(nèi)部PID為1的進(jìn)程發(fā)送SIGTERM信號(hào)。容器內(nèi)PID為1的進(jìn)程會(huì)有10s的優(yōu)雅停止時(shí)間來(lái)執(zhí)行一些清理操作。如果進(jìn)程沒(méi)有處理該信號(hào),則10s后就會(huì)被SIGKILL信號(hào)強(qiáng)制結(jié)束。stop_grace_period屬性可以調(diào)整默認(rèn)為10s的優(yōu)雅停止時(shí)長(zhǎng)。

volumes關(guān)鍵字用于掛載提前創(chuàng)建的卷或者主機(jī)目錄到某個(gè)服務(wù)副本當(dāng)中。在本例中,會(huì)掛載Docker主機(jī)的/var/run/docker.sock目錄到每個(gè)服務(wù)副本的/var/run/docker.sock路徑。這意味著在服務(wù)副本中任何對(duì)/var/run/docker.sock的讀寫操作都會(huì)實(shí)際指向Docker主機(jī)的對(duì)應(yīng)目錄中。

/var/run/docker.sock恰巧是Docker提供的IPC套接字,Docker daemon通過(guò)該套接字對(duì)其他進(jìn)程暴露其API終端。這意味著如果給某個(gè)容器訪問(wèn)該文件的權(quán)限,就是允許該容器接收全部的API終端,即等價(jià)于給予了容器查詢和管理Docker daemon的能力。在大部分場(chǎng)景下這是決不允許的。但是,這是一個(gè)實(shí)驗(yàn)室環(huán)境中的示例應(yīng)用。

該服務(wù)需要Docker套接字訪問(wèn)權(quán)限的原因是需要以圖形化方式展示當(dāng)前Swarm中服務(wù)。為了實(shí)現(xiàn)這個(gè)目標(biāo),當(dāng)前服務(wù)需要能訪問(wèn)管理節(jié)點(diǎn)的Docker daemon。為了確保能訪問(wèn)管理節(jié)點(diǎn)Docker daemon,當(dāng)前服務(wù)通過(guò)部署約束的方式,強(qiáng)制服務(wù)副本只能部署在管理節(jié)點(diǎn)之上,同時(shí)將Docker套接字綁定掛載到每個(gè)服務(wù)副本中。綁定掛載如圖14.3所示。

使用Docker Stack部署應(yīng)用

 

圖14.3 綁定掛載

(5)payment_gateway服務(wù)

payment_gateway服務(wù)中指定了鏡像,掛載了一個(gè)密鑰,連接到網(wǎng)絡(luò),定義了部分部署策略,并且使用了兩個(gè)部署約束。

payment_gateway:
  image: dockersamples/atseasampleshopapp_payment_gateway
  secrets:
    - source: staging_token
      target: payment_token
  networks:
    - payment
  deploy:
    update_config:
      failure_action: rollback
    placement:
      constraints:
        - 'node.role == worker'
        - 'node.labels.pcidss == yes'

除了部署約束node.label之外,其余配置項(xiàng)在前面都已經(jīng)出現(xiàn)過(guò)了。通過(guò)docker node update命令可以自定義節(jié)點(diǎn)標(biāo)簽,并添加到Swarm集群的指定節(jié)點(diǎn)。因此,node.label配置只適用于Swarm集群中指定的節(jié)點(diǎn)上(不能用于單獨(dú)的容器或者不屬于Swarm集群的容器之上)。

在本例中,payment_gateway服務(wù)被要求只能運(yùn)行在符合PCI DSS(支付卡行業(yè)標(biāo)準(zhǔn),譯者注)標(biāo)準(zhǔn)的節(jié)點(diǎn)之上。為了使其生效,讀者可以將某個(gè)自定義節(jié)點(diǎn)標(biāo)簽應(yīng)用到Swarm集群中符合要求的節(jié)點(diǎn)之上。本書在搭建應(yīng)用部署實(shí)驗(yàn)環(huán)境的時(shí)候完成了該操作。

因?yàn)楫?dāng)前服務(wù)定義了兩個(gè)部署約束,所以服務(wù)副本只會(huì)部署在兩個(gè)約束條件均滿足的節(jié)點(diǎn)之上,即具備pcidss=yes節(jié)點(diǎn)標(biāo)簽的worker節(jié)點(diǎn)。

關(guān)于Stack文件的分析到這里就結(jié)束了,目前對(duì)于應(yīng)用需求應(yīng)該有了較好的理解。前文中提到,Stack文件是應(yīng)用文檔化的重要部分之一。讀者已經(jīng)了解該應(yīng)用包含5個(gè)服務(wù)、3個(gè)網(wǎng)絡(luò)以及4個(gè)密鑰。此外讀者還知道了每個(gè)服務(wù)都會(huì)連接到哪個(gè)網(wǎng)絡(luò)、有哪些端口需要發(fā)布、應(yīng)用會(huì)使用到哪些鏡像以及哪些服務(wù)需要在特定的節(jié)點(diǎn)上發(fā)布。

下面開(kāi)始部署。

14.2.3 部署應(yīng)用

在部署應(yīng)用之前,有幾個(gè)前置處理需要完成。

  • Swarm模式:應(yīng)用將采用Docker Stack部署,而Stack依賴Swarm模式。
  • 標(biāo)簽:某個(gè)Swarm worker節(jié)點(diǎn)需要自定義標(biāo)簽。
  • 密鑰:應(yīng)用所需的密鑰需要在部署前創(chuàng)建完成。

1.搭建應(yīng)用實(shí)驗(yàn)環(huán)境

在本節(jié)中會(huì)完成基于Linux的三節(jié)點(diǎn)Swarm集群搭建,同時(shí)能滿足上面應(yīng)用的全部前置依賴。完成之后,實(shí)驗(yàn)環(huán)境如圖14.4所示。

使用Docker Stack部署應(yīng)用

 

圖14.4 示例環(huán)境

接下來(lái)內(nèi)容分為3個(gè)步驟。

(1)創(chuàng)建新的Swarm。

(2)添加節(jié)點(diǎn)標(biāo)簽。

(3)創(chuàng)建密鑰。

首先創(chuàng)建新的三節(jié)點(diǎn)Swarm集群。

(1)初始化Swarm。

在讀者期望成為Swarm管理節(jié)點(diǎn)的機(jī)器上,運(yùn)行下面的命令。

$ docker swarm init
Swarm initialized: current node (lhma...w4nn) is now a manager.
<Snip>

(2)添加工作節(jié)點(diǎn)。

復(fù)制前面輸出中出現(xiàn)的docker swarm join命令。將復(fù)制內(nèi)容粘貼到工作節(jié)點(diǎn)上并運(yùn)行。

//Worker 1 (wrk-1)
wrk-1$ docker swarm join --token SWMTKN-1-2hl6...-...3lqg 172.31.40.192:2377
This node joined a swarm as a worker.

//Worker 2 (wrk-2)
wrk-2$ docker swarm join --token SWMTKN-1-2hl6...-...3lqg 172.31.40.192:2377
This node joined a swarm as a worker.

(3)確認(rèn)當(dāng)前Swarm由一個(gè)管理節(jié)點(diǎn)和兩個(gè)工作節(jié)點(diǎn)構(gòu)成。在管理節(jié)點(diǎn)中運(yùn)行下面的命令。

$ docker node ls
ID            HOSTNAME  STATUS    AVAILABILITY   MANAGER STATUS
lhm...4nn *   mgr-1     Ready     Active         Leader
b74...gz3     wrk-1     Ready     Active
o9x...um8     wrk-2     Ready     Active

Swarm集群目前就緒。

payment_gateway服務(wù)配置了部署約束,限制該服務(wù)只能運(yùn)行在有pcidss=yes標(biāo)簽的工作節(jié)點(diǎn)之上。本步驟中將在wrk-1上添加該節(jié)點(diǎn)標(biāo)簽。

在現(xiàn)實(shí)世界中,添加該標(biāo)簽之前必須將某個(gè)Docker節(jié)點(diǎn)按PCI規(guī)范進(jìn)行標(biāo)準(zhǔn)化。但是,這只是一個(gè)實(shí)驗(yàn)環(huán)境,所以就暫且跳過(guò)這一過(guò)程,直接將標(biāo)簽添加到wrk-1節(jié)點(diǎn)。

在Swarm管理節(jié)點(diǎn)運(yùn)行下面的命令。

(1)添加節(jié)點(diǎn)標(biāo)簽到wrk-1。

$ docker node update --label-add pcidss=yes wrk-1

Node標(biāo)簽只在Swarm集群之內(nèi)生效。

(2)確認(rèn)節(jié)點(diǎn)標(biāo)簽。

$ docker node inspect wrk-1
[
{
    "ID": "b74rzajmrimfv7hood6l4lgz3",
    "Version": {
        "Index": 27
    },
    "CreatedAt": "2018-01-25T10:35:18.146831621Z",
    "UpdatedAt": "2018-01-25T10:47:57.189021202Z",
    "Spec": {
        "Labels": {
            "pcidss": "yes"

        },
        <Snip>

wrk-1工作節(jié)點(diǎn)現(xiàn)在已經(jīng)配置完成,所以該節(jié)點(diǎn)可以運(yùn)行payment_gateway服務(wù)副本了。

應(yīng)用定義了4個(gè)密鑰,這些都需要在應(yīng)用部署前創(chuàng)建。

  • postgress_password。
  • staging_token。
  • revprox_cert。
  • revprox_key。

在管理節(jié)點(diǎn)運(yùn)行下面的命令,來(lái)創(chuàng)建這些密鑰。

(1)創(chuàng)建新的鍵值對(duì)。

密鑰中有3個(gè)是需要加密key的。在本步驟中會(huì)創(chuàng)建加密key,下一步會(huì)將加密key放到Docker密鑰文件當(dāng)中。

$ openssl req -newkey rsa:4096 -nodes -sha256 
  -keyout domain.key -x509 -days 365 -out domain.crt

(2)創(chuàng)建revprox_cert、revprox_key以及postgress_password密鑰。

$ docker secret create revprox_cert domain.crt
cqblzfpyv5cxb5wbvtrbpvrrj

$ docker secret create revprox_key domain.key
jqd1ramk2x7g0s2e9ynhdyl4p

$ docker secret create postgres_password domain.key
njpdklhjcg8noy64aileyod6l

(3)創(chuàng)建stage_token密鑰。

$ echo staging | docker secret create staging_token -
sqy21qep9w17h04k3600o6qsj

(4)列出所有密鑰。

$ docker secret ls
ID          NAME                CREATED             UPDATED
njp...d6l   postgres_password   47 seconds ago      47 seconds ago
cqb...rrj   revprox_cert        About a minute ago  About a minute ago
jqd...l4p   revprox_key         About a minute ago  About a minute ago
sqy...qsj   staging_token       23 seconds ago      23 seconds ago

上面已經(jīng)完成了全部的前置準(zhǔn)備。是時(shí)候開(kāi)始部署應(yīng)用了!

2.部署示例應(yīng)用

如果還沒(méi)有代碼,請(qǐng)先復(fù)制應(yīng)用的GitHub倉(cāng)庫(kù)到Swarm管理節(jié)點(diǎn)。

$ git clone https://github.com/dockersamples/atsea-sample-shop-app.git
Cloning into 'atsea-sample-shop-app'...
remote: Counting objects: 636, done.
Receiving objects: 100% (636/636), 7.23 MiB | 3.30 MiB/s, done. remote:
Total 636 (delta 0), reused 0 (delta 0), pack-reused 636 Resolving
deltas: 100% (197/197), done.
Checking connectivity... done.

$ cd atsea-sample-shop-app

現(xiàn)在已經(jīng)擁有了源碼,可以開(kāi)始部署應(yīng)用了。

Stack通過(guò)docker stack deploy命令完成部署?;A(chǔ)格式下,該命令允許傳入兩個(gè)參數(shù)。

  • Stack文件的名稱。
  • Stack的名稱。

應(yīng)用的GitHub倉(cāng)庫(kù)中包含一個(gè)名為docker-stack.yml的Stack文件。這里會(huì)使用該文件。本書中為Stack起名seastack,如果讀者不喜歡,也可以選擇其他名稱。

在Swarm管理節(jié)點(diǎn)的atsea-sample-shop-app目錄下運(yùn)行下面的命令。

部署Stack(應(yīng)用)。

$ docker stack deploy -c docker-stack.yml seastack
Creating network seastack_default
Creating network seastack_back-tier
Creating network seastack_front-tier
Creating network seastack_payment
Creating service seastack_database
Creating service seastack_appserver
Creating service seastack_visualizer
Creating service seastack_payment_gateway
Creating service seastack_reverse_proxy

讀者可以運(yùn)行docker network ls以及docker service ls命令來(lái)查看應(yīng)用的網(wǎng)絡(luò)和服務(wù)情況。

下面是命令輸出中幾個(gè)需要注意的地方。

網(wǎng)絡(luò)是先于服務(wù)創(chuàng)建的。這是因?yàn)榉?wù)依賴于網(wǎng)絡(luò),所以網(wǎng)絡(luò)需要在服務(wù)啟動(dòng)前創(chuàng)建。

Docker將Stack名稱附加到由他創(chuàng)建的任何資源名稱前作為前綴。在本例中,Stack名為seastack,所以所有資源名稱的格式都如:seastack_<resource>。例如,payment網(wǎng)絡(luò)的名稱是seastack_payment。而在部署之前創(chuàng)建的資源則沒(méi)有被重命名,比如密鑰。

另一個(gè)需要注意的點(diǎn)是出現(xiàn)了新的名為seastack_default的網(wǎng)絡(luò)。該網(wǎng)絡(luò)并未在Stack文件中定義,那為什么會(huì)創(chuàng)建呢?每個(gè)服務(wù)都需要連接到網(wǎng)絡(luò),但是visualizer服務(wù)并沒(méi)有指定具體的網(wǎng)絡(luò)。因此,Docker創(chuàng)建了名為seastack_default的網(wǎng)絡(luò),并將visualizer連接到該網(wǎng)絡(luò)。

讀者可以通過(guò)兩個(gè)命令來(lái)確認(rèn)當(dāng)前Stack的狀態(tài)。docker stack ls列出了系統(tǒng)中全部Stack,包括每個(gè)Stack下面包含多少服務(wù)。docker stack ps <stack-name>針對(duì)某個(gè)指定Stack展示了更詳細(xì)的信息,例如期望狀態(tài)以及當(dāng)前狀態(tài)。下面一起來(lái)了解下這兩條命令。

$ docker stack ls
NAME                SERVICES
Seastack            5

$ docker stack ps seastack
NAME                         NODE    DESIRED STATE   CURRENT STATE
seastack_reverse_proxy.1     wrk-2   Running         Running 7 minutes ago
seastack_payment_gateway.1   wrk-1   Running         Running 7 minutes ago
seastack_visualizer.1        mgr-1   Running         Running 7 minutes ago
seastack_appserver.1         wrk-2   Running         Running 7 minutes ago
seastack_database.1          wrk-2   Running         Running 7 minutes ago
seastack_appserver.2         wrk-1   Running         Running 7 minutes ago

在服務(wù)啟動(dòng)失敗時(shí),docker stack ps命令是首選的問(wèn)題定位方式。該命令展示了Stack中每個(gè)服務(wù)的概況,包括服務(wù)副本所在節(jié)點(diǎn)、當(dāng)前狀態(tài)、期望狀態(tài)以及異常信息。從下面的輸出信息中能看出reverse_proxy服務(wù)在wrk-2節(jié)點(diǎn)上兩次嘗試啟動(dòng)副本失敗。

$ docker stack ps seastack
NAME                NODE      DESIRED    CURRENT ERROR
                              STATE      STATE
reverse_proxy.1     wrk-2     Shutdown   Failed  "task: non-zero exit (1)"
_reverse_proxy.1   wrk-2     Shutdown   Failed  "task: non-zero exit (1)"

如果想查看具體某個(gè)服務(wù)的詳細(xì)信息,可以使用docker service logs命令。讀者需要將服務(wù)名稱/ID或者副本ID作為參數(shù)傳入。如果傳入服務(wù)名稱或ID,讀者可以看到所有服務(wù)副本的日志信息。如果傳入的是副本ID,讀者只會(huì)看到對(duì)應(yīng)副本的日志信息。

下面的docker service logs命令展示了seastack_reverse_proxy服務(wù)的全部副本日志,其中包含了前面輸出中的兩次副本啟動(dòng)失敗的日志。

$ docker service logs seastack_reverse_proxy
seastack_reverse_proxy.1.zhc3cjeti9d4@wrk-2 | [emerg] 1#1: host not found...
seastack_reverse_proxy.1.6m1nmbzmwh2d@wrk-2 | [emerg] 1#1: host not found...
seastack_reverse_proxy.1.6m1nmbzmwh2d@wrk-2 | Nginx: [emerg] host not found..
seastack_reverse_proxy.1.zhc3cjeti9d4@wrk-2 | nginx: [emerg] host not found..
seastack_reverse_proxy.1.1tmya243m5um@mgr-1 | 10.255.0.2 "GET / HTTP/1.1" 302

輸出內(nèi)容為了適應(yīng)頁(yè)面展示,已經(jīng)經(jīng)過(guò)裁剪,但是讀者還是可以看到全部3個(gè)服務(wù)副本的日志(兩個(gè)啟動(dòng)失敗,1個(gè)正在運(yùn)行)。每行的開(kāi)始都是副本的名稱,包括服務(wù)名稱、副本序號(hào)、副本ID以及副本所在主機(jī)的名稱。接下來(lái)是具體的日志輸出。

注:

 

讀者可能已經(jīng)注意到前面日志中全部副本的序號(hào)都是1。這是因?yàn)镈ocker每次只創(chuàng)建一個(gè)副本,并且只有當(dāng)前面的副本啟動(dòng)失敗時(shí)才會(huì)創(chuàng)建新的。

因?yàn)檩敵鰞?nèi)容經(jīng)過(guò)裁剪,所以具體原因很難明確,但看起來(lái)前兩次副本啟動(dòng)失敗原因是其依賴的某個(gè)服務(wù)仍然在啟動(dòng)中(一種啟動(dòng)時(shí)服務(wù)間依賴導(dǎo)致的競(jìng)爭(zhēng)條件)。

讀者可以繼續(xù)跟蹤日志(--follow),查看日志尾部?jī)?nèi)容(--tail),或者獲取額外的詳細(xì)信息(--details)。

現(xiàn)在Stack已經(jīng)啟動(dòng)并且處于運(yùn)行中,看一下如何管理stack。

14.2.4 管理應(yīng)用

Stack是一組相關(guān)聯(lián)的服務(wù)和基礎(chǔ)設(shè)施,需要進(jìn)行統(tǒng)一的部署和管理。雖然這句話里充斥著術(shù)語(yǔ),但仍提醒我們Stack是由普通的Docker資源構(gòu)建而來(lái):網(wǎng)絡(luò)、卷、密鑰、服務(wù)等。這意味著可以通過(guò)普通的Docker命令對(duì)其進(jìn)行查看和重新配置,例如docker network、docker volume、docker secret、docker service等。

在此前提之下,通過(guò)docker service命令來(lái)管理Stack中某個(gè)服務(wù)是可行的。一個(gè)簡(jiǎn)單的例子是通過(guò)docker service scale命令來(lái)擴(kuò)充appserver服務(wù)的副本數(shù)。但是,這并不是推薦的方式!

推薦方式是通過(guò)聲明式方式修改,即將Stack文件作為配置的唯一聲明。這樣,所有Stack相關(guān)的改動(dòng)都需要體現(xiàn)在Stack文件中,然后更新重新部署應(yīng)用所需的Stack文件。

下面是一個(gè)簡(jiǎn)單例子,闡述了為什么通過(guò)命令修改的方式不好(通過(guò)CLI進(jìn)行變更)。

假設(shè)讀者已經(jīng)部署了一個(gè)Stack,采用的Stack文件是前面章節(jié)中從GitHub復(fù)制的倉(cāng)庫(kù)中的docker-stack.yml。這意味著目前appserver服務(wù)有兩個(gè)副本。如果通過(guò)docker service scale命令將副本修改為4個(gè),當(dāng)前運(yùn)行的集群會(huì)有4個(gè)副本,但是Stack文件中仍然是兩個(gè)。得承認(rèn)目前看起來(lái)還不是特別糟糕。但是,假設(shè)讀者又通過(guò)修改Stack文件對(duì)Stack做了某些改動(dòng),然后通過(guò)docker stack deploy命令進(jìn)行滾動(dòng)部署。這會(huì)導(dǎo)致appserver服務(wù)副本數(shù)被回滾到兩個(gè),因?yàn)镾tack文件就是這么定義的。因此,推薦對(duì)Stack所有的變更都通過(guò)修改Stack文件來(lái)進(jìn)行,并且將該文件放到一個(gè)合適的版本控制系統(tǒng)當(dāng)中。

一起來(lái)回顧對(duì)Stack進(jìn)行兩個(gè)聲明式修改的過(guò)程。目標(biāo)是進(jìn)行如下改動(dòng)。

  • 增加appserver副本數(shù),數(shù)量為2~10。
  • 將visualizer服務(wù)的優(yōu)雅停止時(shí)間增加到2min。

修改docker-stack.yml文件,更新兩個(gè)值:services.appserver.deploy.replicas=10和services.visualizer.stop_grace_period=2m。

目前,Stack文件中的內(nèi)容如下。

<Snip>
appserver:
  image: dockersamples/atsea_app
  networks:
    - front-tier
    - back-tier
    - payment
  deploy:
    replicas: 10             <<Updated value
<Snip>
visualizer:
  image: dockersamples/visualizer:stable
  ports:
    - "8001:8080"
stop_grace_period: 2m        <<Updated value
<Snip

保存文件并重新部署應(yīng)用。

$ docker stack deploy -c docker-stack.yml seastack
Updating service seastack_reverse_proxy (id: z4crmmrz7zi83o0721heohsku)
Updating service seastack_database (id: 3vvpkgunetxaatbvyqxfic115)
Updating service seastack_appserver (id: ljht639w33dhv0dmht1q6mueh)
Updating service seastack_visualizer (id: rbwoyuciglre01hsm5fviabjf)
Updating service seastack_payment_gateway (id: w4gsdxfnb5Gofwtvmdiooqvxs)

以上重新部署應(yīng)用的方式,只會(huì)更新存在變更的部分。

運(yùn)行docker stack ps命令來(lái)確認(rèn)appserver副本數(shù)量確實(shí)增加。

$ docker stack ps seastack
NAME                    NODE  DESIRED STATE CURRENT STATE
seastack_visualizer.1   mgr-1 Running       Running 1 second ago
seastack_visualizer.1   mgr-1 Shutdown      Shutdown 3 seconds ago
seastack_appserver.1    wrk-2 Running       Running 24 minutes ago
seastack_appserver.2    wrk-1 Running       Running 24 minutes ago
seastack_appserver.3    wrk-2 Running       Running 1 second ago
seastack_appserver.4    wrk-1 Running       Running 1 second ago
seastack_appserver.5    wrk-2 Running       Running 1 second ago
seastack_appserver.6    wrk-1 Running       Starting 7 seconds ago
seastack_appserver.7    wrk-2 Running       Running 1 second ago
seastack_appserver.8    wrk-1 Running       Starting 7 seconds ago
seastack_appserver.9    wrk-2 Running       Running 1 second ago
seastack_appserver.10   wrk-1 Running       Starting 7 seconds ago

為了本書的排版效果,輸出內(nèi)容有所裁剪,只展示了受變更影響的服務(wù)。

注意關(guān)于visualizer服務(wù)有兩行內(nèi)容。其中一行表示某個(gè)副本在3s前停止,另一行表示新副本已經(jīng)運(yùn)行了1s。這是因?yàn)閯偛艑?duì)visualizer服務(wù)作了修改,所以Swarm集群終止了正在運(yùn)行的副本,并且啟動(dòng)了新的副本,新副本中更新了stop_grace_period的值。

還需要注意的是,appserver服務(wù)目前擁有10個(gè)副本,但不同副本的“CURRENT STATE”一列狀態(tài)并不相同:有些處于running狀態(tài),而有些仍在starting狀態(tài)。

經(jīng)過(guò)足夠的時(shí)間,集群的狀態(tài)會(huì)完成收斂,期望狀態(tài)和當(dāng)前狀態(tài)就會(huì)保持一致。在那時(shí),集群中實(shí)際部署和觀察到的狀態(tài),就會(huì)跟Stack文件中定義的內(nèi)容完全一致。這真是讓人開(kāi)心的事情。

所有應(yīng)用/Stack都應(yīng)采用該方式進(jìn)行更新。所有的變更都應(yīng)該通過(guò)Stack文件進(jìn)行聲明,然后通過(guò)docker stack deploy進(jìn)行部署

正確的刪除某個(gè)Stack方式是通過(guò)docker stack rm命令。一定要謹(jǐn)慎!刪除Stack不會(huì)進(jìn)行二次確認(rèn)。

$ docker stack rm seastack
Removing service seastack_appserver
Removing service seastack_database
Removing service seastack_payment_gateway
Removing service seastack_reverse_proxy
Removing service seastack_visualizer
Removing network seastack_front-tier
Removing network seastack_payment
Removing network seastack_default
Removing network seastack_back-tier

注意,網(wǎng)絡(luò)和服務(wù)已經(jīng)刪除,但是密鑰并沒(méi)有。這是因?yàn)槊荑€是在Stack部署前就創(chuàng)建并存在了。在Stack最上層結(jié)構(gòu)中定義的卷同樣不會(huì)被docker stack rm命令刪除。這是因?yàn)榫淼脑O(shè)計(jì)初衷是保存持久化數(shù)據(jù),其生命周期獨(dú)立于容器、服務(wù)以及Stack之外。

本文摘自《深入淺出Docker》

分享到:
標(biāo)簽:Docker Stack
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定