這次我們將介紹一本有關容器建置與應用的書籍 —— Kubernetes: Up and Running。本書詳細闡述了容器與映像的基本概念,並深入介紹了容器生態系統的運作。對於剛接觸虛擬化技術與容器的新手而言,這是一本十分友善且實用的入門書籍。接下來,我將依序介紹每一章節的重點,並分享一些我的歸納與心得。
Chapter 1. Creating and Running Containers
傳統上,我們將程式碼寫在本地環境中,讓所有程式共用相同的語言版本與套件版本,但這些依賴關係常會增加團隊協作的複雜性與耦合性,這就是容器技術的優勢所在。
容器大致可分為兩種:系統容器模擬虛擬機並運行完整的啟動過程,如 ssh、cron 和 syslog;而應用程式容器則通常運行單一程式。雖然每個容器運行單一程式看似限制,但這樣的設計使得應用程式之間的組合與調整變得更加靈活,並能夠有效地適應不同需求。利用 Docker 建構映像(Image)
在映像建立過程中,雖然刪除的檔案看似消失,但它們實際上仍存在於映像中,只是變得較難訪問。而且每一層都是獨立的,因此對上一層的修改可能會導致下層重新構建與拉取檔案。
為了降低漏洞風險,應該讓每個映像專注於單一功能。舉例來說,可以透過使用許多小型、具高度耦合的小映像來避免映像暴露於無用的庫或過時的漏洞。
Dockerfile 範例:
FROM node:16
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
RUN npm install express
COPY . .
CMD [ "npm", "start" ]
多步驟建置
我們可以將映像建置拆分成多個階段,例如分為 build 與 deploy 兩個階段。這樣可以避免在部署階段包含不必要的建置工具,從而降低映像的大小並加快下載速度。
Dockerfile 範例:
# 第一階段:Build
FROM golang:1.17-alpine AS build
RUN apk update && apk upgrade && apk add --no-cache git nodejs bash npm
RUN go get -u github.com/jteeuwen/go-bindata/...
RUN go get github.com/tools/godep
WORKDIR /go/src/github.com/kubernetes-up-and-running/kuard
COPY . .
ENV VERBOSE=0
ENV PKG=github.com/kubernetes-up-and-running/kuard
ENV ARCH=amd64
ENV VERSION=test
RUN build/build.sh
# 第二階段:Deploy
FROM alpine
USER nobody:nobody
COPY --from=build /go/bin/kuard /kuard
CMD [ "/kuard" ]
此章總結
容器提供了一個乾淨的抽象環境,使應用程式更易於建置、部署與分發,並且能夠彼此隔離,從而簡化管理與運維。
Chapter 2. Deploying a Kubernetes Cluster
Kubernetes 叢集是一個完整、可靠且可擴展的分散式系統,也是容器管理的核心平台。
我們可以透過 kubectl
這個命令列工具來與 Kubernetes API 進行互動。kubectl
用於管理大多數 Kubernetes 物件,例如 Pod、ReplicaSet 和 Services 等。
常用指令來建置與確認 Kubernetes 叢集的狀態:
kubectl version
kubectl get componentstatuses
kubectl get nodes
kubectl describe nodes 節點名稱
kubectl get daemonSets --namespace=kube-system kube-proxy
kubectl get deployments --namespace=kube-system core-dns
kubectl get services --namespace=kube-system core-dns
Chapter 3. Common kubectl Commands
在管理 Kubernetes 叢集時,最常見的操作之一是封鎖與排空節點。封鎖節點會阻止新的 Pod 被調度到該節點上;而排空節點則會刪除當前在該節點上執行的所有 Pod。這些操作通常用於刪除機器進行維護或升級。
在這種情況下,可以使用 kubectl cordon
和 kubectl drain
來安全地將節點從叢集中移除。當機器修復後,可以使用 kubectl uncordon
來重新啟用該節點的 Pod 調度。
需要注意的是,Kubernetes 並沒有 undrain
指令,因為當 Pod 被創建時,它會自動調度到空閒的節點上。通常,快速影響節點(例如機器重啟)的狀況不需要封鎖或排空,只有當節點停止服務的時間較長,並且希望將 Pod 移動到其他節點時,才需要進行封鎖或排空操作。
另外,文中還介紹了一個有助於自動補全指令的工具:bash-completion
。
管理叢集時的常用指令:
kubectl config use-context my-context
kubectl get pods,services
kubectl explain pods
kubectl apply -f obj.yaml
kubectl apply -f myobj.yaml view-last-applied
kubectl delete -f obj.yaml
kubectl delete <resource-name> <obj-name>
kubectl label pods bar color=red
kubectl label pods bar color-
kubectl logs <pod-name>
kubectl exec -it <pod-name> -- bash
kubectl attach -it <pod-name>
kubectl cp <pod-name>:</path/to/remote/file> </path/to/local/file>
kubectl get events
kubectl top nodes
Chapter 4. Pods
設計 Pod
設計 Pod 時,最關鍵問題是:「如果這些容器運行在不同的機器上,它們能否正常協作?」若答案是否定的,則將容器放入同一個 Pod 是合理的;若答案是肯定的,則使用多個 Pod 可能更為合適。
舉個例子,WordPress 服務和資料庫是否應該放在同一個 Pod 裡?
首先,WordPress 和資料庫並不是緊密耦合的應用。即使 WordPress 容器和資料庫容器運行在不同的機器上,它們依然可以通過網路有效協作。
其次,您可能不希望將 WordPress 和資料庫作為一個單元進行擴展。WordPress 是無狀態的,擴展其前端非常簡單,只需新增更多的 WordPress Pod。然而,擴展 MySQL 資料庫會比較困難,並且您可能希望為 MySQL 提供專屬的 Pod 和資源。
若將 WordPress 和 MySQL 放在同一個 Pod 中,則兩者的擴展將受到相同策略的限制,這樣的設計通常不夠靈活。
Pod 清單(Pod Manifest)
Kubernetes API 伺服器接收並處理 Pod 清單,並將其儲存於持久化儲存(etcd)中。調度器會透過 Kubernetes API 查找尚未調度到節點的 Pod。
只要有足夠的資源,調度器可以將多個 Pod 部署在同一台機器上。然而,將同一應用程式的多個副本部署在同一機器上會降低可靠性,因為這仍然屬於單一故障域。因此,Kubernetes 調度器會盡可能將來自相同應用程式的 Pod 分散到不同的機器上,以提高系統的可靠性。
資源利用
操作一台機器(無論是虛擬機還是實體機)的基本成本是固定的,不論它是閒置還是滿載。
大多數人選擇使用 Kubernetes 等容器和編排工具,因為它們能有效提高資源利用率,並在鏡像打包與可靠部署方面提供根本性的改進。除了簡化分散式系統開發的應用程式導向語法外,這些工具的另一大優勢是能夠提升叢集中運算節點的整體效能。
Chapter 5. Labels and Annotations
標籤是附加於 Kubernetes 物件(如 Pod 和 ReplicaSet)的鍵值對,用來為物件分組提供基礎。標籤的內容可以是任意的,通常用於識別與組織物件。
註解則是一種類似標籤的儲存機制,用來保存工具和庫可以利用的非識別資訊,通常是鍵值對的形式。
標籤(Label)
標籤是由鍵和值組成的鍵值對,且均由字串表示。標籤的鍵可以分為兩部分:可選的前綴與名稱,兩者由斜線(/
)分隔。鍵的前綴(若有)必須符合 253 字元的 DNS 子網域規範;鍵名稱則必須小於 63 個字元,且以字母或數字開頭和結尾,中間可以包含破折號(-
)、底線(_
)或點(.
)。
合法的標籤鍵範例包括:appVer
、app.version
、ac.com/app-version
。
標籤的常用指令:
kubectl get deployments -L canary # 列出標籤鍵值對
kubectl label deployments alpaca-test "canary-" # 移除標籤
kubectl get pods --show-labels # 列出標籤一覽表
kubectl get pods --selector="app=bandicoot,ver=2" # 列出指定標籤
kubectl get pods --selector="app in (alpaca,bandicoot)" # 列出指定標籤
kubectl get pods -l "ver=2,!canary" # 列出指定標籤
標籤除了幫助用戶組織基礎設施外,還在不同 Kubernetes 物件之間建立關聯。Kubernetes 是一個解耦的系統,沒有層次結構,所有元件獨立運作。但在某些情況下,物件間的關聯至關重要,這些關係通常由標籤和標籤選擇器來定義。

附圖來源:Kubernetes: Up and Running, 3rd Edition 第五章節
註解(Annotations)
註解主要用於存儲工具本身或在外部系統間傳遞配置資訊。與標籤不同,註解並不用於識別和分組物件,而是提供有關物件來源、使用方式或相關策略的附加資訊。
註解的典型用途之一是在滾動部署期間,追蹤部署狀態並提供回滾所需的資訊。註解的鍵格式與標籤類似,但通常具有更強的「命名空間」意圖,例如:deployment.kubernetes.io/revision
或 kubernetes.io/changecause
。
此章總結
標籤用於識別並分組 Kubernetes 叢集中的物件,同時也用於進行選擇器查詢,靈活地將物件分組,例如 Pod。
註解則提供了物件範圍的非識別資訊,主要供自動化工具和客戶端庫使用,並可儲存外部工具(如第三方調度程序或監控工具)的配置資料。
標籤與註解是理解 Kubernetes 叢集如何協同工作的關鍵,能夠釋放 Kubernetes 的真正靈活性,並為建立自動化工具和部署流程奠定基礎。