antony@notes:~/kubernetes$ cat "Kubernetes-CRI-基礎運作.md"
Kubernetes CRI 基礎運作
Kubernetes CRI 基礎運作
:::warning
:::spoiler 目錄
[TOC]
:::
:::success 檢查 node 主機的運作情形
$ kubectl get nodes:::spoiler 命令結果
NAME STATUS ROLES AGE VERSION
m1 Ready control-plane 16h v1.24.0
w1 Ready worker 16h v1.24.0
w2 Ready worker 16h v1.24.0:::
:::success 檢視pod 的運作情況
$ kubectl get pods -n kube-system -o wide:::spoiler 命令結果
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-6d4b75cb6d-58jvb 1/1 Running 2 16h 10.244.0.6 m1 <none> <none>
coredns-6d4b75cb6d-z2sjv 1/1 Running 2 16h 10.244.0.7 m1 <none> <none>
etcd-m1 1/1 Running 3 16h 192.168.61.4 m1 <none> <none>
kube-apiserver-m1 1/1 Running 3 16h 192.168.61.4 m1 <none> <none>
kube-controller-manager-m1 1/1 Running 3 16h 192.168.61.4 m1 <none> <none>
kube-flannel-ds-jpqmz 1/1 Running 2 16h 192.168.61.7 w2 <none> <none>
kube-flannel-ds-qcsfc 1/1 Running 2 16h 192.168.61.6 w1 <none> <none>
kube-flannel-ds-rwmjm 1/1 Running 7 16h 192.168.61.4 m1 <none> <none>
kube-proxy-cx78m 1/1 Running 2 16h 192.168.61.6 w1 <none> <none>
kube-proxy-fcb8s 1/1 Running 3 16h 192.168.61.4 m1 <none> <none>
kube-proxy-tgmbm 1/1 Running 2 16h 192.168.61.7 w2 <none> <none>
kube-scheduler-m1 1/1 Running 3 16h 192.168.61.4 m1 <none> <none>後面加
-o wide可以看到pod 的 ip 位址 和所在的主機 :::
:::success 檢視 CRI-O 的版本
$ crio -versionCRI-O 的版本一定跟著 K8S 的版本在運作
:::spoiler 命令結果
crio version 1.24.1
Version: 1.24.1
GitCommit: edda4988043086ee714c0b651ff91e68fa70adf9
GitTreeState: clean
BuildDate: 2022-07-21T14:19:25Z
GoVersion: go1.18.4
Compiler: gc
Platform: linux/amd64
Linkmode: dynamic
BuildTags: containers_image_openpgp, containers_image_ostree_stub, seccomp, selinux
SeccompEnabled: true
AppArmorEnabled: false:::
:::success crictl 的簡易手冊
$ crictl --help | grep -A 20 COMMANDS::::spoiler 命令結果
COMMANDS:
attach Attach to a running container
create Create a new container
exec Run a command in a running container
version Display runtime version information
images, image, img List images
inspect Display the status of one or more containers
inspecti Return the status of one or more images
imagefsinfo Return image filesystem info
inspectp Display the status of one or more pods
logs Fetch the logs of a container
port-forward Forward local port to a pod
ps List containers
pull Pull an image from a registry
run Run a new container inside a sandbox
runp Run a new pod
rm Remove one or more containers
rmi Remove one or more images
rmp Remove one or more pods
pods List pods
start Start one or more created containers
run,可以透過 cri-o 建立 container :::
$ crictl
NAME:
crictl - client for CRI- crictl 這個套件,專門管理 CRI 的套件
- crictl + crio 約略等於 Podman
- 如果一個系統的 deamon 太多,會很容易被人攻陷,且資源運算上會吃很兇,所以docker 被淘汰
- podman 出生 全名: pod manager ,他可以做到docker 90%可以做的事情,且不需要依靠deamon
:::success
檢視 podman 處理 image 的功能
$ sudo podman --help
load Load image(s) from a tar archive
save Save image(s) to an archive
export Export container's filesystem contents as a tar archive
import Import a tarball to create a filesystem imageCRI-O 並沒有以上 load ( 還原 image )、 save ( 備份 image ) 、build、 export 和 import 的命令
因為 cri-o 只有下載 image 的能力,所以需要 podman 來支援 image 的管理 在老師的系統中使用 CRI-O + podman 來維運 K8s
podman 和 cri-o 上網抓 image 後儲存的位置相同,怎麼證明? :::
Podman 與 CRI-O Image 存儲目錄
檢視 podman 儲存 image 的目錄
$ cat /etc/containers/storage.conf | grep -A 15 '\[storage\]'
[storage]
# Default Storage Driver, Must be set for proper operation.
driver = "overlay"
# Temporary storage location
runroot = "/run/containers/storage"
# Primary Read/Write location of container storage
# When changing the graphroot location on an SELINUX system, you must
# ensure the labeling matches the default locations labels with the
# following commands:
# semanage fcontext -a -e /var/lib/containers/storage /NEWSTORAGEPATH
# restorecon -R -v /NEWSTORAGEPATH
graphroot = "/var/lib/containers/storage"檢視 cri-o 儲存 image 的目錄
$ crio-status config
[crio]
root = "/var/lib/containers/storage"透過 crictl 的命令來看 image 的資訊
$ crictl images
IMAGE TAG IMAGE ID SIZE
docker.io/rancher/mirrored-flannelcni-flannel-cni-plugin v1.1.0 fcecffc7ad4af 8.37MB
docker.io/rancher/mirrored-flannelcni-flannel v0.18.0 744246d629cff 63.3MB
k8s.gcr.io/coredns/coredns v1.8.6 a4ca41631cc7a 47MB
k8s.gcr.io/etcd 3.5.3-0 aebe758cef4cd 301MB
k8s.gcr.io/kube-apiserver v1.24.1 e9f4b425f9192 131MB
k8s.gcr.io/kube-controller-manager v1.24.1 b4ea7e648530d 121MB
k8s.gcr.io/kube-proxy v1.24.1 beb86f5d8e6cd 112MB
k8s.gcr.io/kube-scheduler v1.24.1 18688a72645c5 52.3MB
k8s.gcr.io/pause 3.6 6270bb605e12e 690kB
k8s.gcr.io/pause 3.7 221177c6082a8 718kB透過 sudo podman 的命令來看 image 的資訊
$ sudo podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/rancher/mirrored-flannelcni-flannel v0.18.0 744246d629cf 4 days ago 63.3 MB
k8s.gcr.io/kube-apiserver v1.24.1 e9f4b425f919 6 days ago 131 MB
k8s.gcr.io/kube-controller-manager v1.24.1 b4ea7e648530 6 days ago 121 MB
k8s.gcr.io/kube-scheduler v1.24.1 18688a72645c 6 days ago 52.3 MB
k8s.gcr.io/kube-proxy v1.24.1 beb86f5d8e6c 6 days ago 112 MB
docker.io/rancher/mirrored-flannelcni-flannel-cni-plugin v1.1.0 fcecffc7ad4a 10 days ago 8.37 MB
k8s.gcr.io/etcd 3.5.3-0 aebe758cef4c 6 weeks ago 301 MB
k8s.gcr.io/pause 3.7 221177c6082a 2 months ago 718 kB
k8s.gcr.io/coredns/coredns v1.8.6 a4ca41631cc7 7 months ago 47 MB
k8s.gcr.io/pause 3.6 6270bb605e12 9 months ago 690 kB可以發現 Podman 和 CRI-O 儲存 image 的資訊
備份 image
$ sudo podman save docker.io/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.0 > flannel-plugin.tar
備份 image
$ sudo podman save docker.io/rancher/mirrored-flannelcni-flannel:v0.18.1 > flannel.tar
還原 image
$ sudo podman load < flannel-plugin.tarCrun 與 runC 大小比較
$ ls -lh `which runc`
-rwxr-xr-x 1 root root 9.1M Aug 2 18:39 /usr/bin/runc
$ ls -lh `which crun`
-rwxr-xr-x 1 root root 383K Apr 28 06:20 /usr/bin/cruncrun 與 runc 效能比較
## 建立 Container 所需的rootfs
$ mkdir -p ~/wulin/rt/rootfs; cd ~/wulin/rt/rootfs; curl -o alpine.tar.gz http://dl-cdn.alpinelinux.org/alpine/v3.14/releases/x86_64/alpine-minirootfs-3.14.2-x86_64.tar.gz; tar xvf alpine.tar.gz ;rm alpine.tar.gz; cd ..
## 更改權限
$ sudo chown root:root -R rootfs/
## 產生 config.json
$ runc spec實測 runc
$ time for i in {1..100}; do echo "exit" | sudo runc run b1 &>/dev/null; doneoutput :
real 0m3.238s
user 0m1.386s
sys 0m1.392s實測 crun
$ time for i in {1..100}; do echo "exit" | sudo crun run b1 &>/dev/null; doneoutput :
real 0m1.081s
user 0m0.545s
sys 0m0.418s設定 CRI-O 執行 crun
3 台主機: m1 w1 w2 都要設定
$ sudo nano /etc/crio/crio.conf
[crio.runtime]
# Overide defaults to not use systemd cgroups.
conmon_cgroup = "pod"
cgroup_manager = "cgroupfs"
default_runtime = "crun"
[crio.runtime.runtimes.crun]
runtime_path = "/usr/bin/crun"
runtime_type = "oci"
runtime_root = ""
[crio.network]
network_dir = "/etc/cni/net.d/"
plugin_dir = "/opt/cni/bin"default_runtime = "crun",設定 CRI-O 用 crun 來建 Cotainer[crio.runtime.runtimes.crun],下面放 crun 的設定項目runtime_path,設定 crun 放在哪runtime_type,crun 用的標準- CRI-O 內定使用 runc 建 Container,但 crun 比較快,所以修改 CRI-O 設定檔來使用 crun,代表最底層 container 的執行從 runc 改成 crun。
- 為什麼有 crun 可以用?因為有安裝 podman,podman 內定使用 crun 建 Container。
都設定好後,要重啟 node
$ ssh w1 sudo reboot
$ ssh w2 sudo reboot
$ sudo reboot好了後,確定 nodes 是否正常運作
$ kg nodes再確定主機內的 pods 是否都有 running
$ ks補充 :
crun,由安裝 podman 附帶安裝。
Kubernetes 檢測
透過 kubectl 產生一個 pod
$ kubectl run nginx --image=quay.io/cloudwalker/nginx因為只有指定一個 image 所以 只會這個 pod 只會產生一台 container
檢查 pod 運作資訊
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 22s
READY 1/1,後面的 1 是 pod 裡有幾台Container,前面的 1 是 pod 的裡面的 Container 是否有 running ,如果有 running 就會顯示 1
curl pod 的 ip 看網站有沒有順利啟動
$ curl http://10.244.1.2
<title>Welcome to nginx!</title>
...以下省略檢視 K8s Cluster 的網路運作

當我們建立了一個 pod ,裡面的 Container 起了一個網站,這台 pod 會得到一個 Virtul IP ,這個虛擬 IP 是透過 iptables 做出來的,我們可以在 m1 、 w1 和 w2 都能用 curl 指令連到 pod 所建立的網站。
建立和執行我們的 pod
$ kubectl run a1 -it --image=quay.io/cloudwalker/alpine -- sh
-it, 給一個虛擬終端機--,分割符號,後面是針對 pod 所要下達的命令
進 pod , 安裝 curl 指令
$ apk add curl連線到剛剛建立 nginx 的那台 pod
$ curl http://10.244.1.2
<title>Welcome to nginx!</title>
...以下省略更新網路示意圖

小總結
- VM m1、w1、w2 皆使用 NAT 模式,由這三臺 VM 組成 Keubernetes Cluster
- pod 是由 Keubernetes 部署的,具備 IP Address(Virtual IP)
- Virtual IP|沒有設定在網路卡上,是透過 iptables 實作出來的 IP Address
- 因為上述架構的關係 pod、node 之間能實現網路通訊
by 第三組
刪除剛剛建立的兩台 pod
$ kubectl delete pods a1
$ kubectl delete pods nginxKubernetes CNI 基礎運作
Flannel CNI 單一節點運作架構

m1:~$ ifconfig
cni0 Link encap:Ethernet HWaddr 0E:31:89:91:11:C2
inet addr:10.244.0.1 Bcast:10.244.0.255 Mask:255.255.255.0
...
$ ssh w1 'ifconfig'
cni0 Link encap:Ethernet HWaddr 82:58:F3:07:50:67
inet addr:10.244.1.1 Bcast:10.244.1.255 Mask:255.255.255.0
...
$ ssh w2 'ifconfig'
cni0 Link encap:Ethernet HWaddr 06:B1:21:B1:1F:8B
inet addr:10.244.2.1 Bcast:10.244.2.255 Mask:255.255.255.0
m1:~$ brctl show
bridge name bridge id STP enabled interfaces
cni0 8000.0e31899111c2 no vethbb0b5903
vethfc422baa
$ ssh w1 'brctl show'
bridge name bridge id STP enabled interfaces
cni0 8000.8258f3075067 no
$ ssh w2 'brctl show'
bridge name bridge id STP enabled interfaces
cni0 8000.06b121b11f8b no vethfff77f1d
$ ps aux | grep -v grep | grep flanneld
root 4406 0.1 0.6 1335180 37392 ? Ssl 14:52 0:09 /opt/bin/flanneld --ip-masq --kube-subnet-mgr- 因 w1 及 w2 沒有建立過 POD, 所以沒有建立 cni0 橋接器, 一但有建立 POD, cni0 橋接器便會建立
插播
建立 mysql Contianer
準備和進入工作目錄、編輯 Dockerfile
$ mkdir mydb; cd mydb
$ nano DockerfileFROM quay.io/cloudwalker/mysql-server
ENV MYSQL_ROOT_PASSWORD bigred
ADD myuser.sql /docker-entrypoint-initdb.d
EXPOSE 3306FROM,指定要用哪一片 image 建立新的 image ,這裡指定的是quay.io/cloudwalker/mysql-serverENV,等等在 build image 的時候,宣告 變數MYSQL_ROOT_PASSWORD的值等於bigredADD,image 做出來後,將 myuser.sql 這個檔案複製到 image 的/docker-entrypoint-initdb.d目錄- 要
ADD的檔案,需要和 Dockerfile 放在同一層目錄
- 要
EXPOSE 3306,在 Container 上開一個對外的 3306 port
編輯 muser.sql
$ nano myuser.sql
CREATE USER 'bigred'@'%' IDENTIFIED WITH mysql_native_password BY 'bigred';
GRANT ALL PRIVILEGES ON *.* TO 'bigred'@'%' WITH GRANT OPTION;
flush privileges;build image
$ sudo podman build --no-cache -t mydb .output :
STEP 1/4: FROM quay.io/cloudwalker/mysql-server
STEP 2/4: ENV MYSQL_ROOT_PASSWORD bigred
WARN[0000] HEALTHCHECK is not supported for OCI image format and will be ignored. Must use `docker` format
--> c0485a22f11
STEP 3/4: ADD myuser.sql /docker-entrypoint-initdb.d
WARN[0000] HEALTHCHECK is not supported for OCI image format and will be ignored. Must use `docker` format
--> c0a9de19856
STEP 4/4: EXPOSE 3306
COMMIT mydb
WARN[0000] HEALTHCHECK is not supported for OCI image format and will be ignored. Must use `docker` format
--> 11a146f48e4
Successfully tagged localhost/mydb:latest
11a146f48e4c2b108f161d7ea8224ce1317594152399ad592ace997f90a148cc- 出現 Warning 的原因是因為,image 的格式有分 OCI 和 Docker 。
- Docker 的格式有健康檢查,如果由 image 建出來的 Container 不健康,例如 Container 在 running 時,沒有開 3306 port ,他就會提醒。
- OCI 的格式沒有健康檢查的服務。
檢查 image 有沒有建出來
$ sudo podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/mydb latest 11a146f48e4c 5 minutes ago 439 MBrun Container
$ sudo podman run --rm --name bobo -d -p 3306:3306 localhost/mydb檢查 Container 的狀態
$ sudo podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
13b1733d3975 localhost/mydb:latest mysqld 10 seconds ago Up 9 seconds ago 0.0.0.0:3306->3306/tcp bobo登入 mysql
$ mysql -ubigred -p -h $IP
Enter password:bigred
MySQL [(none)]> select user,host from mysql.user;
+------------------+-----------+
| user | host |
+------------------+-----------+
| bigred | % |
| healthchecker | localhost |
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+------------------+-----------+
6 rows in set (0.001 sec)建立 gocgi Container
$ wget http://www.oc99.org/zip/gocgi.zip
$ unzip gocgi.zip
$ tree gocgi
gocgi
├── Dockerfile
├── go.mod
├── gocgi
├── main
├── main.go
└── www
├── cgi
│ ├── cgidb.sh
│ ├── cgitbl.sh
│ ├── hs2.sh
│ └── mysql.sh
├── css
│ └── styles.css
├── html
│ ├── db.html
│ ├── hs2.html
│ ├── index.html
│ ├── mysql.html
│ └── tbl.html
├── img
│ └── 2085263.png
├── index.html
└── js
6 directories, 17 files檢視 main.go
package main
import (
"net/http"
"net/http/cgi"
)
func cgiMySQL(w http.ResponseWriter, r *http.Request) {
handler := cgi.Handler{Path: "./www/cgi/mysql.sh"}
handler.ServeHTTP(w, r)
}
func cgiHS2(w http.ResponseWriter, r *http.Request) {
handler := cgi.Handler{Path: "./www/cgi/hs2.sh"}
handler.ServeHTTP(w, r)
}
func main() {
static := http.FileServer(http.Dir("./www/"))
http.Handle("/",static)
http.HandleFunc("/mysql", cgiMySQL)
http.HandleFunc("/hs2", cgiHS2)
http.ListenAndServe(":8080", nil)
}檢視 Dockerfile
FROM quay.io/cloudwalker/alpine
RUN apk update && apk upgrade && mkdir /www
ADD gocgi /
ADD www /www/
CMD ["/gocgi"]FROM quay.io/cloudwalker/alpine,指定quay.io/cloudwalker/alpine這片 image 建立新的 imageRUN,在建立 image 時,執行apk update && apk upgrade && mkdir /www,系統更新和在 image 的根目錄下建立 www 目錄ADD gocgi /,將 gocgi 這支程式拷貝到 image 的根目錄ADD www /www/,將www目錄下的所有子目錄和檔案拷貝到 image 的/www目錄下CMD ["/gocgi"],等等 run Container 時,內定執行的命令是 gocgi 這支程式
build image
$ sudo podman build -t localhost/gocgi .檢查 image 有無 build 成功
$ sudo podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/gocgi latest 99424c6c5514 31 seconds ago 20.1 MB用 localhost/gocgi 這片 image 建 Container
$ sudo podman run --name mybobo -d -p 80:8080 localhost/mycgi檢查 Container 的狀態
$ sudo podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
13b1733d3975 localhost/mydb:latest mysqld About an hour ago Up About an hour ago 0.0.0.0:3306->3306/tcp bobo
c6194081d78b localhost/gocgi:latest /gocgi 4 seconds ago Up 4 seconds ago 0.0.0.0:80->8080/tcp mybobo檢測服務
$ curl http://192.168.179.4
<h1>HaHa</h1>