基础概念
Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
Pod是一组(一个或多个) 容器
,这些容器共享存储、网络、以及怎样运行这些容器的声明。其中共享上下文包括一组 Linux namespace、控制组(cgroup)和可能一些其他的隔离方面, 即用来隔离容器的技术。 在 Pod 的上下文中,每个独立的应用可能会进一步实施隔离。
Pod 通常不是直接创建的,而是使用工作负载资源创建的
Pod的一些小知识点
运行方式
pod很少有直接创建的,当然,个别排查工具就是直接拉起一个pod,比如dnsutils。专门用于排查dns问题,更多的情况下,pod是有控制器(Deployment 、DS控制器、sts等)进行创建并进行资源管理,Pod不具备自愈能力,挂了就是挂了
,因此需要控制器进行管理
内部容器之间协调工作
因为pod是由一组容器构建的最小化的工作单元,所以多个容器之间是可以互相协调工作的。但是前提是pod内各个容器的内部数据资源需要共享
例如:假设此时Pod内有以下资源
- 业务容器(service-a) ,具有挂载卷v-log
- 日志收集服务(log-agent),具有挂载卷v-log
业务容器通过挂载卷v-log,将日志写入至 /mnt/log/service
目录
日志收集服务可以通过挂载卷v-log,读取 /mnt/log/service
目录内的数据内容,并进行相应处理,这就实现了一个简单的边车采集日志功能
Pod的生命周期
- Pending
Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。 - Running
至少其中有一个主要容器正常启动,或者正在重启 - Succeeded or Failed
取决于 Pod 中是否有容器以失败状态结束 - Unknown
出现了一些未知的异常情况
Pod的检测探针
每个pod运行的情况不一样,有些pod确实需要存活检测,如果有问题,k8s可以及时发现,并重新拉起一个新的pod,k8s中一共有三种探针机制
livenessProbe(存活性检测)
指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略决定未来。如果容器不提供存活探针, 则默认状态为 Success。
readinessProbe(就绪检测,可以拨入流量)
指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。 初始延迟之前的就绪态的状态值默认为 Failure。 如果容器不提供就绪态探针,则默认状态为 Success。
startupProbe(启动完毕检测)
指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被 禁用,直到此探针成功为止。如果启动探测失败,kubelet 将杀死容器,而容器依其 重启策略进行重启。 如果容器没有提供启动探测,则默认状态为 Success。
正确的停止一个pod
以JAVA的微服务为例子,程序就绪之后,一般会向注册中心发送注册信息,并暴露自己的ip、端口等基本内容,但是在程序停止时,如果没有正确的接受到停止运行的命令,则只能等待注册中心将当前容器标记为不健康,并移除,但是等待期间,依然会有流量进入,那就肯定是404或者500,对用户造成不好的体验
使用PreStop进行处理
Kubernetes为我们提供了两种钩子函数:
- PostStart :这个钩子在容器创建后立即执行。但是,并不能保证钩子将在容器ENTRYPOINT之前运行,因为没有参数传递给处理程序。 主要用于资源部署、环境准备等。不过需要注意的是如果钩子花费时间过长以及于不能运行或者挂起,容器将不能达到Running状态。另外,PostStart的执行相对于容器的代码执行是异步的。
- PreStop :钩子在容器终止前立即被调用。它是阻塞的,意味着它是同步的,所以它必须在删除容器的调用触发之前完成。主要用于优雅关闭应用程序、通知其他系统等。如果钩子在执行期间挂起,Pod阶段将停留在Running状态并且不会达到failed状态。另外,PreStop的执行现对于SIGTERM信息,也是异步的,k8s也不会等待PreStop执行完成。
简单的示例代码
apiVersion: v1
kind: Pod
metadata:
name: erp-service
spec:
containers:
- name: erp-service
image: xxxxx/erp-service:1.0.0.20210314
ports:
- containerPort: 8080
lifecycle:
preStop:
exec:
## 发送停止命令到当前服务,让其主动脱离注册中心并离线
command:
- bash
- -c
- 'curl -X GET http://127.0.0.1:8080/service-shutdown'
使用Init容器进行协助初始化
每个 Pod 中可以包含多个容器, 应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。
Init 容器特点
- 它们总是运行到完成。
- 每个都必须在下一个启动之前成功完成。如果 Pod 的 Init 容器失败,kubelet 会不断地重启该 Init 容器直到该容器成功为止
- 不支持 lifecycle、livenessProbe、readinessProbe 和 startupProbe, 因为它们必须在 Pod 就绪之前运行完成
- 如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。 每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时, Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行
- 每个 Init 容器会在网络和数据卷初始化之后按顺序启动。
- 在所有的 Init 容器没有成功之前,Pod 将不会变成 Ready 状态。 Init 容器的端口将不会在 Service 中进行聚集。正在初始化中的 Pod 处于 Pending 状态, 但会将状况 Initializing 设置为 false。
如果 Pod 重启,所有 Init 容器必须重新执行。因为 Init 容器可能会被重启、重试或者重新执行,所以 Init 容器的代码应该是幂等的。 特别地,基于 emptyDirs 写文件的代码,应该对输出文件可能已经存在做好准备。
简单的 Init 容器示例
yml来自k8s官方模版
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app.kubernetes.io/name: MyApp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]