本篇文章介紹使用 Docker 打包軟體,參考官方文件

Dockerfile

Docker 藉由讀取 Dockerfile 裡面的指令建立 images。Dockerfile 是一個「文字檔」,使用特定的指令,將應用程式組裝在 container 中。
Dockerfile 的規範格是可以參考 Docker Reference

底下提供一些常見指令:

Instruction Description
FROM <image> 作為基礎的 Docker image
RUN <command> 在當前的 image 之上,添加一個 layer 並在之中執行命令,RUN 通常使用 shell form 格式運行
WORKDIR <directory> 設定工作路徑給任何指令,例如: RUNCMDENTRYPOINTCOPYADD
COPY <src> <dest> 複製檔案或目錄,從主機的 <src> 位置,複製到 container 的 <dest> 位置
CMD <command> 使用 image 啟動 container 時,預設的執行方式,每個 Dockerfile 只會有一個 CMD,當有多個存在時只有最後一個有效

在建立 image 時,Dockerfile 是非常重要的檔案,且非常方便自動化建立。
預設的 Dockerfile 檔案名稱是 Dockerfile,不帶有任何副檔名。使用預設名稱能夠不使用額外參數執行 docker build
如果需要獨特的 Dockerfile 名稱,慣例名稱是 <something>.Dockerfile
在使用 docker build 可以使用 --file 選項來選擇非預設檔案名稱的 Dockerfile

Example

Flask sample code

建立一個 Python Flask 應用程式,裡面包含檔案 hello.py,內容如下

1
2
3
4
5
6
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
return "Hello World!"

Dockerfile sample code

建立一個 Dockerfile 檔案,檔案名稱是 Dockerfile,內容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# syntax=docker/dockerfile:1
FROM ubuntu:22.04

# install app dependencies
RUN apt-get update && apt-get install -y python3 python3-pip
RUN pip install flask==2.1.*

# install app
COPY hello.py /

# final configuration
ENV FLASK_APP=hello
EXPOSE 8000
CMD flask run --host 0.0.0.0 --port 8000

第一行 Parser directives

第一行的 # syntax 是 Parser directives,用來告訴 Parser 要什麼語法解析這個檔案
Parser directives 必須出現在第一行,前面不包含任何指令、註解或空白

官方推薦使用 docker/dockerfile:1,他代表使用第一版本的最新 Releases。

1
# syntax=docker/dockerfile:1

第二行 FROM

這行代表使用 ubuntu 22.04 版本作為基底的 image。ubuntu:22:04 的符號代表 name:tag,可以使用符號選擇特定的版本
預設會到 Docker Hub 下載這個公開的 image

1
FROM ubuntu:22.04

第五行 RUN

這個 RUN 指令執行 shell command

在這個範例中,我們的 Context 是整個 Ubuntu 作業系統,所以我們可以使用套件管理工具 apt
指令中更新 apt,並下載 python3 和 python3-pip 套件
而指令 # install app dependencies 只是代表一行註解,使用 # 作為起始標頭,可以用註解紀錄 dockerfile 的工作流程

1
2
# install app dependencies
RUN apt-get update && apt-get install -y python3 python3-pip

第六行 RUN

第二個 RUN 指令使用上一層安裝的 pip 套件安裝 flask 網站框架。

1
RUN pip install flask==2.1.*

第九行 COPY

COPY 指令複製本機的 hello.py 到 image 的根目錄之中。
執行這個指令後,我們可以在 image 使用 /hello.py 找到該檔案

1
COPY hello.py /

第十二行 ENV

ENV 指令是設定 Linux 環境變數,FLASK_APP 是 flask 需要的變數,缺少這個設定會讓 flask 不知道哪裡找 hello.py

1
ENV FLASK_APP=hello

第十三行 EXPOSE

EXPOSE 指令指出這個服務會監聽 8000 port,這不是必需的步驟,但這個步驟可以讓使用者了解這個 image 所做的事

1
EXPOSE 8000

第十四行 CMD

CMD 指令設定使用者啟動 image 成為 container 要執行的指令。在範例中是執行 flask 監聽 8000 port

1
CMD flask run --host 0.0.0.0 --port 8000

Testing

用剛才編寫的 dockerfile,建立 image。-t test:latest 這個選項是設定 image 的名稱 (required) 和標籤 (optional)
. 代表使用當前目錄建立 Context。範例中,當前位置是 Dockerfile 的位置,也是所需檔案 (hello.py) 的當前位置
注意: 避免使用 / 建立 Context,他可能造成將所有根目錄的檔案都放在裡面

1
docker build -t test:latest .

現在可以執行你剛建立的 image

1
docker run -p 8000:8000 test:latest

並且使用瀏覽器開啟 http://localhost:8000