概述#
要實作 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 foodescribe 會列出 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