iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 5
3
DevOps

Kubernetes 30天學習筆記系列 第 5

[Day 5] 在 Minikube 上跑起你的 Docker Containers - Pod & kubectl 常用指令

前言

回顧前幾天的學習筆記,我們現在已經知道

在前四天打好基礎後,今天的學習筆記中,將會介紹

  • 認識 Kubernetes 最小運行單位 - Pod
  • 如何與 Pod 中的 container 互動
  • 常見的 kubectl 指令

小提醒:今天的程式碼都可以在 demo-pod 上找到唷

認識 Kubernetes 最小運行單位 - Pod

在開始將我們 前天打造的 Docker Container 運行在 Kubernetes 之前,我們需要先認識Pod

Pod 是什麼

Kubernetes 上會運行很多個不同種類型的應用服務(applications),而一個 Pod 在Kubernetes世界中就相當於一個application。
Pod有以下特點,

  • 每個 Pod 都有屬於自己的 yaml
  • 一個 Pod 裡面可以包含一個或多個 Docker Container
  • 在同一個 Pod 裡面的 containers,可以用 local port numbers 來互相溝通

在這裡我們會以昨天打造好的 docker image 來做示範,若讀者有自己的Docker Image,在以下的指令中都可以替換成自己的 Docker Image。

關於示範的 Docker Image,可以參考 [Day 3] 打造你的Docker containers

如何建立一個 Pod

以下 my-first-pod.yaml 是我們今天會用到的 yaml 檔,

# my-first-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  labels:
    app: webserver
spec:
  containers:
  - name: pod-demo
    image: zxcvbnius/docker-demo
    ports:
    - containerPort: 3000
  • apiVersion
    apiVersion 是代表目前 Kubernetes 中該元件的版本號。以上述的例子 Podv1,而 v1也是目前Kubernetes中核心的版本號。在日後也會陸續看到 betav1, v1alpha1 等版本號,更多 Kubernetes API 的版本號,可至 官網 API versioning查看。

  • metadata
    在 metadata 中,有三個重要的 Key,分別是 name, labels, annotations

    • metadata.name
      我們可以在 metadata.name 的欄位指定這個 Pod 的名稱,這裡 Pod 的名稱就是 my-pod
    • metadata.labels
      metadata.labels 是 Kubernetes 的是核心的元件之一,Kubernetes 會透過 Label Selector 將Pod分群管理。在之後 [Day 10] Kubernetes世界不可缺少的 - Labels 學習筆記中,將會詳細介紹 Labels 的功能。
    • metadata. annotations
      annotations 的功能與 labels 相似。相較於labels,annotations 通常是使用者任意自定義的附加資訊,提供外部進行查詢使用,像是版本號,發布日期等等。
  • spec
    最後 spec 的部分則是定義 container,在這個範例中,一個 Pod 只運行一個 container。

    • container.name
      我們可以在這 container 中設定 container 的名稱
    • container.image
      Image 則是根據 Docker Registry 提供的可下載路徑。
    • container.ports
      最後 ports 的部分則是可以指定,該 container 有哪些 port number 是允許外部資源存取,而在這裡我們只允許container中的port 3000對外開放。

在了解 my-first-pod.yaml 每一行在做什麼事情之後,我們可以使用 kubectl create 指令在 Kubernetes Cluster 中建立 Pod 物件

kubectl-create-pod

這樣,就建立好 my-app 這個 Pod 了。可以用 kubectl get pods 查看目前 pods 的狀態

kubectl-pod-creating

可以看到 ContainerCreating 的狀態,如果再等一下就會看到狀態變為 Running ,代表 Pod 已經正常開始跑了。

kubectl-pod-running

我們也可以用 kubectl describe 指令可以看到更多關於 my-pod 這個物件的資訊 ,包含我們設置的 Pod Name,labels, 以及這個 pod 的歷史狀態,更多的 log 在 describe-my-pod.log

$ kubectl describe pods my-pod
Name:         my-pod
Namespace:    default
.....
Events:
  Type    Reason                 Age   From               Message
  ----    ------                 ----  ----               -------
  Normal  Scheduled              7m    default-scheduler  Successfully assigned my-pod to minikube
  Normal  SuccessfulMountVolume  7m    kubelet, minikube  MountVolume.SetUp succeeded for volume "default-token-wxjzb"
  Normal  Pulling                7m    kubelet, minikube  pulling image "zxcvbnius/docker-demo"
  Normal  Pulled                 7m    kubelet, minikube  Successfully pulled image "zxcvbnius/docker-demo"
  Normal  Created                7m    kubelet, minikube  Created container
  Normal  Started                7m    kubelet, minikube  Started container

如何與 Pod 中的 container 互動

my-pod 中,有個 container 運行 API server, port number 3000。然而,我們要怎麼與他做互動呢?常見存取 Pod 資源的方法有兩種,

方法1:透過kubectl port-forward

kubectl 提供一個指令 port-forward 能將pod中的某個port number,與本機端的port做mapping 。在今天最後 常用kubectl指令 章節中會提到更多關於 kubectl port-forward 指令的介紹,

$ kubectl port-forward my-pod 8000:3000
Forwarding from 127.0.0.1:8000 -> 3000

看到 Forwarding from 127.0.0.1:8000 -> 3000 代表 port-forward 成功,現在可以在本機端的瀏覽器打開 http://127.0.0.1:8000 ,就可以看到我們運行的 API Server 吐回來的訊息 Hello World!

kubectl-port-forward

方法2:建立一個 Service

之後的學習筆記 中也會針對 Kubernetes 中的 Service 詳細介紹。而在這章節,我們則是透過 kubectl expose 指令幫我們在Kubernetes建立一個 Service 物件。

kubectl port-forward 是將 pod 的 port mapping 到本機端上,而 kubectl expose 則是將 pod 的 port 與 Kubernetes Cluster 的 port number 做 mapping。

我們先可以使用 minikube status 查看目前 minikube-vm 是使用本機端哪個內部網址

minikube-status

接著輸入 kubectl expose 指令,創建一個名為 my-pod-service 的 Service 物件

$ kubectl expose pod my-pod --type=NodePort --name=my-pod-service
service "my-pod-service" exposed

這時我們可以再輸入 kubectl get services 查看目前運行的 Services 有哪些

$ kubectl get services
NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
kubernetes       ClusterIP   10.96.0.1      <none>        443/TCP          9h
my-pod-service   NodePort    10.97.118.40   <none>        3000:30427/TCP   1m

可以看到 my-pod-servicemy-pod 的 port number 30003 與 minikube-vm 上的 port number 30427 做 mapping。接著可以使用 minukube service 的指令快速找到 my-pod-service 的 url

$ minikube service my-pod-service --url
http://192.168.99.104:30427

這時再從你的本機端上的瀏覽器打開 http://192.168.99.104:30427 ,就可以看到 hello world 的字樣。

minikube-service-url

Kubernetes Cluster 內部會有一套網路系統,會替每個 Pod 建立一個 Cluster IP,這個 IP 是由 Kubernetes 內部隨機產生的。這個 Cluster IP 只有Cluster內部資源可以使用;外部資源是無法透過 Cluster IP 與 Pods 互動,所以我們需要再建立一個 Service 元件作為一個橋樑,讓 Cluster 以外的服務也可以與 Pod 做互動。在 kubectl get services 可以看到 TYPE , CLUSTER-IP , EXTERNAL-IP ,在之後 [Day 9] 如何讓外部服務與pods的溝通管道 - Services 會再詳細介紹。

常見的 kubectl 指令

以下列出幾種我們常用到的指令,

取得 Kubernetes Cluster 中所有正在運行的 Pods 的資訊

$ kubectl get pods

如果加上--show-all,則會顯示所有 Pods

$ kubectl get pods --show-all

取得某一個 Pod 的詳細資料

$ kubectl describe pod <pod>  

將某一 Pod 中指定的 port number expose 出來讓外部服務存取(建立一個新的 Service 物件)

$ kubectl expose pod <pod> --port=<port> --name=<service-name>

將某一 Pod 中指定的 port number mapping 到本機端的某一特定 port number

$ kubectl port-forward <pod> <external-port>:<pod-port>

當一個 container 起來之後,有時希望能進到 container 內部去看 logs,可以使用 kubectl attach 這個指令

$ kubectl attach <pod> -i

可以對 Pod 下一個內部指令

$ kubectl exec <pod> -- <command>

如果還記得 第三天 介紹到的Docker Container,會記得在 my-pod 的/app 資料夾底下有 API Server 的原始程式碼與 Dockerfile,我們可以用 ls 列出 /app 資料夾底下的所有檔案,如下圖所示

kubectl-exec

可以新增 Pod 的 Labels

$ kubectl label pods <pod> <label-key>=<label-value>

可以先用 kubectl get pod --show-labels 查看目前 my-pod 有哪些 labels,

$ kubectl get pods  --show-labels
NAME      READY     STATUS    RESTARTS   AGE       LABELS
my-pod    1/1       Running   0          14h       app=webserver

如果我們想要新增 labels,可以輸入以下指令

$ kubectl label pods my-pod version=latest
pod "my-pod" labeled

再次用 kubectl get pod --show-labels 查看,可以發現,LABELS 欄位多了一個 version

$ kubectl get pod --show-labels
NAME      READY     STATUS    RESTARTS   AGE       LABELS
my-pod    1/1       Running   0          14h       app=webserver,version=latest

在未來學習筆記中 [Day 10] Kubernetes 世界不可缺少的 - Labels 有更多關於 Labels 的介紹。

使用 alpine 查看 cluster 狀況

alpine 提供非常輕量級的 Docker Image,大小只有 5MB 上下。可以藉由在 alpine下 指令,在 Kubernetes Cluster 中與其他 Pods 互動,非常適合用來 debug。以下面指令為例,在輸入下述指令後,我們就可以進到 alpine 的 shell。

$ kubectl run -i --tty alpine --image=alpine --restart=Never -- sh

是否還記得我們今天提到,在 Kubernetes Cluster 中,會給每個 Pod 一個 Cluster IP 且只有在 Cluster 裡才可以存取。而我們可以透過 alpine 在 Kubernetes Cluster 中訪問其他 Pods。

可以用 kubectl describe 去查 Pod 目前 Cluster IP,以my-pod為例,目前的cluster ip是 172.17.0.4

$ kubectl describe pod my-pod
Name:         my-pod
Namespace:    default
Node:         minikube/192.168.99.104
.... 
Status:       Running
IP:           172.17.0.4

這時我們可以用 curl 指令去訪問Pod中container跑在port number 3000的API service 。不過我們需要先在 alpine 中安裝 curl 套件。

$ apk add --no-cache curl

安裝完之後,我們可以輸入 curl http://172.17.0.4:3000

kubectl-apline-curl

存取成功後,會看到 Hello World! 字串

總結

今天介紹 kubectl 常用指令以外,也認識了 Kubernetes 的第一個元件,Pod。之後的學習筆記中,會分享當有多個 Pods 同時在 Kubernetes Cluster 中時,我們會如何去管理、擴張以及確保每個 Pod 目前的運行狀態

Q&A

依舊歡迎大家給予建議與討論,如果能按個讚給些鼓勵也是很開心唷 : )

勘誤

感謝 @Samina Fu 網友的提醒,文中指令介紹應為 $ kubectl port-forward <pod> <external-port>:<pod-port>

參考連結


上一篇
[Day 4] 上傳 Docker Image 到 Docker Hub
下一篇
[Day 6] 實際環境運行的 Kubernetes - Node & Architecture Overview
系列文
Kubernetes 30天學習筆記30
1
kim_chang
iT邦新手 5 級 ‧ 2018-01-10 11:43:43

寫得很詳細 推!

0
Samina Fu
iT邦新手 5 級 ‧ 2018-01-23 14:34:10

您好!感謝您的這一系列文章,很詳盡,學習到很多。
關於上述中$ kubectl port-forward <port> <external-port>:<pod-port> 的部分,<port> 應該改為 <pod>
稍微看了一下 kubectl port-forward -h 的內容所得到的資訊。
謝謝

Hi @Samina Fu
哈很開心也很謝謝您的支持!是 <pod> 沒錯,已修正!
真的非常感謝你!

0
the8trigrams
iT邦新手 5 級 ‧ 2018-09-10 12:31:23

請問一下, 我跑 kubectl create -f my-first-pod.yaml 這句時報了以下的錯誤, 是什麼原因呢? 謝謝

[root@minikube ~]# kubectl create -f my-first-pod.yaml
error: the path "my-first-pod.yaml" does not exist

我找到原因了, 原本要有這個檔案才可以跑, 還以為是利用這個指令去生成

沒錯 XD
/images/emoticon/emoticon12.gif

我要留言

立即登入留言