一. 什么是 Pod
Pod 是一个或多个容器的组合。这些容器共享存储、网络和命名空间,以及运行规范。在 Pod 中,所有容器都被统一安排和调度。对于具体应用而言,Pod 是它们的逻辑主机,Pod 包含业务相关的多个应用容器。所以,Pod 是一组具有共享命名空间、IP地址和端口的容器的集合
1. 从使用的角度来看
在实际的使用时,单个容器是无法单独来支撑我们的应用的,往往需要很多微服务才能组成一个系统,并且还会存在A服务依赖B服务,B服务需要和C服务共用某个目录。另外,在使用裸容器时,很难实现对容器内进行健康检査以及横向扩容等操作,而 Pod 可以轻松解决这些问题
2. 从 Kubernetes 的角度来看
Docker 只是容器 Runtime(运行时)的一种们还有很多容器 Runtime,比如 Rkt、CRI-0等,而Kuberetes 作为目前最流行的容器编排工具,需要支持各个 Runtime 并且不依赖于底层 Runtime 的实现技术,于是就抽象出了 Pod 这个概念,用于管理多个紧密相连的符合 CRI标准的容器
Pod 可以简单的理解为一组、一个或多个容器,每个 Pod 还包含一个 Pause 容器,Pause 容器是 Pod的父容器主要负责僵尸进程的回收管理。同时,通过 Pause 容器可以使同一个 Pod 里面的不同容器共享存储、网络、PID、IPC(进程间通信)等
,容器之间可以使用 Localhost:Por 的方式相互访问,可以使用 volume 实现数据共享。根据 Docker 的构造,Pod 可以被创建为一组具有共享命名空间、IP 地址和端口的容器
Pod 有两个必须知道的特点:
网络
:每一个 Pod 都会被指派一个唯一的 !p 地址,在 Pod 中的每一个容器共享网络命名空间,包括Ip 地址和网络端口。在同一个 Pod 中的容器可以同 1ocalhost 进行互相通信。当 Pod 中的容器需要与Pod 外的实体进行通信时,则需要通过端口等共享的网络资源
存储
:Pod 能够被指定共享存储卷的集合,在 Pod 中所有的容器能够访问共享存储卷,允许这些容器共享数据。存诸卷也允许在一个 Pod 持久化数据,以防止其中的容器需要被重启
3.Pod 的状态
(1)kubectl 命令创建 pod
[root@k8s-master ~]# ku run nginx --image=nginx:1.7.9 --labels="app=nginx"
(2)查看 pod
[root@k8s-master ~]# ku get pods -n default
[root@k8s-master ~]# ku get pods -A
(3)查看 Pod 的更多信息
[root@k8s-master ~]# ku get pods nginx -o wide
(4)查看 Pod 日志
[root@k8s-master ~]# curl 10.244.85.193
[root@k8s-master ~]# ku logs nginx
(5)以 yaml 格式显示 Pod 详细信息
[root@k8s-master ~]# ku get pod nginx -o yaml
(6)显示资源的详细描述信息
[root@k8s-master ~]# ku describe pod nginx
备注:
命令 | 含义 |
---|---|
kubectl get | 常用于査看同一资源类型的一个或多个资源对象,可以使用-0 参数自定义输出格式 |
kubectl describe | 侧重于描述指定资源的各方面的详细信息,不仅会返回节点信息,还会返回在其上运行的 Pod 的摘要、节点事件等信息 |
(7)在 Pod 的容器中执行命令
[root@k8s-master ~]# ku exec nginx -c nginx -- date
备注:
命令 | 含义 |
---|---|
-c | 指定 Pod 中容器的名字 |
(8)登录到 Pod 中的容器中
[root@k8s-master ~]# ku exec -it nginx -c nginx -- bash
任意节点测试
备注:
命令 | 含义 |
---|---|
kubectl exec it nginx-- bash | 如果登录的时候不指定容器,就登录到Pod 中的第一个容器中 |
(9)在线编辑运行中的资源对象
[root@k8s-master ~]# ku edit pod nginx
(10)将 Pod 的端口映射到宿主机
[root@k8s-master ~]# ku port-forward --address 0.0.0.0 pod/nginx 8080:80
任意节点测试
(11)在宿主机和 Pod 的容器之间拷贝文件
[root@k8s-master ~]# echo "this is my k8sAndnginx" > index.html
[root@k8s-master ~]# ku cp index.html nginx:/usr/share/nginx/html
任意节点测试
(12)Pod 的状态
[root@k8s-master ~]# ku get pods -n default
可以看到此时的 Pod 的状态是 Running,Pod 的状态不仅仅只有 Running,常见的其他状态如表所示:
状态 | 说明 |
---|---|
Pending(挂起) | Pod 已经被 Kubernetes 系统接收,但是仍有一个或多个容器未被创建,可以通过kubectl describe 查看处于Pending 状态的原因 |
Running(运行中) | Pod 已经被绑定到一个节点上,并且所有的容器都已经被创建,而且至少有一个是运行的状态、正在启动或者重启,可以通过 kubectl logs 査看 Pod 的日志 |
Succeeded | 所有容器执行成功,并终止,并且不会再次重启,可以通过kubectl logs 査看 Pod 的日志 |
Failed(失败) | 所有容器都已终止,并且至少一个容器以失败的方式终止,也就是说这个容器要么以非零状态退出,要么被系统终止可以通过 logs 和 describe 査看 Pod 的日志和状态 |
Unknown(未知) | 通常是由于通信问题造成的无法获得 Pod 的状态 |
ImagePullBackOff ErrImagePull | 镜像拉取失败,一般是由于镜像不存在、网络不通或者需要登录认证引起的,可以使用 describe 命令查看具体的原因 |
CrashLoopBackOff | 容器启动失败,可以通过 logs 命令查看具体的原因,一般为启动命令不正确、健康检查不通过等原因 |
OOMKilled | 容器内存溢出,一般是容器的内存 Limit 设置的过小,或者程序本身有内存溢出,可以通过 logs 查看程序的启动日志 |
Terminating | Pod 正在被删除,可以通过 describe 查看状态 |
SysctlForbiden | Pod 自定义了内核配置,但 kubectl 没有添加内核配置或配置的内核参数不支持,可以通过 describe 查看具体原因 |
Completed | 容器内部主进程退出,一般计划任务执行结束会显示该该状态,此时可以通过 logs 查看容器日志 |
Containercreating | Pod 正在创建,一般正在下载镜像,或者有配置不当的地方,可以通过 describe 查看具体原因 |
(13)删除 Pod
[root@k8s-master ~]# ku delete pods nginx
二. Pod 探针
在生产环境中,进程正常启动并不代表应用能正常处理请求,所以合理的设计应用的健康检査尤其重要。在使用裸机或裸容器部署时,一般很难对应用做很完善的健康检査,而 Pod 提供的探针可以很方便的用来检测容器的应用是否正常
1. Pod 探针的实现方式
目前探针有3种检测方式,可以根据不同的场景选择合适的健康检查方式,分别是ExecAction、TCPSocketAction 和 HTTPGetAction。具体实现方式如表所示
实现方式 | 说明 |
---|---|
ExecAction | 在容器内执行一个指定的命令,如果命令返回值为0,则认为容器健康 |
TCPSocketAction | 通过 TCP 连接检查容器指定的端口,如果端口开放,则认为容器健康 |
HTTPGetAction | 对指定的URL进行Get请求,如果状态码在200-400之间,则认为容器健康 |
2. 容器状态
上述的检查方式可以被周期性的执行,每次检査容器后可能得到的容器状态如表所示
状态 | 说明 |
---|---|
Success(成功) | 容器检查成功 |
Failure(失败) | 容器检查失败 |
Unknown(未知) | 诊断失败,因此不采取任何措施 |
3. Pod 探针类型
Pod 探针有三类,分别是:livenessProbe(存活探针)、readinessProbe(就绪探针)、startupProbe(启动探针)
(1)livenessProbe(存活探针)
它被用来知道一个容器是否在正常运行。如果容器未能通过存活探针的检查,则系统会认为该容器已经进入了一个必须被重启的状态,从而自动重启这个容器。这种机制可以确保容器在出现问题后能够自动恢复到可用状态
存活探针支持以下几种类型:
类型 | 说明 |
---|---|
HTTP GET请求 | 通过发送 HTTP 请求到容器内的某个 URL 来检测容器是否处于健康状态 |
Exec 执行命令 | 在容器内执行一个自定义命令或可执行文件,并根据其退出码判断容器是否健康 |
Socket | 尝试打开一个 TCP socket 连接到容器上的指定端口,如果连接成功则认为容器是健TCP康的 |
(2)readinessProbe(就绪探针)
判断容器是否能够进入 ready 状态,用于确定 Pod 中的容器是否已准备好接收流量。与1ivenessProbe 不同,readinessProbe 主要关注的是容器是否已经准备好为服务提供者处理请求。如果容器没有通过就绪探针的检査,Kubernetes 将不会把任何新的网络流量路由到这个容器上
当一个容器报告自己尚未准备好时,Kubernetes可能会采取以下行动:
- 服务(service)不会将流量路由到未准备好的 Pod
- 如果 Pod 是副本集(Replicaset)、部署(Deployment)、状态集(statefulset)等的一部分控制器会认为这个实例不可用
- 对于使用 Pod 的滚动更新策略的情况,就绪探针可以帮助确保新版本的 Pod 在旧版本被终止之前就已经准备好了
就像 livenessProbe 一样,readinessProbe 也支持多种类型的探测方法:
类型 | 说明 |
---|---|
HTTP GET 请求 | 发送 HTTP 请求到容器内的某个 URL |
Exec执行命令 | 在容器内执行一个自定义命令或可执行文件 |
TCP Socket | 尝试建立一个到容器上的指定端口的 TCP 连接 |
(3)startupProbe(启动探针)
判断容器内的应用是否启动成功,在 success 状态前,其它探针都处于无效状态。它专门用于检测容器是否完成了初始化并进入了预期的运行状态。与 livenessProbe(存活探针)和 readinessProbe(就绪探针)不同,startupProbe专注于容器启动阶段,并且仅在容器启动过程中使用
startupProbe 的主要作用是在容器启动期间持续检査容器是否已经完成启动。一旦容器通过了startupProbe 的检査,Kubernetes 就会认为容器已经成功启动,并停止对该容器的启动探针检查。如果容器始终无法通过启动探针的检査,那么 Kubernetes 将会根据配置重试一定的次数,超过重试次数后可能会采取进一步的措施,如重启容器
三. Pod 镜像拉取策略和重启策略
1. 镜像拉取策略
在发布应用或者更改控制器配置时,会触发 Pod 的滚动更新,此时针对容器的镜像有不同的拉取方式。如表所示
操作方式 | 说明 |
---|---|
Always | 总是拉取,无论镜像是否存在,总是拉取 |
Never | 无论是否存在都不会拉取 |
IfNotPressent | 镜像不存在时拉取镜像,是 k8s 默认的策略但是如果 tag为latest,则总是拉取 |
指定拉取策略:
[root@k8s-master ~]# ku run nginx --image=nginx:1.7.9 --labels="app=nginx" --image-pull-policy=Never
2. Pod 重启策略
在 Kubernetes 中,Pod 的重启策略(Restart Policy)定义了当容器退出或失败时,kubelet 如何处理容器。重启策略是 Pod 级别的配置,适用于Pod 中的所有容器
在 Always 策略中,只要容器退出(无论退出码是什么),kubelet 都会自动重启容器。适用于需要持续运行的服务(如 web 服务器、数据库等)
在 onFailure 策略中,只有当容器以非零退出码退出时,kubelet 才会重启容器,如果容器正常退出(退出码为 ),则不会重启。适用于任务型 Pod(如批处理任务),任务完成后不需要重启
在 Never 策略中,无论容器以何种方式退出,kubelet 都不会重启容器。适用于一次性任务,任务完成后不需要重启
各个策略的简要说明如表:
操作方式 | 说明 |
---|---|
Always | 容器退出即重启,适用于长期运行的服务 |
OnFailure | 容器失败时重启,适用于任务型工作负载 |
Never | 容器退出后不重启,适用于一次性任务 |
指定重启策略:
[root@k8s-master ~]# ku delete pod nginx
[root@k8s-master ~]# ku run nginx --image=nginx:1.7.9 --labels="app=nginx" --restart=OnFailure
四. 创建一个简单的 Pod
1. 编写一个简单的 Pod
[root@k8s-master ~]# vim aaa.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
name: nginx
spec:
containers:
- name: nginx01
image: nginx:1.7.9
ports:
- containerPort: 80
- name: nginx02
image: nginx:1.7.9
ports:
- containerPort: 8080
[root@k8s-master ~]# ku delete pods nginx
[root@k8s-master ~]# ku get pods
No resources found in default namespace.
[root@k8s-master ~]# ku create -f aaa.yaml
pod/nginx created
[root@k8s-master ~]# ku get pods
NAME READY STATUS RESTARTS AGE
nginx 2/2 Running 0 2s
2. 编写 Pod 配置文件 frontend-localredis-pod.yaml
[root@k8s-master ~]# vim frontend-localredis-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: redis-php
labels:
name: redis-php
spec:
containers:
- name: frontend
image: kubeguide/guestbook-php-frontend:localredis
imagePullPolicy: IfNotPresent
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 1
ports:
- containerPort: 80
- name: redis
image: kubeguide/redis-master
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6379
restartPolicy: OnFailure
[root@k8s-master ~]# ku create -f frontend-localredis-pod.yaml
[root@k8s-master ~]# ku get pods
NAME READY STATUS RESTARTS AGE
nginx 1/2 CrashLoopBackOff 10 (69s ago) 27m
redis-php 2/2 Running 0 7s
备注:
命令 | 含义 |
---|---|
apiVersion:v1 | 必选,版本号 |
kind: Pod | 必选,资源类型 |
metadata | 必选,元数据 |
name:redis-php | 必选,Pod 名称 |
labels | 自定义的 pod 标签列表 |
name:redis-php | 标签值 |
spec | 必选,Pod 中容器的详细信息 |
containers | 必选,Pod 中的容器列表 |
name:frontend | 必选,自定义的容器名称 |
image:kubeguide/guestbook-php-frontend:localredis | 必选,容器的镜像名称 |
imagePullPolicy:IfNotPresent | 镜像拉取策略 |
livenessProbe | 设置存活探针 |
tcpsocket | 测试某端口是否可以连接 |
port:80 | 指定要测试的端口 |
initialDelaySeconds:1 | 指定 kubelet 在执行第一次探测前应该等待1秒,即第一次探测是#在容器启动后的第2秒才开始执行。默认是8秒,最小值是0 |
periodseconds:3 | 指定了 kubelet 应该每 3 秒执行一次存活探测。默认是 10 秒。最小值是 1 |
timeoutseconds:1 | 当探测失败时,Kubernetes 在超时之前等待的时间。存活探测情况下的放弃就意味着重新启动容器。就绪探测情况下的放弃Pod 会被打上未就绪的标签。默认值是 3。最小值是 1 |
ports | 需要暴露的端口号列表 |
-containerPort:80 | 容器需要监听的端口号 |
- name:redis | 另一个容器的名字 |
image: kubeguide/redis-master | 另一个容器的镜像 |
ports | 需要暴露的另一个容器的端口列表 |
- containerPort:6379 | 容器需要监听的端口号 |
restartPolicy: onFailure | 重启策略 |
3. Pod 文件语法
(1)Pod 文件的一级属性
一级属性主要包含5部分:
apiVersion版本,由 kubernetes 内部定义,版本号必须可以用 kubectl api-versions查询到
kind 类型,由 kubernetes 内部定义,版本号必须可以用 kubectl api-resources 查询到
metadata<0bject>元数据,主要是资源标识和说明,常用的有 name、namespace、labels 等
spec描述,这是配置中最重要的一部分,里面是对各种资源配置的详细描述
status<0bject>状态信息,里面的内容不需要定义,由 kubernetes 自动生成
(2)spec(规格)属性
在一级属性中,spec是研究的重点,它的常见子属性有:
子属性 | 含义 |
---|---|
containers<[ ]0bject>容器列表 | 用于定义容器的详细信息 |
nodeName | 根据 nodeName 的值将 pod 调度到指定的 Node 节点上 |
nodeSelector <map[ ]> | 根据NodeSelector中定义的信息选择将该Pod调度到包含这些label的Node 上 |
hostNetwork | 是否使用主机网络模式,默认为 false,如果设置为 true,表示使用宿主机网络 |
volumes<[ ]0bject> | 存储卷,用于定义 Pod 上面挂在的存储信息 |
restartPolicy | 重启策略,表示 Pod 在遇到故障的时候的处理策略 |
(3)通过kubectl explain 命令来查看每种资源的可配置项
kubectl explain pod
kubectl explain deployment
kubectl explain service
kubectl explain pod.metadata
kubectl explain pod.spec.containers
(4)运行 kubectl create 命令创建此 Pod
[root@k8s-master ~]# vim nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
[root@k8s-master ~]# ku delete pod nginx
pod "nginx" deleted
[root@k8s-master ~]# ku create -f nginx-pod.yaml
pod/nginx created
[root@k8s-master ~]# ku get pods
\NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 92s
redis-php 2/2 Running 0 54m
五. Pod 的基本用法
1. 编写 pod 文件,将两个容器放在同一个 pod 中
[root@k8s-master ~]# vim nginx-php.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-php
labels:
name: nginx-php
spec:
containers:
- name: nginx-app
image: nginx:1.7.9
ports:
- containerPort: 80
- name: php-app
image: bitnami/php-fpm
imagePullPolicy: Never
ports:
- containerPort: 9000
2. 部署 nginx 的 Pod 文件
[root@k8s-master ~]# ku create -f nginx-php.yaml
[root@k8s-master ~]# ku get pods
3. 查看 Pod 的详细信息
[root@k8s-master ~]# ku describe pod nginx-php
4. 暴露端口
[root@k8s-master ~]# ku expose pod nginx-php --port=8080 --target-port=80 --type=NodePort --name=nginx-php
5. 查看端口映射
[root@k8s-master ~]# ku get pod,svc nginx-php -o wide
6. 测试访问
浏览器访问:http://192.168.10.101:31533
六. 静态 Pod
静态 Pod 是由 kubelet 进行管理的仅存在于各个Node上的Pod他们不能通过 AP讲不Seni理,无法于 Replicationcontroller、Deployment 或者 DaemonSet 进行关联,并且 kubelet 无法对他们进行健康检査。静态 Pod 总是由 kubelet 创建的,并且总在 kubelet 所在的 Node 上运行
1. 编写 yaml
2. 查看 Pod
[root@k8s-master manifests]# ku get pods
3. 删除静态 Pod 的方法
失败的删除
成功的删除
备注:
不能用如下语句删除ku delete pod nginx-k8s-master这样删除,会让 pod 处于 pending 状态,但无法删除
六. Pod 启动过程与运行状态
创建完之后,直到持久运行起来,中间有很多步骤,也就有很多出错的可能,因此会有很多不Pod同的状态
在 Pod 的启动过程中,会涉及到多个关键组件,保证 Pod 能够顺利的启动完成,这些关键组件和作用如下所示:
关键组件 | 作用 |
---|---|
API Server | 接收和处理 Pod 创建请求 |
etcd | 存储集群状态和 Pod 定义 |
Scheduler | 将 Pod 调度到合适的节点 |
kubelet | 在节点上管理 Pod 的生命周期 |
容器运行时 | 负责容器的创建和运行 |
通过这些步骤,Kubernetes确保 Pod 能够按照预期启动并运行
1. Pod 的启动过程包含的步骤
Pod 的启动过程是 Kubernetes 中一个关键的操作,涉及多个步骤和组件协同工作。以下是 Pod 启动的主要过程:
(1)用户提交 Pod 定义
用户通过 kubectl 或其他工具提交 Pod 的 YAML 或 JSON 定义文件 Kubernetes API Server
(2)API server 接收请求
API Server 接收到 Pod 创建请求后,会进行身份验证和授权检査,确保请求合法
通过检査后,API Server 将 Pod 的定义信息存储到 etcd 中
(3)scheduler 调度 Pod
Scheduler 监控 API Server,发现有待调度的 Pod
Scheduler 根据 Pod 的资源需求、节点亲和性、污点容忍等策略,选择一个合适的节点
Scheduler 将 Pod 与节点绑定,并将绑定信息更新到 etcd
(4)kubelet 创建 Pod
目标节点上的 kubelet 监控 API Server,发现有新的 Pod 被调度到本节点
kubelet 根据 Pod 定义,调用容器运行时(如 Docker、containerd)创建容器
kubelet 还会为 Pod 设置网络(通过 CNI 插件)和存储卷(如 emptyDir、hostPath 或持久卷)
(5)容器运行时启动容器
容器运行时根据 kubelet 的指令,拉取镜像(如果本地没有)并启动容器
容器启动后,运行时向 kubelet 报告容器状态
(6)kubelet 更新 Pod 状态
kubelet 监控容器的运行状态,并将 Pod 的状态更新到 API Server
API Server 将状态信息存储到 etcd
(7)Pod 进入运行状态
当所有容器成功启动并运行后,Pod 进入 Running 状态
如果容器启动失败,kubelet 会根据重启策略(如 Always、0nFailure)决定是否重启容器
(8)探针检查(可选)
如果 Pod 定义了存活探针(Liveness Probe)或就绪探针(Readiness Probe),kubelet 会定期执行这些探针
探针检查失败可能导致容器重启或Pod 从服务端点移除
(9)Pod 可用
当 Pod 的所有容器正常运行并通过就绪探针检査后,Pod 被视为可用,可以接收流量或执行任务
(10)持续监控
kubelet 持续监控 Pod 的状态,确保其健康运行
如果 Pod 或容器出现问题,kubelet 会根据配置采取相应措施(如重启容器)
2. Pod 的运行状态
运行状态 | 说明 |
---|---|
Pending | 表示 APIServer 创建了 Pod 资源对象并已经存入了 etcd 中,但是它并未被调度完成(比如还没有调度到某台 node 上),或者仍然处于从仓库下载镜像的过程中 |
Running | Pod 已经被调度到某节点之上,并且 Pod 中所有容器都已经被 kubelet 创建。至少有一个容器正在运行,或者正处于启动或者重启状态(也就是说 Running 状态下的 Pod 不一定能被正常访问) |
succeeded | 有些 pod 不是长久运行的,比如 job、cronjob,一段时间后 Pod 中的所有容器都被成功终止,并且不会再重启。需要反馈任务执行的结果 |
Failed | Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非。状态退出或者被系统终止,比如command写的有问题 |
Unknown | 表示无法读取 Pod 状态,通常是 kube-contro1ler-manager 无法与 Pod 通信 |