iT邦幫忙

2021 iThome 鐵人賽

DAY 4
1
DevOps

前端工程師學習 DevOps 之路系列 第 4

Day04-管理 Docker 的各種組合(Docker Compose)

  • 分享至 

  • xImage
  •  

前言

今天的文章要來介紹點不一樣的,想像一下一個完整的專案一定包含前端、後端、資料庫這三個東西,假如今天我要利用 Docker 完成這三件事情的部屬勢必得寫個簡單的 shellscript 來跑 docker build 以及 docker run,但這樣實在是難以管理,光是 image 的 ID 要一個一個對照就是件很麻煩的事了,當然這件事情 Docker 也知道,所以今天的文章就要利用另一種方式來管理多個 Docker image 及 container,這個工具就叫做 Docker Compose

什麼是 Docker Compose

就字面上的意思來說 compose 其實就是組合的意思,所以 Docker Compose 就是把專案內需要用到的 image 進行組合。既然都可以組合這些 image了,所以 Docker Compose 當然也可以管理利用這些 image 跑起來的container,接下來就正式進入 Docker Compose 的寫法吧!

Docker Compose 寫法

首先 Docker Compose 會以 YAML 格式進行設定,YAML 格式簡單來說就是一種可讀性高,用來表達資料序列化的格式,而 Docker Compose 的副檔名會以 .yml 作為結尾,所以整體的檔案名就會像是這樣:docker-compose.yml 這種形式存在。

一般來說 Docker Compose 內部可以分為四個區塊:

  • version

    version 代表著這份 Docker Compose file 的版本,不同的版本其 Docker engine 的支援度不同,目前有 version 1 、 version 2、 version 3 三種版本,最常使用且支援度最高的是 version 3,寫法上也很簡單就像這樣:

    version: '3'
    
  • services

    對於 Docker Compose 來說,只要是此專案需要用到的東西都統稱為服務(services),假如今天有一個專案需要以下幾個結構:

    • 前端(web)
    • 網頁伺服器(nginx)
    • 反向代理伺服器(middleware)
    • 後端(backend)
    • 資料庫(db)

    則這個專案就會有五種服務,這些 service 的描述會寫在一個大的 services 區塊內,這樣講可能有點抽象,所以接下來筆者要帶讀者們一步一步把 service 建起來吧!筆者會盡量用淺顯易懂的方式讓讀者可以了解 service 的寫法。

    首先要先定義這個 service 的名稱,這樣 Docker Compose 在建立這些 service 時才會知道要用什麼名稱來定義,寫法就像這樣:

    services:
      web:
        # write web settings
    

    如果有寫過 python 的讀者應該會覺得這種寫法應該跟 python 是蠻像的,用冒號跟縮排的方式來概括這個區塊要表達的事項,看了上面的寫法應該不難懂 service 的定義方式,其中的 web 就代表有一個 service 叫做 web,定義好 service 的名稱後接下來就要指定要這個 service 運行哪個 Docker image,寫法就像這樣:

    # image 來自 Dockerfile build
    web:
      build: ./front-end
    
    # image 來自 Docker Hub
    mysql:
      build: mysql:5.7
    

    定義好來源後接下來就要指定與外部對接的接口了,今天啟動這個 service 最重要的功能就是要能與其他的 service 甚至是外來的 request 進行溝通,如果沒有打開對應的接口這樣不管如何操作都沒辦法使用到這個 service,所以下一步很重要的步驟就是指定對外的接口,寫法就像這樣:

    # ports 寫法會是 "HOST:CONTAINER",其中 HOST 代表機器的接口,而 CONTAINER 代表的則是容器自身的對外接口
    ports:
      "80:80" # 這句話代表的是機器的 80 port 會對應到 container 的 80 port,所以只要 container 在啟動時有開放 80 port,就可以很順利的對應到機器對外的 80 port 了。
    
    # 假如只寫一個則代表 "CONTAINER"
    ports:
      "80"
    

    假如每個服務彼此之間有相依性才能啟動成功的話,Docker Compose 也可以很簡單的達到這個需求,舉例來說:一定要先把資料庫啟動才能讓後端連接到資料庫,這兩個服務彼此之間就有相依性的存在了,這個寫法也很簡單就像下面這樣:

    depends_on:
      - db # 這個寫法就代表這個服務要啟動前,db 這個服務一定要先啟動才可以。
    

    最後就要來講 container 的重啟了,Docker Compose 最重要的就是管理各 service 啟動後的 container,所以假如有 service 需要重啟當然也要有對應的重啟方式,這些也都可以利用 Docker Compose 進行設定,寫法就像這樣:

    # restart 有四種參數:"no"、always、on-failure、unless-stopped
    restart: always
    

    最後組合起來就會像這樣:

    最後再來講一個設定,相信大家在開發的時候很常使用到環境變數吧,像前端可能就會寫一個 .env 檔,然後搭配 process.env 的方式來取得環境變數的資料,但通常這些環境變數檔案是不會輕易擺在專案內的,畢竟就是因為這些資料很敏感所以才會寫成環境變數,這些其實也都可以利用 Docker Compose 的設定來完成,這邊以資料庫舉例寫法就像下面這樣:

    environment:
      MYSQL_DATABASE: 'mytestdb'
      MYSQL_USER: 'testuser'
      MYSQL_PASSWORD: 'password'
      MYSQL_ROOT_PASSWORD: 'password'
    
  • volumes

    volumes 的存在就是為了讓每次重啟 container 時都還可以引用到之前所存放的資料,相信在前面的 Dockerfile 練習時有發現每次將 container 停止後,再次啟動時會發現之前在裡面設定好的檔案都消失了,假如要能夠保存這些資料就必須要利用 volume 這個觀念,volumes 提供了一套讓 container 可以保存或共享資料的方法,而 Docker Compose 可以輕鬆地做到這點,所以這也是筆者沒有在前面的文章先提到這個觀念的關係。

    而 volumes 可以搭配寫在 service 區塊內的 volumes 就像下面這樣:

    services:
      db:
        image: db
        volumes:
          - data-volume:/var/lib/db
    
      volumes:
        data-volume:
    

    可以看到在 db 這個 service 內有一個 volumes,這個 volumes 拿到的 data-volume 這個檔案會映射到 image 內的 /var/lib/db 這個資料夾內,那這個 data-volume 哪來呢?就是透過最外面的 volumes 傳進來的,而最外層的 volumes 的 data-volume 則可以透過外部掛載的方式帶進來,上面聽起來有點像在繞口令,但可以想像成檔案掛載這種方式就是由外到內一層一層傳進去各個 service 內。

  • networks

    networks 主要在做的事情就是專案內各個 container 的溝通,沒有 network 的幫忙是沒辦法順利完成這個動作的,在 network 中會搭配一些 driver,常見的有:

    • bridge: 將各個服務建立一座可以互相溝通的橋樑。
    • overlay: 各 container 之間啟用 multi-host 通訊,可以想像成多個機器內的 container 彼此之間可以互相溝通。

    但其實每個 container 在沒有設定 network 前都會有一個 default network,這個 default network 就是 bridge,而 overlay 的 multi-host 通訊其實跟 Docker swarm 比較有關係,但是 Docker swarm 其實某種程度來說跟後續要介紹的 K8s 有點像所以這邊就不細討 network 的溝通方式了,這些都會在 K8s 的相關介紹中一一為讀者說明,接下來就簡單的演示一下 network 的寫法:

    networks:
      myNetwork:
        driver: bridge
    

最後要提一下一個重要的觀念,不管是 Dockerfile 還是 Docker Compose 都會用到映射這個觀念,而映射簡單來說就是把本地端的檔案丟給 Docker Container 內部使用。

Docker Compose 指令集

上面講完了 Docker Compose 的觀念以及寫法後,最後就要來提一下如何透過指令來建立這些 service 並且管理。

  • docker-compose build:建立由 Docker Compose 管理的 Docker image。

  • docker-compose up -d:建立並啟動由 Docker Compose 管理的 container,加上 -d 代表的是讓這些 container 運行在背景,只要打上 docker-compose up 都會讓這些 container 以及 image 重新被建立。

  • docker-compose stop:停止由 Docker Compose 管理的所有 container。

  • docker-compose start:啟動由 Docker Compose 管理的 container,與 docker-compose up -d 的差別在於,docker-compose start 只會執行已經存在但目前是暫停狀態的 container。

  • docker-compose restart:重新啟動由 Docker Compose 管理的 container。

  • docker-compose down:停止並刪除由 Docker Compose 管理的 container。

小結

這三天終於把 Docker 比較基礎的觀念跟用法都講完了,其實 Docker 能玩的東西非常多而且還有很多更進階的用法,像是 swarm 等等,但礙於鐵人賽的篇幅筆者就不一一細說了,而且剛剛提到的那些進階的 Docker 工具其實在接下來的 K8s 文章中都會提到,所以筆者這邊就只介紹比較基本的 Docker 觀念及用法而已。

如果對於文章有任何問題都歡迎留言,接下來就要進入本系列文最重要的重頭戲:K8s 的相關介紹了!


上一篇
Day03-開始使用Docker吧(DockerFile)
下一篇
Day05-Kubernetes 那些事 -基本觀念與操作
系列文
前端工程師學習 DevOps 之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言