繼承擴充 Dockerfile 的另一種方法 — Dockerfile+
Last updated on Nov 15, 2024 by Amo Chen ‐ 3 min read
在軟體開發實務中,經常需要為不同環境撰寫不同的 Dockerfile,例如,本地開發環境通常需要啟用自動偵測程式碼變動並自動重新載入的功能 (通常稱為 reload 功能),而生產環境則不需要這類自動重新載入的機制。
有些人可能會使用 multi-stage build 的方式,從共用的 base image 繼承並擴充。不過,本文將介紹另一種方法,使用 Dockerfile+做到 Dockerfile 的繼承與擴充。
本文環境
- macOS
- OrbStack Version 1.7.5
Dockerfile+ 簡介
Dockerfile+ 是一個針對 Docker 語法進行擴充的開源專案,旨在解決 Dockerfile 語法的局限性,提供更靈活的撰寫方式。雖然最初的目標是增強 Dockerfile 的彈性,但目前該專案只推出了 INCLUDE+
語法(即便如此,也增加很多方便性),這一功能允許在 Dockerfile 中包含其他文件 Dockerfile 的內容,為 Dockerfile 的管理提供了新的可能性。
INCLUDE+ 語法與範例
先看範例,可以直接理解 INCLUDE+
可以達到的目的。
以下是本文專案資料夾的結構,僅以 3 個檔案作為示範:
.
├── Dockerfile
├── Dockerfile.local
└── app.py
app.py
的內容如下,僅是 1 個簡單的 Flask app:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
接著講解重點。
在專案資料夾中的 Dockerfile
中,定義了將 app.py
編譯成 Docker Image 的相關步驟,它使用 gunicorn 介接使用 Flask開發的 HTTP 伺服器,是一種適合 production 環境的作法:
Dockerfile
FROM python:3.13-slim
WORKDIR /app
RUN pip install gunicorn flask
COPY app.py /app
EXPOSE 5000
CMD ["gunicorn", "app:app", "-b", "0.0.0.0:5000"]
不過,上述做法並不適合開發環境,因為開發時我們經常需要更改程式碼。
如果每次更動程式碼都需要重新編譯、啟動容器(container),將會對開發效率大打折扣,所以開發環境通常都會開啟除錯模式(debug mode)或者 auto-reload 等功能,讓程式碼變更立即生效。
所以較好的辦法是提供一個專門給開發環境使用的 Dockerfile。
我們可以使用 INCLUDE+
語法,在基於 production ready 的 Dockerfile 上做出繼承效果。以下是使用 INCLUDE+
語法的範例,該範例可以看到 Dockerfile.local
引入 Dockerfile
的內容後,新增一組 CMD
指令,覆寫原本的 CMD
指令,使得 Dockerfile.local
能夠使用除錯模式,有利於本地端進行開發,同時也不影響原本 Dockerfile
的內容:
Dockerfile.local
# syntax = edrevo/dockerfile-plus
INCLUDE+ Dockerfile
CMD ["flask", "--app", "app", "--debug", "run", "--host=0.0.0.0"]
p.s. # syntax = edrevo/dockerfile-plus
是使用 INCLUDE+
時必須的語法,並非註解
實際使用情境
有了 INCLUDE+
之後,如果需要建立開發環境,只要輸入類似以下的 docker 指令進行編譯,就能夠有開發環境專用的 image 可以使用:
$ docker build -t app-local -f Dockerfile.local .
再來,我們可以使用 -v
參數,將含有程式碼的資料夾掛載(mount)到 docker 容器內:
$ docker run -it -v $(pwd):/app app-local
接著就可以直接修改程式碼,並且看到 docker 容器內顯示 reloading
的字樣,反應程式碼的變更,例如本文範例的執行結果:
* Serving Flask app 'app'
* Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://192.168.215.2:5000
Press CTRL+C to quit
* Restarting with stat
* Debugger is active!
* Debugger PIN: 210-435-178
* Detected change in '/app/app.py', reloading
* Restarting with stat
* Debugger is active!
* Debugger PIN: 210-435-178
總結
這就是方便的 INCLUDE+
語法擴充介紹!
總結來說,INCLUDE+
相當適合只需要微調 CMD
或 RUN
的情況,如果要微調的部分很多或是用上一些 INCLUDE+
不支援的語法的情況時,建議還是使用 multi-stage builds,讓不同的 docker image 基於同一份 base docker image 進行擴充較為合適。
以上!
Enjoy!
References
edrevo/dockerfile-plus: New commands for Dockerfile