Skip to content

antony@notes:~/kubernetes$ cat "Kubernetes-CRI-基礎運作.md"

Kubernetes CRI 基礎運作

2022-08-30· kubernetes ·系統工程

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 -version

CRI-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 image

CRI-O 並沒有以上 load ( 還原 image )、 save ( 備份 image ) 、buildexportimport 的命令

因為 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.tar

Crun 與 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/crun

crun 與 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; done

output :

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; done

output :

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 nginx

Kubernetes 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 Dockerfile
FROM quay.io/cloudwalker/mysql-server

ENV MYSQL_ROOT_PASSWORD bigred
ADD myuser.sql /docker-entrypoint-initdb.d

EXPOSE 3306
  • FROM,指定要用哪一片 image 建立新的 image ,這裡指定的是 quay.io/cloudwalker/mysql-server
  • ENV,等等在 build image 的時候,宣告 變數 MYSQL_ROOT_PASSWORD 的值等於 bigred
  • ADD,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 MB

run 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 建立新的 image
  • RUN,在建立 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>
tags: 系統工程