kubernetes Pod&资源清单

kubernetes资源清单&资源控制器
摘要由CSDN通过智能技术生成

Pod

Pod是Kubernetes的最重要最基本的概念。它是能够被创建,调度和管理的最小部署单元。一个Pod代表集群中一个运行的进程。

Pod的组成

一个Pod由一个特殊的根容器Pause容器和若干个紧密相关的用户业务容器组成。
Pause容器作为Pod的根容器,它的状态代表整个容器组的状态。
Pod里的多个容器共享Pause容器的IP,共享Pause容器挂载的Volume.
Kubernetes为每个Pod都分配了唯一的IP地址,称之为Pod IP,一个Pod里的多个容器共享Pod IP地址。
Kubernetes要求底层网络支持集群内任意两个Pod之间的TCP/IP直接通信,这通常采用虚拟二层网络技术来实现。
一个Pod里的容器与另外主机上的Pod容器能够直接通信。

Pod里面的容器除了共享网络和存储外,还共享:
PID namespace:一个Pod内的容器能够看到对方容器的进程
IPC namespace:一个Pod内的容器能够使用POSIX消息队列进行通信
UTS namespace : 一个Pod内的容器共享主机名。

Pod一旦被创建,就会被放入的etcd中存储,随后会被Master调度到某个具体的Node上进行绑定,随后该Pod被对应的Node上的kubelet进程实例化一组相关的Docker容器并启动起来。
在默认情况下,当Pod里的某个容器停止时,Kubernetes会重启整个Pod;如果Pod所在的Node宕机,则会将这个Node上的所有Pod重新调度到其他节点上。

Event是一个事件的记录,记录事件的最早产生时间,最后重现时间,重复次数,发起者,
类型以及导致此事件的原因等众多信息。 Pod同样有Event记录,可以用来定位问题查找原因。

Pod的生命周期

在这里插入图片描述
在这里插入图片描述
和其他组件的交互

与API Server交互
API Server 提供了集群与外部交互的接口,通过 kubectl 命令或者其他 API 客户端提交 pod spec 给 API Server 作为pod创建的起始。Pod 与 API Server 交互的主要流程如下:
API Server 在接收到创建pod的请求之后,会根据用户提交的参数值来创建一个运行时的pod对象。
根据 API Server 请求的上下文的元数据来验证两者的 namespace 是否匹配,如果不匹配则创建失败。
Namespace 匹配成功之后,会向 pod 对象注入一些系统数据,如果 pod 未提供 pod 的名字,则 API Server 会将 pod 的 uid 作为 pod 的名字。
API Server 接下来会检查 pod 对象的必需字段是否为空,如果为空,创建失败。
上述准备工作完成之后会将在 etcd 中持久化这个对象,将异步调用返回结果封装成 restful.response,完成结果反馈。
至此,API Server 创建过程完成,剩下的由 scheduler 和 kubelet 来完成,此时 pod 处于 pending 状态。
与scheduler交互
当提交创建 pod 的请求与 API Server 的交互完成之后,接下来由 scheduler 进行工作,该组件主要是完成 pod 的调度来决定 pod 具体运行在集群的哪个节点上。
注意,此处声明一点,API Server 完成任务之后,将信息写入到 etcd 中,此时 scheduler 通过 watch 机制监听到写入到 etcd 的信息然后再进行工作。
Scheduler 读取到写入到 etcd 中的 pod 信息,然后基于一系列规则从集群中挑选一个合适的节点来运行它,调度时主要通过三步来确定 pod 运行节点:
节点预选:基于一系列预选规则(如 PodFitsResource 和 MatchNode-Selector 等)对每个节点进行检查,将不符合的节点过滤掉从而完成节点预选。
节点优选:对预选出的节点进行优先级排序,以便选出最适合运行 pod 对象的节点。
从优先级结果中挑选出优先级最高的节点来运行 pod 对象,当此类节点多个时则随机选择一个。
注:如果有特殊 pod 资源需要运行在特殊节点上,此时可以通过组合节点标签以及 pod 标签和标签选择器等来实现高级调度,
如 MatchInterPodAffinity、MatchNodeSelector 和 PodToleratesNodeTaints 等预选策略,他们为用户提供自定义 Pod 亲和性或反亲和性、节点亲和性以及基于污点及容忍度的调度机制。

启停流程

启动pod流程分析
1.kubelet 通过 API Server 监听 etcd 目录,同步 pod 列表。如果发现有新的 pod 绑定到本节点,则按照 pod 清单要求创建 pod,

2.如果是发现 pod 被更新,则做出相应更改。读取到 pod 的信息之后,如果是创建和修改 pod 的任务,则做如下处理:
	为该 pod 创建一个数据目录
	从 API Server 读取该 pod 清单
	为该 pod 挂载外部卷
	下载 pod 所需的 Secret

3.检查已经运行在节点中 pod,如果该 pod 没有容器或者 Pause 容器没有启动,则先停止pod里所有的容器进程。

4.使用 pause 镜像为每个pod创建一个容器,该容器用于接管 Pod 中所有其他容器的网络。为 pod 中的每个容器做如下处理:
	为容器计算一个 hash 值,然后用容器的名字去查询对于 docker 容器的 hash 值。
	若查找到容器,且两者的 hash 值不同,则停止 docker 中容器中进程,并停止与之关联的 pause 容器,
	若相同,则不做处理。若容器被终止了,且容器没有指定的重启策略,则不做任何处理调用 docker client 

5.下载容器镜像,并启动容器。
Pod终止过程

1.用户发出删除 pod 命令
2.Pod 对象随着时间的推移更新,在宽限期(默认情况下30秒),pod 被视为“dead”状态
3.将 pod 标记为“Terminating”状态
4.与第三步同时运行,监控到 pod 对象为“Terminating”状态的同时启动 pod 关闭过程
5.与第三步同时进行,endpoints 控制器监控到 pod 对象关闭,将pod与service匹配的 endpoints 列表中删除
6.如果 pod 中定义了 preStop 钩子处理程序,则 pod 被标记为“Terminating”状态时以同步的方式启动执行;
	若宽限期结束后,preStop 仍未执行结束,第二步会重新执行并额外获得一个2秒的小宽限期
7.Pod 内对象的容器收到 TERM 信号,宽限期结束之后,若存在任何一个运行的进程,pod 会收到 SIGKILL 信号,
	Kubelet 请求 API Server 将此 Pod 资源宽限期设置为0从而完成删除操作

在一个pod中,可以运行多个容器,但通常在一个pod里面运行一个容器,容器在创建之前,有多个初始化容器(init container)用来进行初始化环境,init container执行完,它就退出了,接下来是主容器(main container)开始启动,主容器启动时也要初始化主容器里面的环境,在主容器刚启动时,用户可以手动嵌入一个操作叫post start;在主容器结束前,也可以做一个收尾操作pre stop,用来在主容器结束前做一个清理.

初始化容器

1. init container(初始化容器)

每个容器都可以存放一些初始化容器(init container),这个初始化容器的目的就在运行真正容器之前的一些准备工作,例如拷贝文件,初次化文件,或者获取一些敏感字段如密码,秘钥等。为什么这样做呢?有以下几个点

a.假设每个容器里面都带有一些拷贝的命令工具,如zip,或者crul等工具,就会造成每一个容器的大小会增加,因为这些unzip等工具,在容器运行当中是不会使用到的,这样变成工具冗余了,所以希望能在初次化容器中完成所有工作后就把容器关闭。
b.因为在真正启动的容器当中,是不可以访问敏感字段空间的,所以初次化容器就能把需要的敏感字段拿到后,赋予给主容器当中,这样就不会出现主容器的安全性问题了。
c.这里注意的是,初次容器是同步运行的,按顺序执行,第一初次化容器执行容器失败,是不会进入第二个初次化容器的。
d.这里也涉及到初次化容器的启动策略
 
2. start (启动容器)
初次化容器全部执行完成后,将会全部被杀掉,然后主容器将会被启动

3. readiness (探针)
启动过程中,会带有探针,目的是检查容器是否启动成功,如果成功,才会把服务端口暴露出去

4. liveness (存活)
在整个过程中会检查主容器的存活状态

5. stop (停止容器)
最后就是停止容器,这里必须是人为的停止或者控制器停止
Init 容器与普通的容器非常像,除了如下两点:

它们总是运行到完成。
Init 容器不支持 Readiness,因为它们必须在 Pod 就绪之前运行完成。
每个 Init 容器必须运行成功,下一个才能够运行。
如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的 restartPolicy 值为 Never,它不会重新启动。

Init 容器能做什么?

Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。
Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。
应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
Init 容器能以不同于Pod内应用容器的文件系统视图运行。因此,Init容器可具有访问 Secrets 的权限,而应用容器不能够访问。
由于 Init 容器必须在应用容器启动之前运行完成,因此 Init容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。
因为Init容器具有与应用程序容器分离的单独镜像,所以它们的启动相关代码具有如下优势:
>它们可以包含 并运行实用工具,但是出于安全考虑,是不建议在应用程序容 器镜像中包含这些实用工具的

>它们可以包含使川工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建镜像没必要FROM另一个镜像, 只要在安装过程中使用类似sed、awk、python 或dig这样的二工具。
	应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建-一个单独的镜像。

>Init 容器使用Linux Namespace, 所以相对应用程序容器来说具有不同的文件系统视图。因此,它们能够具有访问Secret的权限,而应用程序容器则不能。

>它们必 须在应川程序容器启动之前运行完成,而应川程序容器是并行运行的,所以Init容器能够提供了一-种简单的阳塞或延迟应川容器的启动的方法,直到满足了-组先决条件。

生命周期的状态

Pending Pod 已被 Kubernetes 接受,但尚未创建一个或多个容器镜像。这包括被调度之前的时间以及通过网络下载镜像所花费的时间,执行需要一段时间。
Running Pod 已经被绑定到了一个节点,所有容器已被创建。至少一个容器正在运行,或者正在启动或重新启动。
Succeeded 所有容器成功终止,也不会重启。
Failed 所有容器终止,至少有一个容器以失败方式终止。也就是说,这个容器要么已非 0 状态退出,要么被系统终止。
Unknown 由于一些原因,Pod 的状态无法获取,通常是与 Pod 通信时出错导致的。
在Pod启动过程中,Init容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下-一个容器启动之前成功退出

如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的restartPolicy 指定的策略进行重试。
	然而,如果Pod的restartPolicy 设置为Always, Init 容器失败时会使用RestartPolicy策略

在所有的Init 容器没有成功之前,Pod将不会变成Ready状态。Init容器的端口将不会在Service中进行聚集。
	正在初始化中的Pod处于Pending状态,但应该会将Initializing 状态设置为true,

如果Pod重启,所有Init容器必须重新执行,这就是幂等。不管重启多少次,每一次重启的状态都是一样的。

对Init容器spec的修改被限制在容器image 字段,修改其他字段都不会生效。更改Init容器的image 字段,等价于重启该Pod

Init容器具有应用容器的所有字段。除了readinessProbe,因为Init 容器无法定义不同于完成(completion)的就绪(readiness) 之外的其他状态。
	这会在验证过程中强制执行在Pod中的每个app和Init容器的名称必须唯-; 与任何其它容器共享同-一个名称,会在验证时抛出错误

案例

vim init.yml
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec: 
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-C''echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox
    command: [ ' sh''-C''until nslookup myservice; do echo waiting for myservice; sleep 2;done;'] #定义一个反向循环,一直循环访问dns,请求获取myservice的IP,如果没有获取到就一直循环。
  - name: init-mydb
    image: busybox
    command: ['sh', '-C''until nslookup mydb; do echo waiting for mydb; sleep 2; done;']

#设置两个init进程,

运行init.yml文件时,因为找不到init-myservice和init-mydb服务,所以不停的执行初始化。

#添加上面的init-myservice和init-mydb服务
vim server.yml
kind: Service
apiVersion: v1
metadata :
  name: myservice
spec :
  ports :
    - protocol: TCP
    port: 80
    targetPort: 9376
kind: Service
apiVersion: v1
metadata :
  name: mydb
spec :
  ports :
    protocol: TCP
    port: 80
    targetPort: 9377
# 运行第一个文件
kubectl get pod
kubectl log myapp-pod -c init-myservice #查看一个init的日志,就会发现找不到服务的报错,并一直重启

#运行server.yml后,创建了init-myservice和init-mydb服务,这时dns就会获取这两个容器的解析,myapp-pod就会请求dns服务器,从而退出循环

Pod的健康检查

对Pod的健康检查可以通过两类探针来检查:LivenessProbe和ReadinessProbe:

LivenessProbe探针:用于判断容器是否存活(running状态),如果LivenessProbe探针探测到容器不健康,
则kubelet杀掉该容器,并根据容器的重启策略做响应处理.

ReadinessProbe探针:用于判断容器是否启动完成(ready状态),可以接受请求。如果ReadinessProbe探针探测失败,
则Pod的状态被修改。Endpoint Controller将从service的Endpoint中删除包含该容器所在的Pod的Endpoint。
kubelet定制执行LivenessProbe探针来诊断容器的健康状况,有三种方式:
1.ExecAction:在容器内部执行一个命令,如果该命令的返回值为0,则表示容器健康。
2.TCPSocketAction:通过容器ip地址和端口号执行TCP检查,如果能够建立tcp连接表明容器健康。
3.HTTPGetAction:通过容器Ip地址、端口号及路径调用http get方法,如果响应的状态吗大于200且小于400,则认为容器健康。

就绪检测
readinesesProbe-httpget

apiVersion: v1
kind: Pod
metadata:
  name: readiness-httpget-pod
  namespace: default
spec:
  containers:
  - name: readiness-httpget-container
    image: nginx
    imagePullPolicy: IfNotPresent
    readinessProbe:
      httpGet:
        port: 80 !
        path: /index1.htm1 I
      initialDelaySeconds: 1  #隔一秒检测
      periodSeconds: 3    #检测三次
vim read.yaml
kubectl create -f read.yaml
kubectl exec readiness-httpget-pod -it -- /bin/s
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值