Docker 容器技術已成為現代軟體開發和佈署的根本。理解 Docker CLI 的基本操作,例如 docker run、docker ps、docker start、docker stop 以及 docker attach 等指令,對於有效管理容器生命週期至關重要。此外,由於容器本身的可寫層是暫時的,因此瞭解如何利用 Docker Volume、Bind Mounts 等機制來實作資料持久化儲存也同樣重要。這能確保重要的資料,例如資料函式庫內容或使用者上傳的檔案,不會因為容器的移除或重啟而遺失。善用這些技術能夠提升應用程式的可靠性和穩定性,是 Docker 生態系統中不可或缺的一環。
使用Docker CLI的基礎操作
本章節旨在介紹Docker CLI的基本指令及其應用,而非詳盡地解釋每個Docker命令。我們將重點介紹與Docker守護程式和容器互動所需的常見命令。由於我們認為理解磁碟區和網路組態對於本文至關重要,因此我們將對這些主題進行詳細闡述。
Docker命令分類別
Docker命令大致可分為兩類別:一般Docker命令和Docker管理命令。標準的Docker命令允許您管理容器,而管理命令則允許您管理Docker選項,例如管理磁碟區和網路組態。
docker help
當您忘記某個選項或命令的語法時,Docker提供了docker help命令來幫助您重新整理記憶。每當您在使用Docker命令時遇到困難,docker help都是您的最佳選擇。
docker run
要執行一個容器,您需要使用docker run命令並提供映像名稱。在執行docker run命令之前,您應該瞭解在啟動容器時可以提供的選項。
簡單範例
最簡單的執行NGINX網頁伺服器的命令如下:
docker run bitnami/nginx:latest
雖然這會啟動一個執行NGINX的容器,但它會在前台執行。
背景執行
要將容器作為背景程式執行,您需要在Docker命令中新增-d選項,這將使您的容器在分離模式下執行。當您執行一個分離的容器時,您只會看到容器ID,而不是互動式或附加的螢幕。
docker run -d bitnami/nginx:latest
自定義容器名稱
預設情況下,容器一旦啟動就會被賦予一個隨機的名稱。如果您不為容器分配名稱,當您開始在單一主機上執行多個容器時,很快就會變得混亂。為了使管理更容易,您應該始終以一個易於管理的名稱啟動您的容器。Docker在run命令中提供了另一個選項:--name選項。根據前面的例子,我們將我們的容器命名為nginx-test。我們的新docker run命令將如下所示:
docker run --name nginx-test -d bitnami/nginx:latest
驗證容器執行狀態
要驗證容器是否以nginx-test的名稱執行,我們可以使用docker ps命令列出容器。
docker ps
每天,您都需要檢索正在執行的容器列表或已停止的容器列表。Docker CLI有一個名為ps的選項,可以列出所有正在執行的容器,或者如果您在ps命令中新增額外的選項,也可以列出所有正在執行和已停止的容器。輸出的內容包括容器的ID、映像標籤、進入命令、建立日期、狀態、埠和容器名稱。
檢視執行中的容器
docker ps
檢視所有容器(包括已停止的)
docker ps -a
您可以透過檢視列表中的STATUS欄位來判斷哪些容器正在執行,哪些已經停止。正在執行的容器將顯示執行時間,例如Up xx hours或Up xx days。然而,如果容器因任何原因停止,狀態將顯示它停止的時間,例如Exited (1) 3 days ago。
docker start 和 stop
要停止一個正在執行的容器,可以使用docker stop選項加上您要停止的容器的名稱。由於主機上的資源有限,您可能希望停止容器以釋放資源,以便同時執行其他容器。
如果您需要在未來再次啟動該容器進行額外的測試或開發,可以執行docker start 容器名稱,這將以原始啟動時的所有選項(包括任何網路或磁碟區分配)啟動容器。
docker attach
您可能需要互動式地存取容器以進行故障排除或檢視日誌檔案。連線到正在執行的容器的一種方法是使用docker attach 容器名稱命令。當您附加到一個正在執行的容器時,您將連線到該容器的程式,因此,如果您附加到一個執行某個程式的容器,您很可能不會看到任何命令提示符。事實上,您可能會看到空白螢幕,直到容器輸出一些資料到螢幕上。
附加到容器時必須小心——您可能會意外地停止正在執行的程式,從而停止容器。以附加到執行NGINX的網頁伺服器為例,首先,我們需要使用docker ps驗證容器正在執行:
docker ps
然後,使用以下命令附加到該容器:
docker attach nginx-test
注意事項
附加到容器的過程中要小心操作,避免意外停止容器的程式。
參考圖表說明
此圖示展示了Docker容器的基本操作流程。
圖表翻譯:
此圖表展示了使用Docker CLI的基本流程。首先,您需要啟動Docker並執行docker run命令。您可以選擇在背景執行容器或自定義容器名稱。背景執行需要使用-d選項,而自定義名稱則需要使用--name選項。無論哪種方式,您都可以使用docker ps來列出所有正在執行的容器。如果需要檢視所有容器(包括已停止的),可以使用docker ps -a命令。
Docker 與容器基礎
容器操作與互動
使用 docker attach 命令可以將目前的終端機附加到正在執行的容器上。以 docker attach bbadb2bddaab 為例,當你執行此命令後,會發現畫面上沒有任何變化。這是因為 attach 命令只是將你的終端機連線到容器的主程式,在此例中是 NGINX 程式。
互動與輸出
當你對容器發出 curl 請求時,你會在附加的終端機上看到 NGINX 的輸出日誌。這表明 attach 命令已經成功連線到容器的 NGINX 程式。
注意事項
- 當你使用
Ctrl + C終止附加的程式時,NGINX 程式也會被終止,因為Ctrl + C會傳送 SIGINT 訊號給 NGINX 程式,導致程式停止。 - 停止主程式會導致容器停止執行。
使用 docker exec 命令
相比於 attach,docker exec 命令提供了一個更好的互動方式。你可以使用 docker exec 在容器內執行特定的命令或程式,而不會影響容器的主程式。
語法與範例
docker exec -it <容器名稱或ID> <要執行的命令>
例如,使用 docker exec -it 0a7c916e7411 bash 可以在 NGINX 容器內開啟一個互動式的 bash 終端機。
內容解密:
-it選項告訴 Docker 以互動模式開啟一個偽終端機(pseudo-TTY)。<容器名稱或ID>指定要操作的容器。<要執行的命令>在此例中是bash,表示在容器內開啟一個 bash 終端機。
容器日誌管理
使用 docker logs 命令可以檢視容器的日誌輸出。
語法
docker logs <容器名稱或ID>
例如,docker logs 7967c50b260f 將輸出 ID 為 7967c50b260f 的容器的日誌。
日誌選項
你可以使用不同的選項來控制日誌的輸出,例如 --tail、--since 等,以取得更具體的日誌資訊。
容器移除
當你需要重複使用同一個容器名稱時,你需要先移除舊的容器。使用 docker rm 命令可以移除指定的容器。
範例
docker rm nginx-test
這將移除名為 nginx-test 的容器,使你可以再次使用該名稱啟動新的容器。
重點整理
- 使用
docker attach可以附加到容器的主程式,但需注意不要誤終止程式。 - 使用
docker exec可以在容器內執行特定命令,是更靈活的互動方式。 - 使用
docker logs可以檢視容器的日誌輸出,幫助排查問題。 - 使用
docker rm可以移除不再需要的容器,以便重複使用容器名稱。
為什麼需要持久化資料
在前面的章節中,我們討論了Docker容器的基本概念以及如何使用Docker CLI命令來管理和操作容器。然而,在實際應用中,我們經常需要處理持久化資料的問題。持久化資料是指那些需要在容器重新啟動或刪除後仍然保留的資料,例如資料函式庫中的記錄、使用者上傳的檔案等。
讓我們考慮一個實際的例子。假設我們有一個系統,需要佈署一個MySQL資料函式庫,並由一個根據NGINX的Web應用程式提供前端支援。我們使用標準的docker run命令啟動了兩個容器,分別執行MySQL資料函式庫和Web應用程式。經過初步測試,使用者確認一切正常。然而,在幾天后,我們收到了一封來自安全部門的電子郵件,要求我們盡快佈署一個新的MySQL補丁來修復一個安全漏洞。
於是,我們建立了一個新的MySQL映象,其中包含了最新的補丁,並將其推播到我們的容器登入檔中。然後,我們停止了正在執行的容器,刪除了舊的容器,並使用新的映象重新啟動了一個新的MySQL容器。然而,當我們登入到新的容器中時,卻發現資料函式庫中的記錄全部丟失了。
問題的原因
這個問題的原因在於容器的可寫層是暫時的。當我們刪除舊的容器時,包含資料函式庫記錄的可寫層也被刪除。當新的容器啟動時,它建立了一個新的可寫層,而MySQL資料函式庫則被重新初始化,導致資料丟失。
解決方案
為瞭解決這個問題,我們需要將資料儲存在容器的可寫層之外,使用持久化儲存。Docker提供了多種持久化儲存選項,包括:
- Docker卷(Volumes)
- Docker繫結掛載(Bind Mounts)
- tmpfs掛載(tmpfs Mounts)
Docker卷(Volumes)
Docker卷是一種由Docker管理的持久化儲存機制。它允許我們將資料儲存在容器的可寫層之外,並且可以在多個容器之間分享。
Docker繫結掛載(Bind Mounts)
Docker繫結掛載允許我們將主機檔案系統中的目錄或檔案掛載到容器中。這種方式可以讓我們將資料儲存在主機檔案系統中,並且可以在容器之間分享。
tmpfs掛載(tmpfs Mounts)
tmpfs掛載是一種將資料儲存在主機記憶體中的持久化儲存機制。它不是真正的持久化儲存,因為當容器重新啟動或主機重啟時,資料將會丟失。然而,在某些特定的場景中,tmpfs掛載可以提供高效能的臨時儲存。
如何選擇持久化儲存選項
那麼,如何選擇適合的持久化儲存選項呢?這取決於我們的具體需求和場景。Docker卷和繫結掛載都可以提供持久化儲存,但是它們的管理方式和暴露的資料不同。我們需要根據自己的需求選擇適合的選項。
練習題
- 當容器被刪除時,下列哪種儲存方式可以保留資料?
- A. 容器的可寫層
- B. Docker卷
- C. tmpfs掛載
- D. 繫結掛載
- 答案:B、D
- 下列哪種儲存方式可以將主機檔案系統中的目錄或檔案掛載到容器中?
- A. Docker卷
- B. 繫結掛載
- C. tmpfs掛載
- D. 以上皆非
- 答案:B
- tmpfs掛載有什麼特點?
- A. 資料儲存在主機檔案系統中
- B. 資料儲存在主機記憶體中
- C. 資料在容器重新啟動後仍然保留
- D. 資料在主機重啟後仍然保留
- 答案:B
練習題內容解密:
練習題1:當容器被刪除時,下列哪種儲存方式可以保留資料?
- 容器的可寫層(A)是暫時的,當容器被刪除時,資料將會丟失。
- Docker卷(B)和繫結掛載(D)都是持久化儲存,可以保留資料。
- tmpfs掛載(C)是將資料儲存在主機記憶體中,當容器重新啟動或主機重啟時,資料將會丟失。
練習題2:下列哪種儲存方式可以將主機檔案系統中的目錄或檔案掛載到容器中?
- 繫結掛載(B)允許我們將主機檔案系統中的目錄或檔案掛載到容器中。
練習題3:tmpfs掛載有什麼特點?
- tmpfs掛載(B)是將資料儲存在主機記憶體中,而不是主機檔案系統中。
- tmpfs掛載的資料在容器重新啟動或主機重啟時將會丟失。
圖表說明
圖表翻譯:
此圖表展示了Docker容器使用的不同儲存方式。可寫層是暫時的,當容器被刪除時,資料將會丟失。Docker卷和繫結掛載是持久化儲存,可以保留資料。tmpfs掛載是將資料儲存在主機記憶體中,當容器重新啟動或主機重啟時,資料將會丟失。
使用 Docker 資料卷的技術解析
Docker 資料卷(Docker Volumes)是為容器提供持久化資料的首選方案。所謂資料卷,簡單來說就是主機上的一個目錄,透過資料卷掛載對映到容器中使用。當建立一個資料卷時,主機檔案系統上會建立一個新的目錄,通常位於 /var/lib/docker/volumes/<資料卷 ID>/。如果具有主機的 root 存取許可權,可以像檢視其他目錄一樣檢視其檔案結構。下圖展示了執行容器的 Docker 主機上 volumes 目錄下的目錄結構:
Docker 資料儲存機制
為了在重新啟動之間維護資訊,Docker 使用名為 Boltdb 的快速資料函式庫在主機上的各種資料函式庫中儲存關鍵元資料。Boltdb 是用 Go 語言編寫的,用於儲存永續性鍵值。在瀏覽 /var/lib/docker 資料夾時,您可能會遇到兩個 Boltdb 資料函式庫:
/var/lib/docker/volumes/metadata.db:維護 Docker 資料卷的元資料,如名稱、驅動程式、標籤和選項。/var/lib/docker/network/files/local-kv.db:維護 Docker 網路的元資料。
本章重點關注資料,因此我們將使用 metadata.db 資料函式庫。
建立 Docker 資料卷
在使用資料卷之前,必須先建立它。建立 Docker 資料卷可以手動使用 Docker CLI 完成,也可以由 Docker 守護程式在容器啟動時自動建立。由於這兩種方法都是由 Docker 建立的,因此它們由 Docker 本身擁有和管理,使得使用 Docker CLI 管理和追蹤它們變得容易。
使用 CLI 建立資料卷
要建立 Docker 資料卷,可以使用以下命令:
docker volume <選項>
可用的選項如下:
| 選項 | 說明 |
|---|---|
| create | 建立一個新的資料卷 |
| inspect | 顯示一個或多個資料卷的詳細資訊 |
| ls | 列出所有資料卷 |
| prune | 刪除未使用的資料卷 |
| rm | 刪除一個或多個資料卷 |
要建立新的資料卷,請使用 create 選項:
docker volume create <可選的資料卷名稱>
執行 create 命令後,您將看到建立的資料卷名稱。如果沒有提供可選的資料卷名稱,Docker 將分配一個資料卷 ID 作為名稱。未提供資料卷名稱而建立的資料卷稱為匿名資料卷。
匿名資料卷與命名資料卷
匿名資料卷可能會隨著您在主機上新增使用資料卷的容器而難以追蹤。因此,建議在建立時為您的資料卷命名,而不是讓 Docker 生成一個長的匿名資料卷名稱。
任何在建立時提供了資料卷名稱的資料卷都稱為命名資料卷。要建立命名資料卷,您需要在 docker volume create 命令中提供資料卷名稱。
docker volume create my-named-volume
#### 內容解密:
此命令用於建立一個名為 my-named-volume 的 Docker 資料卷。Docker 將在 /var/lib/docker/volumes 目錄下建立一個對應的目錄,用於儲存與該資料卷相關的資料。如果未指定名稱,Docker 將自動生成一個隨機的名稱。
將資料卷掛載到容器中
將資料卷掛載到容器中的過程對於命名或匿名資料卷是相同的。前面已經介紹瞭如何使用 Docker CLI 建立資料卷,但沒有解釋如何讓 Docker 自動建立資料卷。
本文將解釋如何讓 Docker 自動建立並掛載一個資料卷,以及如何將先前建立的命名資料卷掛載到容器中。
自動建立與掛載資料卷
在將資料捲到容器中時,您需要向 docker run 命令提供 --mount 或 -v 選項。如果正在執行標準容器,可以使用任一選項,但 -v 是最常用的選項。
將命名資料卷掛載到 MySQL 容器
假設之前建立了一個名為 pv-mysql-data 的資料卷,現在要啟動 MySQL 容器並掛載該命名資料卷,以實作持久化資料函式庫。要將資料卷掛載到容器中,需要在啟動容器時傳遞 -v 選項。-v 選項需要兩個引數:資料卷名稱和容器掛載點。
docker run --name mysql-01 -v pv-mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-password -d mysql
#### 內容解密:
此命令用於啟動一個名為 mysql-01 的 MySQL 容器,並將之前建立的 pv-mysql-data 資料卷掛載到容器的 /var/lib/mysql 目錄。同時,透過 -e 選項設定了 MySQL 的 root 使用者密碼。-d 選項使容器在後台執行。
Docker 資料卷掛載流程
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Docker容器基礎操作與持久化儲存
package "Docker 架構" {
actor "開發者" as dev
package "Docker Engine" {
component [Docker Daemon] as daemon
component [Docker CLI] as cli
component [REST API] as api
}
package "容器運行時" {
component [containerd] as containerd
component [runc] as runc
}
package "儲存" {
database [Images] as images
database [Volumes] as volumes
database [Networks] as networks
}
cloud "Registry" as registry
}
dev --> cli : 命令操作
cli --> api : API 呼叫
api --> daemon : 處理請求
daemon --> containerd : 容器管理
containerd --> runc : 執行容器
daemon --> images : 映像檔管理
daemon --> registry : 拉取/推送
daemon --> volumes : 資料持久化
daemon --> networks : 網路配置
@enduml
圖表翻譯: 此圖表展示了 Docker 資料卷的使用流程。首先,建立一個 Docker 資料卷。然後,將該資料卷掛載到容器中使用,從而實作持久化儲存。即使容器重新啟動,儲存在資料卷中的資料仍然保持不變,確保了資料的永續性。