前言
整个k8s是推荐我们使用资源文件清单的格式编写, 资源清单有5个顶级的字段组成:apiVersion、kind、metadata、spec、status ,status是k8s集群运行的时候需要去关注的,即机器需要去关注的,而前面这四个,不管是开发工程师还是运维工程师都需要做一些基本的了解,以及探讨pod的生命周期。
apiVersion: group/apiversion # 如果没有给定 group 名称,那么默认为 core,可以使用
kubectl apiversions # 获取当前 k8s 版本上所有的 apiVersion 版本信息( 每个版本可能不
同 )
kind: #资源类别
metadata:#资源元数据
name
namespace
lables
annotations # 主要目的是方便用户阅读查找
spec: # 期望的状态(disired state)
status:# 当前状态,本字段由 Kubernetes 自身维护,用户不能去定义
k8s版本信息:比如我们的java,有jdk1.6、jdk1.7、jdk1.8这样的版本,而k8s集群,官方也定义了一些标准(每个版本可能不同)。
使用kubectl命令可以查看apiVersion的各个版本信息
kubectl api-versions
资源类别:在java世界里,万物皆为对象,我们都把它分为一个又一个类, 通过类去new一个对象。
而在我们的k8s集群里,万物皆为资源,比如pod、deployment、节点信息等,有了资源就有了对象,所以种类这块儿为我们定义了很多很多资源,和java一样,这些资源可能不满足需求,可以自定义一些资源。
资源元数据 :我们最开始接触数据源是在jdbc的时候,数据源的元数据,整个metadata下面又定义了一些子类型的数据:
name:数据源的名字,定义的是pod, 比如之前定义的tomcat9
namespace: 具体归属于某个工作空间
labels:自定义标签
annotations:主要目的是方便用户阅读查找
期望状态:比如期望pod需要实现的功能,期望tomcat搭建一个集群
当前状态:本字段由 Kubernetes 自身维护,用户不能去定义;
当我对某个资源不是太清楚时,我们可以通过命令行去查找:
kubectl explain pod
kubectl explain deployment
kubectl explain svc
资源清单中大致可以分为如下几种类型:
<[]string> <[]Object> <map[string]string>
apiVersion <string> #表示字符串类型
metadata <Object> #表示需要嵌套多层字段
labels <map[string]string> #表示由k:v组成的映射
finalizers <[]string> #表示字串列表
ownerReferences <[]Object> #表示对象列表
hostPID <boolean> #布尔类型
priority <integer> #整型
name <string> -required- #如果类型后面接 -required-,表示为必填字段
pod的第一个生命周期,是k8s通过kubectl命名去执行的执行的时候,整个k8s集群会帮忙创建一个基础镜像,基础镜像之后呢,才是我们上图看见的第一个大的生命周期(initc),初始化容器的过程,初始化过程结束后,就会到达Main C,Main C就是主要运行的那个container的运行状态,比如我们之前做的tomcat9,他就是Main C,在整个Main C过程中,做各种各样的操作。
比如我们现在打Main C是mysql ,它肯定会涉及到一些数据的映射,比如docker里的卷 volume,初始化的卷就是在init C中帮我们完成的初始化动作,包括它的网络数据的传输,数据共享的过程,都是在这个阶段去完成的。
整个pod的初始化过程,首先经历一个start,最后经历一个stop,这两个过程呢,我们把它称之为函数,具体是什么函数呢,就是callback (回调函数),我们可以通过在Main C初始化之前去做一些操作,在它停止工作或者死亡的时候,我们去做一些操作,这样我们可以把代码或脚本放到初始化开始,包括它的容器停止之前这样一系类动作;在Main C里还涉及 到另外两个 readiness 和 liveness ,它俩叫容器的探测
就绪型性测: 指我们整个容器判定它是否已经启动了,比如说我们部署了一台gitLab服务器,对外的时候呢,我们可能观察到这个服务器属于一个running的状态,但实际上我们都知道gitLab启动是要很长时间的,gitLab服务器还没启动完成,无法对外提供正常的服务;所以我们可以通过readiness 就绪性检测判断容器是否已经准备好了,可以对外提供服务;
存活性探测:比如mysql容器、tomcat容器对外已经服务了一段时间了,但是由于某种原因tomcat容器已经不能再正常对我们的service进行服务了,但是我们整个pod的运行情况 任然属于一个running状态,这个时候再去访问tomcat的时候就会出现各种各样的问题,所以我们需要一个这个pod是否存活的状态,如果没有存活的话,那我们就涉及到是否需要重启。
##实验需要准备镜像
docker pull busybox:1.32.0
docker pull nginx:1.17.10-alpine
pod/initcpod.yml文件,需要准备busybox:1.32.0镜像
apiVersion: v1
kind: Pod
metadata:
name: initcpod-test
labels:
app: initcpod-test
spec:
containers:
- name: initcpod-test
image: busybox:1.32.0
imagePullPolicy: IfNotPresent
command: ['sh','-c','echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.32.0
imagePullPolicy: IfNotPresent
command: ['sh','-c','until nslookup myservice; do echo waitting for myservice; sleep 2;done;']
- name: init-mydb
image: busybox:1.32.0
imagePullPolicy: IfNotPresent
command: ['sh','-c','until nslookup mydb; do echo waitting for mydb; sleep 2;done;']
restartPolicy: Always
运行完initcpod-test之后,发现其需要初始化两个容器init-myservice 、init-mydb,但是由于目前还没有启动这两个容器,通过kubectl logs initcpod-test -c init-myservice 一直打印Can't find myservice.svc.cluster.local: No answer
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
selector:
app: myservice
ports:
- port: 80
targetPort: 9376
protocol: TCP
启动:
myservice应用已经初始化好了。
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
selector:
app: mydb
ports:
- port: 80
targetPort: 9377
protocol: TCP
启动
mydb 应用启动完成后,initcpod-test也启动完成了。
#先查看pod启动情况
kubectl get pods
#详细查看pod启动情况
kubectl describe pod initcpod-test
#查看initcpod-test中的第一个initContainer日志
kubectl logs initcpod-test -c init-myservice
#运行init-myservice服务
kubectl apply -f init-myservice.yml
#查看init-myservice服务运行情况
kubectl get svc
#查看initcpod-test运行情况,需要耐心等一会,会发现pod的第一个init已经就绪
kubectl get pods
#运行init-mydb服务
kubectl apply -f init-mydb.yml
#查看init-myservice服务运行情况
kubectl get svc
#查看initcpod-test运行情况,需要耐心等一会,会发现pod的两个init已经就绪,pod状态为ready
kubectl get pod -w
容器就绪检测案例,需要准备nginx:1.17.10-alpine镜像。
apiVersion: v1
kind: Pod
metadata:
name: readinesspod
labels:
app: readinesspod-test
spec:
containers:
- name: readinesspod-test
image: nginx:1.17.10-alpine
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
port: 80
path: /index1.html
initialDelaySeconds: 2 #初始化时间
periodSeconds: 3 #重新检测时间
restartPolicy: Always
#创建pod
kubectl apply -f readinesspod.yml
#检查pod状态,虽然pod状态显示running但是ready显示0/1,因为就绪检查未通过
kubectl get pods
#查看pod详细信息,文件最后一行显示readiness probe failed。。。。
kubectl describe pod readinesspod
#进入pod内部,因为是alpine系统,需要使用sh命令
kubectl exec -it readinesspod sh
#进入容器内目录
cd /usr/share/nginx/html/
#追加一个index1.html文件
echo "welcome BCST" >> index1.html
#退出容器,再次查看pod状态,pod已经正常启动
exit
kubectl get pods
根据描述得知,nginx容器没有index1.html文件
apiVersion: v1
kind: Pod
metadata:
name: livenessprobe1
labels:
app: livenessprobe1-test
spec:
containers:
- name: livenessprobe1-test
image: busybox:1.32.0
imagePullPolicy: IfNotPresent
command: ['/bin/sh','-c','touch /tmp/livenesspod;sleep 30; rm -rf /tmp/livenesspod; sleep 3600']
livenessProbe:
exec:
command: ['test','-e','/tmp/livenesspod']
initialDelaySeconds: 1 # 初始化时间
periodSeconds: 3 # 重新检测时间
restartPolicy: Always
通过touch创建一个临时文件livenesspod,30s后删除,然后通过存活探针检测临时文件是否存在,不存在则重启pod;
#创建pod
kubectl apply -f livenessprobe1.yml
#监控pod状态变化,容器正常启动
kubectl get pod -w
#等待30秒后,发现pod的RESTARTS值从0变为1.说明pod已经重启一次
apiVersion: v1
kind: Pod
metadata:
name: livenessprobe2-test
labels:
app: livenessprobe2-test
spec:
containers:
- name: livenessprobe2-test
image: nginx:1.17.10-alpine
imagePullPolicy: IfNotPresent
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 10 # 初始化时间
periodSeconds: 3 #再次检测时间
timeoutSeconds: 5 #超时时间
restartPolicy: Always
由于nginx端口为80,存活检测监听8080端口,8080端口没有反馈信息后重启pod,RESTARTS值从0变为1
#创建pod
kubectl apply -f livenessprobe2.yml
#查看pod状态
kubectl get pod -w
postStart函数,需要准备busybox:1.32.0镜像 ;
apiVersion: v1
kind: Pod
metadata:
name: post-start-test
labels:
app: post-start-test
spec:
containers:
- name: post-start-test
image: busybox:1.32.0
imagePullPolicy: IfNotPresent
lifecycle:
postStart:
exec:
#创建/BCST/k8s目录
command: ['mkdir','-p','/BCST/k8s']
command: ['sh','-c','sleep 5000']
restartPolicy: Always
在容器启动之前,通过postStart函数创建目录
#创建pod
kubectl apply -f lifeclepod.yml
#查看pod状态
kubectl get pod
#进入容器内部,查看是否创建了/BCST/k8s/目录
kubectl exec -it post-start-test sh
pod对象自从创建开始至终止退出的时间范围称为生命周期,在这段时间中,pod会处于多种不同 的状态,并执行一些操作;其中,创建主容器为必须的操作,其他可选的操作还包括运行初始化容器 (init container)、容器启动后钩子(start hook)、容器的存活性探测(liveness probe)、就绪性 探测(readiness probe)以及容器终止前钩子(pre stop hook)等,这些操作是否执行则取决于pod 的定义 。
使用 kubectl get pods 命令,status被称之为相位(phase)。
无论是手动创建还是通过控制器创建pod,pod对象总是应该处于其生命进程中以下几个相位之一:
pod的相位是在其生命周期中的宏观概念,而非对容器或pod对象的综合汇总,而且相位的数量和含义被严格界定。
pod是k8s的基础单元,以下为一个pod资源对象的典型创建过程:
除了创建应用容器之外,用户还可以为pod对象定义其生命周期中的多种行为,如初始化容器、存活性探测及就绪性探测等。
初始化容器 初始化容器即应用程序的主容器启动之前要运行的容器,常用于为主容器执行一些预置操作,它们具 有两种典型特征
有不少场景都需要在应用容器启动之前进行部分初始化操作,例如,等待其他相关联组件服务可 用、基于环境变量或配置模板为应用程序生成配置文件、从配置中心获取配置等。
初始化容器的典型应用需求具体包含如下几种。
pod资源的spec.initContainers字段以列表的形式定义可用的初始容器,其嵌套可用字段类似spec.containers。
容器生命周期钩子使它能够感知其自身生命周期管理中的事件,并在相应的时刻到来时运行由用户 指定的处理程序代码。k8s为容器提供了两种生命周期钩子:
postStart:于容器创建完成之后立即运行的钩子处理器(handler),不过k8s无法确保它一定会 于容器中的entrypoint之前运行。
preStop:于容器终止操作之前立即运行的钩子处理器,它以同步的方式调用,因此在其完成之前 会阻塞删除容器的操作调用。
钩子处理器的实现方法有Exec和HTTP两种,前一种在钩子事件触发时直接在当前容器中运行由用户定 义的命令,后一种则是在当前容器中向某url发起http请求。postStart和preStop处理器定义在 spec.lifecycle嵌套字段中。
容器探测是pod对象生命周期中的一项重要的日常任务,它是kubelet对容器周期性执行的健康状态诊断,诊断操作由容器的处理器进行定义。k8s支持三种容器探针用于pod探测:
ExecAction:在容器中执行一个命令,并根据其返回的状态码进行诊断的操作称为Exec探测,状 态码为0表示成功,否则即为不健康状态
TCPSocketAction:通过与容器的某TCP端口尝试建立连接进行诊断,端口能够成功打开即为正 常,否则为不健康状态。
HTTPGetAction:通过向容器IP地址的某指定端口的指定path发起HTTP GET请求进行诊断,响应 码大于等于200且小于400时即为成功 。
任何一种探测方式都可能存在三种结果:
success(成功):容器通过了诊断
failure(失败):容器未通过诊断
unknown(未知):诊断失败,因此不会采取任何行动
kubelet可在活动容器上执行两种类型的检测:
(livenessProbe)存活性检测:用于判定容器是否处于运行状态,一旦此类检测未通过,kubelet将杀死容器并根据restartPolicy决定是否将其重启;未定义存活性检测的容器的默认状态为success。
(readinessProbe)就绪性检测:用于判断容器是否准备就绪并可对外提供服务;未通过检测的容器意味着尚未准备就绪,端点控制器会将其IP从所有匹配到此pod对象的service对象的端点列表中移除;检测通过之后,会再次将其IP添加至端点列表中。
容器程序发生崩溃或容器申请超出限制的资源等原因都可能会导致pod对象的终止,此时是否应该 重建该pod对象则取决于其重启策略(restartPolicy)属性的定义:
Always:但凡pod对象终止就将其重启,此为默认设定
OnFailure:仅在pod对象出现错误时方才将其重启
Never:从不重启
restartPolicy适用于pod对象中的所有容器,而且它仅用于控制在同一节点上重新启动pod对象的相关容器。首次需要重启的容器,将在其需要时立即进行重启,随后再次需要重启的操作将由kubelet延迟 一段时间后进行,且反复的重启操作的延迟时长依次为10s、20s、40s、80s、160s和300s,300s是最大延迟时长。事实上,一旦绑定到一个节点,pod对象将永远不会重新绑定到另一个节点,它要么被重启,要么终止,直到节点发生故障或被删除。
当用户提交删除请求之后,系统就会进行强制删除操作的宽限期倒计时,并将TERM信息发送给 pod对象的每个容器中的主进程。宽限期倒计时结束后,这些进程将收到强制终止的KILL信号,pod对象随即也将由api server删除,如果在等待进程终止的过程中,kubelet或容器管理器发生了重启,那么终止操作会重新获得一个满额的删除宽限期并重新执行删除操作。
一个典型的pod对象终止流程具体如下:
默认情况下,所有删除操作的宽限期都是30s,不过,kubectl delete命令可以使用“--grace-period=”选 项自定义其时长,若使用0值则表示直接强制删除指定的资源,不过此时需要同时使用命令“--forece”选 项。
我是小堂,下期见~
·········· END ··············