Kubernetes目前大约每年发布三次,由于迭代速度快,目前市场上绝大部分的教程相对陈旧。更重要的是,从Kubernetes 1.20开始,Kubernetes官方宣布逐步弃用Docker作为容器运行时,并计划在Kubernetes 1.24版本中完全移除对Docker作为容器运行时的支持。这意味着,从Kubernetes 1.24版本开始,将不能使用Docker作为容器运行时来运行Kubernetes节点上的Pods。因此,市场上关于直接使用containerd容器运行时的新版Kubernetes教程几乎没有,更重要的是因为的Kubernetes涉及到镜像需要单独配置才能获取,这无疑拉高了初学者门槛。本教程采用互联网的形式进行发布,便于保持与Kubernetes最新版的同步,尽量自包含,便于读者学习、实践。
关键字:Kubernetes 1.32; containerd; nerdctl; debain 12
整体规划
为方便后续内容学习,本部分将基于【Kubernetes部署与运维07 Helm部署】中的环境开展Kubernetes的Pod创建与运行学习。整体规划如下:
| 虚拟机名称 | IP地址 | 主机名 | 域名 | CPU核心 | 内存 | 角色 |
|---|---|---|---|---|---|---|
k8s_Master1_2G | 192.168.152.200 | master1 | master.rz | 2 | 2GB | master |
K8s_Worker1_2G | 192.168.152.201 | worker1 | worker1.rz | 1 | 2GB | worker |
K8s_Worker2_2G | 192.168.152.202 | worker2 | worker2.rz | 1 | 2GB | worker |
参见【Kubernetes部署与运维02 Nerdctl Rootful部署】,Kubernetes基础环境各组件与版本信息如下:
- nerdctl: v1.7.7
- containerd: v1.7.22
- runc: v1.1.14
- CNI plugins: v1.5.1
- BuildKit: v0.15.2
- Stargz Snapshotter: v0.15.1
- imgcrypt: v1.1.11
- RootlessKit: v2.3.1
- slirp4netns: v1.3.1
- bypass4netns: v0.4.1
- fuse-overlayfs: v1.13
- containerd-fuse-overlayfs: v1.0.8
- Kubo (IPFS): v0.29.0
- Tini: v0.19.0
- buildg: v0.4.1
Kubernetes版本号为1.32。
理论知识
Pod的概念与作用
【官方参考文档】
https://kubernetes.io/zh/docs/concepts/workloads/pods/
Pod(就像在豌豆荚中)是一组(一个或多个)容器;这些容器共享存储、网络等信息与资源。
Pod中的内容总是并置的并且一同调度,在共享的上下文中运行。Pod所建模的是特定于应用的“逻辑主机”,其中包含一个或多个应用容器,这些容器是相对紧密的耦合在一起的。在非云环境中,在相同的物理机或虚拟机上运行的应用类似于在同一逻辑主机上运行的云应用。
Pod是Kubernetes中可以创建和部署的最小也是最简的单位,在指副本数量时,其单位就是Pod;Pod中封装着应用的容器(有的情况下是好几个容器),存储、独立的网络IP,管理容器如何运行的策略选项;Pod代表着部署的一个单位:Kubernetes中应用的一个实例,可能由一个或者多个容器组合在一起共享资源;- 有些
Pod具有Init容器和应用容器。Init容器会在启动应用容器之前运行并完成。
Pod的作用如下:
- 方便管理:在
Kubernetes中Pod是容器Container的载体,一个Pod里面拥有一个或多个容器Container,作为一个逻辑单元,方便管理; - 资源共享和通信:同一个
Pod中的容器Container共享一个网络栈和存储,相互之间可以直接通过localhost进行通信,同时也共享同一块存储卷。
Kubernetes直接管理对象是Pod,而不是底层的Container,对于Container的操作,被封装在Pod中,不会直接操作。这意味着,Pod也可以包含其他公司的容器产品,比如CoreOS的rkt或阿里巴巴的Pouch。
Pod内部的资源共享
Pod被设计成支持形成内聚服务单元的多个协作过程(形式为容器)。容器之间可以共享资源和依赖、彼此通信、协调何时以及何种方式终止自身:
- 网络共享:每个
Pod都会被分配一个唯一的IP地址。Pod中的所有容器共享网络空间,包括IP地址和端口。Pod内部的容器可以使用localhost互相通信。Pod中的容器与外界通信时,必须分配共享网络资源(例如使用宿主机的端口映射); - 存储共享:可为
Pod指定多个共享的存储Volume。Pod中的所有容器都可以访问共享的Volume。Volume也可以用来持久化Pod中的存储资源,以防容器重启后文件丢失。
多个容器Container是否可以放到同一个Pod中最重要的判定标准为,这些容器Container的生命周期是否一致。
案例实践
前期准备
1)同时开启K8s_Master1_2G、K8s_Worker1_2G、K8s_Worker2_2G三台虚拟机。
2)在主节点master1上创建/root/tutor/workloads-pods文件夹:
root@master1:~# mkdir -p /root/tutor/workloads-pods
命令行方式创建、查看与删除Pod
【实践01-使用命令行创建、查看、删除Pod】
通过命令行方式对Pod进行查看、创建与删除。
1)可使用kubectl run --image=<imageName> <podName>命令进行Pod创建:
root@master1:~# kubectl run --image=nginx pod-test
pod/pod-test created
创建了第一个
Pod,名为pod-test。
2)使用kubectl get pods命令查看defaults命名空间中的Pod:
root@master1:~# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-test 0/1 ContainerCreating 0 31s
root@master1:~# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-test 1/1 Running 0 107s
由于Pod的启动涉及到拉取镜像等动作,因此需要一定的时间与周期。起初pod-test处于ContainerCreating状态,随后在Pod完全启动之后,进入到Running状态。
3)查看核心组件是否处于正常状态时使用了kubectl -n kube-system get pods,其中-n kube-system参数就是指定查看kube-system命名空间下的核心组件。在未给出命名空间的情况下,kubectl命令默认仅访问defaults命令空间下的资源。此外,kubectl命令还提供了--all-namespaces参数,来访问所有命名空间下的资源。
root@master1:~# kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
default pod-test 1/1 Running 0 30m
kube-system calico-kube-controllers-5745477d4d-x4dbj 1/1 Running 6 (33m ago) 38h
kube-system calico-node-d9sv5 1/1 Running 6 (33m ago) 38h
kube-system calico-node-ntx28 1/1 Running 5 (33m ago) 22h
kube-system calico-node-zpbc2 1/1 Running 5 (33m ago) 24h
kube-system coredns-6766b7b6bb-hqgsd 1/1 Running 6 (33m ago) 40h
kube-system coredns-6766b7b6bb-w8ztk 1/1 Running 6 (33m ago) 40h
kube-system etcd-master1 1/1 Running 7 (33m ago) 40h
kube-system kube-apiserver-master1 1/1 Running 7 (33m ago) 40h
kube-system kube-controller-manager-master1 1/1 Running 7 (33m ago) 40h
kube-system kube-proxy-b8n2k 1/1 Running 5 (33m ago) 22h
kube-system kube-proxy-h2v5l 1/1 Running 7 (33m ago) 40h
kube-system kube-proxy-jf5tm 1/1 Running 5 (33m ago) 24h
kube-system kube-scheduler-master1 1/1 Running 7 (33m ago) 40h
kube-system metrics-server-554dcb6944-kplgb 1/1 Running 3 (33m ago) 19h
其中NAMESPACE列给出了Pod所在的命名空间,RESTARTS列为重启次数。这里的重启次数是指容器的重启次数,这个概念与容器技术中的docker restart <container>是有差异的。这里的重启次数是相当于docker rm -f <container> && docker run <image>两个命令的综合效果,也就是把之前的容器抛掉(rm -f),然后再启(run)一个新容器。
4)可使用kubectl delete pod <podName>命令删除指定的Pod:
root@master1:~# kubectl delete pod pod-test
pod "pod-test" deleted
root@master1:~# kubectl get pods
No resources found in default namespace.
配置文件方式创建与删除Pod
【实践02- 配置文件方式创建、删除Pod】
除使用命令行的方式进行Pod的创建、查看与删除之外,还可以使用yaml配置文件创建Pod与删除Pod。
1)在主节点master1上的/root/tutor/workloads-pods文件夹中创建pod1.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-nginx
spec:
containers:
- name: c-nginx
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
该yaml文件描述了一个Pod资源(kind字段为Pod),Pod名为pod-nginx。Pod内含有一个名为c-nginx的容器,容器对应的镜像为nginx。imagePullPolicy: IfNotPresent表示当本地存在nginx:1.26-alpine时,将不从网上拉取,而是直接使用本地镜像。
2)可使用kubectl create -f命令,指定yaml文件创建对应的资源,并进行查看:
root@master1:~/tutor/workloads-pods# ll
total 4
-rw-r--r-- 1 root root 108 Jan 31 09:48 pod1.yaml
root@master1:~/tutor/workloads-pods# kubectl create -f pod1.yaml
pod/pod-nginx created
root@master1:~/tutor/workloads-pods# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-nginx 1/1 Running 0 5s
root@master1:~/tutor/workloads-pods# kubectl -n default get pods
NAME READY STATUS RESTARTS AGE
pod-nginx 1/1 Running 0 17s
可以看到未使用在未指定命名空间的情况下,创建的Pod处于默认的default命名空间。
3)可使用kubectl -n <namespace> create在指定的命名空间中创建对应的资源:
root@master1:~/tutor/workloads-pods# kubectl create namespace n-test
namespace/n-test created
root@master1:~/tutor/workloads-pods# kubectl -n n-test create -f pod1.yaml
pod/pod-nginx created
root@master1:~/tutor/workloads-pods# kubectl -n n-test get pods
NAME READY STATUS RESTARTS AGE
pod-nginx 1/1 Running 0 102s
root@master1:~/tutor/workloads-pods# kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
default pod-nginx 1/1 Running 0 4m12s
...
n-test pod-nginx 1/1 Running 0 105s
这里先创建名为n-test的命名空间,然后使用pod1.yaml配置文件创建Pod时在命令行中通过-n n-test参数指定在n-test命名空间中创建。随后,在n-test命令空间中查看Pod。最后,使用--all-namespace参数,查看所有命名空间下的Pod,可以发现在default和n-test两个命名空间中均有一个名为pod-nginx的Pod,进一步验证了各命名空间在资源名称上的隔离性。
4)可在yaml文件中同时描述多个资源,各资源之间使用---分隔。并且,可以在资源的元数据(metadata字段)中通过namespace来指定资源所在的命名空间。在workloads-pods文件夹内创建pod2.yaml文件,内容如下:
apiVersion: v1
kind: Namespace
metadata:
name: n-test2
---
apiVersion: v1
kind: Pod
metadata:
name: pod-nginx
namespace: n-test2
spec:
containers:
- name: c-nginx
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
整个yaml文件由两部分资源描述构成,使用---分隔。第一个资源描述n-test2命名空间,第二个资源描述pod-nginx,其在n-test2命名空间。
5)使用kubectl create -f命令创建pod2.yaml文件中描述的资源:
root@master1:~/tutor/workloads-pods# ll
total 8
-rw-r--r-- 1 root root 108 Jan 31 09:48 pod1.yaml
-rw-r--r-- 1 root root 190 Jan 31 09:58 pod2.yaml
root@master1:~/tutor/workloads-pods# kubectl create -f pod2.yaml
namespace/n-test2 created
pod/pod-nginx created
root@master1:~/tutor/workloads-pods# kubectl -n n-test2 get pods
NAME READY STATUS RESTARTS AGE
pod-nginx 1/1 Running 0 19s
在使用-f pod2.yaml文件创建资源时,创建了两个资源namespace/n-test2和pod/pod-nginx。创建时,/之前的namespace和pod表示资源类型,/之后的n-test2和pod-nginx表示资源名称。
6)清理之前创建的容器与命名空间:
root@master1:~/tutor/workloads-pods# kubectl delete namespaces n-test n-test2
namespace "n-test" deleted
namespace "n-test2" deleted
root@master1:~/tutor/workloads-pods# kubectl delete pod pod-nginx
pod "pod-nginx" deleted
root@master1:~/tutor/workloads-pods# kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system calico-kube-controllers-5745477d4d-x4dbj 1/1 Running 7 (23m ago) 38h
kube-system calico-node-d9sv5 1/1 Running 7 (23m ago) 38h
kube-system calico-node-ntx28 1/1 Running 6 (23m ago) 23h
kube-system calico-node-zpbc2 1/1 Running 6 (23m ago) 25h
kube-system coredns-6766b7b6bb-hqgsd 1/1 Running 7 (23m ago) 40h
kube-system coredns-6766b7b6bb-w8ztk 1/1 Running 7 (23m ago) 40h
kube-system etcd-master1 1/1 Running 8 (23m ago) 40h
kube-system kube-apiserver-master1 1/1 Running 8 (23m ago) 40h
kube-system kube-controller-manager-master1 1/1 Running 8 (23m ago) 40h
kube-system kube-proxy-b8n2k 1/1 Running 6 (23m ago) 23h
kube-system kube-proxy-h2v5l 1/1 Running 8 (23m ago) 40h
kube-system kube-proxy-jf5tm 1/1 Running 6 (23m ago) 25h
kube-system kube-scheduler-master1 1/1 Running 8 (23m ago) 40h
kube-system metrics-server-554dcb6944-kplgb 1/1 Running 4 (23m ago) 20h
在删除命名空间n-test、n-test2时,命名空间内相应的Pod等资源也均被删除掉。
7)可在一个Pod内包含多个容器。在workloads-pods文件夹内创建pod3.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-nginx
spec:
containers:
- name: c-nginx
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
- name: c-tomcat
image: tomcat
imagePullPolicy: IfNotPresent
该yaml文件中,containers字段含有两个容器c-nginx与c-tomcat。每个-name项对应于一个容器。
8)使用kubectl create -f创建pod3.yaml文件中描述的资源:
root@master1:~/tutor/workloads-pods# ll
total 12
-rw-r--r-- 1 root root 108 Jan 31 09:48 pod1.yaml
-rw-r--r-- 1 root root 190 Jan 31 09:58 pod2.yaml
-rw-r--r-- 1 root root 145 Jan 31 10:12 pod3.yaml
root@master1:~/tutor/workloads-pods# kubectl create -f pod3.yaml
pod/pod-nginx created
root@master1:~/tutor/workloads-pods# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-nginx 0/2 ContainerCreating 0 11s
root@master1:~/tutor/workloads-pods# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-nginx 2/2 Running 0 40s
其中,READY列,/前的值表示当前启动的容器的数量,而/后的值为Pod中容器的总数。只有当两个容器(c-nginx和c-tomcat)均启动了,READY列的值才会变为2/2。
9)在此期间,使用kubectl describe pod命令查看pod-nginx的详细信息:
root@master1:~/tutor/workloads-pods# kubectl describe pod pod-nginx
Name: pod-nginx
Namespace: default
Priority: 0
Service Account: default
Node: worker2/192.168.152.202
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m51s default-scheduler Successfully assigned default/pod-nginx to worker2
Normal Pulling 2m51s kubelet Pulling image "nginx"
Normal Pulled 2m51s kubelet Successfully pulled image "nginx" in 274ms (274ms including waiting). Image size: 72080558 bytes.
Normal Created 2m51s kubelet Created container: c-nginx
Normal Started 2m51s kubelet Started container c-nginx
Normal Pulling 2m51s kubelet Pulling image "tomcat"
Normal Pulled 2m17s kubelet Successfully pulled image "tomcat" in 33.276s (33.276s including waiting). Image size: 224181504 bytes.
Normal Created 2m17s kubelet Created container: c-tomcat
Normal Started 2m17s kubelet Started container c-tomcat
由于排版限制,输出内容中略去部分列内容。
Node: worker2/192.168.152.202表示当前Pod运行于worker2节点之上。- 在
Events中,第一行Normal Scheduled 2m51s default-scheduler Successfully assigned default/pod-nginx to worker2,表示成功为当前Pod分配至工作节点worker2; Normal Pulling 2m51s kubelet Pulling image "nginx",表示当前正在从镜像仓库拉取(Pulling)镜像nginx。kubectl describe命令的输出,可作为运维诊断时的重要参考。当两个镜像均拉取完成,相应的容器均运行起来之后,查看Pod资源信息,其READY列变为2/2。
Pod的镜像拉取与重启
【实践03- 查看、设置镜像拉取与重启相关策略】
查看容器镜像拉取策略,及Pod重启策略,并进行镜像的拉取及观察Pod的重启。
1)使用kubectl get pod <podName> -o yaml命令可以查看指定Pod信息的yaml格式,在其输出中含有容器镜像的拉取策略与重启策略:
root@master1:~/tutor/workloads-pods# kubectl get pods pod-nginx -o yaml
apiVersion: v1
kind: Pod
metadata:
...
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: c-nginx
resources: {}
...
- image: tomcat
imagePullPolicy: Always
name: c-tomcat
resources: {}
...
restartPolicy: Always
...
其中,imagePullPolicy描述了Pod中容器的镜像拉取策略,而restartPolicy则描述了Pod的重启策略。
镜像拉取策略imagePullPolicy有三种取值:
Always:不论本地是否已经存在所需镜像,每次均重新下载镜像(默认);Never:仅使用本地镜像,从不下载。若本地没有所需镜像,报错;IfNotPresent:仅当本地没有所需镜像时,才从仓库下载镜像。
重启策略restartPolicy有三种取值:
Always:除了Running状态外,均重启容器;OnFailure:失败状态才重启容器;Never:无论失败或完成(正常退出)状态,均不重启容器。
2)重启策略可以通过kubectl get pods命令输出的RESTARTS列的值反映出来。查看当前系统中pod--nginx的扩展信息:
root@master1:~/tutor/workloads-pods# kubectl get pods pod-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE ...
pod-nginx 2/2 Running 0 18m 10.244.189.68 worker2 ...
由于排版限制,略去部分列内容。当前运行于工作节点worker2之上的pod-nginx,其RESTARTS列的值为0,表示重启了0次。
3)在worker2中,使用nerdctl命令查看容器状态:
root@worker2:~# nerdctl -n k8s.io ps
CONTAINER ID IMAGE STATUS NAMES
...
39ab2069a0ac docker.io/library/tomcat:latest Up k8s://default/pod-nginx/c-tomcat
...
e932b5a04d59 docker.io/library/nginx:latest Up k8s://default/pod-nginx/c-nginx
在Kubernetes 1.32中,相较于Kubernetes 1.20,在工作节点worker2之上,重启Containerd引擎(服务)已经无法直接影响RESTARTS列(重启次数)列的值,Kubernetes进一步优化。
4)可以直接对worker2进行系统重启:
root@worker2:~# reboot
5)再次回到主节点master1上查看当前系统中pod-nginx的扩展信息:
root@master1:~/tutor/workloads-pods# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master1 Ready control-plane,master 41h v1.32.1
worker1 Ready worker 26h v1.32.1
worker2 Ready worker 24h v1.32.1
root@master1:~/tutor/workloads-pods# kubectl get pods pod-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE ...
pod-nginx 2/2 Running 2 (55s ago) 8m39s 10.244.189.70 worker2 ...
注意,Kubernetes对于节点状态的监测并并不是实时性,因此对于将工作节点worker2关机或重启时,在kubectl get nodes中,worker2依然为Ready状态。同时,由于工作节点worker2重启,因此pod-nginx中的两个容器c-nginx与c-tomcat均重启了,其对应的RESTARTS状态直接为2(1次为c-nginx,1次为c-tomcat)。
6)在worker2中,使用nerdctl命令查看容器状态:
root@worker2:~# nerdctl -n k8s.io ps
CONTAINER ID IMAGE STATUS NAMES
...
250290f4f0ac docker.io/library/tomcat:latest Up k8s://default/pod-nginx/c-tomcat
...
ab55626db6e9 docker.io/library/nginx:latest Up k8s://default/pod-nginx/c-nginx
与之前的nerdctl命令查看容器状态输出内容相比,CONTAINER ID值均发生变化,说明所有容器均重新创建了。
7)最后,在主节点master1上清除pod-nginx:
root@master1:~/tutor/workloads-pods# kubectl delete pod pod-nginx
pod "pod-nginx" deleted
收尾工作
1)使用poweroff命令,关闭三台虚拟机。
2)AI时代背景之下,运维将从传统CPU服务器切入到GPU服务器与端边设备,对于运维开发人员,技术玩家而言,也同步需要跟上新的技术栈。本学习内容涉及到的软件包、配置文件等资源,可以直接从百度网盘下载获取:
- 百度网盘分享文件:
Kubernetes1.32 - 链接:
https://pan.baidu.com/s/18XeGQ28BDPjHh8JKj0uZFQ?pwd=6x17提取码:6x17