Docker Engine 作為容器技術的核心,扮演著容器建立、執行和管理的重要角色。理解 Docker Engine 的運作機制對於有效運用容器技術至關重要。本文從 Docker 工作站的安裝與組態開始,逐步引導讀者瞭解 Docker 的核心概念,包含映像檔的提取與執行、容器的互動式操作、容器生命週期管理等。接著,文章探討 Dockerfile 的撰寫技巧與最佳實踐,包含基礎映像檔的選擇、多階段建置、映像檔層級的最佳化等,以提升建置效率和安全性。最後,文章簡要概述了 Docker 在雲原生應用、微服務架構和 DevOps 實踐等領域的應用前景。
深入理解 Docker Engine 的工作原理,首先需要掌握 Docker 的核心元件:docker、docker-machine 和 docker-compose。透過 docker info 命令可以驗證 Docker 安裝狀態並檢視系統資訊。接著,提取 alpine 映像檔,並使用 docker run 命令啟動一個互動式 Shell,體驗容器化的操作環境。docker ps -a 命令則可以檢視所有容器的狀態,包含已停止的容器。hello-world 範例清晰地展示了 Docker 客戶端、守護程式、映像檔倉函式庫和容器之間的互動流程。更進一步地,Dockerfile 提供了定義映像檔的標準化方法,其指令集涵蓋了映像檔建置的各個環節,從基礎映像檔的選擇、軟體套件的安裝、檔案的複製到啟動命令的設定。遵循 Dockerfile 的最佳實踐,例如使用 .dockerignore 檔案、最小化層級數量和保持容器的單一關注點,可以最佳化映像檔大小、提升建置效率並增強安全性。
Docker Engine 深度解析與實務操作
Docker Engine 是 Docker 技術的核心,負責容器的建立、執行和管理。本章將探討 Docker Engine 的工作原理,並透過實際操作示範其強大的功能。
Docker 工作站安裝與組態
Docker 是一項快速發展的技術,因此建議參考 Docker 官方的最新安裝進行安裝。基礎安裝包含核心技術:docker、docker-machine 和 docker-compose。
驗證 Docker 安裝
執行 docker 命令可檢視使用說明。若對可用命令或引數有疑問,可嘗試在無引數的情況下執行該命令(見清單 4-1)。
清單 4-1. 顯示 Docker 使用說明
$ docker
Usage: docker COMMAND
A self-sufficient runtime for containers
...
使用 docker info 命令可顯示系統範圍的資訊(清單 4-2),這也是驗證 Docker 安裝是否正常的簡便方法。
清單 4-2. 顯示 Docker 系統資訊
$ docker info
Containers: 12
Running: 2
Paused: 0
Stopped: 10
Images: 23
Server Version: 17.06.0-ce
...
取得與執行 Alpine Docker 映像檔
在清單 4-3 中,我們提取了最小的 Docker 映像檔 alpine 到本地映像檔集合中。alpine 根據 Alpine Linux,具有完整的套件索引,大小僅為 5MB,是構建最小映像檔的優秀起點。
清單 4-3. 提取 alpine Docker 映像檔
$ docker pull alpine
Using default tag: latest
latest: Pulling from library/alpine
0a8490d0dfd3: Pull complete
Digest: sha256:dfbd4a3a8ebca874ebd2474f044a0b33600d4523d03b0df76e5c5986cb02d7e8
Status: Downloaded newer image for alpine:latest
執行互動式 Shell
可透過 run 命令執行已下載的 alpine 映像檔的互動式 Shell(見清單 4-4)。按 Ctrl+D 可終止 Shell 程式並傳回主機系統。
清單 4-4. 執行互動式 Shell 至 alpine 容器
$ docker run -it alpine /bin/sh
/ # ls
bin etc lib mnt root sbin sys usr
dev home media proc run srv tmp var
/ # whoami
root
/ # ps
PID USER TIME COMMAND
1 root 0:00 /bin/sh
7 root 0:00 ps
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /bin/sh
8 root 0:00 ps aux
#### 內容解密:
-
docker run -it alpine /bin/sh:執行alpine映像檔並啟動互動式 Shell。-i:啟動互動式容器。-t:分配虛擬終端。/bin/sh:在容器中執行的命令。
-
ls:列出根目錄下的檔案和目錄。 -
whoami:顯示當前使用者身份。 -
ps和ps aux:顯示當前 Shell 的程式和所有程式。
理解 Docker 容器與映像檔
執行 alpine 映像檔時,Docker Engine 會建立一個臨時層疊加在映像檔上,形成一個可互動的容器。容器終止後,底層映像檔保持不變,而讀寫層與容器繫結。
檢視所有容器
使用 docker ps -a 可檢視所有容器,包括已離開的容器(清單 4-5)。
清單 4-5. 顯示所有 Docker 程式
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b04dfee8fc1c alpine "/bin/sh" 49 minutes ago Exited ... clever_khorana
#### 內容解密:
docker ps -a:列出所有容器,包括執行中和已停止的。-a:顯示所有容器,而不僅是執行中的容器。
Hello World 示例
使用 docker run hello-world 可執行 hello-world 映像檔(清單 4-9)。該命令展示了 Docker 的基本工作原理,包括客戶端與守護程式的互動、映像檔提取和容器建立。
清單 4-9. 執行 hello-world 映像檔
$ docker run hello-world
Hello from Docker.
This message shows that your installation appears to be working correctly.
...
#### 內容解密:
docker run hello-world:執行hello-world映像檔。- Docker 使用者端聯絡 Docker 守護程式。
- Docker 守護程式從 Docker Hub 提取
hello-world映像檔。 - Docker 守護程式建立一個新容器並執行輸出訊息。
- 輸出結果被傳回使用者端並顯示在終端上。
隨著容器技術的不斷發展,Docker Engine 將繼續演進,提供更強大的功能和更好的效能。未來,我們可以期待在更多領域看到 Docker 的應用,如雲原生應用、微服務架構和 DevOps 實踐等。
Docker 工作流程
graph LR;
A[客戶端] -->|傳送指令|> B[Docker守護程式];
B -->|提取映像檔|> C[Docker Hub];
B -->|建立容器|> D[容器執行環境];
D -->|執行應用程式|> E[輸出結果];
E -->|傳回結果|> A;
圖表翻譯:
此圖展示了Docker的工作流程:
- 客戶端傳送指令給Docker守護程式。
- Docker守護程式負責提取映像檔從Docker Hub。
- 建立容器並在容器執行環境中執行應用程式。
- 輸出結果並將結果傳回給客戶端。
結語
透過本章的學習,我們對 Docker Engine 有了更深入的理解。掌握 Docker 的基本操作和原理,將有助於我們在實際工作中更好地應用這項技術,提升開發效率和佈署靈活性。未來,我們將繼續探索 Docker 在更多場景下的應用和實踐。
第5章:Dockerfile 詳解
Docker 映像檔是由一系列層(layers)堆積疊而成,每一層代表著對映像檔的基本、無狀態的變更。第一層可能是虛擬機器的作業系統(例如 Debian 或 Ubuntu 的 Docker 映像檔),接下來是安裝應用程式所需的依賴套件,最後則是應用程式的原始碼。利用 Dockerfile 是利用這個系統的最佳方式。
Dockerfile 最佳實踐
Dockerfile 是一種指令碼,用於自動化建置 Docker 映像檔。這個指令碼使用了一種特定領域的語言,告訴 Docker 守護行程(daemon)如何逐步建置一個 Docker 映像檔。當守護行程被指示建置映像檔時,它會按照 Dockerfile 中的指示進行建置。
Docker 在建立 Dockerfile 時,建議遵循以下最佳實踐:
- 容器應該是短暫的或無狀態的,能夠以最少的設定和組態重新例項化。
- 使用
.dockerignore檔案,類別似於.gitignore。 - 避免安裝不必要的套件。
- 每個容器應該只負責一個任務。
- 最小化層的數量。
- 對多行引數進行排序。
無狀態容器
現代軟體開發的最佳實踐之一是,將軟體設計為彼此獨立的程式,不分享任何資源,這種架構通常被稱為微服務1。雖然一個應用程式可能同時執行多個程式,但這些程式應該是無狀態的。如果需要在程式終止後保留任何資訊,應將這些資訊寫入有狀態的後端服務中,例如資料函式庫(如 MongoDB 或 Postgres)或鍵值儲存(如 Redis)。
Dockerfile 基本結構
Dockerfile 由一系列指令組成,每個指令都會建立一個新的層。以下是一些常見的 Dockerfile 指令:
# 使用官方的 Python 映像檔作為基礎
FROM python:3.9-slim
# 設定工作目錄
WORKDIR /app
# 複製 requirements.txt 檔案到工作目錄
COPY requirements.txt .
# 安裝依賴套件
RUN pip install --no-cache-dir -r requirements.txt
# 複製應用程式碼到工作目錄
COPY . .
# 設定環境變數
ENV NAME World
# 執行應用程式
CMD ["python", "app.py"]
內容解密:
FROM指令用於指定基礎映像檔,本例中使用的是官方的 Python 3.9 映像檔。WORKDIR指令用於設定工作目錄,本例中設定為/app。COPY指令用於複製檔案到容器中,本例中先複製requirements.txt,然後複製應用程式碼。RUN指令用於執行命令,本例中用於安裝依賴套件。ENV指令用於設定環境變數,本例中設定了NAME環境變數。CMD指令用於指定容器啟動時執行的命令,本例中執行python app.py。
建置 Docker 映像檔
要建置 Docker 映像檔,需要在包含 Dockerfile 的目錄中執行以下命令:
docker build -t my-python-app .
內容解密:
docker build命令用於建置 Docker 映像檔。-t引數用於指定映像檔的名稱,本例中為my-python-app。.表示 Dockerfile 位於目前目錄。
執行 Docker 容器
建置完成後,可以使用以下命令執行 Docker 容器:
docker run -p 80:80 my-python-app
內容解密:
docker run命令用於執行 Docker 容器。-p引數用於對映容器內的連線埠到主機,本例中將容器內的 80 連線埠對映到主機的 80 連線埠。my-python-app是要執行的映像檔名稱。
第5章:Dockerfile 詳解
在前面的章節中,我們已經瞭解到 Docker 容器可以被視為系統程式的抽象。實際上,Docker 容器是由 Docker 守護程式管理的程式。因此,定義 Docker 映像的最佳實踐是將其視為完全無狀態的。這意味著我們應該能夠關閉一個容器並將其從系統中移除,然後使用相同的映像啟動一個相同的容器,而不會對我們的工作產生任何影響。
單一關注點容器
早期的 Dockerfile 最佳實踐主張「每個容器一個程式」。然而,隨著 Docker 的發展,這種做法已經被證明是不可行的。Jupyter 就是一個典型的例子,它不能被定義為只執行一個程式。
儘管如此,最佳實踐仍然認為每個容器應該具有單一關注點。雖然 Jupyter 可能需要多個程式才能正常執行,但我們會專門使用一個容器來執行 Jupyter。如果我們希望與 Postgres 資料函式庫互動,我們會使用另一個專門處理該資料函式庫的容器。這樣做的最終目標是保持應用程式關注點的分離和模組化。
專案:Docker 映像倉函式庫
在本章中,您將開發一個包含多個 Dockerfile 的倉函式庫,每個 Dockerfile 定義了一個您在工作中可能會使用的獨立映像。在開發和維護這些透過 Dockerfile 定義的映像的過程中,您將探索定義映像的語法以及構建和維護映像的最佳實踐。您的最終目標是建立一套映像,這些映像將成為您開發用於執行資料科學工作的模組化系統的主要構建模組。
準備本地開發環境
首先,您需要為即將進行的開發工作準備本地機器。清單 5-1 展示瞭如何建立一個專案目錄並將其初始化為 git 倉函式庫。
清單 5-1. 準備本地開發環境
$ mkdir ch_5_dockerfiles && cd ch_5_dockerfiles
$ git init
$ touch README.md
$ git add README.md
$ git commit -m 'init'
組態 GitHub
在 GitHub 上建立一個名為 Dockerfiles 的倉函式庫。建立倉函式庫後,將本地目錄連線到遠端 GitHub 倉函式庫(清單 5-2)。
注意:您需要組態您的 GitHub 帳戶以透過 SSH 連線。有關詳細檔案,請參閱 https://help.github.com/articles/connecting-to-github-with-ssh/。
清單 5-2. 將本地倉函式庫連線到 GitHub
$ git remote add origin git@github.com:<username>/dockerfiles.git
$ git push -u origin master
使用 Dockerfile 建置映像
Dockerfile 與建置(編譯)的 Docker 映像之間的聯絡是透過 docker build 命令建立的。docker build 命令告訴 Docker 守護程式使用指定的上下文和 Dockerfile 建置映像。上下文指的是將用於建置特定映像的檔案集合。上下文將由包含的 PATH 指定。您可以檢視 docker build 的要求,以瞭解這可能是什麼樣子(清單 5-3)。
清單 5-3. 顯示 docker build 說明
$ docker build
"docker build" 需要恰好1個引數。
參見 'docker build --help'。
用法:docker build [選項] 路徑 | 網址 | -
正如您所看到的,docker build 需要 PATH 或 URL 作為最終引數。這就是上下文。
Dockerfile 語法
Dockerfile 是使用一種簡單的特定領域語言構建的(參見清單 5-4)。指令不區分大小寫,但按照慣例以全大寫形式寫出。指令按順序傳遞,Dockerfile 應被視為傳遞給 Docker 守護程式的指令碼。
清單 5-4. Dockerfile 語法
# 註解
指令 引數
設計 gsl 映像
您要構建的第一個映像與第3章中使用的 GSL 映像相同。該映像用於使用 GNU Scientific Library(GSL)編譯程式碼,GSL 是計算數學中使用的 C 工具套件,尤其是在 BLAS 生態系統中使用。您使用 gcc 映像作為基礎映像來構建此映像,從而確保您擁有編譯 C 程式碼所需的所有工具。
建立 gsl 原始碼目錄
首先,您為這個特定的映像建立一個目錄,並例項化您的 Dockerfile(清單 5-5)。
清單 5-5. 為 gsl 映像建立包含空 Dockerfile 的目錄
$ mkdir gsl
$ touch gsl/Dockerfile
在清單 5-6 中,為了構建 gsl 映像,您使用 docker build 命令,使用相對參照的資料夾 gsl 作為上下文。-t 標誌告訴守護程式將該映像命名為 joshuacook/gsl。您最初嘗試構建失敗,因為您尚未向 Dockerfile 新增任何命令。
清單 5-6. 執行 Docker 建置
$ docker build -t joshuacook/gsl gsl
正在向 Docker 守護程式傳送建置上下文 53.25 kB
來自守護程式的錯誤回應:Dockerfile (Dockerfile) 不能為空
定義 gsl 映像
讓我們像第3章那樣定義 gsl 映像,使用由三個命令定義的三個層,如清單 5-7 所示。
清單 5-7. gsl/Dockerfile
FROM gcc
LABEL maintainer=@joshuacook
RUN apt-get update && \
apt-get install -y \
gsl-bin \
libgsl0-dbg \
libgsl0-dev \
libgsl0ldbl
建置 gsl 映像
在清單 5-8 中,定義了映像後,您使用 docker build 命令構建映像,再次命名該映像並提供 gsl 目錄作為上下文。
清單 5-8. 執行 Docker 建置
$ docker build -t joshuacook/gsl gsl
正在向 Docker 守護程式傳送建置上下文 14.85 kB
步驟 1 : FROM gcc
latest:從 library/gcc 提取中...
...
步驟 3 : RUN apt-get update && apt-get install -y gsl-bin libgsl0-dbg libgsl0-dev libgsl0ldbl
...
#### 內容解密:
FROM gcc:此指令指定了基礎映像,即gcc。這是因為我們需要gcc編譯器來編譯使用 GSL 的 C 程式碼。LABEL maintainer=@joshuacook:此指令為映像增加了一個標籤,指定了維護者為@joshuacook。RUN apt-get update && apt-get install -y gsl-bin libgsl0-dbg libgsl0-dev libgsl0ldbl:此指令更新了包列表並安裝了 GSL 相關的包,包括執行時、二進位制檔案、除錯符號和開發檔案。
這些指令共同定義了一個用於編譯使用 GSL 的 C 程式碼的 Docker 映像。
提交變更到 GitHub
在繼續之前,您應該提交對 Dockerfile 所做的更改並將更改推播到 GitHub(參見清單 5-12)。
清單 5-12. 提交變更到 GitHub
$ git add .
$ git commit -m '新增 gsl Dockerfile'
$ git push origin master
透過這種方式,我們完成了 gsl 映像的定義和建置,並將其相關程式碼提交到了 GitHub。接下來,我們可以繼續探索其他 Dockerfile 的最佳實踐和相關技術。