如何為初學者編寫 Dockerfile

如何為初學者編寫 Dockerfile

在深入探討什麼是 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:設定後續 RUNCMDENTRYPOINT 指令在 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 夢想成真。

推薦閱讀:

  1. 開發 ESRGAN 4x 升級工具的最終指南
  2. 掌握 Stable Diffusion LoRA:成功策略