Kubernetes POD生命周期
文章目录
POD创建流程
kubectl命令 --> api server接收所有指令 --> etcd 存储所有组件的数据 --> scheduler 进行调度计算 --> etcd 存储所有组件的数据 --> kubelet 客户端,接收创建任务
kuberctl 创建pod
使用资源清单创建pod
Master节点的API Server接收创建请求
将创建请求数据放入ETCD中
API server取出数据交给Scheduler
Scheduler资源计算,任务调度,将资源计算的数据放入ETCD中
API server取出计算后的数据,交给Controller
Controller根据资源,控制Node节点上的kubelet创建pod
kubelet接收到请求后,创建POD
首先要创建根容器
POD中的其它容器,通过container网络模式挂载到根容器上
kube-proxy提供网络服务
生命周期
## init container
初始化容器是指,在主容器启动之前,我们可以让他做一些准备工作。
比如:
1.两个容器做了共享存储,那么我们可以让它先启动一个容器,来对目录进行更改用户和授权
2.容器需要连接数据库,那么可以让初始化容器检测数据库是否可以正常连接,如果可以再启动主容器
## hook
PostStart:在容器启动创建后,立即执行,但时间不能太长,否则容器不会是running状态
PreStop:在容器停止前,执行一些命令,主要用于优雅关闭程序
## liveness probe
存活探针,用于定义容器内,应用是否满足探针指定状态
## readiness probe
就绪探针,指定何时允许容器进入流量
POD针对应用封装
那么我们在工作中,一个pod究竟要放几个容器?
在实际工作中我们除了完成任务以外还需要考虑以后扩容的问题,就拿wordpress举例,有以下两种方案:
第一种:全部放一个pod里,适用于个人网站,可扩展性不强,单点不安全
第二种:wordpress和MySQL分开
那么如何扩容呢?如果第一种方案大家会发现没有办法很好的扩容,因为数据库和wordpress已经绑定成一个整体了,扩容wordpress就得扩容mysql。而第二种方案就要灵活的多。
总结:数据库、redis等比较重要的容器最好单独独立出来,业务层面、应用层面可以在一起,具体一个pod内起多少容器是没有定数的,只能按业务划分
初始化容器
初始化容器完成了它的任务后就会退出,不会再占用资源
[root@db01 ~]$ vim init_nginx.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx-init
spec:
volumes:
- name: nginx-index # //挂载路径被设置为nginx-index变量
emptyDir: {} # //emptyDir:被挂载的路径不在宿主机上,随机目录,容器关闭就会消失,临时的
initContainers: # initContainers:初始化容器,与containers语法一样,只是做的事情不同
- name: init
image: busybox
imagePullPolicy: IfNotPresent
args: [/bin/sh, -c, 'echo k8s >> /usr/share/nginx/html/index.html'] # //执行一个命令
volumeMounts:
- name: nginx-index
mountPath: "/usr/share/nginx/html" # //将容器中目录挂载到指定共享目录
containers: # //containers:容器
- name: nginx
image: nginx:alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- name: nginx-index
mountPath: "/usr/share/nginx/html" # //主容器的Index目录也挂共享目录
[root@db01 ~]$ kubectl apply -f init_nginx.yml
## 验证一下初始化容器是否工作了
[root@db01 ~]$ curl 10.2.2.12
k8s ## //页面改变
## 只有一个容器,初始化容器完成任务后自动退出
[root@db01 ~]$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-init 1/1 Running 0 4m42s 10.2.2.12 db02 <none> <none>
## 查看一下我们利用emptyDir模式启动的挂载目录具体在哪
[root@db02 ~]$ docker ps
[root@db02 ~]$ docker inspect 32f78ce7442b|grep -i -A 5 mount
"Mounts": [
{
"Type": "bind",
"Source": "/var/lib/kubelet/pods/c0464d82-c088-4e5a-afae-50b4c5e807ef/volumes/kubernetes.io~empty-dir/nginx-index",
"Destination": "/usr/share/nginx/html",
"Mode": "",
### Source:宿主机被挂载的临时目录
### Destination:容器挂载的目录
[root@db02 ~]$ cd /var/lib/kubelet/pods/c0464d82-c088-4e5a-afae-50b4c5e807ef/volumes/kubernetes.io~empty-dir/nginx-index
[root@db02 /var/lib/kubelet/pods/c0464d82-c088-4e5a-afae-50b4c5e807ef/volumes/kubernetes.io~empty-dir/nginx-index]$ cat index.html
k8s
## 删除pod,验证临时目录是否还存在
[root@db01 ~]$ kubectl delete pods nginx-init
[root@db02 ~]$ ll /var/lib/kubelet/pods/c0464d82-c088-4e5a-afae-50b4c5e807ef/volumes/kubernetes.io~empty-dir/nginx-index
ls: cannot access /var/lib/kubelet/pods/c0464d82-c088-4e5a-afae-50b4c5e807ef/volumes/kubernetes.io~empty-dir/nginx-index: No such file or directory # //不存在
hook钩子
PostStart启动钩子
apiVersion: v1
kind: Pod
metadata:
name: nginx-hook
spec:
containers:
- name: nginx
image: nginx:alpine
lifecycle: # //钩子
postStart: # //启动钩子,容器启动之前执行
exec: # //指定执行的是命令
command: [/bin/sh, -c, 'echo PostStart > /usr/share/nginx/html/index.html']# //向nginx.index文件中插入数据
ports:
- containerPort: 80
[root@db01 ~]$ kubectl apply -f nginx_post.yml
[root@db01 ~]$ kubectl get pods nginx-hook -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-hook 1/1 Running 0 25s 10.2.2.13 db02 <none> <none>
## 测试一下启动钩子是否执行
[root@db01 ~]$ curl 10.2.2.13
PostStart
PreStop停止钩子
[root@db01 ~]$ vim nginx_pre.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx-prestop
spec:
volumes:
- name: nginxlog # //宿主机被挂载目录设为变量
hostPath: # //使用hostpath模式挂载,宿主机上存在此目录,且永久存在
path: /var/log/nginx/ # //指定被挂载的目录路径
containers:
- name: nginx
image: nginx:alpine
lifecycle: # //钩子
postStart: # //启动钩子
exec: # //执行命令
command: [/bin/sh, -c, 'echo postStart > /usr/share/nginx/html/index.html']
preStop: # //停止钩子
exec: # //执行命令
command: [/bin/sh, -c, 'echo bye > /var/log/nginx/stop.log'] # //容器关闭后,将信息插入日志文件
ports:
- containerPort: 80
volumeMounts: # //容器挂载
- name: nginxlog # //挂载到宿主机共享目录
mountPath: /var/log/nginx/
[root@db01 ~]$ kubectl apply -f nginx_pre.yml
[root@db01 ~]$ kubectl get pods nginx-prestop -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-prestop 1/1 Running 0 16s 10.2.2.14 db02 <none> <none>
## 检测启动钩子
[root@db01 ~]$ curl 10.2.2.14 # //有页面信息,启动钩子以执行
postStart
[root@db02 ~]$ ll /var/log/nginx/ # 宿主机没有停止钩子指定要操作的日志文件
-rw-r--r-- 1 root root 92 Nov 25 20:15 access.log
-rw-r--r-- 1 root root 1730 Nov 25 20:15 error.log
## 检测停止钩子
[root@db01 ~]$ kubectl delete pods nginx-prestop
[root@db02 ~]$ ll /var/log/nginx/
-rw-r--r-- 1 root root 92 Nov 25 20:15 access.log
-rw-r--r-- 1 root root 1730 Nov 25 20:15 error.log
-rw-r--r-- 1 root root 4 Nov 25 20:15 stop.log
[root@db02 ~]$ cat /var/log/nginx/stop.log # 原本不存在的日志文件被创建,且有信息
bye
存活探针
存活探针简单来说就是用来检测容器的应用程序是否还正常工作,如果应用程序不正常,即使容器还活着也没有意义了,所以这时候就可以使用存活探针来探测,如果应用程序不正常,就重启POD。
使用exec检测方法
apiVersion: v1
kind: Pod
metadata:
name: liveness-pod
spec:
volumes:
- name: nginx-html
hostPath: # //使用hostpath模式挂载,宿主机上存在此目录,且永久存在
path: /usr/share/nginx/html/ # //指定被挂载的目录路径
containers:
- name: liveness
image: nginx:alpine
imagePullPolicy: IfNotPresent
lifecycle:
postStart: # 利用启动钩子在容器启动前先往页面添加信息
exec:
command: [/bin/sh, -c, 'echo livenessProbe > /usr/share/nginx/html/index.html']
livenessProbe: # //存活探针
exec: # //以命令方式
command:
- cat # //查看这个页面
- /usr/share/nginx/html/index.html
initialDelaySeconds: 3 # 第一次启动探测在容器启动后3秒开始
periodSeconds: 1 # 容器启动后每隔3秒检查一次
volumeMounts:
- name: nginx-html
mountPath: /usr/share/nginx/html/
[root@db01 ~]$ kubectl apply -f lp_nginx.yml
[root@db01 ~]$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
liveness-pod 1/1 Running 0 20s 10.2.2.17 db02 <none> <none>
## 测试网页是存在的
[root@db01 ~]$ curl 10.2.2.17
livenessProbe
## 测试宿主机挂载点的页面也是存在的
[root@db02 ~]$ cat /usr/share/nginx/html/index.html
livenessProbe
# 测试删除页面
[root@db02 ~]$ rm -rf /usr/share/nginx/html/index.html
## 第一时间没有
[root@db02 ~]$ ll /usr/share/nginx/html/
## 容器被重启后再次生成
[root@db02 ~]$ ll /usr/share/nginx/html/
-rw-r--r-- 1 root root 14 Nov 25 20:48 index.html
# 查看pod详细信息
[root@db01 ~]$ kubectl describe pods liveness-pod
检测到文件不存在后,重启了容器
参数解释
livenessProbe: # 存活探针
exec: # 执行命令
command: # 具体执行的命令及结果,结果为0的状态被视为存活,非零是不健康的
initialDelaySeconds: 3 # 第一次启动探测在容器启动后3秒开始,用于等待容器启动
periodSeconds: 1 # 容器启动后每隔1秒检查一次,默认为10秒,最小为一秒
使用Httpget方法检测
apiVersion: v1
kind: Pod
metadata:
name: liveness-pod
spec:
volumes:
- name: nginx-html
hostPath:
path: /usr/share/nginx/html/
containers:
- name: liveness
image: nginx:alpine
imagePullPolicy: IfNotPresent
lifecycle:
postStart: # 利用启动钩子在容器启动前先往页面添加信息
exec:
command: [/bin/sh, -c, 'echo GetHttp > /usr/share/nginx/html/index.html']
livenessProbe:
httpGet:
path: /index.html # 页面的uri,就是执行 curl 容器ip/index.html
port: 80
initialDelaySeconds: 3
periodSeconds: 3
volumeMounts:
- name: nginx-html
mountPath: /usr/share/nginx/html/
[root@db01 ~]$ kubectl apply -f lp_nginx.yml
[root@db01 ~]$ kubectl get pods liveness-pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
liveness-pod 1/1 Running 0 14s 10.2.2.18 db02 <none> <none>
# 检测宿主机挂载页面
[root@db02 ~]$ cat /usr/share/nginx/html/index.html
GetHttp
# 检查容器日志
[root@db01 ~]$ kubectl logs -f liveness-pod liveness
存活探针一直在用get请求方式curl页面。返回状态码200.页面正常
# 测试删除页面
[root@db02 ~]$ rm -rf /usr/share/nginx/html/index.html
# 查看pod详细信息
[root@db01 ~]$ kubectl describe pods liveness-pod
检测不到后端页面 404报错
检测不到页面后重启了pod
# 检测不到页面后会重启pod,再次访问一下页面,通了
[root@db01 ~]$ curl 10.2.2.18
GetHttp
参数解释
### 参数解释
livenessProbe:
httpGet: # 基于http请求探测
path: /index.html # 请求地址,如果这个地址返回的状态码在200-400之间正常
port: 80 # 请求的端口
initialDelaySeconds: 3 # 第一次启动探测在容器启动后3秒开始,用于等待容器启动
periodSeconds: 3 # 容器启动后每隔3秒检查一次,默认为10秒,最小为一秒
tcpsocket: # 通过socket连接检测,可以用来检测mysql
host: # 检测指定IP
port: # 检测指定端口
就绪探针
有时候我们Pod本身已经起来了,但是pod的容器还没有完全准备好对外提供服务,那么这时候流量进来就会造成请求失败的情况出现,针对这种情况k8s有一种探针叫就绪探针,他的作用就是让k8s知道你的Pod内应用是否准备好为请求提供服务。只有就绪探针ok了才会把流量转发到pod上。
有时候,应用程序会暂时性的不能提供通信服务。 例如,应用程序在启动时可能需要加载很大的数据或配置文件,或是启动后要依赖等待外部服务。 在这种情况下,既不想杀死应用程序,也不想给它发送请求。 Kubernetes 提供了就绪探测器来发现并缓解这些情况。 容器所在 Pod 上报还未就绪的信息,并且不接受通过 Kubernetes Service 的流量。
使用就绪探针
apiVersion: v1
kind: Pod
metadata:
name: readiness-pod
spec:
containers:
- name: readiness-pod
image: nginx
lifecycle: # //钩子
postStart: # //启动钩子
exec:
command: ["/bin/sh", "-c", "echo ok > /usr/share/nginx/html/health.html"]
readinessProbe: # //就绪探针
httpGet: # //使用httpGet方式
path: /actuator/health # 检测此页面url,通过8080端口
port: 8080
initialDelaySeconds: 5 # 第一次启动探测在容器启动后5秒开始
timeoutSeconds: 3 # 探针超时时间
periodSeconds: 3 # 容器启动后每隔3秒检查一次
successThreshold: 3
failureThreshold: 3
livenessProbe: # //存活探针
httpGet:
path: /health.html # 页面的url,就是执行 curl 容器ip/index.html
port: 80
initialDelaySeconds: 3
periodSeconds: 3
[root@db01 ~]$ kubectl apply -f rp_nginx.yml
# pod内没有容器启动成功
[root@db01 ~]$ kubectl get pods readiness-pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
readiness-pod 0/1 Running 0 27s 10.2.2.19 db02 <none> <none>
# 查看pod详细信息
[root@db01 ~]$ kubectl describe pods readiness-pod
8080端口不通,容器不会被启动
# 测试直接curl页面
[root@db01 ~]$ curl 10.2.2.19/health.html # //发现能够访问,按理容器都没启动不应该能访问到才对
ok
##### 注意:只会限制通过 Kubernetes Service 的流量,而我们是通过pod ip 访问的
参数解释
initialDelaySeconds: 5 # 第一次启动探测在容器启动后5秒开始,用于等待容器启动
periodSeconds: 3 # 容器启动后每隔3秒检查一次,默认为10秒,最小为一秒
timeoutSeconds: 3 # 探针超时时间,默认一秒,最小一秒
successThreshold: 3 # 探针失败后最少连续探测成功多少次才被认定为探测成功,默认一次,如果是liveness必须为1
failureThreshold: 3 # 探针成功后被视为失败的探测的最小连续失败次数,默认3次最小一次
POD资源限制
在学习Docker的时候我们知道容器可以使用Linux系统的CGroup技术限制内存和CPU的使用率,那么POD里应该如何限制容器的CPU和内存资源呢?
[root@db01 ~]$ kubectl apply -f mem_cpu.yml
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: resource-demo
image: nginx
ports:
- containerPort: 80
resources: # //资源限制
requests: # //启动该容器所需的资源
memory: 50Mi # //50m的内存
cpu: 1500m # //1500毫核的CPU
limits: # //启动该容器限制最大能使用的资源
memory: 100Mi
cpu: 2000m
[root@db01 ~]$ kubectl apply -f mem_cpu.yml
[root@db01 ~]$ kubectl get pods resource-demo -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
resource-demo 1/1 Running 0 30s 10.2.2.20 db02 <none> <none>
[root@db02 ~]$ docker ps
[root@db02 ~]$ docker inspect 9c99fb3ed4de|grep CgroupParent
"CgroupParent": "kubepods-burstable-podda791c6f_90dd_4b4c_89a4_63359ba0f830.slice", # //此目录记录资源限制信息
参数解释:
requests :节点所需的最小计算资源量,k8s调度的时候的依据值
limits :限制允许的最大计算资源量,真正的资源限制参数
## 限制的资源数必须比需求的资源数大
数值的转换:
1 CPU = 1000m
0.5 CPU = 500m
1 Mib = 1024 Kib
1 MB = 1000 KB
查看验证:
docker inspect 容器ID|grep CgroupParent
## 后缀填上面查找到的存放资源路径
cd /sys/fs/cgroup/cpu/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-poddaxxxxxxxxxxxxxxxxxxxx.slice
cat cpu.cfs_quota_us
200000