iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 22
0
Cloud Native

30 天準備 LPI DevOps Tools Engineer 證照系列 第 22

[Day 22] Docker (8)

Docker Compose

今天來看一下 Docker Compose。Compose 這個工具的用途為定義及運行多容器的 Docker 應用程式,它的設定檔 compose file 以 YAML 格式編寫,通常會命名為 docker-compose.yml。其實 docker-compose.yml 這個檔案在前兩天已經看過了,當時是在服務層級中編寫 docker-compose.yml,並用 docker stack 來部署應用程式。雖然在教學文件中的這個部分有要求安裝 Docker Compose,但在整個教學文件中都沒有用到 docker-compose 指令(它是 Docker Compose 的 CLI 工具)。究竟 Docker Compose 在整個 Docker 生態系中位於什麼位置,和 docker stack 又有什麼不同呢?問了一下 google,參考以下兩篇文章 https://vsupalov.com/difference-docker-compose-and-docker-stack/https://my.oschina.net/guol/blog/1377534,它們的差異之處大概是:

  1. Docker Compose 的前身是 fig,它是一個用於管理部署 Docker 容器的 Python 專案,後來變成 Docker Composer,此工具必須要額外安裝(在 Docker for WindowsDocker for Mac 中已內建)。docker stack 則是包含在 Docker 引擎中的功能,內部是用 Go 編寫,必須配合 swarm 模式才能使用。
  2. Docker Composedocker stack 都使用 docker-compose.yml,但 docker stack 只支援版本 3,兩者支援的指令有些許不同。
  3. docker stack 無法 build 映像檔,須使用已經存在的映像檔。
  4. Docker Compose 更適合用在開發環境。

使用 Compose 基本上可分為三個步驟:

  1. 利用 Dockerfile 定義應用程式的環境,以便於在任何地方重新複製 (reproduce anywhere)。
  2. 利用 docker-compose.yml 定義組成應用程式的服務,使它們能在隔離的環境中一起被執行。
  3. 執行 docker-compose up 開始執行整個應用程式。
    Dockerfile 昨天介紹過,第二個步驟的 compose file 待會會稍作介紹,最後一個步驟則是使用 Docker Compose 的 CLI 來啟動整個服務,它的指令是 docker-compose up。CLI 的指令請參考 https://docs.docker.com/compose/reference/overview/

隨著 swarm 被整合到 Docker 引擎,以及 docker stack 功能的開發,感覺起來 Docker Compose 可能會逐漸 deprecate,但因為 docker stack 還是會用到 compose file,所以來看一下 compose file 的編寫方式,可參考 https://docs.docker.com/compose/compose-file/

Compose file

compose file 目前的版本是第 3 版,這也是 docker stack 支援的版本,以下內容參考第 3 版文件。compose file 會定義應用程式中用到的服務 (service)、網路 (network) 及卷宗 (volume)。先來看一個文件中提供的範例:

version: "3"
services:

  redis:
    image: redis:alpine
    ports:
      - "6379"
    networks:
      - frontend
    deploy:
      replicas: 2
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure

  db:
    image: postgres:9.4
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - backend
    deploy:
      placement:
        constraints: [node.role == manager]

  vote:
    image: dockersamples/examplevotingapp_vote:before
    ports:
      - "5000:80"
    networks:
      - frontend
    depends_on:
      - redis
    deploy:
      replicas: 2
      update_config:
        parallelism: 2
      restart_policy:
        condition: on-failure

  result:
    image: dockersamples/examplevotingapp_result:before
    ports:
      - "5001:80"
    networks:
      - backend
    depends_on:
      - db
    deploy:
      replicas: 1
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure

  worker:
    image: dockersamples/examplevotingapp_worker
    networks:
      - frontend
      - backend
    deploy:
      mode: replicated
      replicas: 1
      labels: [APP=VOTING]
      restart_policy:
        condition: on-failure
        delay: 10s
        max_attempts: 3
        window: 120s
      placement:
        constraints: [node.role == manager]

  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    stop_grace_period: 1m30s
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]

networks:
  frontend:
  backend:

volumes:
  db-data:

這個範例有點長,首先指明這個 compose file 的版本,下面有三個部分,分別是 services、networks、volumes。services 區段定義了 6 個服務,每個服務大致上定義了使用的映像檔、port、網路、卷宗及部署設定,networks 區段和 volumes 區段分別定義了兩個網路及一個卷宗,但沒有任何設定值。因為設定值是有階層之分的,在編寫時請注意一下每個設定值的階層關係。和往常一樣,因為設定值非常的多,大致上瞭解階層較高 (high level) 的設定值有那些就可以了。先來看一下 services 的相關設定。

services

  • build
    建立映像檔的相關設定,請注意 docker stack 要使用事先建立 (pre-built) 的映像檔,會忽略 build 設定。這裡可以指定 build context、Dockerfile 等資訊。
  • command
    覆寫預設的指令。
  • configs
    指令 top level 的設定 (config) 於服務中使用。
  • container_name
    指定容器名稱。
  • deploy
    指定容器部署及運行時的設定值,例如 replicas、資源限制等等。
  • depends_on
    指定服務與其他服務間的相依性,depends_on 中的服務必須先被建立或啟動。
  • entrypoint
    覆寫預設的 entrypoint。
  • env_file / environment
    指定讀入環境變數的檔案或設定環境變數。
  • image
    指定這個容器由那個映像檔建立而成。
  • labels
    給容器添加 metada。
  • links
    將容器連接至其他服務的容器。這個功能在新版是 deprecated 的,除非有必要盡量不要使用。
  • networks
    指定要加入在 top level 中設置的那些網路
  • ports
    揭露指定的 port,因為 parser 的關係,最好使用字串型式表示。
  • volumes
    指定要掛載的路徑或卷宗。

volumes

指定此應用程式會使用的 volume,若不存在則建立。如同昨天看到的,要建立 volume 基本上都用預設值,所以這裡只會給予 volume 名稱作為 key,若要其他的設定值請再參考文件。

networks

指定此應用程式會使用的網路。這裡也都是使用預設值。在單一主機上預設是 bridge 橋接模式,在 swarm 中則是 overlay 模式。若需要其他的設定請再參考文件。

Docker Swarm

接下來看一下 swarm,文件說明放在 Guides > Run your app in production > Configure containers > Scale your app 之下,請參考 https://docs.docker.com/engine/swarm/

Swarm 的基本概念在 Get Started 中已經介紹過了,就操作面而言,建立初始 swarm、加入節點、部署啟動應用程式、查看服務等等也都實作過了,這裡就翻譯一下文件中 overview 提到 swarm 模式的一些特點:

  1. 叢集管理的功能整合到 Docker 引擎中,不需使用其他的編配工具來管理 swarm 叢集。
  2. 去中心化的設計,不需在部署時特別去區分 manager 和 worker 節點的不同,整個 swarm 都可以使用相同的映像檔。
  3. 宣告式 (declarative) 的服務模式,可指定服務堆疊中各個服務的理想狀態。declarative 相對的是 imperative,declarative 通常是表示要達到什麼狀態,而 imperative 則是指要做什麼。比如說,我要有一個服務中的 nginx server 是 declarative,而 imperative 可能是我要先用 apt 安裝 nginx,然後調整設定檔,啟動 daemon 等等動作。
  4. 可指定需要的服務 task 數量,由 Docker engine 動態調整,以維持在想要的狀態。
  5. 在多主機上使用 overlay 網路,swarm manager 會主動分派網路位址給容器。
  6. 可揭露服務的 port 給外部的 load balancer,在內部可以指定服務容器要如何分配給各個節點。
  7. node 間彼此溝通可使用 TLS 連線以確保安全。
  8. 當部署或更新時,可漸進式的在各個節點進行,若發生問題可回復前一個版本。

在應試目標能力中,swarm 還有一點沒提到的,就是 secret 的使用,以下稍微作一些說明。

Docker secrets

和 Ansible Vaults 一樣,Docker secrets 的目的在處理 Docker 中會用到的機敏密資料。Docker secrets 要在 swarm 模式才能使用,並在 manager 節點集中處理,將機敏性資料加密、傳送,只有需要這份資料且被授權的容器可以使用。解密後的資料在容器中會被掛載到記憶體中的檔案系統 ( in-memory file system),路徑預設為 /run/secrets/<secret-name>。在 Docker Composedocker stack 的 compose file 中,也可以定義並使用 docker secrets。以下就跟著文件中的範例操作看看。

因為 Docker secrets 要在 swarm 模式中才能作用,所以先以目前主機的初始一個 swarm。接下來在 Docker 中加入一個 secret,內容是 "This is a secret",並將它命名為 my_secret_data,指令如下:

$ printf "This is a secret" | docker secret create my_secret_data -

建立一個服務名為 redis,並讓它可以存取剛才建立的 secret。

$ docker service create --name redis --secret my_secret_data redis:alpine

確認服務的執行狀況

$ docker service ps redis

ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE               ERROR               PORTS
ylf5t25o2wl1        redis.1             redis:alpine        myvm1               Running             Running about an hour ago

接下來到 redis 容器中查看 secret 在容器中如何被保存。secrets 預設會存放在 /run/secrets 目錄中,以下這個指令會先找到 redis 容器的 ID,並在其中查看 /run/secrets 目錄的內容,可以看到目錄中有一個和剛才建立的 secrets 同名的檔案。

$ docker container exec $(docker ps --filter name=redis -q) ls -l /run/secrets

total 4
-r--r--r--    1 root     root            16 Nov  6 06:14 my_secret_data

同樣使用 docker container exec 指令查看這個檔案的內容。

$ docker container exec $(docker ps --filter name=redis -q) cat /run/secrets/my_secret_data

This is a secret

以上是今天的內容。這幾天從 Docker 官網的 Get Started 開始,瞭解了如何在單一容器及 Docker Swarm 部署應用程式,試著編寫 Dockerfile 以建立映像檔,將其上傳至 registry 並取回。此外還介紹了 Docker Composedocker stack,以及 Docker 網路和卷宗的類型及使用方法。想要進一步研究 Docker 的夥伴,可以參考它們的官方文件,有相當豐富的內容,並針對在生產環境場景如何使用有很多介紹。明天要進入下一個主題,Kubernetes。


上一篇
[Day 21] Docker (7)
下一篇
[Day 23] Kubernetes (1)
系列文
30 天準備 LPI DevOps Tools Engineer 證照30

尚未有邦友留言

立即登入留言