概述#

要實作 Kubernetes(K8s)中常見的進階操作(例如負載均衡、滾動更新、安全與監控),最終都會圍繞在三個基礎物件上:Pod、Service、Deployment,本系列稱為「三兄弟」。本章先從 Pod 開始實作。

Pod 是節點(Node)中最小的執行單位,使用者部署的容器(Container)都會被放進 Pod 中管理。一個 Pod 通常只包含一個容器,但也可以同時容納多個彼此緊密協作的容器。

準備容器映像#

只要符合 Container 規範的服務都能被 Kubernetes 部署,並不限於 Docker。但因為 Docker 仍是目前最普遍的容器工具,本章使用 Docker 作為映像建構工具。

簡易的 Go API#

下面是一個會在 localhost:8080 回應 Hello foo 的 Gin 範例:

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

func main() {
	router := gin.Default()
	router.GET("/", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"data": "Hello foo"})
	})
	router.Run()
}

Dockerfile#

採用多階段建構,先用 golang 映像編譯出二進位檔,再放到輕量的 alpine 映像中執行:

FROM golang:1.18-rc-alpine as builder

WORKDIR /

COPY . .

RUN go mod tidy

RUN go build -o main

FROM alpine:3.15.0-rc.4

WORKDIR /

COPY --from=builder /main .

EXPOSE 8080

ENTRYPOINT ["./main"]

建構並啟動容器確認沒問題:

docker build -t foo .
docker run --rm -p 8080:8080 -it -d foo

推送至 Container Registry#

容器化的便利之一就是把映像推到遠端 Registry,後續任何環境都可以透過 image 名稱與 tag 拉取相同的版本。Kubernetes 也是透過這個機制取得要執行的容器映像。

docker build -t mikehsu0618/foo .
docker push mikehsu0618/foo

範例使用作者個人的 Docker Hub 倉庫;如果只是練習,可以直接使用 mikehsu0618/foo 這個公開映像,不用自己重新建構。

撰寫 Pod 設定檔#

Pod 在 Kubernetes 中以 YAML 描述,下列是最小可用版本:

apiVersion: v1
kind: Pod
metadata:
  name: foo
  labels:
    app: foo
spec:
  containers:
    - name: foo
      image: mikehsu0618/foo
      ports:
        - containerPort: 8080

各欄位的用途:

  • apiVersion:指出該物件在 Kubernetes 中使用的 API 版本。
  • metadata.name:Pod 名稱。
  • metadata.labels:附加在物件上的鍵值組,用來分組與被 Selector 選取。雖然不直接影響核心運作,但會在 Service、Deployment 等地方被廣泛使用。
  • spec.containers:定義一個或多個容器,每個容器都需要 name 與 image。
  • spec.containers.ports.containerPort:容器對外開放的連接埠,需與 Dockerfile 中 EXPOSE 的 8080 一致。

在 Kubernetes 中建立 Pod#

兩種建立資源的常用指令:

kubectl apply -f pod.yaml
# 或
kubectl create -f pod.yaml

兩者差別:

  • create:只用於建立尚未存在的資源;若資源已存在會報錯。
  • apply:宣告式(Declarative)作法,會比對設定差異並更新,是日常較推薦的用法。

確認 Pod 狀態:

kubectl get pods
kubectl describe pod foo

describe 會列出 Pod 的容器狀態、事件(Events)、QoS、Tolerations 等資訊,當 Pod 出問題時是首要的除錯工具。例如 Events 區會記錄 Scheduler 將 Pod 指派到哪個節點、kubelet 何時開始拉取映像、容器何時啟動成功。

用 port-forward 連線 Pod#

為了在本機驗證 Pod 內的服務,可以使用 port-forward 將本機端口導向 Pod 內的容器埠:

kubectl port-forward TYPE/NAME [options] [LOCAL_PORT:]REMOTE_PORT

實際範例:將本機 8080 轉發到 Pod 的 8080:

kubectl port-forward pod/foo 8080:8080

執行後會看到:

Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

此時用 curl 或瀏覽器存取 http://localhost:8080,會收到與直接執行容器時相同的回應。

port-forward 適合除錯,但不適合作為常態暴露入口。Pod 一旦被重新建立,原本的 port-forward 連線就會失效,這也是為什麼下一章會引入 Service。

小結#

至此已完成從寫程式碼、建構容器、推送映像,到在 Kubernetes 中建立第一個 Pod 並存取服務的完整流程。Pod 是後續所有概念的核心,未來無論碰到水平擴展、滾動更新還是健康檢查,都會回到對 Pod 的設定上來。

原文出處#

  • GitHub:https://github.com/MikeHsu0618/2022-ithelp/tree/main/Day6
  • iThome:https://ithelp.ithome.com.tw/articles/10288199