Skip to main content

32 posts tagged with "Kubernetes"

View All Tags

· 8 min read

本文紀錄如何於 Linux(Ubuntu 22.04) 環境上簡易搭建 Kubevirt 的環境

環境搭建

KVM

安裝指令來檢查 qemu 相關狀態

sudo apt install libvirt-clients

使用 virt-host-validate 檢查相關

$ virt-host-validate qemu
QEMU: Checking for hardware virtualization : PASS
QEMU: Checking if device /dev/kvm exists : PASS
QEMU: Checking if device /dev/kvm is accessible : FAIL (Check /dev/kvm is world writable or you are in a group that is allowed to access it)
QEMU: Checking if device /dev/vhost-net exists : PASS
QEMU: Checking if device /dev/net/tun exists : PASS
QEMU: Checking for cgroup 'cpu' controller support : PASS
QEMU: Checking for cgroup 'cpuacct' controller support : PASS
QEMU: Checking for cgroup 'cpuset' controller support : PASS
QEMU: Checking for cgroup 'memory' controller support : PASS
QEMU: Checking for cgroup 'devices' controller support : WARN (Enable 'devices' in kernel Kconfig file or mount/enable cgroup controller in your system)
QEMU: Checking for cgroup 'blkio' controller support : PASS
QEMU: Checking for device assignment IOMMU support : WARN (No ACPI DMAR table found, IOMMU either disabled in BIOS or not supported by this hardware platform)
QEMU: Checking for secure guest support : WARN (Unknown if this platform has Secure Guest support)

可以看到中間有一個錯誤,這時候需要安裝 sudo apt install qemu-kvm 並且調整權限 sudo usermod -aG kvm $USER.

$ virt-host-validate qemu
QEMU: Checking for hardware virtualization : PASS
QEMU: Checking if device /dev/kvm exists : PASS
QEMU: Checking if device /dev/kvm is accessible : PASS
QEMU: Checking if device /dev/vhost-net exists : PASS
QEMU: Checking if device /dev/net/tun exists : PASS
QEMU: Checking for cgroup 'cpu' controller support : PASS
QEMU: Checking for cgroup 'cpuacct' controller support : PASS
QEMU: Checking for cgroup 'cpuset' controller support : PASS
QEMU: Checking for cgroup 'memory' controller support : PASS
QEMU: Checking for cgroup 'devices' controller support : WARN (Enable 'devices' in kernel Kconfig file or mount/enable cgroup controller in your system)
QEMU: Checking for cgroup 'blkio' controller support : PASS
QEMU: Checking for device assignment IOMMU support : WARN (No ACPI DMAR table found, IOMMU either disabled in BIOS or not supported by this hardware platform)
QEMU: Checking for secure guest support : WARN (Unknown if this platform has Secure Guest support)

Kubernetes

透過 minikube 搭建一個 k8s (provider採用 docker 減少第二層虛擬化)

$ minikube start --cni=flannel

叢集準備好後,安裝 kubevirt-operator

$ export VERSION=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases | grep tag_name | grep -v -- '-rc' | sort -r | head -1 | awk -F': ' '{print $2}' | sed 's/,//' | xargs)
$ echo $VERSION
$ kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-operator.yaml
namespace/kubevirt created
customresourcedefinition.apiextensions.k8s.io/kubevirts.kubevirt.io created
priorityclass.scheduling.k8s.io/kubevirt-cluster-critical created
clusterrole.rbac.authorization.k8s.io/kubevirt.io:operator created
serviceaccount/kubevirt-operator created
role.rbac.authorization.k8s.io/kubevirt-operator created
rolebinding.rbac.authorization.k8s.io/kubevirt-operator-rolebinding created
clusterrole.rbac.authorization.k8s.io/kubevirt-operator created
clusterrolebinding.rbac.authorization.k8s.io/kubevirt-operator created
deployment.apps/virt-operator created

實驗當下使用的版本是 v1.1.0-alpha.0,安裝完畢後檢查 kubevirt namespace 的資源

$ kubectl -n kubevirt get pods
NAME READY STATUS RESTARTS AGE
virt-operator-57f9fb965d-5lnqf 1/1 Running 0 46m
virt-operator-57f9fb965d-f5zg4 1/1 Running 0 46m

接下來安裝 CRD 物件

$ kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-cr.yaml

安裝完畢後可以看到有一個名為 kubevirt 的物件(CRD為 kubevirt,簡稱 kv)被創立,因此 operator 就會針對該物件去創立 kubevirt 相關的服務 Pod

$ kubectl -n kubevirt get kv kubevirt -o yaml
apiVersion: kubevirt.io/v1
kind: KubeVirt
metadata:
annotations:
kubevirt.io/latest-observed-api-version: v1
kubevirt.io/storage-observed-api-version: v1
creationTimestamp: "2023-10-10T14:35:55Z"
finalizers:
- foregroundDeleteKubeVirt
generation: 2
name: kubevirt
namespace: kubevirt
resourceVersion: "1490"
uid: bc621d93-4910-4b1f-b3c8-f8f1f4e27a38
spec:
certificateRotateStrategy: {}
configuration:
developerConfiguration: {}
customizeComponents: {}
imagePullPolicy: IfNotPresent workloadUpdateStrategy: {}
$ kubectl -n kubevirt get pods
NAME READY STATUS RESTARTS AGE
virt-api-77f8d679fc-hntws 1/1 Running 0 49m
virt-controller-6689488456-4jtv8 1/1 Running 0 48m
virt-controller-6689488456-68hnz 1/1 Running 0 48m
virt-handler-psc4w 1/1 Running 0 48m

基本上就是預設的設定檔案,然後對應的 API, Controller 以及 Handler 都被創建出來處理後續的操作。

Virtctl

透過官方指令直接抓取對應版本的 virtctl

VERSION=$(kubectl get kubevirt.kubevirt.io/kubevirt -n kubevirt -o=jsonpath="{.status.observedKubeVirtVersion}")
ARCH=$(uname -s | tr A-Z a-z)-$(uname -m | sed 's/x86_64/amd64/') || windows-amd64.exe
echo ${ARCH}
curl -L -o virtctl https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/virtctl-${VERSION}-${ARCH}
chmod +x virtctl
sudo install virtctl /usr/local/bin
-> % virtctl version
Client Version: version.Info{GitVersion:"v1.1.0-alpha.0", GitCommit:"67902ed9de43d7a0b94aa72b8fd7f48f31ca4285", GitTreeState:"clean", BuildDate:"2023-09-18T10:45:14Z", GoVersion:"go1.19.9", Compiler:"gc", Platform:"darwin/arm64"}
Server Version: version.Info{GitVersion:"v1.1.0-alpha.0", GitCommit:"67902ed9de43d7a0b94aa72b8fd7f48f31ca4285", GitTreeState:"clean", BuildDate:"2023-09-18T12:03:45Z", GoVersion:"go1.19.9", Compiler:"gc", Platform:"linux/arm64"}

'''info 官方文件有說明可以透過 kubectl krew 的平台來安裝 virtctl 指令,透過 kubectl krew install virt 來安裝並使用,但是目前並沒有支援 darwin-arm64 (MacOS M1/M2) '''

安裝 VM

透過官方示範檔案部署第一個 VM

$ kubectl apply -f https://kubevirt.io/labs/manifests/vm.yaml
virtualmachine.kubevirt.io/testvm created
$ kubectl get vm
NAME AGE STATUS READY
testvm 7s Stopped False

預設情況下,創建好 VM 並不代表 VM 已經啟動,這時候可以透過 virtctl 將該 VM 給運行起來

$ virtctl start testvm
VM testvm was scheduled to start

當 VM 啟動後,對應的 Pod 就會正式被部署到環境內

$ kubectl get pods -o wide

這時候來研究一下該 Pod 的一些架構

先透過 virtctl console testvm 登入後觀察一下 VM IP

$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc pfifo_fast qlen 1000
link/ether 52:54:00:0c:00:55 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.2/24 brd 10.0.2.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe0c:55/64 scope link
valid_lft forever preferred_lft forever
$ ip r
default via 10.0.2.1 dev eth0
10.0.2.0/24 dev eth0 src 10.0.2.2

IP 是 10.0.2.2 並且 Gateway 是 10.0.2.1 這時候進入到對應的 Pod 去觀察

$ kubectl exec -it virt-launcher-testvm-pnn4j -- bash
bash-5.1$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
link/ether 12:37:77:cf:6d:63 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.244.0.10/24 brd 10.244.0.255 scope global eth0
valid_lft forever preferred_lft forever
3: k6t-eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
link/ether 02:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.1/24 brd 10.0.2.255 scope global k6t-eth0
valid_lft forever preferred_lft forever
4: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc fq_codel master k6t-eth0 state UP group default qlen 1000
link/ether d6:0e:c5:6f:41:f1 brd ff:ff:ff:ff:ff:ff
bash-5.1$

這邊可以看到 Pod 上面的 k6t-eth0 是有 IP 10.0.2.1 同時可以看到下方有一個 tap0 的網卡,該網卡有設定 master k6t-eth0 因此可以推斷 k6t-eth0 是 Linux Bridge, tap0 則是 bridge 下的一個 Port,透過下列指令可以確認


bash-5.1$ ls /sys/class/net/k6t-eth0/brif
tap0
bash-5.1$ ls /sys/class/net/k6t-eth0/bridge/
ageing_time group_fwd_mask multicast_last_member_count multicast_query_response_interval nf_call_arptables root_port vlan_protocol
bridge_id hash_elasticity multicast_last_member_interval multicast_query_use_ifaddr nf_call_ip6tables stp_state vlan_stats_enabled
default_pvid hash_max multicast_membership_interval multicast_router nf_call_iptables tcn_timer vlan_stats_per_port
flush hello_time multicast_mld_version multicast_snooping no_linklocal_learn topology_change
forward_delay hello_timer multicast_querier multicast_startup_query_count priority topology_change_detected
gc_timer max_age multicast_querier_interval multicast_startup_query_interval root_id topology_change_timer
group_addr multicast_igmp_version multicast_query_interval multicast_stats_enabled root_path_cost vlan_filtering
bash-5.1$

k6t-eth0 底下有眾多 bridge 的設定,並且 brif 底下有 tap0,而實務上該 tap0 則是 kvm 創建 vm 後將其綁到 VM 內,因此會與 VM 內的 eth0 掛勾,可以想成是一條大水管,一邊進去另外一邊出來 看來詳細細節還是需要閱讀interface networks,似乎提供不同網路模式來達成不同功能,有空來玩看看彼此差異研究下實作細節。

· 3 min read

如何投過 Bitnami 的 Helm Chart 來安裝 Redis-Cluster

採用 Kustomize + Helm 的方式 (ArgoCD)

$ cat kustomization.yaml
helmCharts:
- name: redis-cluster
includeCRDs: false
valuesFile: redis.yaml
releaseName: redis-cluster
namespace: production
version: 9.0.5
repo: https://charts.bitnami.com/bitnami

$ cat redis.yaml

global:
storageClass: standard-rwo
existingSecret: redis-cluster
existingSecretPasswordKey: password
redis:
resources:
limits:
cpu: 2
memory: 2Gi
requests:
cpu: 0.1
memory: 0.5Gi
podAnnotations:
'xxxxx': 'yyyyy'

這種部署方式就會啟動密碼驗證機制,而密碼則來自於同 namespace 的 secret 物件 redis-cluster 內的 key password.

如果想要無密碼驗證,可以使用下列方式

usePassword: false

'''note 如果已經先行有密碼驗證,則修改此欄位對於運行中的 Redis Cluster 不會有任何效果,這部分需要更多額外操作來完成,砍掉 PVC 重新部署是一個簡單暴力的方式。 '''

由於此架構會部署 Redis-cluster,預設情況下會部署三組(master+worker)的 statefulset,並且給兩組 servicee

redis-cluster                       ClusterIP      10.2.5.248    <none>        6379/TCP                                                                                          213d
redis-cluster-headless ClusterIP None <none> 6379/TCP,16379/TCP 213d

另外要注意的是,redis-cluster 並不適用 kubectl port-forward 的方式連接,因為 redis-cluster 的溝通過程會回傳其他 Pod 的 IP 給你,而每個 Pod 的 IP 都用相同的 Port,因此除非你有辦法於本地產生一些虛擬網卡並且搭配多組 kubectl port-forawrd 幫每個 Pod 都打通,否則存取上會出問題。

舉例來說

$ kubectl port-forward --address 0.0.0.0 pod/redis-cluster-0 6379:6379
Forwarding from 0.0.0.0:6379 -> 6379
$ redis-benchmark -n 1 --cluster
Cluster has 3 master nodes:

Master 0: 1020525d25c7ad16e786a98e1eb7419d609b8847 10.4.0.119:6379
Could not connect to Redis at 10.4.0.119:6379: Connection refused

可以看到透過 port-forward 打進去後,接下來的連線就會轉到其他的 pod 然後就會失敗,因此這種情況要簡單使用還是部署一個包含 redis 指令的 Pod 到同樣的 namespace 並且用 kubectl exec 進去操作會比較順

$ kubectl run --image=hwchiu/netutils test
$ kubectl exec -it test -- bash
root@test:/# redis-benchmark -h redis-cluster -q -c 20 -n 30000
PING_INLINE: 44977.51 requests per second
PING_BULK: 48154.09 requests per second
SET: 45317.22 requests per second
GET: 47169.81 requests per second
INCR: 50251.26 requests per second
LPUSH: 48465.27 requests per second
LPOP: 41265.48 requests per second
SADD: 37878.79 requests per second
SPOP: 49833.89 requests per second
LPUSH (needed to benchmark LRANGE): 51724.14 requests per second
LRANGE_100 (first 100 elements): 43041.61 requests per second
LRANGE_300 (first 300 elements): 35842.29 requests per second
LRANGE_500 (first 450 elements): 36014.41 requests per second
LRANGE_600 (first 600 elements): 33259.42 requests per second
MSET (10 keys): 42796.01 requests per second

· 3 min read

GKE 環境上可以啟動 CA(Cluster-Autoscaling) 來根據資源使用量調整節點的數量,可以視為節點層級的 HPA

基本上只要節點的資源使用率過低,該節點就會被嘗試回收並且將所有的 Workload 都轉移到其他的節點

如果有特別特別重要的 Pod 希望該 Pod 能夠抑制 CA 的行為,有該 Pod 運行的節點都不能被踢除回收的話,可以於 annotations 中加入下列設定

    cluster-autoscaler.kubernetes.io/safe-to-evict: 'false'

該節點就會讓節點沒有辦法順利踢除因此最後不會回收該節點,該指令也要小心使用,若用不好可能會導致節點資源使用率過低最後產生額外的花費。

應用程式本身需要更長時間去調整 GracePeriod (預設 30 秒),可以直接修改 pod.spec.terminationGracePeriodSeconds 此欄位即可

$ kc explain pod.spec.terminationGracePeriodSeconds
KIND: Pod
VERSION: v1

FIELD: terminationGracePeriodSeconds <integer>

DESCRIPTION:
Optional duration in seconds the pod needs to terminate gracefully. May be
decreased in delete request. Value must be non-negative integer. The value
zero indicates stop immediately via the kill signal (no opportunity to shut
down). If this value is nil, the default grace period will be used instead.
The grace period is the duration in seconds after the processes running in
the pod are sent a termination signal and the time when the processes are
forcibly halted with a kill signal. Set this value longer than the expected
cleanup time for your process. Defaults to 30 seconds.

簡易 bash 腳本可以備份目前環境中的所有 secret 物件

function dump_secret {
for i in $(kubectl -n $1 get --no-headers secret | awk '{print $1}'); do
kubectl -n $1 get secret -o yaml $i > $i.yaml;
done
}

function dump_secrets {
for i in $(kubectl get ns --no-headers | awk '{print $1}'); do
if [ ! -d "./$i" ]; then
mkdir $i
fi
echo "Dump $i"
cd $i
dump_secret $i
cd ..
done
}

· 2 min read

Kubernetes 內的容器運行上可能會遇到 OOM (Out Of Memory),通長會有兩種情況

  1. 應用程式本身的 Memory Limit 沒有設定好,因此踩到上限被移除
  2. 眾多應用程式的 Memory Request 沒有設定好,導致系統資源被互搶直到系統沒有足夠記憶體,因此觸發 OOM 開始砍人

這類型的事件可以透過下列的方式去觀測

  1. 安裝 kube event exporter,該專案會將所有 event 以不同的方式輸出。簡易方式可以採用 stdout 的方式輸出
  2. 透過 Logging 系統收集 stdout 的 log,從中分析是否有 OOM 的事件發生,有的話可以發送 Alert

以 Loki 來說,可以採用下列語法去過ㄌㄩ

count_over_time({container="kube-event-exporter"}[1m] | json | __error__ != "JSONParserErr" | reason="OOMKilling")

· 2 min read

GCP 本身有自己的 IAM roles,可以讓所有 GCP 使用者有特定的權限去存取 GKE 叢集,譬如

  1. Kubernetes Engine Cluster Admin
  2. Kubernetes Engine Cluster Viewer
  3. Kubernetes Engine Developer

然而這類型的設定卻有一些限制

  1. 沒有辦法針對 namespace 內去詳細設定
  2. 不方便針對 cluster 層級設定,譬如一個專案內若是有多個 GKE cluster,則權限會全部套用

但是這類型的操作與 gcloud 的整合非常順,可以很輕鬆的就讓所有團得人員獲得 GKE 的存取權限,進而使用 kubectl 等指令

若今天想要修改權限改使用 Kubernetes RBAC 的方式,達到稍微細緻以 namespace 為基底的權限, 並且以群組信箱來當作 subjet 的話則需要一些額外步驟

  1. 將 Google Group 與 GKE 連動,可參考 GKE RBAC
  2. 於 Google Group 將使用者都加入到該群組中
  3. 於 GCP 給予該 Google Group ([email protected]) 一個 Kubernetes Engine Cluster Viewer 的權限,因為所有人都至少要能夠透過 gcloud 去認證獲得 KUBECONFIG 來存取,因此至少要可讀

另外群組的部分,可以採用 nested group,就是所有真正的 group 都加入到上述的 gke-security-groups 內,因此 RBAC 設定的部分就可以採用 [email protected], [email protected] 等方式來設定。

一切完畢後就依照 Kubernetes RBAC 的設定,準備 Role/RoleBinding,其中 RoleBinding 的 Subjects 改成

---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: xxxxxxxxxx
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: xxxxxxxxxxxx
roleRef:
kind: Role
name: xxxxxxxxxx
apiGroup: rbac.authorization.k8s.io

· 4 min read

標題: 「使用 StressChaos 的經驗來學習 Pod Memory 使用情況」 類別: others 連結: https://chaos-mesh.org/blog/how-to-efficiently-stress-test-pod-memory/

本篇文章是來自於 Chaos Mesh 內的官方文章,主要是想要探討為什麼使用 Chaso Mesh 來測試記憶體狀況時結果實際狀況與設定的狀況不一致 文章一步一步的探討所有問題最後同時也整理了一些關於 Kubernetes 內的 Memory 相關機制

文章開頭,作者先部署了一個簡單的 Pod(只有一個 container),該 Pod 針對 Memory 的部分設定 request: 200Mi, limits: 500Mi 結果作者到該 Container 中透過 free 與 top 的指令,都觀察到顯示的記憶體使用量高達 4G,這部分明顯與設定的 limits 500Mi 有所衝突 因此這邊產生了第一個點要特別注意

Kubernetes 是透過 cgroup 來計算與控管 Pod 的 Memory 用量,然而 free/top 等指令並沒有跟 cgroup 整合,因此就算跑到 container 中執行這兩個 指令看到的輸出其實都是 host 相關的,如果想要知道真正 container 相關的數量,還是要使用 cgroup 相關的指令來取得,譬如 cat /sys/fs/cgroup/memory/memory.usage_in_bytes

文章還有特別提到 Kubernetes 會針對 Request/Limit 的設定方式來將你的 Pod 分為三個等級,分別是 BestEffort, Burstable 以及 Guaranteed 其中當系統因為 OOM 不足要開始找受害者下手時,被設定為 Guaranteed 的應用程式則會是最低優先度,只有真的找不到其他受害者時才會來處理 Guaranteed 類型的 Pod。

最後則是更細部的去探討 Kubernetes 關於 Memory 的使用與管理 對於 Kubernetes 來說, 當系統上 Memory 數量不足時,可能會觸發 Evict 的行為,開始將部分運行的 Pod 給踢出該節點,而如同前面所述, Kubernetes 是依賴 Cgroup 來處理的,因此 /sys/fs/cgroup/memory/memory.usage_in_bytes 自然而然就成為其決策的重要參數

其中要注意的是 /sys/fs/cgroup/memory/memory.usage_in_bytes 代表的並不是 "剛剛好系統上正在被使用的 Memory 數量",其數值則是由 "resident set", "cache", "total_inactive_file" 等三個面向組合而成,因此 Kubernetes 實際上會先從 /sys/fs/cgroup/memory/memory.usage_in_bytes 與 /sys/fs/cgroup/memory/memory.stat 取得相關參數,其中後者可以得到如 total_inactive_file 的數量 最後透過下列算式 working_set = usage_in_bytes - total_inactive_file 來得到一個名為 working_set 變數,該變數實際上也可以由 kubectl top 獲取,這也是 kubernetes 用來判斷是否執行 evict 的主要指標。

一個節點還有多少可用的 Memory 則是透過 memory.available = nodes.status.capacity[memory] - working_set 所以每個節點的總共量扣掉 workign_set 就是當前可用量,一旦當前可用量低於門檻時,也就是 k8s 執行 evict 之時 官網文件中其實有滿仔細的去描述這些操作行為 有興趣的可以花點時間全部看完 https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/

· 3 min read

標題: 「Mizu, 一套用來檢視 Kubernetes Traffic 的視覺化工具」 類別: tools 連結: https://getmizu.io/docs/

Mizu 是一個專門針對 Kubernetes 開發的流量分析工具,該工具透過簡單好用的 UI 讓你檢視叢集內的流量走向,其支持的協定有 HTTP, REST, gRPC, Kafka, AMQP 以及 Redis 等相關的應用程式封包。

雖然說透過大部分的 Service Mesh 也都可以提供一樣的功能,但是 Mizu 的特色就是其輕量的架構設計,就是針對流量分析而已,所以如果團隊目前沒有現成的解決方案時, 可以考慮試試看 Mizu 這套輕量級的解決方案。

Mizu 本身由兩個元件組成,分別是 CLI 以及 Agent,當你安裝 Mizu 的 Kubernetes 內時,其會安裝兩個元件

  1. 透過 Daemonset 安裝 Agent 到所有節點
  2. 透過 Pod 安裝一個 API Server

Agent 會針對需求去抓取節點上特定的 TCP 封包(目前也只有支援 TCP 流量,這意味如 ICMP, UDP, SCTP 等就沒有辦法),此外要特別注意這類型的解決方案為了能夠 抓取到節點上的所有流量,通常都會讓這類型的 Agent 都設定為 hostnetwork: true,如此一來該 Agent 才有辦法觀察到節點上的所有網卡來進行流量擷取。

有些 k8s 環境會透過如 OPA(Gatekeeper) 等機制去控管要求所有的 Pod 不准使用 hostnetwork,有這些規範的可能就要注意一下整合上的問題。

有興趣的可以稍微玩看看,看看這類型的工具是否可以幫忙除錯

· 3 min read

標題: 「Datree, Kubernetes Configuration 檢查工具」 類別: tools 連結: https://opensource.com/article/22/4/kubernetes-policies-config-datree

如同各類程式語言的測試框架, Kubernetes 的部署文件(YAML)實際上也是可以導入 CI 的概念,那到底 YAML 檔案有什麼東西需要檢驗? 最基本的概念大致上可以分成三種

  1. YAML 語法的檢查
  2. Kubernetes YAML 的語意檢查
  3. Kubernetes YAML 的設定規範檢查

除了基本的 YAML 部署外,還要考慮一下團隊是採用何種方式來管理 Kubernetes App,譬如原生 YAML, Helm, Kustomize 等各種不同方法。

(1) 的話其實最基本的方式就是使用 yq 指令,其本身就可以檢查基本的 YAML 語法,如果是 Helm 的使用者也可以透過 Helm template 的方式來嘗試渲染,渲染的過程也會幫忙檢查 YAML 的合法性。 (2) 的話其實也有其他如 kubeval 等類型的工具去幫忙檢驗 YAML 內容是否符合 Kubernees Scheme,這邊要特別注意的還有版本問題,畢竟每次升級都會有很多 API Version 被調整 (3) 的話講究的是規範,譬如要求所有 workload 都必須要描述 CPU/Memory 的Request/Limit,或是要求所有容器都要以 non-root 的身份運行, 這部分有如 kube-score,或是基於 REGO 的 conftest 等工具可以檢測。

而今天分享的這個工具 datree 基本上就是一個人包辦上述三個工具,該工具基本上有兩種模式使用

  1. local 使用,就如同上述所有工具一樣,你可以把所有策略與規則都放到本地環境,搭配 git hook, CI pipeline 等概念去執行
  2. datree 還提供了一個中央管理 Policy 的伺服器,每個運行 datree 的環境都可以與該團隊維護的 server 連動,讓你透過網頁的方式去設定想要驗證的 k8s 版本以及想要檢測的規範有哪些。

基本上這類型的工具愈來愈多,找到一個適合團隊的工具將其整合到 CI 中,讓團隊的 Kubernetes YAML 都能夠符合團隊規範,同時也透過 CI 的流程盡可能提早地找出問題

· 4 min read

標題: 「三座獨立 k8s cluster 還是一個跨三個地區的 k8s cluster ?」 類別: kubernetes 連結: https://itnext.io/3-reasons-to-choose-a-wide-cluster-over-multi-cluster-with-kubernetes-c923fecf4644

講到多套 kubernetes 的情況下,目前大部分的文章都會推薦用三套獨立的 kubernetes 叢集而非架設一套同時管理三個地點的 kubernetes 叢集。 本篇文章作者從不同的面向分享為什麼要選擇一個 kubernetes 管全部,而不是要架設三套 kubernetes 叢集。

Latency

一套 kubernetes 最令人詬病且很難處理的就是 Latency 的問題,作者提到 Latency 的問題會影響 ETCD ETCD 被影響後會影響整個叢集的運作,甚至連應用程式相關的處理都會變慢。

作者提到其實這個問題能夠採取兩個步驟來解決

  1. 重新安排 etcd 的節點位置,或是使用 non-etcd 的解決方案
  2. 透過 node labels 讓要使用 etcd 的服務跟 etcd 盡量靠近

註: 我是覺得這說法不能解決問題,一般應用程式要是被分散到不同地區你的存取還是有機會跨地區,除非要很認真地針對不同地區去設計 label,讓應用程式的部屬都只會固定同個地區,但是要這樣搞跟我直接搞三套不覺得後者會比較累。

Security

作者一直強調使用 mesh VPN 來打通底層所有網路封包處理,讓你一個大 k8s 管理多個地區,就不用擔心底層網路問題

單套 k8s 的好處有什麼?作者認為有

No Complicated tooling

作者提到 2021 年的 KubeConf 有各種管理多套 k8s 叢集的工具,如 KubeEdge, OpenShift Edge, Akri, Baetyl, Kubermatic, Rancher, KubeFed... 等,如果用一套大 k8s 就可以不使用這些工具,直接減少與這類型複雜工具的依賴性 一套 k8s 叢集可以讓你使用最簡單也是最習慣的方式來管理所有環境

No extra overhead

每套 K8s 環境中都會有如監控,日誌, registry 等各種工具,多套 k8s 的架構就是每個叢集都要安裝一份,但是如果採用一個大 k8s 的架構就只要維護一份即可 所以可以減少很多不必要的重複安裝。

Ultimate Flexibility

這段其實不很理解,為什麼作者這麼想要推廣 mesh VPN ...

註: 這篇文章底下有留言說探討到說 RBAC 等相關權限問題是個很大的問題,你一套 k8s 很難處理這些,事情沒有想像的這麼簡單

· 3 min read

標題: 「強化 Kubernetes 叢集的必備工具」 類別: kubernetes 連結: https://medium.com/mycloudseries/must-haves-for-your-kubernetes-cluster-to-be-production-ready-dc7d1d18c4a2

作者本篇文章想要分享一個其用來讓一個 Kubernetes 變得能夠真正上戰場的相關工具,因此文章中特別強調是 Production-Ready 的情況。 一個 Production Ready 的 K8s 叢集必須對於下列每個大項目都要有相關處理方式,譬如

  1. Reliability and Availability
  2. Security
  3. Network, Monitoring & Observability
  4. Backup/Recovery
  5. Cost Optimization
  6. Cluster Visualization

Reliability and Availability: 該領域的兩個指標代表的意義不太一樣,但是對於一個提供服務的叢集來說都一樣重要

這邊作者列舉了幾個工具譬如

  1. K8s 內建的 HPA
  2. AWS 的 karpenter,讓你針對基於節點為單位來擴充
  3. Cluster-Autoscaler
  4. Goldilocks

Backup/Recovery 有不少人團隊都對於對於叢集的備份與還原感到頭痛,目前最知名的開源專案莫過於 Velero,其支援不同的儲存設備如 Cloud Storage 等來存放,讓不同環境的 k8s 使用者都有辦法去備份其叢集內的資料

Cost Optimization

對於雲端架構來說,基本上雲端業者的內建功能已經可以針對如 VM, 底層架構等各種服務去列舉出各自的花費金錢,將此概念套入到 Kubernetes 本身大抵上只能理解到 Master Node, Worker Node 等之類的花費, 因此透過 Kubecost 之類的專案來將成本的洞察範圍擴充到 Kubernetes 內部,以 namespace, pod 等各種 k8s 的資源為單位來列舉實際花費的金額,能夠讓團隊更有效地去管理相關花費