這篇網誌中,我們會從無到有逐步建立一份客製映像檔,內容包括:Docker 安裝與配置、基礎映像檔下載、撰寫 Dockerfile,再透過 docker build
建立成映像檔,最後將映像檔上傳至倉庫。
這篇算是 〈WSL|在 WSL2 中安装 Docker〉的前篇?原本是要寫給客戶的教學文件,不過我覺得拿出來當網誌好像也還行?所以就稍微擴寫、改述並刪除了些會被我主管請去喝茶東西,看來應該還能騙到一篇!?
Docker 三元素:Dockerfile、Docker 映像檔以及 Docker 容器(圖片來源: Platformer — A WSO2 Company|Medium)
Step1|Docker 環境確認
既然是客製化 Docker 映像檔,當然得先裝有 Docker 啦!可以先確定版號的指令,來確認開發環境是否安裝有 Docker:
1 |
|
若果正確安裝的話,應該看到相關 Client 與 Server 的版號資訊,類似這樣:
1 |
|
否則會得到 docker 指令不存在的錯誤訊息:
1 |
|
如果已經安裝的話,可以直接跳到 1-2 章節來確認服務是否啟動;若是沒有安裝的話,就跟我一起來裝 Docker 吧!
Step1-1|安裝 Docker
我的開發環境是 Ubuntu 20.04 ,裡面已經有安裝 Docker 了,但我發現 Docker 似乎有新版本,所以打算順便升級 Docker 來玩玩。
在這邊我先移除了舊版的的相關套件,再用設置 Docker 的儲存庫(Repository) 的方式來安裝。這種安裝法會方便於安裝與升級,這也是 Docker 官方推薦的安裝方式。
- 移除舊版 Docker
1
sudo apt-get remove docker docker-engine docker.io containerd runc
- 設置 Docker 的儲存庫
相比以前一行安裝 docker.io,新的版本的多了許多的前置步驟:- 更新 apt-get 索引,並安裝用 HTTPS 傳輸的套件以及 CA 證書
1
2
3
4
5
6$ sudo apt-get update $ sudo apt-get install \ ca-certificates \ curl \ gnupg \ lsb-release
- 添加 Docker 的官方 GPG key
1
2
3$ sudo mkdir -p /etc/apt/keyrings $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg $ sudo chmod a+r /etc/apt/keyrings/docker.gpg
- 然後,我們需要向 sources.list 中添加 Docker 儲存庫
1
2
3$ echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
- 更新 apt-get 索引,並安裝用 HTTPS 傳輸的套件以及 CA 證書
- 安裝 Docker Engine
最後再次更新 apt-get 索引,並才能安裝最新版本的 Docker Engine、containerd 和 Docker Compose。1
2$ sudo apt-get update $ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Step1-2|確認服務是否啟動
安裝完成後,查看一下 Docker 服務是否有正常啟動:
1 |
|
或是
1 |
|
如果正常啟動的話,可以看到綠色的 active 狀態:
正常啟動會顯示綠色的 active
若是未啟動,則啟動 service:
1 |
|
或是
1 |
|
最後,確認是否能夠下載測試映像檔並在容器中運行它:
1 |
|
若是成功執行會印出 Hello from Docker
的訊息並關閉容器:
Hello from Docker~
Step1-3|以非 root 身份管理 Docker
在一般情況下,docker
指令需要 root 權限,其他使用者則必須使用 sudo
才能操作 docker
指令。因此如果不想每次都得在 docker
指令前加上 sudo
,就得將使用者添加一個名為 docker 的群組中。
首先先建立一個名為 docker 的群組,並將使用者添加到其中。當 Docker 守護進程啟動時,它會建立一個可供 docker 群組成員訪問的 Unix domain socket。
1 |
|
更新使用者群組並重啟 docker:
1 |
|
最後,試試看可不可以在沒有 sudo
下執行 docker:
1 |
|
Step2|下載基礎映像檔
若要客製自己的映像檔時,我們必須先選定一個基礎映像檔(Base Image),再依此映像檔,加入所需開發套件和功能,層層堆疊逐步形成特定用途的客製映像檔。
該基礎映像檔的來源,可以是任何公開的映像檔倉庫(Public Image Registry),如 Docker Hub 或是 NVIDIA NGC,裡面存放了數量龐大的映像檔可供使用者下載;當然,也可以是自己或是組織建置的私有倉庫(Private)。
Step2-1|從公開倉庫取得映像檔
從公開倉庫取得映像檔是較常見的方式,通常無須額外權限與設定,就可直接使用下載指令。
以下載 Jupyter Notebook 為例,我們從先在 Docker Hub 上確認所要下載的映像檔與標籤後,就直接使用指令將映像檔下載到本地端。
1 |
|
下載完成後會出現摘要與狀態提示下載成功:
提示下載成功
Step2-2|從私人倉庫取得映像檔
若要從私有倉庫取得映像檔,則必須先登入該倉庫。
1 |
|
docker login
可以登入到指定倉庫,如果未指定倉庫位址,則會預設登入官方的公開倉庫 Docker Hub。
完成登入後,後續的操作可能會與公開倉庫取的存取步驟有所差異,但整體流程差不多:
- 確認所要下載的映像檔與標籤
- 使用指令將映像檔下載到本地端
Step3|撰寫 Dockerfile
挑選完基礎映像檔後,就可根據自身需求撰寫 Dockerfile 加入所需套件和功能。
在撰寫 Dockerfile 時,是以 FROM 指令為開頭,往下根據每一行定義會製作出的一個唯讀資料層,當啟動執行成容器時,才會再疊上寫入層。因此建議撰寫時盡可能刪除每層不必要的資料,以降低映像檔大小。
我這邊就以剛剛從取得映像檔為基礎,向上安裝了 h5py、 pandas 與 gensim…等 Python 套件,以提供一個簡單的 Dockerfile 範例,方便後續說明的進行。
想要詳細了解如何撰寫 Dockerfile 的話,還是建議去看看官方文件 - 〈Best practices for writing Dockerfiles〉,絕對不是因為我不想寫文件了 XDDD
1 |
|
撰寫完成後,將其進行存檔並命名為 Dockerfile
。
Step4|建立映像檔
完成 Dockerfile 的撰寫後,就可以用 docker build
的指令將映像檔建立起來。
1 |
|
其中,-t
是為映像檔進行命名 demo-push
為倉庫與映像檔名稱、 v1
則是標籤,請依照習慣自行命名。指令執行時,它會找尋目前資料夾中名為 Dockerfile 的建置文件;但如果你的建置文件並非取名為 Dockerfile,這時需要在指令中加上 -f
指定建置文件:
1 |
|
如果需要更多關於 docker build 的介紹,請閱讀 Docker 官方文件。
當建立成功後可在終端機上看到下列訊息:
1 |
|
它並不是用於指定 Dockerfile 文件所在的位置的!
它並不是用於指定 Dockerfile 文件所在的位置的!
重點說三次!在這邊
.
確實是用來表示目前目錄,但卻不是用在指定 Dockerfile 所在路徑,因為那是 -f
的守備範圍!那麼指定這目錄的目的?這與 Docker 的運行架構有關:
Docker daemon 與 client 的交互運作(圖片來源: iT 邦幫忙)
在 Docker 的運行架構中,存在 Docker Daemon(服務端守護進程)和 Client 兩個部分。Docker Daemon 會提供一組名為 Docker Remote API 的 REST API;而 Client 的代表就是我們常用的指令,指令則會透過 Docker Remote API 與 Docker Daemon 互動,從而完成各種功能。簡而言之, Docker 的運行架構就是個標準的 C/S 架構。
那麼這邊又產生了一個問題,如果在建構映像檔時有涉及
COPY
、 ADD
...等操作文件的指令時,因為並非在本地建構,而是在服務端建構的,那麼在 C/S 架構中, Docker Daemon 該如何獲得本地檔案?這邊就有一個 映像檔建構上下文(Context)的概念。當建構的時候,使用者會指定建構映像檔上下文的路徑,而 docker build 指令再得知這路徑後,會將這路徑下的所有內容打包上傳給 Docker Daemon。而 Docker Daemon 在收到打包的內容後,會將它展開就能獲得建構映像檔所需的一切檔案。
那回到一開始的問題 docker build 命令後點號(.)的意思,指得就是將目前的目錄下的所有內容打包上傳給 Docker Daemon。
Step5|上傳映像檔
當成功建構映像檔後,若要將它發布出去,可以將其上傳至 Docker Hub。
Docker Hub Icon
Step5-1|註冊與登入
雖先前從 Docker Hub 下載映像檔到本地端時,並不需要登入即可下載;但若要上傳映像檔必須完成登入:
1 |
|
如果沒有帳號則必須先前往官網註冊。
Step5-2|創建儲存庫(Create Repository)
Create Repository
如果沒有現有的儲存庫,可藉由 UI 的填寫建立一個新的儲存庫:
填寫資料建立儲存庫
在建立完成後可以得到一個 push 的指令,其中 tagname 需換成自定義的標籤,我們這邊使用 v1:
1 |
|
Step5-3|本地端映像檔重命名
在上一步驟可以發現從倉庫取得的指令中,其:
- 倉庫與映像檔名稱:
{DockerHub UserName}/{ImageName}
- 倉庫路徑(RegistryURL):
cynthia
- 映像檔名稱(ImageName):
demo-push
- 倉庫路徑(RegistryURL):
- 標籤:
v1
若此時直接使用指令上傳,會得到映像檔不存在錯誤。
1 |
|
這是因為剛剛在建立映像檔時,所使用的倉庫與映像檔名稱為 demo-push
,而非 cynthia/demo-push
,因此需要先重命名:
1 |
|
Step5-4|上傳至倉庫
重新命名後,再使用上傳指令進行上傳:
1 |
|
上傳完成後,在終端機與平台上都可以看到相對應的提示:
參考資料
- Install Docker Engine on Ubuntu。檢自 Docker Documentation (2022-07-13)。
- Xu Sheng (2018-03-09)。docker build命令后 . 号的意思。檢自 XuSheng’s Blog (2022-07-13)。
- Baohua Yang (2022-05-12)。使用 Dockerfile 定制镜像。檢自 Docker 从入门到实践 (2022-07-13)。
更新紀錄
最後更新日期:2022-10-15
- 2022-10-15 發布
- 2022-08-09 完稿
- 2022-07-13 起稿