Kubernetes 教學 第四篇(Network 篇)
CNI
CNI,全名 Container Network Interface,是負責為 Container 提供網路功能的標準化介面,允許不同的插件可以被整合進 K8S 中。
可以在以下場合背後看到 CNI 的運作:
- Pod 網路初始化:CNI 插件配置其網路介面,并且分配 IP。
- Pod 流量交互:配置路由,使得 Pod 間可以彼此通訊,也可以訪問外網。
- 網路隔離:配置網路 Namespace 和防火墻規則,實現網路隔離,增强安全性。
我們可以選擇我們喜歡的 CNI 插件,這些插件遵循 CNI 介面標準,常見的有 Calico 和 Flannel 等,這些可以被很簡單的整合進 K8S 中,替我們管理 Pod 網路。
在一個 Pod 的生命週期,會經歷以下的流程:
- CNI 介面被呼叫,將網路設置、容器屬性傳遞給插件。
- CNI 插件根據傳入參數,爲 Pod 創建網卡、分配 IP、設置路由以及防火牆規則等。
- 完成 Pod 的網路初始化後,Pod 便可以使用網路通訊功能。
- 當 Pod 要被刪除時,CNI 插件會再次被呼叫,清理掉相關設置、釋放 IP 地址等資源。
而在我使用的 microk8s v1.30.4 中,預設的 CNI 插件是 calico v3.25.1,而其預設 container 網段是 10.1.0.0/16,與我內網有所衝突,這部分需要調整。
而我們先檢查一下 calico 的 api 版本:
$ kubectl api-versions | grep calico
crd.projectcalico.org/v1
而事實上,這個不是我們常用的 calico 版本,根據這篇 GitHub Issue 的結論,這不是應該開放給終端使用者的 API,而我在後續的操作上也的確遇到了很多問題,所以我們想辦法先安裝 projectcalico.org/v3
,這個才是一般使用的版本。
安裝 projectcalico.org/v3
移除舊的 Calico CNI:
kubectl apply -f /var/snap/microk8s/current/args/cni-network/cni.yaml
安裝新版本的 Calico CNI:
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.2/manifests/tigera-operator.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.2/manifests/custom-resources.yaml
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.2/manifests/calico.yaml
允許 kubectl
操作 calico
:
apiVersion: operator.tigera.io/v1
kind: APIServer
metadata:
name: default
spec: {}
檢查 apiserver
狀態:
$ kubectl get tigerastatus apiserver
NAME AVAILABLE PROGRESSING DEGRADED SINCE
apiserver True False False 1m10s
檢查 Pod 運行狀態:
kubectl get pods --all-namespace
檢查 API 資源:
kubectl api-resources --api-group=projectcalico.org
檢查 API 版本:
$ kubectl api-versions | grep calico
crd.projectcalico.org/v1
projectcalico.org/v3
調整預設 IPv4 Pool
先查看我們的 IP pools:
$ kubectl get ippools
NAME CREATED AT
default-ipv4-ippool 2024-09-28T08:22:43Z
我們編輯那個 IP pool 即可:
$ kubectl edit ippools default-ipv4-ippool
修改 cidr
改成不會衝突的網段即可。
接下來要重啓所有的 Pods,來讓他們拿到重新分配的 IP。
由於目前沒有跑什麼重要的服務,我就直接使用比較暴力的做法:
$ kubectl delete pods --all --all-namespaces
如果有嚴格的 SLA 或是可靠性需求,那麼我們可能需要採用一些其它方法來降低 downtime 或是損失,例如:
- 針對每個 Deployment 進行
rollout restart
(第三篇提到過的方法)。 - 針對不同的 Node 分開處理,來確保每個 Deployment 在當下都至少還有一份 Replica。
DNS
我們可以透過 Service 甚至是 Ingress Controller 來訪問 Pod,但如果 Pod 之間要互相訪問,那就不適合用這種方式了,而用 DNS 是更好的選擇。
原因如下:
- Service 分配的 ClusterIP 是有可能變動的,例如你修改了 Service 配置。
- Network Policies 主要依賴於 Namespace 和標簽來控制網路流量,如果需要,使用 DNS 會是比 ClusterIP 更好的選擇,提供更高的可讀性。
在預設情況下,我們創建了一個 service,k8s 會自動創建一個 A record:{service-name}.{namespace}.svc.cluster.local
。
例如之前我們創立的 Prometheus:
$ kubectl get svc -n monitoring
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana ClusterIP 10.152.183.109 <none> 3000/TCP 6d18h
prometheus-server ClusterIP 10.152.183.125 <none> 9090/TCP 6d18h
我們便可以從 Grafana 的 GUI 設定 Data source:
當然這個 svc.cluster.local
後綴是可以修改的,但這邊先不嘗試,等改天如果有需求,要使用正規的 K8S cluster 而非 microk8s 的時候再做嘗試。
