K8s知识点整理|Pod的全面总结

Pod剖析

1. 概述

Pod 是 kubernetes 中你可以创建和部署的最小也是最简的单位。Pod 代表着集群中运行的进程。 Pod 中封装着应用的容器(有的情况下是好几个容器),存储、独立的网络 IP,管理容器如何运行的策略选项。Pod 代表着部署的一个单位:kubernetes 中应用的一个实例,可能由一个或者多个容器组合在一起共享资源。

1.1 描述

单个Pod可以类比成独立应用的“逻辑主机”;Pod中可以的共享环境有Linux的namespace[1]、cgroup2和其他可能的隔绝环境 ;Pod中的容器共享IP地址和端口号,每个pod都会有唯一的IP地址;Pod内的容器可以进行IPC3通信,不同的Pod不能直接通过IPC通信;Pod内的容器有访问共享volume的权限,volume跟pod有相同的生命周期,这些volume会被定义成pod的一部分并挂载到应用容器的文件系统中。

  1. Namespace是对全局系统资源的一种封装隔离,使得处于不同namespace的进程拥有独立的全局系统资源,改变一个namespace中的系统资源只会影响当前namespace里的进程,对其他namespace中的进程没有影响;

https://segmentfault.com/a/1190000006908272

  1. cgroup和namespace类似,也是将进程进行分组,但它的目的和namespace不一样,namespace是为了隔离进程组之间的资源,而cgroup是为了对一组进程进行统一的资源监控和限制;

https://segmentfault.com/a/1190000006917884

  1. IPC: InterProcess Communication。 进程间通信 是指在不同进程之间传播或交换信息。通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等 ;
1.2 管理

Pod作为一个独立的部署单位,支持横向扩展和复制。协同调度,协同复制,资源共享,依赖管理,生命周期,Pod都会自动的为容器处理这些问题;

1.3 支持类型
  • 一个 Pod 中运行一个容器。“每个 Pod 中一个容器” 的模式是最常见的用法;在这种使用方式中,你可以把 Pod 想象成是单个容器的封装,kuberentes 管理的是 Pod 而不是直接管理容器。
  • 在一个 Pod 中同时运行多个容器。一个 Pod 中也可以同时封装几个需要紧密耦合互相协作的容器,它们之间共享资源。这些在同一个 Pod 中的容器可以互相协作成为一个 service 单位 —— 一个容器共享文件,另一个 “sidecar” 容器来更新这些文件。Pod 将这些容器的存储资源作为一个实体来管理。

2. 共享资源

2.1 网络

每个 Pod 都会被分配一个唯一的 IP 地址。Pod 中的所有容器共享网络空间,包括 IP 地址和端口。Pod 内部的容器可以使用 localhost 互相通信。Pod 中的容器与外界通信时,必须分配共享网络资源(例如使用宿主机的端口映射)。

2.2 存储

可以为一个 Pod 指定多个共享的 Volume。Pod 中的所有容器都可以访问共享的 volume。Volume 也可以用来持久化 Pod 中的存储资源,以防容器重启后文件丢失。

3. Init容器

3.1 概念

一种专用的容器,在应用程序容器启动之前运行,用来包含一些应用镜像中不存在的实用工具或安装脚本; Init 容器会按顺序在网络和数据卷初始化之后启动,如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的 restartPolicy 为 Never,它不会重新启动。

3.2 与应用容器的区别
  • Init 容器总是运行到成功完成为止;
  • 每个 Init 容器都必须在下一个 Init 容器启动之前成功完成;
3.3 作用
  • 它们可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的;
  • 它们可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中;
  • 应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像;
  • Init 容器使用 Linux Namespace,所以相对应用程序容器来说具有不同的文件系统视图。因此,它们能够具有访问 Secret 的权限,而应用程序容器则不能;
  • 它们必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以 Init 容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件;

4. 生命周期

Pod的生命周期状态

phasedesc
挂起PendingPod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间。
运行中Running该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
成功SucceededPod 中的所有容器都被成功终止,并且不会再重启。
失败FailedPod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
未知Unknown因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。

在这里插入图片描述

在这里插入图片描述

5. 容器探针

kubelet对容器执行定期的健康检查;容器探测用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制。如果经过探测,实例的状态不符合预期,那么k8s就会把问题实例过滤不去承担业务流量;

具体有两种实现方式:

  • liveness probes:存活性探针,用于检测应用实例当前是否处于正常运行状态;如果不是,kubelet 会杀死容器,然后根据重启策略进行重启;

    决定容器是否重启,如果失败,则可以观察到Pod信息中RESTARTS在不断增长;

    其还有以下5种选项

    initialDelaySecond int # 容器启动后等待多少秒执行第一次探测
    timeoutSeconds int # 探测超时时间。默认1秒,最小1秒
    periodSeconds int # 执行探测的频率。默认是10秒,最小1秒
    failureThreshold int # 连续探测失败多少次才被认定为失败。默认是3,最小值是1
    successThreshold int # 连续探测成功多少次才被认定为成功。默认是1
    
  • readiness probes:就绪性探针,用于检测应用实例当前是否可以接收请求,如果不能,K8S不会转发流量, 端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址;

    决定是否将请求转发给容器

kubelet 调用由容器实现的 Handler 有三种探测方式:

  • ExecAction: 在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功,容器启动正常,否则异常。

    spec:
    	containers:
    	- name: nginx
    	
    	livenessProbe:
    		exec:
    			command: ["/bin/sh", "ls -l"] # 执行一个命令
    		initialDelaySecond: 30 #30秒后执行探测
    
  • TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的,容器正常,否则异常;

    spec:
    	containers:
    	- name: nginx
    	
    	livenessProbe:
    		tcpSocket:
    			port: 80 #尝试访问80端口
    
  • HTTPGetAction: 对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码[200, 400)之间,则诊断被认为是成功的,否则异常;

    spec:
    	containers:
    	- name: nginx
    	
    	livenessProbe:
    		httpGet:
    			scheme: HTTP
    			port: 80 #尝试访问80端口
    			path: /hello
    

6. 重启策略

一旦容器探测出现问题,k8s就会对容器所在pod进行重启,这是由pod的重启策略决定的,pod重启策略有3种;

  • Always:容器启动失败时,自动重启容器,是默认值
  • OnFailure:容器终止运行且退出码不为0时重启;
  • Never:不论什么结果,都不重启;

重启策略适用于pod对象中的所有容器,失败的容器由 kubelet 以五分钟为上限的指数退避延迟(10秒,20秒,40秒…)重新启动。首次需要重启的容器,将在其需要时立即重启,随后再需要重启的操作由kubelet 延迟一段时间后进行,且反复重启操作的延迟时间是10s,20s,40s,80s,160s和300s,五分钟是最大延迟时长;成功执行十分钟后重置延迟时间;

spec:
	containers:
	- name: nginx
	
	livenessProbe:
		httpGet:
			scheme: HTTP
			port: 80 #尝试访问80端口
			path: /hello
			
	restartPolicy: Never # 重启策略是Never 该配置属于pod,与container同级

7. 钩子函数

Pod hook(钩子)是由 Kubernetes 管理的 kubelet 发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。可以同时为 Pod 中的所有容器都配置 hook。

类型:

  • postStart: 容器创建之后执行,如果失败了会重启容器;
  • preStop:容器终止之前执行,执行完成之后,容器将成功终止,在其完成之前会阻塞删除容器的操作;

执行流程:

在容器创建之后,容器的 Entrypoint 执行之前,这时候 Pod 已经被调度到某台 node 上,被某个 kubelet 管理了,这时候 kubelet 会调用 postStart 操作,该操作跟容器的启动命令是在同步执行的,也就是说在 postStart 操作执行完成之前,kubelet 会锁住容器,不让应用程序的进程启动,只有在 postStart 操作完成之后容器的状态才会被设置成为 RUNNING。 可参考上方的流程图;

钩子函数支持使用下面三种方式定义:

  • Exec命令:在容器内执行一次命令

    apiVersion: v1
    kind: Pod 
    metadata:
      name: pod-hook-exec
      namespace: dev 
    spec:
      containers:
        - name: main-container
          image: nginx
          ports:
          - name: nginx-port
            containerPort: 80
          lifecycle:
            postStart:
              exec:
                command: ["/bin/sh","-c","touch file.xxxx"] #  启动前创建了一个文件
            preStop:
              exec:
                command: ["/usr/sbin/nginx","-s", "quit"]
    
  • TCP socket:在当前容器尝试访问指定的socket

    apiVersion: v1
    kind: Pod 
    metadata:
      name: pod-hook-exec
      namespace: dev 
    spec:
      containers:
        - name: main-container
          image: nginx
          ports:
          - name: nginx-port
            containerPort: 80
          lifecycle:
            postStart:
            	tcpSocket:
            		port: 8080
    
  • HTTPGet:在当前容器中向某url发起http请求

    apiVersion: v1
    kind: Pod 
    metadata:
      name: pod-hook-exec
      namespace: dev 
    spec:
      containers:
        - name: main-container
          image: nginx
          ports:
          - name: nginx-port
            containerPort: 80
          lifecycle:
            postStart:
            	httpGet:
            		path: / # url地址
            		port: 80 # 端口号
            		host: 192.168.0.1 # 主机地址
            		scheme: HTTP # 支持的协议,http或https
    

8. Pod预设Preset

目的:

需要在一批容器在启动的时候就注入一些信息,比如 secret、volume、volume mount 和环境变量,而又不想一个一个的改这些 Pod 的 template,这时候就可以用到 PodPreset 这个资源对象了。 Pod Preset是用来在 Pod 被创建的时候向其中注入额外的运行时需求的 API 资源。

Kubernetes 提供了一个准入控制器(PodPreset),当其启用时,Pod Preset 会将应用创建请求传入到该控制器上。当有 Pod 创建请求发生时,系统将执行以下操作:

  1. 检索所有可用的 PodPresets
  2. 检查 PodPreset 标签选择器上的标签,看看其是否能够匹配正在创建的 Pod 上的标签。
  3. 尝试将由 PodPreset 定义的各种资源合并到正在创建的 Pod 中。
  4. 出现错误时,在该 Pod 上引发记录合并错误的事件,PodPreset 不会注入任何资源到创建的 Pod 中。
  5. 注释刚生成的修改过的 Pod spec,以表明它已被 PodPreset 修改过。注释的格式为 podpreset.admission.kubernetes.io/podpreset-<pod-preset name>"":"<resource version>"

每个 Pod 可以匹配零个或多个 Pod Prestet;并且每个 PodPreset 可以应用于零个或多个 Pod。 PodPreset 应用于一个或多个 Pod 时,Kubernetes 会修改 Pod Spec。对于 EnvEnvFromVolumeMounts 的更改,Kubernetes 修改 Pod 中所有容器的容器 spec;对于 Volume 的更改,Kubernetes 修改 Pod Spec。

Q&A

为什么不在一个容器内直接运行多个应用程序?
  1. 透明。让pod中的容器对基础设施(业务运行提供功能保障)可见, 例如进程管理和资源监控。这可以为用户带来极大的便利。
  2. 解耦软件依赖。容器可以进行版本管理和独立的编译与发布;
  3. 方便。 用户不必运行自己的进程管理器 ;
  4. 效率。由基础架构提供更多的职责,所以容器可以变得更加轻量级;
两种探针如何选择?
  1. 如果容器中的进程能够在遇到问题或不健康的情况下自行崩溃,则不一定需要存活探针; kubelet 将根据 Pod 的restartPolicy 自动执行正确的操作;
  2. 如果您希望容器在探测失败时被杀死并重新启动,那么请指定一个存活探针liveness probes,并指定restartPolicy 为 Always 或 OnFailure;
  3. 如果要仅在探测成功时才开始向 Pod 发送流量,请指定就绪探针readiness probes。在这种情况下,就绪探针可能与存活探针相同,但是 spec 中的就绪探针的存在意味着 Pod 将在没有接收到任何流量的情况下启动,并且只有在探针探测成功后才开始接收流量;
  4. 如果您希望容器能够自行维护,您可以指定一个就绪探针readiness probes,该探针检查与存活探针不同的端点;
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BugGuys

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值