在深入探討什麼是 Dockerfile 之前,讓我們先做一個小實驗。還記得我們上一節拉取的 Python 映像檔嗎?我們先用 docker run -it 指令進入容器。回想一下 -it 參數的作用——它會為容器配置一個虛擬 TTY,讓使用者可以與容器互動。進入容器後,列出當前目錄的所有檔案:
[root@novita ~]# docker run -it python:3.7 /bin/bash
root@692f87774bf7:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@692f87774bf7:/#
接下來,我們在容器內建立一個名為 hello.py 的檔案,然後再次列出所有檔案:
root@692f87774bf7:/# touch hello.py
root@692f87774bf7:/# ls
bin boot dev etc hello.py home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
可以看到 hello.py 已經建立。現在,退出容器,並再次使用 docker run -it python:3.7 /bin/bash 進入容器的互動模式,然後列出所有檔案:
root@692f87774bf7:/# exit
exit
[root@novita ~]# docker run -it python:3.7 /bin/bash
root@65c767655e8a:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@65c767655e8a:/#
你可能已經發現問題了。奇怪的是,我們剛才建立的檔案消失了。這是因為在容器內進行的操作並不會修改映像檔。容器只是在映像檔上添加了一個可寫入層,就像在字帖上放一張描圖紙——無論你在描圖紙上寫什麼,都不會影響到底層。這個特性有點類似於虛擬機快照。
但問題來了:如果容器內的操作不會修改映像檔,那麼我們如何在不重複某些操作的情況下實現快速部署呢?這樣效率太低。假設你是一個社群媒體平台的技術負責人,突然發生爆紅事件,需要快速擴充數百台雲端伺服器來處理大量用戶流量。你的團隊選擇了 Docker 來部署應用程式。如果採用上述方法部署,用戶可能會很失望。等到服務恢復時,他們可能已經離開了。
這時候就需要 Dockerfile 登場了。根據 Docker 的官方介紹:Docker 可以透過讀取 Dockerfile 中的指令自動建立映像檔。Dockerfile 是一個文字文件,包含使用者可以在命令列中呼叫的所有指令,用來組合映像檔。使用 docker build,使用者可以建立一個自動化建置流程,依序執行多個命令列指令。簡而言之,Dockerfile 是一個文字文件,包含從命令列建立映像檔所需的所有指令。它就像一組積木的組裝說明書,指導你如何將積木組裝成想要的映像檔。
讓我們用一個實際情境來探索如何建構 Dockerfile,這次以 Python 映像檔為例。在我的本機(容器外)有一個名為 Optimal_Hotel_Matching.py 的 Python 腳本,這是一個網頁爬蟲程式。我們嘗試在容器內執行它:果然出現錯誤,因為 Python 映像檔中沒有安裝 requests 這個第三方 HTTP 函式庫。這是一個典型的需要設定依賴環境的場景。我們嘗試用 Dockerfile 來解決這個問題。
在撰寫第一個 Dockerfile 之前,先熟悉一下一些常見的 Dockerfile 指令:
FROM:指定建置時所用的基底映像檔。MAINTAINER:描述映像檔的建立者姓名與電子郵件。RUN:Dockerfile 中最關鍵的指令之一。它會在容器中執行命令並提交結果。CMD:指定容器啟動時要執行的命令。COPY:將主機的檔案複製到容器內的檔案系統中。WORKDIR:設定後續RUN、CMD或ENTRYPOINT指令在 Dockerfile 中的工作目錄。
現在,我們來撰寫第一個 Dockerfile,以滿足我們的需求:安裝 requests 函式庫並執行腳本。以下是可能的解決方案:
FROM python:3.7 # 指定基底映像檔為 python:3.7
MAINTAINER ultra "tech@novita.ai" # 映像檔建立者名稱與電子郵件
RUN pip install requests # 安裝 requests 函式庫
WORKDIR /dockerfileTest # 設定工作目錄
COPY . . # 將當前目錄內容複製到容器中
CMD ["python", "Optimal_Hotel_Matching.py"] # 執行腳本的命令
將上述內容儲存在專案目錄中,檔案名稱為 Dockerfile。現在,使用 docker build 指令建立映像檔,並加上標籤以便識別:
[root@novita dockerfileTest]# docker build --tag python:requests .
Sending build context to Docker daemon 5.12 kB
...
建置完成後,使用 docker images 指令進行驗證:
[root@novita dockerfileTest]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
python requests 04f20acdc288 2 hours ago 926 MB
...
可以看到本機已經產生了一個標記為 requests 的新 Python 映像檔。嘗試執行這個映像檔,看看 No module named 'requests' 的錯誤是否消失,以及程式是否正常執行:
[root@novita dockerfileTest]# docker run python:requests
Computing distance between 116.368816,39.866464 and 116.438946,39.921624
Computing distance between 116.370910,39.869603 and 116.438946,39.921624
...
成功了!容器執行了程式碼並正常結束。
這樣就結束了嗎?在這篇文章中,我分享了 Dockerfile 的一個簡單應用。在實際的企業級生產環境中,Dockerfile 往往更為複雜。
Novita AI 是滿足您 AI 抱負的全方位雲端平台。透過無縫整合的 API、無伺服器運算和 GPU 加速,我們提供經濟高效的工具,協助您快速建置和擴展 AI 驅動的業務。告別基礎架構的困擾,立即免費開始 — Novita AI 讓您的 AI 夢想成真。
推薦閱讀:
