2、pod基础知识

news/2024/7/4 11:20:00/文章来源:https://www.cnblogs.com/ggbaooo/p/18277289

二、Pod 解析

1、基本原理

1.1 什么是Pod

pod demo

Pod 是工作负载在 Kubernetes 上运行的应用程序。在 Kubernetes 中,Pod 代表的是集群上处于运行状态的一组容器的集合

Pod的设计初衷

如果把某个应用的进程进行拆分,拆分成一个一个容器,那就有可能出现某个进程容器被调度到了不同的节点上,往往应用内部的进程与进程间通信(通过 IPC 或者共享本地文件之类)都是要求在本地进行的,也就是需要在同一个节点上运行。

所以需要一个更高级别的结构来将这些容器绑定在一起,并将他们作为一个基本的调度单元进行管理,这样就可以保证这些容器始终在同一个节点上面,这也就是 Pod 设计的初衷。

867eeb8f-507f-46c9-a418-366e094ca19d

Pod 可简单地理解为一组、一个或多个容器,每个Pod还包含一个Pause容器,Pause 容器是 Pod 的父容器,它主要负责僵尸进程的回收管理,同时通过 Pause 容器可以使同一个 Pod 里面的不同容器共享存储、网络、PID、IPC等,容器之间可以使用 localhost:port 相互访问,可以使用 Volume 等实现数据共享。

根据Docker的构造,Pod可被建模为一组具有共享命名空间、卷、IP地址和端口的容器。

1.2 引入Pod的原因

轻量级:Pod 是 Kubernetes 集群中最小的可部署单元,可以轻松地部署、调度和管理。它们可以根据需要创建、销毁或重启,而无需影响集群中的其他部分。

资源共享:Pod 中的容器共享相同的网络和存储资源。这使得它们可以相互通信并访问共享的文件系统。例如,多个容器可以共享同一份配置文件,而不必在每个容器中复制。

网络隔离:Pod 提供了一个虚拟网络环境,可以为容器提供独立的 IP 地址和网络命名空间。这使得容器可以相互隔离,并且可以防止容器之间的网络干扰。

服务发现:Pod 可以被标记和注释,以便 Kubernetes 可以根据标签和注释选择它们。这使得容器可以轻松地与其他容器通信,并允许 Kubernetes 自动发现和管理服务之间的关系。

水平扩展:通过使用 Pod 副本集,可以轻松地创建多个相同配置的 Pod,并在需要时自动扩展它们。这使得应用程序可以根据负载自动调整其资源使用率,并提高可扩展性和可用性。

在之前 Docker 方案时,就会有如下的情况发生:

使用裸容器时,需要将容器内应用程序的端口映射到宿主机,如果容器过多,端口管理就会比较困难,而且容易引起端口冲突。

使用Kubernetes方案解决:

而 Kubernetes 为每个 Pod 都分配一个唯一的IP地址,这样就可以保证不同应用程序可以使用同一个端口,之后通过 Kubernetes 的内部 Service 进行访问,这样就避免了发生端口冲突的问题。

1.3 了解Pod原理

其实 Pod 也只是一个逻辑概念,真正起作用的还是 Linux 容器的 Namespace 和 Cgroup 这两个最基本的概念,Pod 被创建出来其实是一组共享了一些资源的容器而已。

网络

  • 首先 Pod 里面的所有容器,都是共享的同一个 Network Namespace。

存储

  • 但是涉及到文件系统的时候,默认情况下 Pod 里面的容器之间的文件系统是完全隔离的,但是我们可以通过声明来共享同一个 Volume,也就是挂载同一存储卷(默认情况下,在一个Pod中的容器A无法直接查看或访问容器B的文件系统,它们之间的文件操作是隔离的)。加入一个中间容器(没有什么架构是加一个中间件解决不了的?),这个容器叫做 Infra 容器,而且这个容器在 Pod 中永远都是第一个被创建的容器,这样是不是其他容器都加入到这个 Infra 容器就可以了,这样就完全实现了 Pod 中的所有容器都和 Infra 容器共享同一个 Network Namespace 了,如下图所示:

pod infra container

从上面图中我们可以看出普通的容器加入到了 Infra 容器的 Network Namespace 中,所以这个 Pod 下面的所有容器就是共享同一个 Network Namespace 了,普通容器不会创建自己的网卡,配置自己的 IP,而是和 Infra 容器共享 IP、端口范围等,而且容器之间的进程可以通过 lo 网卡设备进行通信:

  • 也就是容器之间是可以直接使用 localhost 进行通信的;
  • 看到的网络设备信息都是和 Infra 容器完全一样的;
  • 也就意味着同一个 Pod 下面的容器运行的多个进程不能绑定相同的端口;
  • 而且 Pod 的生命周期只跟 Infra 容器一致,而与容器 A 和 B 无关。

对于文件系统 Kubernetes 是怎么实现让一个 Pod 中的容器共享的呢?默认情况下容器的文件系统是互相隔离的,要实现共享只需要在 Pod 的顶层声明一个 Volume,然后在需要共享这个 Volume 的容器中声明挂载即可。

pod containers share volumes

1.4 了解init容器

Init 容器是 Kubernetes 中的一种特殊容器,用于在主容器启动之前运行特定的初始化任务。它们通常用于执行一次性的预配置或数据初始化操作,以确保主容器的正常启动和运行。(Pod 的 YAML 文件可以不指定 Init 容器。Init 容器是可选的)

一些常见的用途包括:

  1. 配置和准备环境:Init 容器可以在主容器启动之前设置和准备环境。例如,可以使用 Init 容器来加载配置文件、初始化数据库、创建目录结构等。
  2. 同步和等待:在某些情况下,主容器可能需要依赖其他组件或服务。Init 容器可以用于等待这些依赖项可用后再启动主容器。例如,可以使用 Init 容器等待数据库或消息队列可用后再启动应用程序容器。
  3. 数据预加载:有时候,主容器需要访问大量数据或文件,而这些数据可能需要提前加载到共享卷中。Init 容器可用于在主容器启动之前将数据从外部存储源(如对象存储或数据库)复制到共享卷中。

通过使用 Init 容器,可以确保主容器在正确的环境和依赖项下运行,从而提高应用程序的可靠性和稳定性。在 Kubernetes 中,Init 容器与主容器共享相同的网络和存储空间,并且它们会按照定义的顺序依次执行。只有当所有的 Init 容器都成功完成后,主容器才会被启动。

Tips:如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的 restartPolicy 为 Never,它不会重新启动。

例子如下:

当使用 Init 容器时的一个例子是在部署一个 Web 应用程序时,需要进行一些预处理任务,例如安装依赖项或执行数据库迁移。以下是一个示例:

apiVersion: v1
kind: Pod
metadata:name: my-web-app
spec:containers:- name: main-appimage: my-app-image# 主应用程序容器配置# ...initContainers:- name: init-setupimage: busyboxcommand: ["sh", "-c", "echo 'Initializing setup...'"]# 初始化设置容器配置# ...- name: init-databaseimage: mysql:5.7env:- name: MYSQL_ROOT_PASSWORDvalue: mysecretpasswordcommand: ["sh", "-c", "mysql -uroot -p$MYSQL_ROOT_PASSWORD -e 'CREATE DATABASE mydb;'"]# 数据库初始化容器配置# ...

这个示例中,我们定义了一个 Pod 包含一个主应用程序容器 main-app 和两个 Init 容器 init-setupinit-database

main-app 是运行 Web 应用程序的主容器,我们假设它是由 my-app-image 镜像构建的。

init-setup 是一个 Init 容器,它使用 busybox 镜像,并通过 echo 'Initializing setup...' 命令打印出初始化设置的信息。

init-database 是另一个 Init 容器,使用 mysql:5.7 镜像,通过环境变量 MYSQL_ROOT_PASSWORD 设置 MySQL root 密码,并使用 mysql -uroot -p$MYSQL_ROOT_PASSWORD -e 'CREATE DATABASE mydb;' 命令创建名为 mydb 的数据库。

这样,当 Pod 启动时,它将按照定义的顺序依次执行这两个 Init 容器。首先,init-setup 容器将打印初始化设置的信息。然后,init-database 容器将初始化数据库。

通过定义这些 Init 容器,我们可以在主应用程序启动之前进行一些预处理任务,以确保应用程序正常运行。你可以根据需求添加或修改 Init 容器的配置。

1.5 如何划分 Pod

上面我们介绍了 Pod 的实现原理,了解到了应该把关系紧密的容器划分到同一个 Pod 中运行,那么怎么来区分“关系紧密”呢?举一个简单的示例,比如我们的 Wordpress 应用,是一个典型的前端服务器和后端数据服务的应用,那么你认为应该使用一个 Pod 还是两个 Pod 呢?

如果在同一个 Pod 中同时运行服务器程序和后端的数据库服务这两个容器,理论上肯定是可行的,但是不推荐这样使用,我们知道一个 Pod 中的所有容器都是同一个整体进行调度的,但是对于我们这个应用 Wordpress 和 MySQL 数据库一定需要运行在一起吗?当然不需要,我们甚至可以将 MySQL 部署到集群之外对吧?所以 Wordpress 和 MySQL 即使不运行在同一个节点上也是可行的,只要能够访问到即可。

pod wordpress demo1

但是如果你非要强行部署到同一个 Pod 中呢?从某个角度来说是错误的,比如现在我们的应用访问量非常大,一个 Pod 已经满足不了我们的需求了,扩容的目标也是 Pod,并不是容器,比如我们再添加一个 Pod,这个时候我们就有两个 Wordpress 的应用和两个 MySQL 数据库了,而且这两个 Pod 之间的数据是互相独立的,因为 MySQL 数据库并不是简单的增加副本就可以共享数据了,所以这个时候就得分开部署了,采用第二种方案,这个时候我们只需要单独扩容 Wordpress 的这个 Pod,后端的 MySQL 数据库并不会受到扩容的影响。

pod wordpress demo2

将多个容器部署到同一个 Pod 中的最主要参考就是应用可能由一个主进程和一个或多个的辅助进程组成,比如上面我们的日志收集的 Pod,需要其他的 sidecar 容器来支持日志的采集。所以当我们判断是否需要在 Pod 中使用多个容器的时候,我们可以按照如下的几个方式来判断:

  • 这些容器是否一定需要一起运行,是否可以运行在不同的节点上
  • 这些容器是一个整体还是独立的组件
  • 这些容器一起进行扩缩容会影响应用吗

基本上我们能够回答上面的几个问题就能够判断是否需要在 Pod 中运行多个容器了。

2、Pod 生命周期

pod loap

前面我们已经了解了 Pod 的设计原理,接下来我们来了解下 Pod 的生命周期。下图展示了一个 Pod 的完整生命周期过程,其中包含 Init ContainerPod Hook健康检查 三个主要部分,接下来我们就来分别介绍影响 Pod 生命周期的部分:

首先在介绍 Pod 的生命周期之前,我们先了解下 Pod 的状态,因为 Pod 状态可以反应出当前我们的 Pod 的具体状态信息,也是我们分析排错的一个必备的方式。

2.1 Pod 状态

首先先了解下 Pod 的状态值,我们可以通过 kubectl explain pod.status 命令来了解关于 Pod 状态的一些信息,Pod 的状态定义在 PodStatus 对象中,其中有一个 phase 字段,下面是 phase 的可能取值:

52839bb4-5e71-4234-9613-e7d9d5fba0fa

#kubectl get pod <Podname> -oyaml
kubectl get pod cluster-test-8b47d69f5-dbvvf -oyaml

34710054-f913-4466-a08a-c8228f07cf3b

Tips:kube-controller-manager 就是用来控制 Pod 的状态和生命周期的

phase

  • Pending(挂起)

Pod 信息已经提交给了集群,但仍有一个或多个容器未被创建。可以通过kubectl describe pod -n 命名空间名称 Pod名称 查看处于 Pending 状态的原因。

  • Running(运行中)

Pod已经被绑定到一个节点上,并且所有的容器都已经被创建,而且至少有一个是运行状态、正在启动或者重启,可以通过 kubectl logs -n 命名空间名称 Pod名称 ,查看Pod的日志。

Tips:Pod状态为Running,并不代表Pod正常,也需要READY为N/N

  • Succeeded(成功)

所有容器执行成功并终止,并且不会再次重启。可以通过kubectl logs -n 命名空间名称 Pod名称 查看Pod日志。

  • Failed(失败)

所有容器都已终止,并且至少有一个容器以失败的方式终止,也就是说这个容器要么以非零状态退出,要么被系统终止。

可以通过kubectl logs -n 命名空间名称 Pod名称kubectl describe pod -n 命名空间名称 Pod名称查看Pod日志和状态原因。

  • Unknown(未知)

通常是由于通信问题造成的无法获得 Pod 的状态。

  • ImagePullBackOff ErrImagePull

镜像拉取失败,一般是由于镜像不存在、网络不通或者需要登录认证引起的。

可以通过kubectl describe pod -n 命名空间名称 Pod名称查看Pod状态原因。

  • CrashLoopBackOff

容器启动失败,可以通过 logs 命令查看具体原因,一般为启动命令不正确,健康检查不通过,前台没有该进程等。

可以通过 kubectl logs -n 命名空间名称 Pod名称 查看Pod日志。

  • OOMKilled

容器内存溢出,一般是容器的内存 Limit 设置的过小,或者程序本身有内存溢出。

可以通过 kubectl logs -n 命名空间名称 Pod名称 查看Pod日志。

  • Terminating

Pod 正在被删除。可以通过kubectl describe pod -n 命名空间名称 Pod名称查看Pod状态原因。

  • SysctlForbidden

Pod 自定义了内核配置,但 kubelet 没有添加内核配置或配置的内核参数不支持。

可以通过kubectl describe pod -n 命名空间名称 Pod名称查看Pod状态原因。

  • Completed

容器内部主进程退出,一般计划任务执行结束会显示该状态。

可以通过 kubectl logs -n 命名空间名称 Pod名称 查看Pod日志。

  • ContainerCreating

Pod 正在创建,一般为正在下载镜像,或者有配置不当的地方。

可以通过kubectl describe pod -n 命名空间名称 Pod名称查看Pod状态原因。

PodCondition

除此之外,PodStatus 对象中还包含一个 PodCondition 的数组,里面包含的属性有:

  • lastProbeTime:最后一次探测 Pod Condition 的时间戳。
  • lastTransitionTime:上次 Condition 从一种状态转换到另一种状态的时间。
  • message:上次 Condition 状态转换的详细描述。
  • reason:Condition 最后一次转换的原因。
  • status:Condition 状态类型,可以为 “True”, “False”, and “Unknown”.
  • type:Condition 类型,包括以下方面:
    • PodScheduled(Pod 已经被调度到其他 node 里)
    • Ready(Pod 能够提供服务请求,可以被添加到所有可匹配服务的负载平衡池中)
    • Initialized(所有的init containers已经启动成功)
    • Unschedulable(调度程序现在无法调度 Pod,例如由于缺乏资源或其他限制)
    • ContainersReady(Pod 里的所有容器都是 ready 状态)

2.2 定义一个Pod

编写yml文件

[root@k8s-master01 ~]# cat /yaml/pod/test-nginx.yaml
apiVersion: v1 #必选,API 的版本号
kind: Pod      #必选,类型 Pod
metadata:      #必选,元数据name: nginx  #必选,Pod名称
spec: #必选,用于定义 Pod 的详细信息containers:  #必选,容器列表- name: test-nginx #必选,容器名称image: nginx:1.14.2  #必选,容器镜像地址ports:  #可选,容器需要暴露的端口号列表- containerPort: 80  #暴露的端口号也可以用kubectl run test-nginx --image nginx:1.14.2 --dry-run=client -oyaml > test-nginx.yaml创建yaml文件

创建Pod

#yaml两种方式
cd /yaml/pod/
kubectl create -f test-nginx.yamlkubectl create -f /yaml/pod/test-nginx.yaml#也可以直接run一个pod
kubectl run nginx-run --image=nginx:1.15.12

查看Pod的状态

[root@k8s-master01 pod]# kubectl get pod
NAME                           READY   STATUS              RESTARTS       AGE
cluster-test-8b47d69f5-dbvvf   1/1     Running             21 (18m ago)   39h
nginx                          0/1     ContainerCreating   0              11s[root@k8s-master01 pod]# kubectl get pod -n  default -owide
NAME                           READY   STATUS    RESTARTS       AGE   IP              NODE         NOMINATED NODE   READINESS GATES
cluster-test-8b47d69f5-dbvvf   1/1     Running   21 (30m ago)   39h   172.16.58.199   k8s-node02   <none>           <none>
nginx                          1/1     Running   0              12m   172.16.85.205   k8s-node01   <none>           <none>

2.3 Pod的镜像拉取策略

当你最初创建一个 Deployment、 StatefulSet、Pod 或者其他包含 Pod 模板的对象时,如果没有显式设定的话, Pod 中所有容器的默认镜像拉取策略是 IfNotPresent(除非镜像 tag 为 latest 或没有指定标签)。这一策略会使得 kubelet在镜像已经存在的情况下直接略过拉取镜像的操作。

操作方式 说明
Always 总是拉取,当镜像 tag 为 latest 或没有指定标签时,且 imagePullPolicy 未配置,默认为 Always
Never 不管是否存在都不会拉取,如果镜像已经以某种方式存在本地, kubelet 会尝试启动容器;否则,会启动失败。
IfNotPresent 镜像不存在时拉取镜像,如果 tag 为非 latest,且 imagePullPolicy 未配置,默认为 IfNotPresent。

yaml示例如下,可通过kubectl describe pod <Pod名称>查看效果。

apiVersion: v1 #必选,API 的版本号
kind: Pod      #必选,类型 Pod
metadata:      #必选,元数据name: nginx  #必选,Pod名称
spec: #必选,用于定义 Pod 的详细信息containers:  #必选,容器列表- name: test-nginx #必选,容器名称image: nginx:1.14.2  #必选,容器镜像地址ports:  #可选,容器需要暴露的端口号列表- containerPort: 80  #暴露的端口号imagePullPolicy: Always #总是拉取

Tips:Pod镜像拉取策略是针对Pod中单个容器的行为。

2.4 Pod的重启策略

Pod 的 spec 中包含一个 restartPolicy 字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。

操作方式 说明
Always 默认策略,容器失效时,自动重启该容器。
OnFailure 容器以不为 0 的状态码终止,自动重启该容器。
Never 无论何种状态,都不会重启。

estartPolicy 指通过 kubelet 在同一节点上重新启动容器。通过 kubelet 重新启动的退出容器将以指数增加延迟(10s,20s,40s…)重新启动,上限为 5 分钟,并在成功执行 10 分钟后重置。不同类型的的控制器可以控制 Pod 的重启策略:

  • Job:适用于一次性任务如批量计算,任务结束后 Pod 会被此类控制器清除。Job 的重启策略只能是"OnFailure"或者"Never"
  • ReplicaSetDeployment:此类控制器希望 Pod 一直运行下去,它们的重启策略只能是"Always"
  • DaemonSet:每个节点上启动一个 Pod,很明显此类控制器的重启策略也应该是"Always"

2.5 Pod的三种探针

在生产环境下,进程正常启动并不代表应用能正常处理请求,所以合理地设计应用的健康检查尤为重要。在使用裸机或者裸容器部署时,一般很难对应用做很完善的健康检查,而 Pod 提供的探针可以很方便地用来检测容器内的应用是否正常。目前探针有3种检测方式,可以根据不同的场景选择合适的健康检查方式。

2.5.1 Pod探针的种类

在 Kubernetes 中,一般通过两种类型的探针来监测Pod中的容器:

  1. 存活探针(Liveness Probe):用于监测容器是否仍然处于运行状态(是否还活着)。如果存活探针检测到容器失败,Kubernetes 将会自动重启该容器。
  2. 就绪探针(Readiness Probe):用于监测容器是否已准备好接收流量(是否准备好了)。如果就绪探针检测到容器无法处理流量, Kubernetes 将会停止将流量发送到该容器,直到就绪探针重新检测到容器可接收流量。
种类 说明
startupProbe(启动探针) Kubernetes1.16 新加的探测方式,用于判断容器内的应用程序是否已经启动。如果配置了 startupProbe,就会先禁用其他探测,直到它成功为止。如果探测失败,Kubelet 会杀死容器,之后根据重启策略进行处理,如果探测成功,或没有配置 startupProbe, 则状态为成功,之后就不再探测。
livenessProbe(存活探针) 用于探测容器是否在运行,如果探测失败,kubelet 会“杀死”容器并根据重启策略进行相应的处理。如果未指定该探针,将默认为 Success。
readinessProbe(就绪探针) 一般用于探测容器内的程序是否健康,即判断容器是否为就绪(Ready)状态。如果是,则可以处理请求,反之 Endpoints Controller 将从所有的 Service 的 Endpoints 中删除此容器所在Pod的IP地址,这样我们的流量就不会被路由到这个 Pod 里面来了。如果未指定,将默认为Success。

2.5.2 Pod探针的实现方式

实现方式 说明
Exec 在容器内执行一个指定的命令,如果命令返回值为0,则认为容器健康
TCPSocket 通过 TCP 连接检查容器指定的端口,如果端口开放,则认为容器健康
HTTPGet(最可靠) 对指定的 URL 进行 Get 请求,如果状态码在200~400(不包括400) 之间,则认为容器健康
gRPC 1.24版本开始出现,使用 gRPC 执行一个远程过程调用。 目标应该实现 gRPC 健康检查。如果响应的状态是 "SERVING",则认为诊断成功。 gRPC 探针是一个 Alpha 特性,只有在你启用了 "GRPCContainerProbe" 特性门控时才能使用。

探针结果

结果 说明
Success 容器通过检测
Failure 容器未通过检测
Unknown 检测失败,因此不会采取任何措施。

2.5.3 创建探针Pod

1. 创建一个没有探针的Pod

[root@k8s-master01 pod]# cat /yaml/pod/pod.yaml
apiVersion: v1 # 必选,API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息containers: # 必选,容器列表- name: nginx # 必选,符合 RFC 1035 规范的容器名称image: nginx:1.15.12 # 必选,容器所用的镜像的地址imagePullPolicy: IfNotPresentcommand: # 可选,容器启动执行的命令- sh- -c- sleep 20; nginx -g "daemon off;"ports: # 可选,容器需要暴露的端口号列表- containerPort: 80 # 端口号restartPolicy: Never  #重启策略,无论如何都不会重启

创建Pod,并查看pod分配的IP,最后再curl一下IP。此过程就是演示创建Pod后,由于已有镜像,此时Pod已经Running,也分配了IP,此时Service会把这个Pod IP添加进去到Endpoints 列表。但此时进行curl IP却说端口没通,那么如果此时有流量负载到这个Pod,那就会丢包。(只有Pod的Ready为N/N时,Service才会分配流量到该Pod)

[root@k8s-master01 pod]# kubectl create -f pod.yaml
pod/nginx created[root@k8s-master01 pod]# kubectl get pod -owide
NAME    READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          3s    172.16.58.213   k8s-node02   <none>           <none>[root@k8s-master01 pod]# curl 172.16.58.213
curl: (7) Failed connect to 172.16.58.213:80; Connection refused#yaml写的sleep后再启动nginx进程,Running 20秒后再curl就能访问到nginx了。
[root@k8s-master01 pod]# kubectl get pod -owide
NAME    READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          21s   172.16.58.213   k8s-node02   <none>           <none>[root@k8s-master01 pod]# curl 172.16.58.213
<!DOCTYPE html>
...省略输出 ...

2. 配置livenessProbe(存活探针)

创建一个 livenessProbe(存活)探针的 Pod,其中检测8080端口就是为了模拟检测不到端口。也就是10秒时开始检测,超时2秒还没有检测则检测失败一次。第二次检测在第13秒,超时2秒还没有检测则检测失败两次,在第15秒开始 Kill 容器(此处删除快慢受节点影响,只有删除成功后才会重启Pod中的容器),如果 restartPolicy 为 Always,则会不断的重启 Pod。

[root@k8s-master01 pod]# cat /yaml/pod/livenessProbe.yaml
apiVersion: v1 # 必选,API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据name: nginx-liveness # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息containers: # 必选,容器列表- name: nginx # 必选,符合 RFC 1035 规范的容器名称image: nginx:1.15.12 # 必选,容器所用的镜像的地址imagePullPolicy: IfNotPresentcommand: # 可选,容器启动执行的命令- sh- -c- sleep 10; nginx -g "daemon off;"livenessProbe: # 可选,健康检查tcpSocket: # 端口检测方式port: 8080initialDelaySeconds: 10 # 初始化时间timeoutSeconds: 2 # 超时时间periodSeconds: 3 # 检测间隔successThreshold: 1 # 检查成功为1次表示就绪failureThreshold: 2 # 检测失败2次表示未就绪ports: # 可选,容器需要暴露的端口号列表- containerPort: 80 # 端口号restartPolicy: Never  #重启策略,无论如何都不会重启

eb7ce5ce-1068-4779-9af2-95ff1fbf4279

3. 配置readinessProbe(就绪探针)

创建一个readinessProbe(就绪)探针的 Pod,这个就绪探针将会使用 HTTP GET 请求,访问容器的/index.html路径,并且通过容器内的80端口进行连接。如果探针成功连接并返回合适的响应码,那么 Pod 将被标记为就绪状态,可以开始接收流量。反之,如果探针失败,则 Pod 将被标记为不可用,不会接收到流量。

[root@k8s-master01 pod]# cat /yaml/pod/readinessProbe.yaml
apiVersion: v1 # 必选,API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据name: nginx-readiness # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息containers: # 必选,容器列表- name: nginx # 必选,符合 RFC 1035 规范的容器名称image: nginx:1.15.12 # 必选,容器所用的镜像的地址imagePullPolicy: IfNotPresentcommand: # 可选,容器启动执行的命令- sh- -c- sleep 10; nginx -g "daemon off;"readinessProbe: # 可选,健康检查。注意三种检查方式同时只能使用一种。httpGet: # 接口检测方式path: /index.html # 检查路径port: 80scheme: HTTP # HTTP or HTTPS#httpHeaders: # 可选, 检查的请求头#- name: end-user# value: JasoninitialDelaySeconds: 10 # 初始化时间, 健康检查延迟执行时间timeoutSeconds: 2 # 超时时间periodSeconds: 3 # 检测间隔successThreshold: 1 # 检查成功为 1 次表示就绪failureThreshold: 2 # 检测失败 2 次表示未就绪ports: # 可选,容器需要暴露的端口号列表- containerPort: 80 # 端口号restartPolicy: Never  #重启策略,无论如何都不会重启

创建Pod,然后大致13s的时候才READY状态 1/1,因为检测到存活才会READY状态 1/1。前面的时间 READY 0/1 是因为容器中执行sleep 10,等到执行nginx -g "daemon off;" 也有耗时。

f314bfb9-793b-4e56-854b-b8a04c711971

容器中index.html被改名,探针探测不到,READY状态 0/1。则Pod将被标记为不可用,不会接收到流量,同时查看Pod的详细信息。

1f4f6c2b-f0c8-434c-8d4b-bca94df4e683 23f10f0b-249e-4db9-8428-82dac8ae9562

将容器中的index.html重命名回来后,READY状态 1/1了。

320ddd02-d927-4375-a90e-a9be82cf4ae2

4. 配置startupProbe(启动探针)

有时候会有一些应用在启动时需要比较长的初始化时间,在这种情况下,您不想杀死应用程序,也不想对外提供服务。那么之前两种探针的检测参数设置就得检测相对较长间隔时间,或者较多次数。当 Pod 发生故障,等待时间过长导致"无法容忍"。

要这种情况下,若要不影响对死锁作出快速响应的探测,设置存活探测参数是要技巧的。技巧就是使用 startupProbe(启动探针)来设置启动探测,针对 HTTP 或 TCP 检测,可以通过将 failureThreshold * periodSeconds 参数设置为足够长的时间来应对糟糕情况下的启动时间。

[root@k8s-master01 pod]# cat /yaml/pod/startupProbe.yaml
apiVersion: v1 # 必选,API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据name: nginx-startup # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息containers: # 必选,容器列表- name: nginx # 必选,符合 RFC 1035 规范的容器名称image: nginx:1.15.12 # 必选,容器所用的镜像的地址imagePullPolicy: IfNotPresentcommand: # 可选,容器启动执行的命令- sh- -c- sleep 20; nginx -g "daemon off;"startupProbe:tcpSocket:port: 80initialDelaySeconds: 10 # 初始化时间, 健康检查延迟执行时间timeoutSeconds: 2 # 超时时间periodSeconds: 5 # 检测间隔successThreshold: 1 # 检查成功为 1 次表示就绪failureThreshold: 3 # 检测失败 3 次表示未就绪
#上面这里的配置表示我们的慢速容器最多可以有 15 秒(3 个检查 * 5 秒= 15s)来完成启动。readinessProbe: # 可选,健康检查。httpGet: # 接口检测方式path: /index.html # 检查路径port: 80scheme: HTTP # HTTP or HTTPS#httpHeaders: # 可选, 检查的请求头#- name: end-user# value: JasoninitialDelaySeconds: 10 # 初始化时间, 健康检查延迟执行时间timeoutSeconds: 2 # 超时时间periodSeconds: 3 # 检测间隔successThreshold: 1 # 检查成功为 1 次表示就绪failureThreshold: 2 # 检测失败 2 次表示未就绪livenessProbe: # 可选,健康检查tcpSocket: # 端口检测方式port: 80initialDelaySeconds: 10 # 初始化时间timeoutSeconds: 2 # 超时时间periodSeconds: 3 # 检测间隔successThreshold: 1 # 检查成功为1次表示就绪failureThreshold: 2 # 检测失败2次表示未就绪ports: # 可选,容器需要暴露的端口号列表- containerPort: 80 # 端口号restartPolicy: Never  #重启策略,无论如何都不会重启

Tips:如果 配置了startupProbe,就会先禁用其他探测,直到它成功为止。

另外除了上面的 initialDelaySecondsperiodSeconds 属性外,探针还可以配置如下几个参数:

  • timeoutSeconds:探测超时时间,默认 1 秒,最小 1 秒。
  • successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功,默认是 1,但是如果是 liveness 则必须是 1。最小值是 1。
  • failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败,默认是 3,最小值是 1。

2.6 Pod的生命周期钩子(Hook)

Pod Hook 是由 kubelet 发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。我们可以同时为 Pod 中的所有容器都配置 Hook。

Kubernetes 为我们提供了两种钩子函数:

  • PostStart:这个钩子在容器创建后立即执行。但是,并不能保证钩子将在容器 ENTRYPOINT 之前运行,因为没有参数传递给处理程序。主要用于资源部署、环境准备等。不过需要注意的是如果钩子花费太长时间以至于不能运行或者挂起,容器将不能达到 running 状态。
  • PreStop:这个钩子在容器终止之前立即被调用。它是阻塞的,意味着它是同步的,所以它必须在删除容器的调用发出之前完成。主要用于优雅关闭应用程序、通知其他系统等。如果钩子在执行期间挂起,Pod 阶段将停留在 running 状态并且永不会达到 failed 状态。

Tips:PostStart 或者 PreStop 钩子失败, 它会杀死容器,所以应该让钩子函数尽可能的轻量。当然有些情况下,长时间运行命令是合理的, 比如在停止容器之前预先保存状态。

两种方式来实现上面的钩子函数:

  • Exec - 用于执行一段特定的命令,不过要注意的是该命令消耗的资源会被计入容器。
  • HTTP - 对容器上的特定的端点执行 HTTP 请求。

一个示例yaml文件

[root@k8s-master01 pod]# cat /yaml/pod/pod-preStop_postStart.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-prestop-poststart
spec:containers:- name: pod-prestop-poststartimage: nginx:1.15.12imagePullPolicy: IfNotPresentlifecycle:postStart: # 容器创建完成后执行的指令, 可以是 exec httpGet TCPSocketexec:command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]#preStop:  #效果是在容器被终止前,会先执行一个休眠10秒的命令。#exec:#command:#- sh#- -c#- sleep 10ports: # 可选,容器需要暴露的端口号列表- containerPort: 80restartPolicy: Never

根据上面的yaml进行创建一个 Pod ,配置了 postStart 和 preStop。在启动容器后查看/usr/share/message内容说明已经执行了 postStart。

img

下面看 preStop,这里用 sleep 作示例,当生产环境大多用于优雅退出。也就是使用程序的关闭命令,安全优雅的关闭应用程序。图中进行了 kubectl delete 操作后,重新启动一个 master01 节点的ssh会话,快速 kubectl get pod 查看此时pod的状态,处于Terminating(表示该Pod正在被删除),因为 sleep 命令没结束,且在宽限期最大程度32秒内,所以会等这个20s的 sleep 结束后才会结束 Pod。

img

img

3、Pod的启动和退出流程

3.1 Pod的启动流程

a731e6a7-abd6-406b-a44a-584ad70bd34f

  • 当我们执行kubectl时,Apiserver收到新建pod指令后,pod因选择某个节点部署,此时处于pending状态。
  • 当pod已经选择好节点后,处于ContainerCreating状态。准备拉取镜像。
  • 当成功拉取镜像后,变成Running状态。
  • 当有初始化容器时,先执行初始化容器里面的操作,然后启动主容器。
  • 当启动完成主容器后,如果配置 pod 探针,先执行 startupProbe 探针再执行 livenessProbe 和 readinessProbe 探针。
  • 当健康检查完成后,由 Endpoint 添加Pod IP。

3.2 Pod的退出流程

31cb582b-bfd9-4fb9-b168-c5b116e05388

  1. 当我们执行 kubectl 时,api-server 收到删除 pod 指令后,api-server 会将 pod 状态改为 dead 状态(看不到),再变为 Terminating 状态(表示该Pod正在被删除)。K8S 通知 node 执行 docker stop 命令,docker 会先向容器中 PID 为 1 的进程发送系统信号 SIGTERM(终止程序)。
  2. 正常无流量情况下,在宽限期内(30s)内控制面会将关闭的 Pod 从对应的 EndpointSlice(和 Endpoints)对象中移除。
  3. 如果配置了 PreStop,当流量没有结束的情况下,会在已有的宽限期再加2s,此后控制面会将关闭的 Pod 从对应的 EndpointSlice(和 Endpoints)对象中移除。
  4. 超出终止宽限期限时,kubelet 会触发强制关闭过程。容器运行时会向 Pod 中所有容器内仍在运行的进程发送 SIGKILL 信号。kubelet 触发强制从 API 服务器上删除 Pod 对象的逻辑,并将宽限期设置为 0 (这意味着马上删除)。

3.2.1 指定参数强制删除

执行强制删除时必须同时指定 --force --grace-period=0,强制删除一个 pod 是从集群状态还有 etcd 里立刻删除这个 pod,只是当 Pod 被强制删除时,api-server不会等待来自 Pod 所在节点上的 kubelet 的确认信息:pod 已经被终止。在 API 里 pod 会被立刻删除,在节点上, pod被设置成立刻终止后,在强行杀掉前还会有一个很小的宽限期。

注:本篇学习笔记内容参考杜宽的《云原生Kubernetes全栈架构师》,视频、资料文档等,大家可以多多支持!还有YinJayChen语雀、k8s训练营、“我为什么这么菜”知乎博主等资料文档,感谢无私奉献!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/734455.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

7、高级调度任务

七、高级调度任务、污点与容忍、亲和力(Affinity) 1. Job 1.1 Job概述 Job 是一个资源对象,负责处理任务(即仅执行一次的任务,直到任务完成),并将继续重试 Pod 的执行,它保证批处理任务的一个或多个 Pod 直到指定数量的 Pod 成功终止。Job 跟踪记录成功完成的 Pod 个数…

8、高级调度准入控制

九、资源配额、资源限制、服务质量Qos 1. 节点可用性延伸 已经从多个维度保障了服务的可用性,比如调度到不同的机器和机房、配置可靠的健康检查等。但是上述措施都是基于应用级别去做的,如果我们的 Kubernetes 集群用来运行容器的节点有了故障,带来的影响是很大的,所以在保…

邀请函 | 极限科技全新搜索引擎 INFINI Pizza 亮相 2024 可信数据库发展大会!

过去一年,在全球 AI 浪潮和国家数据局成立的推动下,数据库产业变革不断、热闹非凡。2024 年,站在中国数字经济产业升级和数据要素市场化建设的时代交汇点上,“2024 可信数据库发展大会” 将于 2024 年 7 月 16-17 日在北京悠唐皇冠假日酒店隆重召开,大会将以 “自主、创新…

debian12 创建本地harbor镜像库

前言harbor是一个docker/podman镜像管理库,可用于存储私人镜像。现将本人在debian12系统搭建harbor镜像库的过程记录下来,留作后续参考。 可以参考github harbor项目给定的安装教程,很详细了:https://goharbor.io/docs/2.11.0/install-config/configure-https/ 正文harbor 镜…

1、Kubernetes基础

一、Kubernetes基础 1. 为什么要用Kubernetes 在业务开始进行容器化时,前期需要容器化的项目可能并不多,涉及的容器也并不多,此时基于Docker容器直接部署至宿主机也能实现自己的需求。但是随着项目越来越多,管理的容器也越来越多,此时使用“裸容器”部署的方式管理起来就显…

一、Kubernetes基础

一、Kubernetes基础 1. 为什么要用Kubernetes 在业务开始进行容器化时,前期需要容器化的项目可能并不多,涉及的容器也并不多,此时基于Docker容器直接部署至宿主机也能实现自己的需求。但是随着项目越来越多,管理的容器也越来越多,此时使用“裸容器”部署的方式管理起来就显…

工创赛总结与展望——概述

开始 我们队是从2023年寒假开始准备的,我是做嵌入式软件的,那时候找了两个队友,机械Z和硬件Q,都是寒假前联系的,准备在寒假多学习一些相关内容,开学开干;寒假时,硬件Q联系不上了,队里缺画板子的,我寒假玩FreeRtos玩一半,开始学习硬件设计;整个寒假没有准备什么和工…

Halcon图像和文件操作

文件操作 dev_get_window (WindowHandle) * 遍历文件夹 list_files (C:/Users/Desktop/halcon deeplearn/Train_images, [files, recursive], Files) * 便利文件夹中的图像文件 list_image_files (C:/Users/Desktop/halcon deeplearn/Train_images/梨, default, [], ImageFiles…

36、k8s-Ingress的使用-搭建ingress-nginx服务和ingress-controller控制器--http代理

1、搭建ingress服务环境(安装ingress-controller控制器)--这里使用nginx做负载均衡 1、创建文件:mkdir /opt/ingresscd /opt/ingress 2、获取ingress-nginx和ingress控制器的yaml文件:##创建ingress-controller控制器的yaml文件wget https://github.com/kubernetes/ingress…

25、k8s-pod的控制器-第四种-DaemonSet(DS)-有几个node就自动创建几个pod

概念:DaemonSet类型的控制器可以保证集群中的每一台(或指定)节点上都运行一个副本、一般适用于日志收集、节点监控场景等、也就是说、如果一个pod 提供的功能是节点级别的(每个节点都需要且只需要一个)、那么这类pod就适合使用DaemonSet类型的控制器创建 DaemonSet的特点…

24、k8s-pod的控制器-第三种-HPA(Horizontal Pod Autoscaler)-自动调整pod的数量

监测pod的使用情况来做调整 概念:HPA可以获取每个pod的利用率、然后和HPA中定义的指标(如cpu、内存等使用情况)进行对比、同时计算出需要伸缩的具体值、最后实现pod数量的调整、其实HPA与之前的Deployment 控制器一样、也属于一种kubernetes资源对象、它通过追踪分析目标pod…

编译安装Haproxy

一、三种软负载均衡器的区别 1、关于三种负载均衡器的性能对比: LVS是基于内核实现的,他的性能最好; 其次是haproxy,最后是nginx 关于三种负载均衡器的代理类型对比: LVS只支持基于ip的四层代理转发,也不支持正则匹配; haproxy和nginx都可以作为四层代理和七层代理,同时…

CentOS7.9部署站点运行

简介 本章节主要讲的是在Linux系统CentOS7.9上去完成.NET Core 6.0软件的安装,确定Linux的版本是x64还是arm64的,然后到.NET Core的官网下载6.0的SDK,并进行安装 步骤 1.进入站点目录 2.运行站点 3.配置 Nginx 站点代理 4.浏览站点 实施 1.进入站点目录[root@ml006 /]# cd /…

三大财务报表之间的勾稽关系

财务须知:三大财务报表之间的勾稽关系是怎样,附合并报表系统 三大财务报表是利润表、资产负债表、现金流量表,财务报表之间有勾稽关系,好比资产负债表是底子,利润表就是外面的面子,而现金流量表就是实实在在的日子,可以通过财务报表看出企业财务经营状况是怎么样,那他们…

MMM高可用配置

目录1.MMM的概述2.MMM的工作原理3.如何实现主主复制 1.MMM的概述 MMM(Master-Master replication manager for MySQL,MySQL主主复制管理器) 是一套支持双主故障切换和双主日常管理的脚本程序。MMM 使用 Perl 语言开发,主要用来监控和管理 MySQL Master-Master (双主)复制…

《Programming from the Ground Up》阅读笔记:p1-p18

《Programming from the Ground Up》学习第1天,p1-18总结,总计18页。 一、技术总结 1.fetch-execute cycle p9, The CPU reads in instructions from memory one at a time and executes them. This is known as the fetch-execute cycle。 2.general-purpose vs special-pu…

SpringMVC-02-什么是SpringMVC

1、概述Spring MVC是Spring Framework的Web开发部分,是基于Java实现MVC的轻量级Web框架。官方文档:https://docs.spring.io/spring-framework/docs/4.3.24.RELEASE/spring-framework-reference/html/ 中文官方文档:https://www.w3cschool.cn/spring_mvc_documentation_lines…

视图控制器UINavigationController的介绍与基本使用

UINavigationController 是 iOS 中用于管理视图控制器层次结构的一个重要组件,通常用于实现基于堆栈的导航。它提供了一种用户界面,允许用户在视图控制器之间进行层次化的导航,例如从列表视图到详细视图。 UINavigationController 的主要功能管理视图控制器堆栈:使用一个堆…

拉普拉斯网格变形实现

因为课题需要,除了RBF还做了一个Laplace网格变形,其他大佬已经把原理写的很详细了,我就简单介绍一下公式,主要还是写写实现过程。过程同样参考了大佬的部分代码,而且实现的时候刚开始敲代码不久,所以有点乱QAQ。 首先,计算离散拉普拉斯坐标,网格上的点vi的拉普拉斯坐标…