Hello Docker World

今天要開始了解 Docker 世界了,首先會先說明 Docker 的基本概念,接著再以驗證指令 docker run hello-world 為例,解釋背後細節。

基本概念

Docker 的世界裡,有三個主要元件如下:

  • 映像檔(image)
  • 容器(container)
  • 倉庫(repository)

執行 Docker 的主機,稱為 Host

在 host 執行 docker run 指令時,Docker 會操作這三個元件來完成任務。首先來了解這三個元件。

Image

Image 包裝了一個執行特定環境所需要的資源。

每個 image 都有獨一無二的 digest,這是從 image 內容做 sha256 產生的。這個設計能讓 image 無法隨意改變內容,維持資料一致性。

雖然 image 裡有必要的資源,但它無法獨立執行,必須要靠 container 間接執行。

Container

基於 image 可以建立出 Container

它的概念像是建立一個可讀寫內容的外層,架在 image 上。實際存取 container 會經過可讀寫層與 image,因此看到的內容會是兩者合併後的結果。

Container 特性跟 image 不一樣,因為有可讀寫層,所以 container 可以讀寫,也可以拿來執行。

Repository

Repository 是存放 image 的空間。

Docker 設計類似分散式版本控制的方法來存放各種 image。而分散式架構就會有類似 git 的 pull / push 行為,實際做的事也跟 git 類似:為了要跟遠端的 repository 同步。

另一個與 repository 很像,但容易混用的名詞為 Registry,後者涵蓋範圍更廣,包含了更多 repository 與身分驗證功能等,通常比較常討論的也是 registry。

目前 Docker 預設的 registry 為 DockerHub,大多數程式或服務的 image 都能在上面找得到。


Image、container、repository 之間的關係就像光碟一樣:早期世紀帝國等光碟遊戲,會需要搭配其他可讀寫空間(如硬碟),才有辦法執行。

  • Image 像光碟片一樣,唯讀且不能獨立執行
  • Container 像硬碟一樣,可讀可寫可執行
  • Repository 則是光碟盒,而 Registry 則是像光碟零售商

執行驗證指令

安裝好環境後,第一次執行驗證指令 docker run hello-world 範例如下:

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:7f0a9f93b4aa3022c3a4c147a449bf11e0941a1fd0bf4a8e6c9408b2600777c5
Status: Downloaded newer image for hello-world:latest

Hello from Docker!

docker run 有明確執行的意思。回頭看一開始的元件說明可以了解,docker run 會建立一個 container 並執行;而因為 container 需要基於 image 建立,所以 docker run 有個必要的參數是 image 名稱,即 hello-world

它的訊息非常長,但實際上可以分為兩個區塊:

確認 Image 存在 Repository

首先先確認 hello-world 是否存在於本機的 repository,本機找不到的話,就需要從遠端的 repository 下載。

下面即為找不到 image,並從遠端下載的訊息:

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:7f0a9f93b4aa3022c3a4c147a449bf11e0941a1fd0bf4a8e6c9408b2600777c5
Status: Downloaded newer image for hello-world:latest

Docker 設計 image 名稱會包含 registry 的路徑,若沒有的話,則預設是 DockerHub

建立 Container 並執行

確認好 Image 存在或下載好後,即可建立 Container 並執行。

docker run 預設的行為是:

  1. 前景建立並執行 container
  2. 等待執行程式結束(exit)後,會回到前景的命令提示字元
  3. 該 container 會被標記成結束狀態

以本範例來說,資訊顯示完回到命令提示字元時,上面三個步驟就都完成了。步驟二在執行過程很明顯,而步驟一與三所提到的 container 可以使用 docker ps 查看:

docker ps -a

裡面的訊息如下:

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
6d7e00198a56 hello-world "/hello" 12 seconds ago Exited (0) 11 seconds ago relaxed_bhabha

docker ps 可以看 container 的概況,除了列出有哪些 container 外,也有其他欄位了解 container 相關資訊。

首先可以注意到 STATUS 欄位狀態為 Exited (0),後面的數字為程式結束後回傳的狀態碼,通常 0 為正常結束,非 0 則是有錯誤。

最開頭的 CONTAINER ID 與最後的 NAMES 是獨一無二的,可以多執行幾次 docker run,接著就會看到很多不一樣名字的 container。

移除 Container

若一直不斷執行 docker run hello-world 的話,就會造成 container 數量不斷成長。雖然使用到容量不多,但在管理上多少會造成困擾。

最簡單的方法是,沒有要再用的 container 就移除它。以上面的範例為例,移除 container 的指令如下:

# 使用 CONTAINER ID: 6d7e00198a56 或 NAMES: relaxed_bhabha 皆可
docker rm 6d7e00198a56

# 移除完使用 docker ps 再檢查一次
docker ps -a

docker rm 是移除 container 的指令,只要 container 不是處於 Up 正在執行中的狀態,即可使用 docker rm 移除。

指令補充說明

docker run

使用 IMAGE 建立新的 container 並執行指令,用法如下:

docker run IMAGE

IMAGE 會先從本機 repository 找,有的話就執行;若沒有的話,會到遠端 repository 下載並執行。

docker ps

列出已建立的 container。

docker ps
  • -a|--all 列出所有的 container

docker rm

移除指定的 container,用法如下:

docker rm CONTAINER [CONTAINER...]

CONTAINER 可以是 docker ps 查到的 CONTAINER ID 或 NAMES。若需要移除多個 container,可以使用空白隔開每個 container 名稱,如:

docker rm container_a container_b

今日自我回顧

Image、container、repository,三個元件之間的關係,可以畫成示意圖如下:

今天的說明搭配此圖,相信讀者能更了解 docker run 與元件如何互動。

  • 解釋 Docker 三種元件之間的關係
  • 練習 docker run 指令執行 hello-world image
  • 練習 docker ps 指令,觀察 container 狀態
  • 練習 docker rm 指令,整理 container 列表