繼承擴充 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+ 相當適合只需要微調 CMDRUN 的情況,如果要微調的部分很多或是用上一些 INCLUDE+ 不支援的語法的情況時,建議還是使用 multi-stage builds,讓不同的 docker image 基於同一份 base docker image 進行擴充較為合適。

以上!

Enjoy!

References

edrevo/dockerfile-plus: New commands for Dockerfile

對抗久坐職業傷害

研究指出每天增加 2 小時坐著的時間,會增加大腸癌、心臟疾病、肺癌的風險,也造成肩頸、腰背疼痛等常見問題。

然而對抗這些問題,卻只需要工作時定期休息跟伸展身體即可!

你想輕鬆改變現狀嗎?試試看我們的 PomodoRoll 番茄鐘吧! PomodoRoll 番茄鐘會根據你所設定的專注時間,定期建議你 1 項辦公族適用的伸展運動,幫助你打敗久坐所帶來的傷害!

贊助我們的創作

看完這篇文章了嗎? 休息一下,喝杯咖啡吧!

如果你覺得 MyApollo 有讓你獲得實用的資訊,希望能看到更多的技術分享,邀請你贊助我們一杯咖啡,讓我們有更多的動力與精力繼續提供高品質的文章,感謝你的支持!