Kubernetes 教學系列 - 如何建立 Pod
這次來介紹在 K8S 究竟如何建立 Pod,而 Pod 在 K8S 上是什麼功用可以參考我寫的文章:Kubernetes 元件原理介紹。Pod 是節點裡面的最小單位,簡單來說就是 Pod 就是放置容器服務的地方。通常一個 Pod 對應到一個容器,也可以一個 Pod 裡面放置多個容器。因此如何建立 Pod 是要先建立我們的 Container。
建立 Container
建立 Container 的方式我們選擇使用 Docker,事實上只要是 Container-based 的應用,K8S 的 Pod 可以佈署,而不是只有 Docker 出產的 Container 才可以使用,只是因為 Docker 實在是太方便了。而有關 Docker 的詳細介紹這邊就不詳談了。這次的應用我們用 Golang 來示範。
Golang 程式碼
直接上程式碼:
1 | package main |
這邊利用 gin 框架來實現 web service,而我們簡單定義一個 GET API,用來之後看我們的 Container 是否有被成功建立。
Dockerfile 撰寫
1 | FROM golang:1.13 |
接下來可以 build 我們 Container 所需要的 Image
1 | docker build -t web-app . |
試著運行在 Local 運行 Container,並且將其 web-app 的 port 導引到 local 的 8080 port,並看是否可以正常運作:
1 | docker run -p 8080:8080 -it web-app |
如果 OK 的話會看到 Gin 框架的 debug log 輸出:
這時候利用 curl 工具來存取 /health API 試試看是否可以 JSON Response:
1 | curl http://localhost:8080/health |
正常的話會看到:
1 | {"status":"ok"} |
將 Image Push 到 Container Registry
現在 Container 運行正常了,但是我們需要將 Container 放置在 Container Registry 上,由於架設 K8S 我要採用的方式是使用 Minikube 來架設,但是 Minikube 本身也有提供 Container Registry,因此我們可以將 Image 推到 Minikube 裡面也可以推到 DockerHub 上。
推到 DockerHub
1 | # 先將Image打上tag => account/image_name:version |
推到 Minikube
基本上這個原理就是,因為 Minikube 裡面也有一個 Docker,因此就是透過在 Minikube 的 Docker 將 local 的 Image Build 出來放置在 Minikube Container Registry。
先執行這個指令:
1 | minikube docker-env |
接著可以看到會提示我們執行怎樣的指令可以做替換:
1 | & minikube -p minikube docker-env | Invoke-Expression |
接著 Local 端的 Docker 就變成是在 Minikube 內的 Docker 了,然後在 Local 上重新 Build Image 即可。
建立 Pod 設定檔
現在,Image 有了,Container run 起來也能夠正常運行了,就差 Pod 設定檔了。對於 K8S 而言,我們如果要 Deploy Pod,都需要撰寫 Pod 的設定檔。設定檔的格式是採用 yml 的方式,所以撰寫起來算是很容易理解,直接上 Pod:
1 | apiVersion: v1 |
-
apiVersion
apiVersion 是代表目前 Kubernetes 中該元件的版本號。 -
metadata
最主要可以拿來定義以下三個欄位:-
metadata.name
代表這個 Pod 的名稱 -
metadata.labels
這個 Label 下面可以以 Key Value 的方式來自定義值,為什麼需要這個?這是因為 K8S 可以透過 Label Selector 將 Pod 進行分 Group,如此一來我們就可以對某 Group 進行某特定指令的效果。因此通常會定義一個 Pod 裡面裝的 Container 的名字之類的來做識別。
-
metadata. annotations
annotations 也是跟 Label 一樣可以以 Key Value 的方式來自定義值,通常會定義一些 Build, release, or image information like timestamps, release IDs, git branch, PR numbers, image hashes, and registry address 等等,直接抄官方說法 XD,因為這些訊息可以供外部進行查詢使用。
-
-
spec
前面都只是定義 Pod 相關資訊而已,最後 spec 的部分才是定義 Pod 裡面的 container 從哪裡來等設定。可以注意到是用 containers 因此這邊其實更可以知道一個 Pod 可以設定多個 Container 的。
- container.name
設定 container 的名稱 - container.image
這是代表 image 的路徑,如果是在 DockerHub 上的話就寫如上面那樣即可。 - container.ports
ports 的部分可以設定 containerPort,這個代表是這個 container 只能開放哪個 port 來讓外部資源存取。所以根據程式碼是 listen 8080 port,所以這邊就是定義 8080 port。
在 K8S 上建立 Pod
在 K8S 上不管是建立甚麼資源通常都會使用兩種指令:
1 | kubectl apply -f pod.yaml |
通常第一次建立資源的時候會使用 create 指令,而在之後如果有更改資源的設定檔想要更新的話就會採用 apply,而如果重複使用 create 的話在第二次會報錯誤,apply 則是會建立或更新的操作。
這邊先透過 Minikube 建立起 K8S cluster 環境:
1 | minikube start |
現在的 minikube 建立 cluster 的方式有三種,分別是 hyper,virtualbox,docker,如果沒有在 start 這邊特定指定 **–driver** 的話會預設採用 docker 來做建立,所以本篇文章是透過 Docker 建立起 K8S cluster 環境。
接著就可以先透過 create 來產生 Pod:
1 | kubectl create -f pod.yaml |
接著來看是否有被成功建立:
這樣會取得所有的 pods
1 | kubectl get pods |
如果運作正常就會看到以下的結果:
1 | NAME READY STATUS RESTARTS AGE |
可以用 kubectl describe
指令可以看到更多關於 web-app-pod
這個物件的資訊:
1 | kubectl describe pod web-app-pod |
1 | Name: web-app-pod |
這邊看到的資訊有些也是對應 pod 設定檔而出現相對應的值,例如 Name,Labels,Annotations,Containers 等等,而在下方的 Events 可以看到當建立 pod 的時候會執行怎樣的操作,拉 image,建立 Container 等行為,如果有錯誤的話也會顯示在這邊。
如何與 Pod 中的 container 互動
現在 pod 內的 Container 已經被成功起起來了,根據我們的 Code,是開啟 listen 8080 port web-server,但是由於 Pod 是被包在 Cluster 裡面的 Node,以 Minikube 來說,在這個 K8S cluster 只有一個 Node,而 Node 放著我們剛剛建立出來的 Pod,但是外部是沒辦法直接與 Pod 中的 Container 互動的。
使用 kubectl port-forward
port-forward
的指令可以讓 pod 中的某個 port number 與 Local 端的 port 做映射,讓我們存取 Local 端的 port 的時候就能將流量導到 pod 中。
1 | kubectl port-forward web-app-pod 8080:8080 |
指定 pod 名稱,前面為 Local port,後面為 pod 內的 port。會出現以下的內容即成功~
1 | Forwarding from 127.0.0.1:8080 -> 8080 |
接著我們透過 curl 工具來存取 localhost:8080/health
試試看:
1 | curl http://localhost:8080/health |
沒意外的話會得到 {"status": "ok"}
,這樣就能成功存取到。
透過在 K8S 上建立 Service
可以直接透過 kubectl expose 指令
在 K8S 上建立一個 Service。當然也是可以撰寫 Service 設定檔來達到這件事情,這在之後的文章會詳談 Service 的功用,可以將 Service 想成是負責將 pod 做對外連線的資源。
1 | kubectl expose pod web-app-pod --type=NodePort --name=web-app-service |
然後再透過 kubectl get services
,看是否有成功建立 Service:
1 | kubectl get services |
1 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE |
其實這邊就可以看的出來,指令 --type=NodePort
的功用就是會在 Node 上產生隨機 port,這邊是 31014
與 pod port 8080 做對應。可是要記住的是 Node 本身在 Minikube 是一台虛擬機,所以他只是將 Cluster 這個 Node 虛擬機與 pod port 做映射,而現在的問題是如果去存取 Node 的 port,外部才可以連線。
可以透過 minikube 的指令直接取得 service url:
1 | minikube service my-pod-service --url |
如果 Minikube Driver 是用 Docker 的話會得到以下的內容,因為事實上 Node 是透過 Docker 模擬出來的,所以 Local 要直接做存取的話,Minikube 這邊會透過將 Node Container Port 與 Local Port 在做一次映射:
1 | 🏃 Starting tunnel for service web-app-service. |
所以這邊就會拿到 local 端的 64191 port 的對應,反之如果你直接 exec 到 Minikube Node 的 Container 也是可以的:
1 | docker exec -it 47c8098c5313 /bin/bash |
這樣的話也可以存取 Pod 內的 Container。
Q&A
- 網路上有比較多的範例都是 Minikube Driver 是採用 Virtualbox 的做法,所以再取得 service url 的時候會取得虛擬機的 ip 與 Node 對應的 port,所以這樣的話就不會像上面範例一樣是採用 Docker 並且再轉一次映射到 Local 的做法。
總結
這篇文章主要是介紹從建立自己的 Image 及 Container 再來如何在 K8S 建立 Pod 等操作,下一篇文章會介紹 Pod 常用的其他指令操作,還有其他更細節的地方。
最後最後!請聽我一言!
如果你還沒有註冊 Like Coin,你可以透過我的邀請註冊連結來免費註冊,註冊完後就可以在文章最下方幫我按下 Like 按鈕,而 Like 最多可以點五次,如此一來你不用付出任何一塊錢,就能給我寫這篇文章最大的回饋!