DevOps
CICD
K8s
Docker
不知道你有沒有好奇過把kube-apiserver
刪除過?筆者就曾經好奇把它刪掉過,想看看會發生甚麼事XD,結果發現根本刪不掉阿!一旦刪除之後,馬上就會重建一個新的。而且不只是kube-apiserver
而已喔,像kube-scheduler
也是,到底是為甚麼哩?這其中肯定有甚麼,我們今天就來看看吧~
首先要先了解Pod
的創建過程為何。
當一個Pod
被創立時,是由Control Plane
節點建立Pod
的YAML檔,假設名為 pod-def.yaml file,輸入kubectl apply -f
命令創建該Pod
後(或以kubectl run
命令創建),是透過kube-apiserver
命令Node
中的kubelet
元件,kubelet
透過啟動一個名為k8s.gcr.io/pause:3.2
的image
來創建此Pod
。
docker images 命令可以看到這個image
Pod
及Container
名稱不能大寫哦~
但是Pod
創建方式其實不只上述一種。舉例來說,假設這個K8s Cluster
只有一個Node
,既沒有Control Plane
,也沒有第二個Node
,是個單一節點的集群。那麼,這個集群即無法透過kube-apiserver
通知kubelet
創建Pod
(因為沒有Control Plane
)。所以有另一種創建Pod
的方式:
將pod-def.yaml file放在特定路徑的目錄下,由
kubelet
定期掃描這個目錄下的YAML file來創建Pod
。用這種方式創建的Pod
,稱為Static Pod
。Static Pod
是由kubelet
進行管理的只存在特定Node
上的Pod
kubelet
是創建Pod的主要元件,kubelet
會有兩種input
Static Pod
Control Plane
利用kube-apiserver
並通過HTTP API endpoint的方式所以,Pod
依創建方式可分為兩種
當kubelet
創建Static Pod
時,會在同集群的kube-apiserver
中創建一個新的mirror object。Control Plane
可透過kubectl
觀察這個Pod
,但是無法操作(修改、刪除),這是因為kubectl
指令必須搭配kube-apiserver
使用,而這時看到的Pod
只是該Static Pod
的mirror object
。
你可能會好奇為甚麼需要Static Pod
,直接使用一般Pod
不行嗎?這是因為Static Pod
不需依靠Controller Plane
的物件,所以可以透過Static Pod
創建屬於自己Node
中的controller plane
物件,例如,Control Plane
中的controller.yaml, etcd.yaml等等,其實都算是一種Static Pod
。Static Pod
還有另一個好處,就是不用擔心Controller Plane
server crash。而就算 Static Pod
發生crash,kubelet
也會自動restart一個新的。
這就是為甚麼在 Control Plane
上使用kubectl get all --namespace=kube-system
指令時,看到的所有物件都是Pod
,這些就是以Static Pod
的形式運行在K8s
集群中的。Control Plane
節點上的物件基本上都是以Static Pod
的方式創建,畢竟Control Plane
若crash掉整個Cluster就完蛋了~
當使用 kubectl get po -A 時,要如何得知那些Pod
是Static Pod
,那些不是呢? 其實很簡單,只要Pod name
後面跟著 <Control Plane-Name> 的,就都是Static Pod
。像是下圖中的kube-apiserver-g8master
, kube-controller-manager-g8master
等等都是Static Pod
哦~
-A
: All namespaces
剛剛有提到,Static Pod
的創建方式是由kubelet
定期掃描特定目錄下的YAML file來創建,那麼,這個目錄是甚麼目錄呢?
配置文件就是放在特定目錄下 YAML 格式的 Pod
定義文件。用 kubelet --pod-manifest-path = 來啟動kubelet
,kubelet
定期的去掃描這個目錄,根據這個目錄下出現或消失的 YAML 文件來創建或刪除Static Pod
,那麼,要如何知道這個目錄在哪裡呢?可以通過以下指令 ps -aux | grep kubelet 來觀察
也可先進入
/etc/systemd/system/kubelet.service.d
目錄下查看10-kubeadm.conf
這個檔案
$ ps -aux | grep kubelet
root 665 3.9 1.5 1705920 64016 ? Ssl 00:50 50:30 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --cgroup-driver=cgroupfs --pod-infra-container-image=k8s.gcr.io/pause:3.1 --resolv-conf=/run/systemd/resolve/resolv.conf
root 3100 6.3 6.2 496088 248664 ? Ssl 00:50 81:37 kube-apiserver --advertise-address=192.168.17.131 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/etc/kubernetes/pki/ca.crt --enable-admission-plugins=NodeRestriction --enable-bootstrap-token-auth=true --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --insecure-port=0 --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=6443 --service-account-key-file=/etc/kubernetes/pki/sa.pub --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/etc/kubernetes/pki/apiserver.crt --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
george 15571 0.0 0.0 21532 1060 pts/0 S+ 22:15 0:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn kubelet
然後,找到 --config=/var/lib/kubelet/config.yaml 這個參數,並且檢查 config.yaml
這個檔案:
$ cat /var/lib/kubelet/config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 0s
cacheUnauthorizedTTL: 0s
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
rotateCertificates: true
runtimeRequestTimeout: 0s
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s
找到這一行
staticPodPath: /etc/kubernetes/manifests
這個/etc/kubernetes/manifests
路徑就是創建Static Pod的特定目錄啦~
這個路徑一般來說都是固定的,但有些考題會特意將路徑改變,所以建議還是依照上述方法查找路徑比較好喔~
這邊有個觀念很重要
直接用kubectl delete po <static-pod-name> 指令刪除Static Pod 是無法成功的,因為 kubelet 會定期檢查特定目錄下的檔案,即使Static Pod被刪除,但只要其 YAML FILE 還存在,kubelet就會重新創建一個新的Static Pod。若要刪除Static Pod,需刪除其目錄下的 YAML FILE
創建Static Pod
方式分為兩種:設定檔方式及HTTP方式。
在g8node
上創建Static Pod
,先找到創建的特定目錄,在該目錄下創建Static-Pod.yaml,使用最簡單的nginx image
做範例,內容如下:
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
role: myrole
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
但是,若直接將此 Static Pod
創建起來,會一直進入CrashBackOff
狀態,需要重新config你的kubelet
才可以。
輸入 KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --pod-manifest-path=<static-pod-dic>"
KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --pod-manifest-path=/etc/kubernetes/manifest"
## 接著重啟kubelet
systemctl restart kubelet
到Control Plane
查看,就發現 Pod
處於 Running STATUS
囉~
$ kubectl get po
NAME READY STATUS RESTARTS AGE
static-web-g8node1 1/1 Running 0 3h31m
這種方式是透過設定kubelet
的啟動參數--manifest-url
,kubelet
定期從該URL位址下載Pod
的定義檔案,並以yaml或json的檔案格式進行解析,然後建立Pod
。
這種方式實現方法和設定檔方式其實是一致的
前幾天我們說過Control Plane
的組成元件包含:
從哪裡可以驗證這些元件真的存在呢?
可以進入 /etc/kubernetes/manifests 這麼目錄下查看
$ ls /etc/kubernetes/manifests
etcd.yaml kube-apiserver.yaml kube-controller-manager.yaml kube-scheduler.yaml
確實有這四個元件,我們來看看其中的 kube-scheduler
長甚麼樣
$ cat kube-scheduler.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
...
有沒有發現,這些元件都是Pod
,又都位於 Control Plane
的 /etc/kubernetes/manifests
目錄下,是不是覺得很熟悉?沒錯,其實這些元件都是以 Static Pod
的方式運行於 K8s
集群中的喔~
簡單整理一下Static Pod
的特性:
kuber-apiserver
,即使kuber-apiserver
故障也能正常創建Static Pod
Kubelet
定期掃描特定目錄,一旦該 Pod
結束但YAML還在,則會重新被啟動Kubelet
本身會 Mirror 該 Pod
的資訊,所以才可以透過 kubectl
等相關資訊去看到好啦,今天就到這囉~ 謝謝大家~
Create static Pods
[Kubernetes] Static Pod 介紹
You can find me on
KUBELET_ARGS="--cluster-dns=10.254.0.10 ..." --cluster-dns 需要按照/config.yaml 設置嗎 ?