docker中pod生命周期的示例分析
这篇文章给大家分享的是有关docker中pod生命周期的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
查看资源配置清单帮助
[root@master manifests]# kubectl explain pods.spec.containers #查看帮助
资源配置清单分类
自主式pod资源:
资源的清单格式:
一级字段:apiVersion(group/version组成),kind,metadata(包括name,namespace,labels,annotations),spec ,status。
pod资源-spec.containers
- name:pod名字
image:镜像名字
imagePullPolicy:表示从哪拉镜像,Always(不管本地有没有镜像,都要从仓库中下载镜像,也就是说,即使本地有镜像了,也不使用本地镜像,而是从仓库下载), Never(从来不从仓库下载镜像,也就是说本地有镜像就用,没有就算了), IfNotPresent(如果本地存在就直接使用,不存在才从仓库下载)。默认的策略是:当镜像标签版本是latest,默认策略就是Always;如果指定特定版本默认拉取策略就是IfNotPresent。
如上图,指定ImagePullPolicy策略为ifNotPresent后,即使image指定的版本未latest,这样每次启动容器,也不会从仓库重新下载镜像了。
ports:指定暴露容器端口号,可以指定多个端口,如下:
[root@master manifests]# cat pod-demo.yaml apiVersion: v1kind: Podmetadata: name: pod-demo namespace: default labels: app: myapp #kv格式的,也可以用花括号表示 tier: frontend #定义所属的层次spec: containers: - name: myapp #前面的-号表示这是一个列表格式的,也可以用中括号表示 image: tomcat ports: - name: http containerPort: 80 - name: https containerPort: 443 - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent #指定ImagePullPolicy策略为ifNotPresent后,即使image指定的版本未latest,以后每次启动容器,也不会从仓库重新下载镜像了 command: - "/bin/sh" - "-c" - "echo $(date) >> /usr/share/nginx/html/index.html; sleep 5" #以上命令也可以写作:command: ["/bin/sh","-c","sleep 3600"]
args:相当于dockerfile里面的cmd
command:相当于docker里面的Entrypoint
如果既没有指定args,也没有指定command,那么会默认使用dockfile的cmd和entrypoint。
如果指定了command,但没有提供args,那么就直接运行command。
如果指定了args,但是没指定command,那么将使用镜像中的entrypoint命令,把我们写的args当做参数传递给镜像中的entrypoint。
如果既用来command,又用了args,那么镜像中的cmd和entrypoint将被忽略,而使用K8s提供的command with args。
参考文档:https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/
标签
标签是k8s极具特色的管理方式。一个标签可以对应多个资源,一个资源也可以有多个标签,它们是多对多的关系。
一个资源拥有多个标签,可以实现不同维度的管理。
标签是key=value格式的,key最大63个字符,只能是字母、数字、_、-、.五种类型的组合。只能以字母或数字开头结尾。
我们也可以使用标签选择器来指定能使用哪些标签。
可以使用如下命令看标签:
[root@master manifests]# kubectl get pods --show-labelsNAME READY STATUS RESTARTS AGE LABELSpod-demo 1/2 CrashLoopBackOff 24 1h app=myapp,tier=frontend
可以用-l来过滤包含app标签的pod
[root@master manifests]# kubectl get pods -l app --show-labelsNAME READY STATUS RESTARTS AGE LABELSpod-demo 1/2 CrashLoopBackOff 25 1h app=myapp,tier=frontend
给资源对象打标签,我们再给前面创建的pod-demo pod打个release=canary的标签:
[root@master manifests]# kubectl label pods pod-demo release=canarypod/pod-demo labeled
[root@master manifests]# kubectl get pods -l app --show-labelsNAME READY STATUS RESTARTS AGE LABELSpod-demo 1/2 CrashLoopBackOff 27 1h app=myapp,release=canary,tier=frontend
修改标签的值:
[root@master manifests]# kubectl label pods pod-demo release=stable --overwritepod/pod-demo labeled
[root@master manifests]# kubectl get pods -l app --show-labelsNAME READY STATUS RESTARTS AGE LABELSpod-demo 1/2 CrashLoopBackOff 27 1h app=myapp,release=stable,tier=frontend
查找既有release标签,又拥有app标签的:
[root@master manifests]# kubectl get pods -l app,release --show-labelsNAME READY STATUS RESTARTS AGE LABELSpod-demo 1/2 CrashLoopBackOff 27 2h app=myapp,release=stable,tier=frontend
标签选择器分为:等值关系的标签选择器和集合关系的标签选择器。
等值关系的标签选择器:可以用=或者==表示等于,!=表示不等于:
[root@master manifests]# kubectl get pods -l release=stable --show-labelsNAME READY STATUS RESTARTS AGE LABELSpod-demo 1/2 CrashLoopBackOff 29 2h app=myapp,release=stable,tier=frontend
[root@master manifests]# kubectl get pods -l release=stable,app=myapp --show-labelsNAME READY STATUS RESTARTS AGE LABELSpod-demo 1/2 CrashLoopBackOff 30 2h app=myapp,release=stable,tier=frontend
[root@master manifests]# kubectl get pods -l release!=stable --show-labelsNAME READY STATUS RESTARTS AGE LABELSclient 1/1 Running 0 1d run=clientmyapp-fcc5f7f7c-4x2p7 0/1 ImagePullBackOff 0 1d pod-template-hash=977193937,run=myappmyapp-fcc5f7f7c-dnkdq 0/1 ImagePullBackOff 0 1d pod-template-hash=977193937,run=myappmytomcat-5f8c6fdcb-7t5s2 1/1 Running 0 1d pod-template-hash=194729876,run=mytomcatmytomcat-5f8c6fdcb-lhcsc 1/1 Running 0 1d pod-template-hash=194729876,run=mytomcatmytomcat-5f8c6fdcb-rntrg 1/1 Running 0 1d pod-template-hash=194729876,run=mytomcatnginx-deploy-5b595999-fpm8x 1/1 Running 0 1d pod-template-hash=16151555,release=canary,run=nginx-deploy
集合关系的标签选择器:key in (value1,value2...),key notin (value1,value2...),!key
[root@master ~]# kubectl get pods -l "release in (canary,beta,alpha)" --show-labelsNAME READY STATUS RESTARTS AGE LABELSnginx-deploy-5b595999-fpm8x 1/1 Running 0 1d pod-template-hash=16151555,release=canary,run=nginx-deploy
[root@master ~]# kubectl get pods -l "release notin (canary,beta,alpha)" --show-labelsNAME READY STATUS RESTARTS AGE LABELSclient 1/1 Running 0 1d run=clientmyapp-fcc5f7f7c-4x2p7 0/1 ImagePullBackOff 0 1d pod-template-hash=977193937,run=myappmyapp-fcc5f7f7c-dnkdq 0/1 ImagePullBackOff 0 1d pod-template-hash=977193937,run=myapp
我们知道pod控制器和service都是要通过标签来进行关联,通常使用matchLabels,matchExpressions。许多资源支持内嵌字段定义其使用的标签选择器。
matchLabels:直接给定键值,相当于使用等值关系一样;
matchExpressions:基于给定的表达式来定义使用标签选择器,格式为{key!"KEY",operator:"OPERATOR",values:[VAL1,VAL2,....]},常用的操作符有:
1)In,NotIn,:values字段的值必须为非空列表
2)Exists,NotExists:values字段的值必须为空列表
不光pods有标签,nodes等对象都有标签,如下:
[root@master ~]# kubectl get nodes --show-labelsNAME STATUS ROLES AGE VERSION LABELSmaster Ready master 4d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=master,node-role.kubernetes.io/master=node1 Ready4d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node1node2 Ready 4d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node2
上面的标签是内建的标签,其中beta.kubernetes.io这部分是能在dns中解析的,该部分字符长度不能超过253个字符。
同样,我们也可以给nodes打标签,比如我们下面给node1节点打个disktype=ssd的标签
[root@master ~]# kubectl label nodes node1 disktype=ssdnode/node1 labeled
[root@master ~]# kubectl get nodes --show-labelsNAME STATUS ROLES AGE VERSION LABELSmaster Ready master 4d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=master,node-role.kubernetes.io/master=node1 Ready4d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=node1node2 Ready 4d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node2
节点选择器-nodeSelector和nodeName
nodeSelector:可以使pod运行在指定的node节点上,我们如下举例演示该功能。
[root@master ~]# kubectl get pods -o wideNAME READY STATUS RESTARTS AGE IP NODEclient 1/1 Running 0 2d 10.244.2.4 node2myapp-fcc5f7f7c-4x2p7 0/1 ImagePullBackOff 0 1d 10.244.1.9 node1myapp-fcc5f7f7c-dnkdq 0/1 ImagePullBackOff 0 1d 10.244.2.6 node2mytomcat-5f8c6fdcb-7t5s2 1/1 Running 0 1d 10.244.2.8 node2mytomcat-5f8c6fdcb-lhcsc 1/1 Running 0 1d 10.244.2.7 node2mytomcat-5f8c6fdcb-rntrg 1/1 Running 0 1d 10.244.1.10 node1nginx-deploy-5b595999-fpm8x 1/1 Running 0 1d 10.244.1.7 node1pod-demo 1/2 CrashLoopBackOff 303 1d 10.244.2.11 node2
上面我们看到pod-demo运行在node2节点上,下面我们让它运行在node1节点上。我们刚才在node1上打了个disktype=ssd的标签,所以我们用nodeSelector在资源清单中如下定义:
[root@master manifests]# cat pod-demo.yaml apiVersion: v1kind: Podmetadata: name: pod-demo namespace: default labels: app: myapp #kv格式的,也可以用花括号表示 tier: frontend #定义所属的层次spec: containers: - name: myapp #前面的-号表示这是一个列表格式的,也可以用中括号表示 image: tomcat ports: - name: http containerPort: 80 - name: https containerPort: 443 - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent #指定ImagePullPolicy策略为ifNotPresent后,即使image指定的版本未latest,以后每次启动容器,也不会从仓库重新下载镜像了 command: - "/bin/sh" - "-c" - "echo $(date) >> /usr/share/nginx/html/index.html; sleep 5" #以上命令也可以写作:command: ["/bin/sh","-c","sleep 3600"] nodeSelector: #指定该pod运行在有disktype=ssd标签的node节点上 disktype: ssd
[root@master manifests]# kubectl delete -f pod-demo.yaml pod "pod-demo" deleted
[root@master manifests]# kubectl create -f pod-demo.yaml pod/pod-demo created
[root@master manifests]# kubectl get pods -o wideNAME READY STATUS RESTARTS AGE IP NODEclient 1/1 Running 0 2d 10.244.2.4 node2myapp-fcc5f7f7c-4x2p7 0/1 ImagePullBackOff 0 1d 10.244.1.9 node1myapp-fcc5f7f7c-dnkdq 0/1 ImagePullBackOff 0 1d 10.244.2.6 node2mytomcat-5f8c6fdcb-7t5s2 1/1 Running 0 1d 10.244.2.8 node2mytomcat-5f8c6fdcb-lhcsc 1/1 Running 0 1d 10.244.2.7 node2mytomcat-5f8c6fdcb-rntrg 1/1 Running 0 1d 10.244.1.10 node1nginx-deploy-5b595999-fpm8x 1/1 Running 0 1d 10.244.1.7 node1pod-demo 2/2 Running 2 37s 10.244.1.14 node1
上面看到,pod-demo运行在了带有disktype=ssd标签的node1节点上了。
那么有人可能会问了,我们可不可以指定pod-demo运行在指定node上呢。当然可以了,这个选项就是nodeName。大家可以自定去测试。
资源注解annotations
与labels的区别是,annotaitons不能用于挑选资源对象,仅用于为对象提供原数据。这些元数据可能被某些程序所用到,而且很重要。annotations的键值对没有字符数限制。
查看资源的注解:
[root@master manifests]# kubectl delete -f pod-demo.yaml pod "pod-demo" deleted
[root@master manifests]# cat cat pod-demo.yaml cat: cat: No such file or directoryapiVersion: v1kind: Podmetadata: name: pod-demo namespace: default labels: app: myapp #kv格式的,也可以用花括号表示 tier: frontend #定义所属的层次 annotations: chenzx.com/created-by: "cluster-admin" #这是注解的键值对spec: containers: - name: myapp #前面的-号表示这是一个列表格式的,也可以用中括号表示 image: tomcat ports: - name: http containerPort: 80 - name: https containerPort: 443 - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent #指定ImagePullPolicy策略为ifNotPresent后,即使image指定的版本未latest,以后每次启动容器,也不会从仓库重新下载镜像了 command: - "/bin/sh" - "-c" - "echo $(date) >> /usr/share/nginx/html/index.html; sleep 5" #以上命令也可以写作:command: ["/bin/sh","-c","sleep 3600"] nodeSelector: #指定该pod运行在有disktype=ssd标签的node节点上 disktype: ssd
[root@master manifests]# kubectl create -f pod-demo.yaml pod/pod-demo created
[root@master manifests]# kubectl describe pods pod-demoAnnotations: chenzx.com/created-by=cluster-adminStatus: RunningIP: 10.244.1.15
pod的生命周期
一个容器里面可以运行多个进程,但是通常我们只在容器里面运行一个进程。
在一个pod中,可以运行多个容器,但是通常我们只在一个pod里面运行一个容器。
一个容器在创建之前,有多个初始化容器(init container)用来进行初始化环境,init container执行完,它就退出了。接下来是主容器(main container)开始启动,主容器启动时也要初始化主容器里面的环境。在主容器刚刚启动之后,用户可以手动嵌入做一个操作叫post start。在主容器结束前,也可以做一个收尾操作pre stop,用来在主容器结束前做一个清理。
在post start后,就开始做健康检查,第一个健康检查叫存活状态检查(liveness probe ),用来检查主容器存活状态的;第二个健康检查叫准备就绪检查(readyness probe),用来检查主容器是否启动就绪。
pod的状态有:
a) Pending:当启动一个容器时,发现条件不满足,就会进入pending状态;
b) Runing
c)Failed
d)Succeeded
e) Unknown;如果kubelete出现故障,那么apiserver就连不上kubelete了,就会出现未知的错误
创建pod的过程:pod创建时先和apiserver沟通,然后把信息存储在etcd中;接下来apiserver会请求scheduler,并把调度的结果也保存在etcd中。假如scheduler把pod调度到node1节点上了,此时node1节点上的kublete会从etcd中拿到用户创建的清单,根据清单在node1上运行这个pod。不管pod在node1上运行成功还是失败,都会把结果反馈给apiserver,同时把运行结果保存在etcd中。
健康检查分三个层次:1、直接执行命令;2、向tcp连接请求;3、向http发get请求。
总结:pod生命周期中的重要行为:
1)初始化容器
2)容器探测(liveness存活行探测和readness准备就绪探测)
livenessProbe(存活状态探测)
存活不一定就绪。
[root@master manifests]# kubectl explain pods.spec.containers.livenessProbe
可以看到有三种探针,exec、 httpGet、tcpSocket
failureThreshold表示探测失败次数,默认是3探测次失败,才认为是真失败了。
periodSeconds:周期间隔时长,默认10s探测一次;
timeoutSeconds:超时时间,表示发出探测,对方始终没有响应,需要等多久,默认等1s
initialDelaySeconds:默认是容器一启动就开始探测,但是此时容器可能还没启动完呢,所以这时探测肯定是失败的。所以initialDelaySeconds表示容器启动多长时间后才开始探测。
[root@master manifests]# kubectl explain pods.spec.containers.livenessProbe.exec
[root@master manifests]# cat liveness.exec.ymal apiVersion: v1kind: Podmetadata: name: liveness-exec-pod namespace: defaultspec: containers: - name: liveness-exec-container image: busybox:latest imagePullPolicy: IfNotPresent #如果存在就不要下载了 command: ["/bin/sh","-c","touch /tmp/healthy;sleep 60;rm -f /tmp/healthy;sleep 3600"] livenessProbe: #存活性探测 exec: command: ["test","-e","/tmp/healthy"] #-e表示探测文件是否存在 initialDelaySeconds: 1 #表示容器启动后多长时间开始探测 periodSeconds: 3 #表示每隔3s钟探测一次
[root@master manifests]# kubectl create -f liveness.exec.ymal pod/liveness-exec-pod created
[root@master manifests]# kubectl get pods -wNAME READY STATUS RESTARTS AGEliveness-exec-pod 1/1 Running 2 4m
[root@master manifests]# kubectl get pods -wNAME READY STATUS RESTARTS AGEliveness-exec-pod 1/1 Running 4 6m
[root@master manifests]# kubectl get pods -wNAME READY STATUS RESTARTS AGEclient 1/1 Running 0 3dliveness-exec-pod 1/1 Running 5 9m
[root@master manifests]# kubectl get pods -wNAME READY STATUS RESTARTS AGEclient 1/1 Running 0 3dliveness-exec-pod 1/1 Running 9 23m
可以看到restart此时在随着时间增长。
上面的例子是用exec执行命令进行探测的。
下面我们看看基于tcp和httpget探测的选项。
[root@master manifests]kubectl explain pods.spec.containers.livenessProbe.tcpSocket
[root@master manifests]# kubectl explain pods.spec.containers.livenessProbe.httpGet
下面举个例子:
[root@master manifests]# cat liveness.httpget.yaml apiVersion: v1kind: Podmetadata: name: liveness-httpget-pod namespace: defaultspec: containers: - name: liveness-httpget-container image: nginx:latest imagePullPolicy: IfNotPresent #如果存在就不要下载了 ports: - name: http containerPort: 80 livenessProbe: #存活性探测 httpGet: port: http path: /index.html initialDelaySeconds: 1 periodSeconds: 3 #表示每隔3s钟探测一次
[root@master manifests]# kubectl create -f liveness.httpget.yaml
[root@master manifests]# kubectl get podsNAME READY STATUS RESTARTS AGEliveness-httpget-pod 1/1 Running 0 4m
[root@master manifests]# kubectl exec -it liveness-httpget-pod -- /bin/sh# rm -rf /usr/share/nginx/html/index.html
[root@master manifests]# kubectl get podsNAME READY STATUS RESTARTS AGEliveness-httpget-pod 1/1 Running 1 27m
上面可以看到,当删除pod里面的/usr/share/nginx/html/index.html,liveness监测到index.html文件被删除了,所以restarts次数为1,但是只重启一次,不会再重启了。这是因为重启一次后,nginx容器就重新初始化了,里面就会又生成index.html文件。所以里面就会有新的index.html文件了。
readlinessProbe(准备就绪型探针)
[root@master manifests]# cat readiness-httpget.ymal apiVersion: v1kind: Podmetadata: name: readdliness-httpget-pod namespace: defaultspec: containers: - name: readliness-httpget-container image: nginx:latest imagePullPolicy: IfNotPresent #如果存在就不要下载了 ports: - name: http containerPort: 80 readinessProbe: #准备型探针 httpGet: port: http path: /index.html initialDelaySeconds: 1 periodSeconds: 3 #表示每隔3s钟探测一次
[root@master manifests]# kubectl create -f readiness-httpget.ymal pod/readdliness-httpget-pod created
[root@master ~]# kubectl get podsNAME READY STATUS RESTARTS AGEreaddliness-httpget-pod 1/1 Running 0 16h
[root@master ~]# kubectl exec -it readdliness-httpget-pod -- /bin/sh# rm -rf /usr/share/nginx/html/index.html
[root@master ~]# kubectl get podsNAME READY STATUS RESTARTS AGEreaddliness-httpget-pod 0/1 Running 0 16h
上面可以看到,ready变成0/1了,但是status是runing的,这就是说nginx进程是在的,只是index.html不见了,可以判定nginx没有就绪。
postStart(启动后钩子)
[root@master ~]# kubectl explain pods.spec.containers.lifecycle.postStart
postStart是指容器在启动之后立即执行的操作,如果执行操作失败了,容器将被终止并且重启。而重启与否是由重启策略。
[root@master manifests]# cat poststart-pod.yaml apiVersion: v1kind: Podmetadata: name: poststart-pod namespace: defaultspec: containers: - name: busybox-httpd image: busybox:latest imagePullPolicy: IfNotPresent lifecycle: #生命周期事件 postStart: exec: command: ["mkdir", "-p","/data/web/html"] #这个command是定义postStart后的需要执行的命令 command: ["/bin/sh","-c","sleep 3600"] #这是定义容器里面执行的命令,不过这个命令要先于postStart里面的command #args: ["-f","-h /data/web/html"] #-f是前台,-h是家目录
[root@master manifests]# kubectl create -f poststart-pod.yaml pod/posttart-pod created
说明:删除的方法
[root@master manifests]# kubectl delete -f poststart-pod.yaml pod "posttart-pod" deleted
[root@master manifests]# kubectl get podsNAME READY STATUS RESTARTS AGEpoststart-pod 1/1 Running 0 3m
[root@master manifests]# kubectl exec -it poststart-pod -- /bin/sh/ # ls /dataweb/ # ls /data/web/html/
上面看到在容器启动后,建立了/data/web/html目录。这就是postStart的用法。
preStop(终止之前钩子)
[root@master ~]# kubectl explain pods.spec.containers.lifecycle.preStop
preStop是指容器在终止前要立即执行的命令,等这些命令执行完了,容器才能终止。
容器的重启策略-restartPolicy
一旦pod中的容器挂了,我们就把容器重启。
策略包括如下:
Always:表示容器挂了总是重启,这是默认策略
OnFailures:表容器状态为错误时才重启,也就是容器正常终止时才重启
Never:表示容器挂了不予重启
对于Always这种策略,容器只要挂了,就会立即重启,这样是很耗费资源的。所以Always重启策略是这么做的:第一次容器挂了立即重启,如果再挂了就要延时10s重启,第三次挂了就等20s重启...... 依次类推
容器的终止策略
k8s会给容器30s的时间进行终止,如果30s后还没终止,就会强制终止。
总结
pod: apiVersion kind metadata spec status(只读) spec: containers nodeSelector nodeName restartPolicy: Always,Never,OnFailure containers: name image imagePullPolicy: Always、Never、IfNotPresent ports: name containerPort livenessProbe readinessProbe liftcycle ExecAction: exec TCPSocketAction: tcpSocket HTTPGetAction: httpGet
感谢各位的阅读!关于"docker中pod生命周期的示例分析"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!