四、K8s 最小调度单元 Pod 概述

4.1 Pod 是什么?

4.1.1 Pod 概述及举例

Pod 资源对应的官方文档:https://kubernetes.io/docs/concepts/workloads/pods/

image-20251230102551021

可以把 Pod 看成一个“豌豆荚”,里面有很多的“豆子”(容器)。

Pod 是 K8s 中的最小调度单元;

K8s 是通过定义一个 Pod 的资源,然后在 Pod 里面运行容器(可以看上面的示例图);

容器需要指定一个镜像,这样就可以运行具体的服务。

  • 一个 Pod 封装一个容器(也可以封装多个容器),Pod 容器里共享存储、网络等。

也就是说:应该把整个 Pod 看做虚拟机,然后每个容器相当于运行在虚拟机的进程之中。

image-20251230103113018

  • Pod 是需要调度到 K8s 集群的工作节点来运行,具体调度到哪个节点,是根据 scheduler 调度器实现的。

举个例子:

部署一个 Tomcat 应用,如果不用容器,我们可能会部署到物理机、虚拟机或者云主机上面;此时,出现 K8s 之后,我们就可以定义一个 Pod 资源,在 Pod 里面一个创建一个 Tomcat 容器,因此,Pod 充当的是一个逻辑主机的角色。

4.1.2 Pod 如何管理多个容器?

image-20251230191745916

Pod 中可以同时运行多个容器;同一个 Pod 中的容器会自动的分配到同一个 node 上。同一个 Pod 中的容器共享资源、网络环境,他们总是被同时调度,在一个 Pod 中同时运行多个容器是一种比较高级的用法,只有当你的容器需要紧密配合协作的时候才考虑这种模式。

  • 一些Pod有init容器和应用容器。 在应用程序容器启动之前,运行初始化容器。
4.1.3 Pod 网络

Pod 是有IP地址的,假如 Pod 不是共享物理机 IP,由网络插件(Calico,Flannel,Weave)划分的IP,每个Pod都被分配唯一的 IP 地址。

4.1.3.1 Docker 容器互联的方式

​ 创建新容器的时候,**通过--net container参数,**指定其和已经存在的某个容器共享一个 Network Namespace。如下图所示:

右侧新建的Container,其网卡共享左侧的容器。

因此不会拥有自己独立的 IP,而是共享左侧容器的IP,端口范围等网络资源

image-20260102162515822

4.1.3.2 K8s 中容器共享的方式

​ 在 k8s 中,启动 Pod 是,会先启动一个 pause 的容器,然后将后续所有容器都 “link” 到这个 pause 的容器,以此来实现网络共享。

image-20260102170016361

4.1.4 Pod 存储

​ 创建 Pod 的时候可以指定挂载的存储卷。Pod 中所有的容器都可以访问共享卷,允许这些容器共享数据。

Pod 只要挂载持久化数据卷,Pod 重启之后数据还是会存在的。

image-20260102170223710

4.2 之前学习过容器,为何还需要 Pod ?

4.2.1 解释说明

​ Pod 是由一组紧耦合的容器组成的容器组(Pod 可以比作容器的集合),当然目前最流行的就是Docker、containerd、podman容器,Pod就可以作为1或者多个容器的载体。

  • Pod 中所用容器都会被一致调度、同节点部署,并且在一个“共享环境”中运行。
  • “共享环境”(包括):
    • 所有容器共享一个IP地址和端口空间;意味着:容器之间可以直接通过 localhost 高效访问,不会有端口冲突;
    • 允许容器之间共享存储卷,通过文件系统交互信息;
      • ps:当 K8s 挂载 Volume 到 Pod 上,本质上是将 volume 挂载到 Pod 中的每一个容器里。
    • Pod 中所有容器使用同一个网络的 namespace ,即相同的 IP 地址和 Port 空间。
4.2.2 代码自动更新

image-20260102172031539

​ 假如生产环境部署了一个go的应用,而且部署了几百个节点,希望这个应用可以定时的同步最新的代码,以便自动升级线上环境。这时,我们不希望改动原来的go应用,可以开发一个Git代码仓库的自动同步服务,然后通过Pod的方式进行编排,并共享代码目录,就可以达到更新java应用代码的效果。

4.2.3 收集业务日志

image-20260102172111578

​ 某服务模块已经实现了一些核心的业务逻辑,并且稳定运行了一段时间,日志记录在了某个目录下,按照不同级别分别为 error.log、access.log、warning.log、info.log,现在希望收集这些日志并发送到统一的日志处理服务器上。

​ 这时我们可以修改原来的服务模块,在其中添加日志收集、发送的服务,但这样可能会影响原来服务的配置、部署方式,从而带来不必要的问题和成本,也会增加业务逻辑和基础服务的藕合度。

如果使用Pod的方式,通过简单的编排,既可以保持原有服务逻辑、部署方式不变,又可以增加新的日志收集服务。

​ 而且如果我们对所有服务的日志生成有一个统一的标准,或者仅对日志收集服务稍加修改,就可以将日志收集服务和其他服务进行Pod编排,提供统一、标准的日志收集方式。

​ 这里的“核心业务服务”、“日志收集服务”分别是一个镜像,运行在隔离的容器环境中。

4.3 Pod 工作方式

​ 在K8s中,所有的资源都可以使用一个yaml文件来创建,创建Pod也可以使用yaml配置文件。或者使用kubectl run在命令行创建Pod(不常用)。

4.3.1 自主式 Pod

所谓的自助式 Pod,就是直接定义一个 Pod 资源,如下:

# 工作节点上传所需镜像并手动导入(资源包上传)
n1 && n2 ~]# ctr -n k8s.io images import xianchao-tomcat.tar.gz

# 工作节点编写yaml文件(前期学习只需要复制yaml文件即可,后期学习自主编写)
[root@k8s-master1 ~]# mkdir pod		# 在控制节点创建一个专门放置yaml文件的目录
[root@k8s-master1 ~]# cd pod/
[root@k8s-master1 pod]# vim pod-tomcat.yaml
apiVersion: v1
kind: Pod
metadata:
  name: tomcat-test
  namespace: default
  labels:
    app:  tomcat
spec:
  containers:
  - name:  tomcat-java
    ports:
    - containerPort: 8080
    image: xianchao/tomcat-8.5-jre8:v1
    imagePullPolicy: IfNotPresent
    
# 更新yaml资源文件并查看pod状态
[root@k8s-master1 pod]# kubectl apply -f pod-tomcat.yaml
[root@k8s-master1 pod]# kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
tomcat-test   1/1     Running   0          13s

# 删除pod并查看变化(模拟生产环境中误删pod --> 自助式pod的问题)
[root@k8s-master1 pod]# kubectl delete pods tomcat-test
# 发现pod不存在,已经被删除了
[root@k8s-master1 pod]# kubectl get pods
No resources found in default namespace.

通过上面可以看到,如果直接定义一个Pod资源,那Pod被删除,就彻底被删除了,不会再创建一个新的Pod,这在生产环境还是具有非常大风险的,所以今后我们接触的Pod,都是控制器管理的。

4.3.2 控制器管理 Pod

常见的管理 Pod 控制器:Replicaset、Deployment、Job、CronJob、Daemonset、Statefulset。

控制器管理的 Pod 可以确保 Pod 始终在指定的副本数运行(即使删除,控制器也会新建一个相同的 pod 以保证副本数稳定)。

# 演示如下:

# 上传实验所需镜像
n1 && n2]# ctr -n k8s.io images import xianchao-nginx.tar.gz

# 控制节点创建yaml文件
[root@k8s-master1 pod]# vim nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment			# 控制器
metadata:
  name: nginx-test
  labels:
    app: nginx-deploy
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2				# 副本数为2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: my-nginx
        image: xianchao/nginx:v1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        
# 更新资源yaml文件
[root@k8s-master1 pod]# kubectl apply -f nginx-deploy.yaml
# 查看控制器的状态
[root@k8s-master1 pod]# kubectl get deploy
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
nginx-test   2/2     2            2           22s
# 查看pods的状态
[root@k8s-master1 pod]# kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
nginx-test-5fbcf9f6-wcr9v   1/1     Running   0          26s
nginx-test-5fbcf9f6-wn7hk   1/1     Running   0          26s

# 新开一个终端去监控pods的实时状态
[root@k8s-master1 ~]# watch -n1 kubectl get pods

# 发现:随便删除一个pod,控制器会立即启动一个相同的pod以保持副本数的稳定(如下.gif图所示)
[root@k8s-master1 pod]# kubectl delete pods nginx-test-xxxx
[root@k8s-master1 pod]# kubectl get pods

因此这种管理方式更可靠!

4.4 创建 Pod 过程

4.4.1 核心过程

**1. 提交请求:**Kubectl 将Pod 提交至 apiserver ,apiserver 验证后将元数据持久化到 etcd

**2.调度分配:**scheduler 通过 watch 机制监听 etcd 中的新 Pod,执行调度算法选择节点,并将绑定信息写回 etcd

**3.节点执行:**目标节点的 kubelet 通过 watch 获取绑定信息,调用容器进行时(ps:containerd)创建并启用容器

**4.状态同步:**kubelet 将 Pod 运行状态上报 apiserver,apiserver 更新 etcd 中的状态数据

4.4.2 使用 yaml 文件创建pod
4.4.2.1 Pod资源清单–常用参数及解释

示例文件

apiVersion: v1                  # Kubernetes API版本(Pod属于核心v1组)
kind: Pod                       # 资源类型
metadata:						# 元数据定义字段
  name: nginx-pod               # Pod名称
  namespace: default            # 所属命名空间
  labels:                       # 标签(用于服务发现/调度)
    app: nginx
spec:                           # 期望状态定义
  containers:                   # 容器列表
  - name: nginx-container       # 容器名称
    image: nginx:1.25           # 镜像地址
    imagePullPolicy: Nerver		# 拉取策略
    ports:
    - containerPort: 80         # 容器暴露端口
    resources:                  # 资源限制
      limits:
        memory: "128Mi"         # 最大内存
        cpu: "500m"             # 最大CPU(500毫核)
      requests:
        memory: "64Mi"          # 预留内存
        cpu: "250m"             # 预留CPU
  restartPolicy: Always         # 重启策略(Always/OnFailure/Never)
  nodeSelector:                 # 节点选择器(调度约束)
    disktype: ssd
  volumes:                      # 存储卷定义
  - name: cache-volume
    emptyDir: {}                # 临时存储卷
4.4.2.2 实操练习
[root@k8s-master1 pod]# vim pod-first.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: tomcat
  name: tomcat-test
  namespace: default
spec:
  containers:
    - name: tomcat-java
      image: xianchao/tomcat-8.5-jre8:v1
      imagePullPolicy: IfNotPresent
      ports:
        - containerPort: 8080
        
[root@k8s-master1 pod]# kubectl apply -f pod-first.yaml
[root@k8s-master1 pod]# kubectl get pods
4.4.3 使用命令行创建pod(不推荐)
[root@k8s-master1 pod]# docker images
REPOSITORY                  TAG       IMAGE ID       CREATED       SIZE
xianchao/tomcat-8.5-jre8    v1        4ac473a3dd92   7 years ago   108MB

[root@k8s-master1 pod]# kubectl run tomcat --image=xianchao/tomcat-8.5-jre8:v1 --image-pull-policy='IfNotPresent' --port=8080

[root@k8s-master1 pod]# kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
tomcat                      1/1     Running   0          7s
4.4.4 常见的命令
# 查看帮助手册
]# kubectl --help

# 查看节点状况
[root@k8s-master1 ~]# kubectl get nodes
NAME                    STATUS     ROLES           AGE   VERSION
k8s-master1.kaser.org   NotReady   control-plane   39m   v1.31.3
k8s-node1.kaser.org     NotReady   <none>          41s   v1.31.3
k8s-node2.kaser.org     NotReady   <none>          37s   v1.31.3

# 将工作节点打标签,以便于观察 --> work
~]# kubectl label nodes k8s-node1.kaser.org node-role.kubernetes.io/work=work
~]# kubectl label nodes k8s-node2.kaser.org node-role.kubernetes.io/work=work

# 再次查看,发现标签已经打上
[root@k8s-master1 ~]# kubectl get nodes
NAME                    STATUS   ROLES           AGE     VERSION
k8s-master1.kaser.org   Ready    control-plane   7d      v1.31.3
k8s-node1.kaser.org     Ready    work            6d23h   v1.31.3
k8s-node2.kaser.org     Ready    work            6d23h   v1.31.3

# 查看命名空间
[root@k8s-master1 pod]# kubectl get namespace
NAME              STATUS   AGE
default           Active   7d		# 默认命名空间
kube-node-lease   Active   7d
kube-public       Active   7d
kube-system       Active   7d

# 查看pod(默认namespace=dafault,省略不写)
[root@k8s-master1 pod]# kubectl get pods
[root@k8s-master1 pod]# kubectl get pods -n xxx

# 查看namespace=kube-system内的pod(-n xxxx 即可)
[root@k8s-master1 pod]# kubectl get pods -n kube-system

# 查看IP/pod被调度在哪个工作节点上
[root@k8s-master1 pod]# kubectl get pods -owide

# 可以查看对应的yaml文件
[root@k8s-master1 pod]# more pod-first.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: tomcat
  name: tomcat-test
  namespace: default
spec:
  containers:
    - name: tomcat-java			# 这里查看容器名
      image: xianchao/tomcat-8.5-jre8:v1
      imagePullPolicy: IfNotPresent
      ports:
        - containerPort: 8080

# 进入pod里面的容器(不指定就什么都不加,指定进入哪个文件就加参数 -c xxx容器名 )
[root@k8s-master1 pod]# kubectl exec -it tomcat-test -- /bin/bash
bash-4.4# exit

[root@k8s-master1 pod]# kubectl exec -it tomcat-test -c tomcat-java -- /bin/bash
bash-4.4# exit

# 查看pod具有哪些标签可以结合grep使用
[root@k8s-master1 pod]# kubectl get pods --show-labels
[root@k8s-master1 pod]# kubectl get pods --show-labels | grep tomcat

# 这种情况是知道要找哪些标签的pod( -l app=xxx标签名)
[root@k8s-master1 pod]# kubectl get pods -l app=tomcat

# 查看具体pod的日志( logs pod名称 )
[root@k8s-master1 pod]# kubectl logs tomcat-test

# 查看具体pod的详细信息( describe pods pod名称)
[root@k8s-master1 pod]# kubectl describe pods tomcat-test
# 删除pod两种方式
	# 1.删除pod (kubectl delete pod pod名称)
	# 2.删除yaml文件 (kubectl delete -f xxx.yaml文件)
# 第一种:
[root@k8s-master1 pod]# kubectl delete pod tomcat-test
# 第二种:
[root@k8s-master1 pod]# kubectl delete -f pod-first.yaml

# 以上为自主式pod删除方式,两种方式都可以
# 以下为控制器pod删除方式
# 第一种删除之后,控制器会立即新建一个保持副本数稳定
# 第二种是直接删除yaml文件,即为永久删除,如下动图所示:

# 可以另外启动一个终端去监控
[root@k8s-master1 ~]# watch -n1 kubectl get pods
# 执行yaml文件创建pod
[root@k8s-master1 pod]# kubectl apply -f nginx-deploy.yaml
# 尝试常规删除,发现不行
[root@k8s-master1 pod]# kubectl delete pod nginx-test-5fbcf9f6-4m45r
[root@k8s-master1 pod]# kubectl delete pod nginx-test-5fbcf9f6-xfsv8
[root@k8s-master1 pod]# kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
nginx-test-5fbcf9f6-mcdxj   1/1     Running   0          7s
nginx-test-5fbcf9f6-vg5d4   1/1     Running   0          7s

# 尝试删除yaml文件,即可永久删除
[root@k8s-master1 pod]# kubectl delete -f nginx-deploy.yaml
[root@k8s-master1 pod]# kubectl get pods
No resources found in default namespace.
## 五、K8s名称空间及资源配额

5.1 namespace 名称空间

image-20260107214516260

命名空间又称为“namespace(ns)”,也称为虚拟机群。它们底层都依赖于同一个物理集群,K8s 支持多个虚拟机群。

命名空间适用于存在很多跨团队或项目的场景。

对于只有几个或几十个用户的集群,根本不需要创建或考虑命名空间。

5.2 namespace 与 resourcequota 资源配额 的使用案例

# 新建一个命名空间 test
[root@k8s-master1 pod]# kubectl create ns test

# 新建一个资源配额 yaml 文件放到 test 的命名空间里
[root@k8s-master1 pod]# vim namespace-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: mem-cpu-quota	# resourcequota的名称
  namespace: test		# 在哪个命名空间
spec:
  hard:
    limits.cpu: "4"			# 所有容器的 cpu 限制总和 <= 4CPU
    limits.memory: "4Gi"	# 所有容器的 内存 限制总和 <= 4GiB
    requests.cpu: "2"		# 所有容器的 cpu 请求总和 <= 2CPU
    requests.memory: "2Gi"	# 所有容器的 内存 请求总和 <= 2GiB

# 查看
[root@k8s-master1 pod]# kubectl get resourcequota -n test
NAME            AGE   REQUEST                                     LIMIT
mem-cpu-quota   11m   requests.cpu: 0/2, requests.memory: 0/2Gi   limits.cpu: 0/4, limits.memory: 0/4Gi

# 养成查找文档的习惯
https://kubernetes.io/zh-cn/docs/concepts/policy/resource-quotas/

# 创建pod时候必须设置资源限额,否则创建失败,如下:
[root@k8s-master1 pod]# more pod-test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-test
  namespace: test
  labels:
    app: tomcat-pod-test
spec:
  containers:
    - image: xianchao/tomcat-8.5-jre8:v1
      imagePullPolicy: IfNotPresent
      name: tomcat-test
      ports:
        - containerPort: 8080
      resources:
        limits:
          memory: "2Gi"
          cpu: "2"
        requests:
          memory: "100Mi"
          cpu: "500m"

[root@k8s-master1 pod]# kubectl get resourcequota -n test
NAME            AGE   REQUEST                                            LIMIT
mem-cpu-quota   72m   requests.cpu: 500m/2, requests.memory: 100Mi/2Gi   limits.cpu: 2/4, limits.memory: 2Gi/4Gi

[root@k8s-master1 pod]# kubectl get pod -n test
NAME       READY   STATUS    RESTARTS   AGE
pod-test   1/1     Running   0          5s

更多推荐