概述
Docker 是一個提供開發, 運送, 以及運行應用的開放平台。 妥善地使用 Docker, 你可以將你的應用從基礎設施分離, 並且如管理應用般的管理基礎設施。 Docker 可讓你更快速的輸送你的程式碼, 更快速的測試, 以及更快速的部署, 讓開發到運行之間的週期更加縮短。
Docker 藉由使用工作流程以及工具來融合 kernel 容器化功能, 讓你可以管理以及部署你的應用。
Docker 容器可以直接地被使用在 Kubernetes, 這讓 Docker 可以很簡單的被運行在 Kubernetes Engine, 在學習 Docker 的一些重要的核心知識後, 你將擁有可以開始開發 Kubernetes 以及容器化應用的技能組合。
學習目標
在本教程中, 你將會學習到以下:
- 如何建立, 運行, 以及 debug Docker 容器
- 如何從 Docker Hub 以及 Google Container Registry 拉下 Docker 鏡像
- 如何將 Docker 鏡像推上 Google Container Registry
事前準備
這是個入門等級的教程。 只有一點點, 或是完全沒有 Docker 相關知識也是 okay 的。 建議熟悉 Cloud Shell 以及其命令列工具, 但非必要。 如果你在尋找在一個範圍內更進階的學習素材的話, 可以參考以下的教程:
- App Dev: Deploying the Application into Kubernetes Engine - Python
- Hello Node Kubernetes
- Managing Deployments Using Kubernetes Engine
如果你已經準備好了, 往下滑開始設定教程環境吧
設定及要求
在你按下 Start Lab 按鈕之前
詳讀所有的教學。 Labs 是有時間限制的, 而且你不可以停止時間倒數。 倒數計時器在你按下 Start Lab 按鈕後開始倒數, 上面顯示的時間為你還能使用 Cloud 資源的時間。
Qwiklabs 的手把手環境, 讓你可以在真實環境中來操作進行 Qwiklabs 上提供的課程, 而不是在一個模擬或是展示的環境。 我們透過提供你一個全新的、暫時的帳號密碼, 在計時器歸零之前, 你可以用來登入並存取 Google Cloud Platform。
你需要什麼?
要完成這個 lab, 你需要:
- 一個一般的網路瀏覽器(推薦 Chrome)
- 完成這個 lab 的時間
備註: 如果你已經有你自己的個人 GCP 帳號或專案,請不要使用在這一個 lab
現在你已經開始你的 lab
, 你將會登入 Google Cloud Shell
主控台, 然後開啟命令列工具
如何開始你的 lab, 然後登入 Console?
- 按下 Start Lab 按鈕。 如果你需要付費, 會有一個彈出視窗來讓你選擇付費的方式。 在左方你會看到一個面板, 上面有暫時的帳號密碼, 你必須使用這些帳號密碼在此次 lab
- 複製
username
, 然後點擊Open Google Console
。 Lab 會開啟另外一個視窗, 顯示選擇帳號
的頁面
tip: 開啟一個全新的視窗,然後跟原本的頁面並排
- 在
選擇帳號
頁面, 點擊Use Another Account
- 登入頁面開啟, 貼上之前複製的
username
以及password
, 然後貼上
重要:必須使用之前於 Connection Details 面板
取得的帳號密碼,不要使用你自己的 Qwiklabs 帳號密碼。 如果你有自己的 GCP 帳號, 請不要用在這裡(避免產生費用)
- 點擊並通過接下來的頁面:
- 接受
terms
以及conditions
- 不要增加
recovery optoins
或two factor authentication
(因為這只是一個臨時帳號) - 不要註冊免費體驗
- 接受
稍待一些時候, GCP 控制台將會在這個視窗開啟。
啟動 Google Cloud Shell
Google Cloud Shell
是載有開發工具的虛擬機器。 它提供了5GB的 home 資料夾, 並且運行在 Google Cloud
上。 Google Cloud Shell
讓你可以利用 command-line 存取 GCP
資源
- 在
GCP 控制台
, 右上的工具列,點擊Open Cloud Shell
按鈕
- 在打開的對話框裡, 按下
START CLOUD SHELL
:
你可以立即按下 START CLOUD SHELL
當對話視窗打開。
連結並提供環境會需要一點時間。 當你連結成功, 這代表你已成功獲得授權, 且此專案已被設為你的專案ID, 例如:
gcloud 是 Google Cloud Platform
的 command-line 工具, 他已事先被安裝在 Cloud Shell
並且支援自動補齊
使用這個 command, 你可以列出有效帳戶名稱:
gcloud auth list |
輸出:
Credentialed accounts: |
範例輸出:
Credentialed accounts: |
你可以使用以下 command 來列出專案 ID
gcloud config list project |
輸出:
[core] |
範例輸出:
[core] |
gcloud
的完整文件可以參閱 Google Cloud gcloud Overview
Hello World
打開 Cloud Shell 並輸入以下指令來運行一個 hello world 容器
docker run hello world |
(輸出)
Unable to find image 'hello-world:latest' locally |
這個簡單的容器回傳 Hello from Docker!
到你的螢幕上。 儘管指令很簡單, 但仔細看看在輸出中, 執行步驟的數量。 Docker daemon 搜尋名為 hello-world 的鏡像, 但沒有在本地端找到, 所以從名為 Docker Hub 的公開 registry 拉下這個鏡像, 並且使用這個鏡像建立了容器, 最後運行容器。
執行以下的指令檢視從 Docker Hub 拉下的 Docker 鏡像
docker images |
(輸出)
REPOSITORY TAG IMAGE ID CREATED SIZE |
這是一個從 Docker Hub 公開 registry 被拉下的鏡像。 鏡像 ID 為 SHA256 加密 格式 - 這個欄位明確的指定被提供的鏡像。 當 docker daemon 無法在本地端找到鏡像, 預設會自動地從公開 registry 尋找鏡像。 讓我們再次運行容器:
docker run hello-world |
(輸出)
Hello from Docker! |
注意到, 當你第二次執行這個指令, docker daemon 在本地端找到了這個鏡像並且使用這個鏡像運行容器。 不需要再從 Docker Hub 拉下鏡像。
最後, 執行以下指令來檢視運行中的容器:
docker ps |
(輸出)
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES |
目前並沒有運行中的容器。 你之前運行的 hello-world 容器已經退出了。 如果要檢視所有的容器, 包含已經結束運行的容器, 可以執行 docker ps -a
:
docker ps -a |
(輸出)
CONTAINER ID IMAGE COMMAND ... NAMES |
這會顯示 Container ID
, 這是一個由 Docker 建立的 UUID, 用以辨識容器, 除此之外, 還有一些容器的資訊。 容器的 Names
也是隨機產生的, 但你也可以使用 docker run --name [container-name] hello-world
來指定它
建立
現在讓我們來建立一個基於 node 簡單應用的 Docker 鏡像。 執行以下指令來建立並且切換到這個名為 test
的資料夾
mkdir test && cd test |
建立一個 Dockerfile
:
cat > Dockerfile <<EOF |
這個檔案指示 Docker daemon 該怎樣建立這個鏡像
- 第一行指定了基礎鏡像, 在這個範例中為 node 版本 6 的官方 Docker 鏡像
- 第二行, 我們指定了容器內的工作(目前)目錄
- 第三行, 我們當層資料夾內的內容(容器外), 複製到容器內
- 最後, 我們暴露了容器的 port, 所以此容器可經由該 port 被存取, 然後運行 node 的指令來運行應用
花一些時間看一下 Dockerfile command references 來了解 Dockerfile
中每一行的意思
現在, 你將寫入 node 應用, 且在那之後你將建立鏡像
執行以下指令來建立 node 應用
cat > app.js <<EOF |
這是一個簡單的 HTTP server, 監聽 port 80 且回傳 “Hello world.”
現在讓我們來建立鏡像吧
再次注意, "."
這個符號代表目前的資料夾為止, 所以你必須要在有 Dockerfile 的資料夾底下運行這個指令
docker build -t node-app:0.1 . |
這個指令可能會花個幾分鐘才會執行完畢。 當它執行結束, 你的輸出應會如下:
Sending build context to Docker daemon 3.072 kB |
-t
是為使用 name:tag
語法來命名鏡像的 tag, 鏡像名稱為 node-app
, tag
為 0.1
, 高度建議當建立鏡像時一定要使用 tag 。 如果你沒指定 tag, tag 將預設為 latest
, 這會讓你更難分辨新舊鏡像。 也請注意到, 在鏡像被建立的過程中, Dockerfile
中的每一行指令在中間的容器層中造成什麼樣的結果。
現在, 執行以下指令來檢視建立的鏡像:
docker images |
輸出應如下:
REPOSITORY TAG IMAGE ID CREATED SIZE |
注意到, node
為基礎鏡像, 而 node-app
為你建立的鏡像。 在移除 node
鏡像之前, 你必須要先移除 node-app
。 鏡像的大小跟虛擬機比起來的話小了非常多。 其他版本的 node 鏡像, 像是 node:slim
以及 node:alpine
提供了更小的體積, 更好的攜帶性。 降低鏡像大小的主題, 你可探索更進階的主題。 你可以在 官方倉庫 檢視所有的版本
運行
在這個章節中, 執行這個程式碼, 使用之前建立的鏡像運行容器:
docker run -p 4000:80 --name my-app node-app:0.1 |
(輸出)
Server running at http://0.0.0.0:80/ |
--name
flag 讓你可以自由的命名你的容器。 -p
指定容器映射本機端的 port 4000 到容器內的 port 80, 而現在你應可經由 http://localhost:4000
存取 server。 如果沒有做 port 映射, 你將無法經由 localhost 來存取容器
打開另外一個終端機 (在 Cloud Shell, 點擊 +
icon), 然後測試 server
curl http://localhost:4000 |
(輸出)
Hello World |
第一個終端機視窗開啟多久, 這個容器就會運行多久。 如果你想要將容器運行在背景中 (不會綁住終端機), 你需要指定 -d
flag
關閉第一個終端機視窗, 然後執行以下指令來停止並移除容器:
docker stop my-app && docker rm my-app |
現在執行以下指令來開始在背景運行另外一個容器:
docker run -p 4000:80 --name my-app -d node-app:0.1 |
(輸出)
CONTAINER ID IMAGE COMMAND CREATED ... NAMES |
從 docker ps
的輸出, 我們可以看到容器正在運行中。 你可以執行 docker logs [container_id]
指令來檢視 logs
小技巧: 你不需要完整的容器 ID, 只要前幾個字是獨一無二足以代表這個容器。 舉例來說, 你可以執行 docker ps 17b
, 如果你的容器 ID 是 17bcaca6f...
docker logs [container_id] |
(輸出)
Server running at http://0.0.0.0:80/ |
現在讓我們來修改應用。 在 Cloud Shell, 打開之前建立的 test 資料夾:
cd test |
使用你的編輯器 (比如 namo 或 vim) 來編輯 app.js
, 然後將 “Hello World” 替換成其他字串:
.... |
建立這個新的鏡像, 並給予 tag 0.2
:
docker build -t node-app:0.2 . |
(輸出)
Step 1/5 : FROM node:6 |
注意到, 在 step 2我們使用了以存在的緩存層。 從 step 3 開始, 層被修改了因為我們在 app.js
中做了一些變更
使用新的鏡像版本啟動另外一個容器。 注意到我們是如何的映射本機端的 port 8080, 而不是 port 80, 我們不能在使用 port 4000 因為它已經在使用中了。
docker run -p 8080:80 --name my-app-2 -d node-app:0.2 |
(輸出)
CONTAINER ID IMAGE COMMAND CREATED |
測試容器
curl http://localhost:8080 |
(輸出)
Welcome to Cloud |
現在測試第一個容器
curl http://localhost:4000 |
(輸出)
Hello World |
Debug
現在我們已經熟悉如何建立以及運行容器, 來學習一下一些 debugging 的方法。
你可以使用 docker logs [container_id
來檢視容器的日誌, 如果你想要檢視即時的日誌輸出的話, 可以使用 -f
選項
docker logs -f [container_id] |
(輸出)
Server running at http://0.0.0.0:80/ |
有時, 你可能會想要啟動一個容器內的 Bash, 你可以使用 docker exec 來做到這件事。 打開另外一個終端機 (在 Cloud Shell, 點擊 + 圖示), 然後執行以下指令:
docker exec -it [container_id] bash |
-it
flags 讓你可以分配一個虛擬的 TTY 給容器, 保持輸入開啟並與之互動。 注意到目前 bash 正運行在 Dockerfile
內指定的 WORKDIR
資料夾 (/app), 現在你有一個容器內的互動式的 shell 可以用來 debug 了
(輸出)
root@xxxxxxxxxxxx:/app# |
檢視資料夾
ls |
(輸出)
Dockerfile app.js |
若要離開 Bash, 在 Bash 中輸入 exit:
exit |
你可以使用以下指令來檢視容器的元資料
docker inspect [container_id] |
(輸出)
[ |
使用 --format
從回傳的 JSON 當中檢查特定的欄位。 例如說:
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' [container_id] |
(輸出)
192.168.9.3 |
務必到以下的連結去參考更多有關 debugging 的資訊
發佈
現在, 你將推送你的鏡像到 Google Container Registry (gcr)。 在那之後, 你將會將本地的容器以及鏡像都刪除來模擬一個全新的環境, 然後從遠端拉取鏡像並啟動容器。 這將是 Docker 容器可攜性的最佳示範。
要推送鏡像到你的私人 gcr 的 registry, 你需要 tag registry 的名稱到這個鏡像。 格式就像是 [hostname]/[project-id]/[image]:[tag]
GCR 的格式:
[hostname]
= gcr.io[project-id]
= 你的 project ID[image]
= 你的鏡像名稱[tag]
= 你選擇的 tag, 若無特別指定, 預設為 “latest”
你可以執行以下指令來找到你的 project ID
gcloud config list project |
(輸出)
[core] |
給予 tag node-app:0.2
, 並將 [project-id]
替換成你的設定
docker tag node-app:0.2 gcr.io/[project-id]/node-app:0.2 |
docker images |
(輸出)
REPOSITORY TAG IMAGE ID CREATED |
將這個鏡像推送到 gcr, 記住要將 [project-id]
替換成你的設定
docker push gcr.io/[project-id]/node-app:0.2 |
(輸出)
The push refers to a repository [gcr.io/[project-id]/node-app] |
從瀏覽器拜訪鏡像位址來確認鏡像已存在於 gcr, 你可以從主控台到 Tools > Container Registry 或是拜訪 http://gcr.io/[project-id]/node-app
, 顯示頁面應如下:
現在讓我們測試這個鏡像。 你可以開啟一個新的 VM, ssh 到這個 VM, 然後安裝 gcloud, 但為求簡單化, 我們將簡單的移除所有的容器以及鏡像來模擬一個全新的環境。
停止並刪除所有的容器:
docker stop $(docker ps -q) |
在移除 node 鏡像之前, 你必須要移除它的子鏡像 (node:6
的), 運行已下指令, 記得將 [project-id]
替換成你自己的
docker rmi node-app:0.2 gcr.io/[project-id]/node-app node-app:0.1 |
(輸出)
REPOSITORY TAG IMAGE ID CREATED SIZE |
現在你應該有一個虛擬全新的環境。 拉取並運行鏡像。 記得將 [project-id]
替換成你自己的
docker pull gcr.io/[project-id]/node-app:0.2 |
(輸出)
Welcome to Cloud |
測試進度
點擊 Check my progress 來確認目前的進度。如果你已經成功發布容器鏡像到 Container Registry, 你將獲得一個評價分數。
在這裏, 我們示範了容器的可攜帶性。 只要機器上有安裝 Docker (實機或虛擬機), 你可以從公開或私人的 registries 拉取鏡像並運行容器。 在你的機器上除了 Docker, 你不需要再安裝其他的應用相依。
恭喜
你已經完成本教程
留言