兩個初學者最容易卡關的概念

Dockerfile 與 Docker Compose 是 Docker 兩個最重要的概念,也是初學者最容易卡關的地方,本文以 使用需求 為觀點解釋這兩者的差異。

Image 與 Container


在解釋 Dockerfile 與 Docker Compose 之前,先複習兩個更基礎的概念:

Image


將 Service 打包成 image,通常會從 Docker Hub 下載官方的 image 使用,也可以根據官方的 image 再包成自己的 image,或者完全自行製作自己的 image。

Container


Image 類似 template,基於壓好的 image 產生隔離的執行環境,稱之為 container。

一般會以 Microservice 方式使用 container,也就是會同時啟動多個 container 形成 service。

Image 與 container 都會佔硬碟空間,尤其 container 若執行完畢後,雖然 container 從記憶體釋放,但在硬碟仍然會留一份 container 的 屍體 ,需要自行刪除,或者在 docker run 時增加 --rm 參數,在執行完自行從硬碟刪除 container

Dockerfile


實務上我們會從 Docker Hub 下載官方的 Docker Image 使用,但官方的 image 功能可能過於陽春,我們可能想根據自己的需求,再安裝其他的 app,最後再打包成自己的 Docker image。

在傳統 VM 時代,要打造自己的 image,必須用 export 方式,但這樣有幾個缺點:

  • Image 可能非常龐大
  • 安裝步驟無法進 git 版控

Docker 以 Infrastructure as Code 概念,將 infrastructure 以 code 形式描述:

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
FROM ubuntu:latest

# Install Linux library dependency
RUN apt-get update
RUN apt-get install -y wget apt-transport-https gpg

# Install microsoft.gpg
RUN wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.asc.gpg
RUN mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/
RUN wget -q https://packages.microsoft.com/config/ubuntu/18.04/prod.list
RUN mv prod.list /etc/apt/sources.list.d/microsoft-prod.list
RUN chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg
RUN chown root:root /etc/apt/sources.list.d/microsoft-prod.list

# Install .NET Core SDK
RUN apt-get update
RUN apt-get install -y dotnet-sdk-2.1

# Display Greeting
CMD [ "echo", "Ubuntu 18.04 LTS with .NET Core 2.1"]

以上為典型的 Dockerfile,只需一個文字檔,就清楚描述一個 Docker image。

以前若要在 Ubuntu 安裝其他 dependency,只能透過 Bash 安裝一堆 package,最後再 export 成 image,但 image 可能很龐大,且安裝步驟也無法 git 版控。

但透過 Dockerfile 之後,整個新的 Ubuntu 都是以 code 形式描述,你只要將 Dockerfile 給其他人,對方只要使用 docker build 就能自行根據 Dockerfile 建立 Docker image,最後再根據 docker run 執行客製化過的 Ubuntu container。

  • Dockerfile 檔案很小,只是文字檔而已
  • 由於 Dockerfile 是文字檔,可以 git 版控

簡單的說,Dockerfile 就是描述如何產生客製化的 image,只是採用 code 形式描述

Docker Compose


實務上一個服務,一定由眾多 service 共同運作。如一個典型的 Web 服務,最少就必須有

.NET Core Runtime + Nginx + Redis + PosgreSQL

4 個 service 一起運行,若只使用 docker run,則勢必寫 Bash 來管理 4 個 service,還必須考慮:

  • 4 個 service 必須在同一個虛擬 network 下
  • 4 個 service 的啟動順序

… 等問題。

Docker 為此提出 Docker Compose 概念,在 docker-compose.yml 檔描述各 service 間的參數與關係:

docker-compose.yml

1
version: "3"

services:
  netcore:
    image: microsoft/dotnet
    container_name: MyNETCore
    volumes:
      - ${NETCORE_HOST_DIR}:/code/
    tty: true
    networks: 
      - netcore-dev
    depends_on:
      - postgres

  postgres:
    image: postgres
    container_name: MyPostgres
    volumes:
      - ${POSTGRES_HOST_DIR}/data:/var/lib/postgresql/data
    expose:
      - "5432"
    ports:
      - "${POSTGRES_PORT}:5432"
    environment:
      - POSTGRES_DB=${POSTGRES_DB}
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    networks:
      - netcore-dev

networks:
  netcore-dev:

以上為典型的 docker-compose.yml,只需一個文字檔,就清楚描述 .NET Core Runtime 與 PostgreSQL 兩個 service,將 docker-compose.yml 拿到任何裝有 Docker 的電腦,都成重現 .NET Core + PostreSQL 的環境,也就是 Infrastructure as Code

  • docker-compose.yml 檔案很小,只是文字檔而已
  • 由於 docker-compose.yml 是文字檔,可以 git 版控

間單的說,docker-compose.yml 就是 container 的管理文件,只是採用 code 形式描述

FAQ


Q:Dockerfiledocker-compose.yml 看起來很像,都是在描述 server,有什麼差別呢 ?

  • Dockerfile 是用來描述 image,也就是如何產生客製化的 image,通常用來安裝 package,將檔案複製進 image 用
  • docker-compose.yml 是用來描述 container,也就是管理一個以上的 container,彼此串連,把同一組架構寫在一起,通常用來設定 container 參數,設定 container 的網路,設定 container 啟動順序或 service 的環境變數 … 等

Q:Dockerfile 是用來描述 image,docker-compose.yml 是用來描述 container,但若我們還有客製化的 邏輯 該怎麼辦 ?

若在使用 Dockerfiledocker-compose.yml 時,還必須搭配額外的 if elsefor loop 邏輯,就必須再搭配 Bash。

Dockerfiledocker-composer.yml 只是設計用來描述 infrastructure,並不是描述 邏輯

Q:單一 service 也適用 docker-compose.yml 嗎 ?

由於實務上,儘管是單一 service,如只為了使用 PostgreSQL,也必須在 docker run 搭配一堆參數,但人的腦容量有限,很難記住所有的參數,與其寫在 Bash,建議寫在 docker-compose.yml ,統一由 docker-compose 管理。

Conclusion


  • Dockerfile 用來描述 image;而 docker-compose.yml 用來描述 container
  • Dockerfiledocker-compose.yml 還無法達到客製化的需求,就必須搭配 Bash
  • Dockerfiledocker-compose.yml 都是文字檔,因此檔案很小,也容易 git 版控,實現 Infrastructur as Code 理想。
  • 儘管只有一個 container,也建議使用 docker-compose.yml
2018-06-05