Pod中如何管理多个容器
Pod中可以同时运行多个进程(作为容器运行)协同工作。同一个Pod中的容器会自动的分配到同一个 node 上。同一个Pod中的容器共享资源、网络环境和依赖,它们总是被同时调度。
注意在一个Pod中同时运行多个容器是一种比较高级的用法。只有当你的容器需要紧密配合协作的时候才考虑用这种模式。例如,你有一个容器作为web服务器运行,需要用到共享的volume,有另一个“sidecar”容器来从远端获取资源更新这些文件,如下图所示:
Pod中可以共享两种资源:网络和存储。
- 网络:每个Pod都会被分配一个唯一的IP地址。Pod中的所有容器共享网络空间,包括IP地址和端口。Pod内部的容器可以使用
localhost
互相通信。Pod中的容器与外界通信时,必须分配共享网络资源(例如使用宿主机的端口映射)。
- 存储:可以Pod指定多个共享的Volume。Pod中的所有容器都可以访问共享的volume。Volume也可以用来持久化Pod中的存储资源,以防容器重启后文件丢失。
Pod容器分类
•Infrastructure Container:基础容器,维护整个Pod网络空间
•InitContainers:初始化容器,先于业务容器开始执行
•Containers:业务容器,并行启动
kubernetes中pod创建流程
Pod是Kubernetes中最基本的部署调度单元,可以包含container,逻辑上表示某种应用的一个实例。例如一个web站点应用由前端、后端及数据库构建而成,这三个组件将运行在各自的容器中,那么我们可以创建包含三个container的pod。
具体的创建步骤包括:
(1)客户端提交创建请求,可以通过API Server的Restful API,也可以使用kubectl命令行工具。支持的数据类型包括JSON和YAML。 (2)API Server处理用户请求,存储Pod数据到etcd。 (3)调度器通过API Server查看未绑定的Pod。尝试为Pod分配主机。 (4)过滤主机 (调度预选):调度器用一组规则过滤掉不符合要求的主机。比如Pod指定了所需要的资源量,那么可用资源比Pod需要的资源量少的主机会被过滤掉。 (5)主机打分(调度优选):对第一步筛选出的符合要求的主机进行打分,在主机打分阶段,调度器会考虑一些整体优化策略,比如把容一个Replication Controller的副本分布到不同的主机上,使用最低负载的主机等。 (6)选择主机:选择打分最高的主机,进行binding操作,结果存储到etcd中。 (7)kubelet根据调度结果执行Pod创建操作: 绑定成功后,scheduler会调用APIServer的API在etcd中创建一个boundpod对象,描述在一个工作节点上绑定运行的所有pod信息。运行在每个工作节点上的kubelet也会定期与etcd同步boundpod信息,一旦发现应该在该工作节点上运行的boundpod对象没有更新,则调用Docker API创建并启动pod内的容器。
调度约束
https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
scheduler组件
k8s调度器会将pod调度到资源满足要求并且评分最高的node上。
我们可以使用多种规则比如:
1.设置cpu、内存的使用要求
2.增加node的label,并通过pod.Spec.NodeSelector进行强匹配;
3.直接设置pod的nodeName,跳过调度直接下发。
k8s 1.2加入了一个实验性的功能:affinity。意为亲和性。这个特性的设计初衷是为了替代nodeSelector,并扩展更强大的调度策略。
调度器的工作机制是这样的
一、预备工作 1、缓存所有的node节点,记录他们的规格:cpu、内存、磁盘空间、gpu显卡数等; 2、缓存所有运行中的pod,按照pod所在的node进行区分,统计每个node上的pod request了多少资源。request是pod的QoS配置。 3、list & watch pod资源,当检查到有新的Pending状态的pod出现,就将它加入到调度队列中。 4、调度器的worker组件从队列中取出pod进行调度。 二、调度过程 1、先将当前所有的node放入队列; 2、执行predicates算法,对队列中的node进行筛选。这里算法检查了一些pod运行的必要条件,包括port不冲突、cpu和内存资源QoS(如果有的话)必须满足、挂载volume(如果有的话)类型必须匹配、nodeSelector规则必须匹配、硬性的affinity规则(下文会提到)必须匹配、node的状态(condition)必须正常,taint_toleration硬规则(下文会提到)等等。 3、执行priorities算法,对队列中剩余的node进行评分,这里有许多评分项,各个项目有各自的权重:整体cpu,内存资源的平衡性、node上是否有存在要求的镜像、同rs的pod是否有调度、node affinity的软规则、taint_toleration软规则(下文会提到)等等。 4、最终评分最高的node会被选出。即代码中suggestedHost, err := sched.schedule(pod)一句(plugin/pkg/scheduler/scheduler.go)的返回值。 5、调度器执行assume方法,该方法在pod调度到node之前,就以“该pod运行在目标node上” 为场景更新调度器缓存中的node 信息,也即预备工作中的1、2两点。这么做是为了让pod在真正调度到node上时,调度器也可以同时做后续其他pod的调度工作。 6、调度器执行bind方法,该方法创建一个Binding资源,apiserver检查到创建该资源时,会主动更新pod的nodeName字段。完成调度
nodeSelector用于将Pod调度到匹配Label的Node上
将标签附加到node
[root@k8s-master1 ~]# kubectl label nodes 192.168.0.126 env_role=dev node/192.168.0.126 labeled [root@k8s-master1 ~]# kubectl label nodes 192.168.0.125 env_role=test node/192.168.0.125 labeled [root@k8s-master1 ~]# kubectl get nodes --show-labels NAME STATUS ROLES AGE VERSION LABELS 192.168.0.125 Ready <none> 2d4h v1.13.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,env_role=test,kubernetes.io/hostname=192.168.0.125 192.168.0.126 Ready <none> 2d4h v1.13.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,env_role=dev,kubernetes.io/hostname=192.168.0.126
将nodeSelector字段添加到pod配置中
[root@k8s-master1 ~]# vim pod2.yaml apiVersion: v1 kind: Pod metadata: name: nginx
labels:
app: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent nodeSelector: env_role: dev [root@k8s-master1 ~]# kubectl create -f pod2.yaml pod/nginx created
查看pod
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
[root@k8s-master1 ~]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 115s [root@k8s-master1 ~]# kubectl describe pod nginx Name: nginx Namespace: default Priority: 0 PriorityClassName: <none> Node: 192.168.0.126/192.168.0.126 Start Time: Fri, 21 Dec 2018 14:07:49 +0800 Labels: <none> Annotations: <none> Status: Running IP: 172.17.92.2 Containers: nginx: Container ID: docker://8c7e442cc83b6532b3bda707f389fa371861d173e9395149bbede9e166bf559c Image: nginx Image ID: docker-pullable://nginx@sha256:1a0043cfb1987774c6981c41e49f758c58ace64c30e1c4ecff5cedff0b5c88da Port: <none> Host Port: <none> State: Running Started: Fri, 21 Dec 2018 14:07:50 +0800 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-7vs6s (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-7vs6s: Type: Secret (a volume populated by a Secret) SecretName: default-token-7vs6s Optional: false QoS Class: BestEffort Node-Selectors: env_role=dev Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m11s default-scheduler Successfully assigned default/nginx to 192.168.0.126 Normal Pulled 2m11s kubelet, 192.168.0.126 Container image "nginx" already present on machine Normal Created 2m10s kubelet, 192.168.0.126 Created container Normal Started 2m10s kubelet, 192.168.0.126 Started container
nodeName用于将Pod调度到指定的Node名称上
spec.nodeName
用于强制约束将Pod调度到指定的Node节点上,这里说是“调度”,但其实指定了nodeName的Pod会直接跳过Scheduler的调度逻辑,直接写入PodList列表,该匹配规则是强制匹配。
[root@k8s-master1 ~]# vim pod3.yaml apiVersion: v1 kind: Pod metadata: name: pod-example labels: app: nginx spec: nodeName: 192.168.0.125 containers: - name: nginx image: nginx:1.15 [root@k8s-master1 ~]# kubectl create -f pod3.yaml pod/pod-example created
查看pod
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
[root@k8s-master1 ~]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 10m pod-example 1/1 Running 0 22s [root@k8s-master1 ~]# kubectl describe pod pod-example Name: pod-example Namespace: default Priority: 0 PriorityClassName: <none> Node: 192.168.0.125/192.168.0.125 Start Time: Fri, 21 Dec 2018 14:17:47 +0800 Labels: app=nginx Annotations: <none> Status: Running IP: 172.17.19.2 Containers: nginx: Container ID: docker://5e33eacb41e9b4ffd072141af63209229543105feb804d23b72a09be9e414409 Image: nginx:1.15 Image ID: docker-pullable://nginx@sha256:5d32f60db294b5deb55d078cd4feb410ad88e6fe77500c87d3970eca97f54dba Port: <none> Host Port: <none> State: Running Started: Fri, 21 Dec 2018 14:17:48 +0800 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-7vs6s (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-7vs6s: Type: Secret (a volume populated by a Secret) SecretName: default-token-7vs6s Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Pulled 31s kubelet, 192.168.0.125 Container image "nginx:1.15" already present on machine Normal Created 31s kubelet, 192.168.0.125 Created container Normal Started 30s kubelet, 192.168.0.125 Started container
从私有镜像仓库拉取镜像
参考:https://kubernetes.io/docs/concepts/containers/images/
查看docker登陆私有仓库的凭据
[root@k8s-node01 ~]# cat .docker/config.json |base64 -w 0
ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjAuMTIyIjogewoJCQkiYXV0aCI6ICJiM0J6T2xCQWMzTjNNSEprIgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOC4wOS4wIChsaW51eCkiCgl9Cn0=
创建Secret
[root@k8s-master1 tomcat]# vim registry-pull-secret.yaml apiVersion: v1 kind: Secret metadata: name: registry-pull-secret data: .dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjAuMTIyIjogewoJCQkiYXV0aCI6ICJiM0J6T2xCQWMzTjNNSEprIgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOC4wOS4wIChsaW51eCkiCgl9Cn0= type: kubernetes.io/dockerconfigjson [root@k8s-master1 tomcat]# kubectl create -f registry-pull-secret.yaml secret/registry-pull-secret created [root@k8s-master1 tomcat]# kubectl get secret NAME TYPE DATA AGE default-token-7vs6s kubernetes.io/service-account-token 3 44h registry-pull-secret kubernetes.io/dockerconfigjson 1 23s
创建pod时,设置从私有仓库拉取镜像
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
[root@k8s-master1 tomcat]# vim tomcat.yaml apiVersion: apps/v1beta2 kind: Deployment metadata: name: tomcat-deployment namespace: default spec: replicas: 3 selector: matchLabels: app: tomcat template: metadata: labels: app: tomcat spec: imagePullSecrets: - name: registry-pull-secret #secret 登陆仓库的凭据 containers: - name: tomcat image: 192.168.0.122/ceba/tomcat #镜像地址 imagePullPolicy: Always #设置每次创建pod都重新拉取镜像 ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: tomcat-service labels: app: tomcat spec: type: NodePort ports: - port: 80 targetPort: 8080 selector: app: tomcat
镜像拉取策略
•IfNotPresent:默认值,镜像在宿主机上不存在时才拉取
•Always:每次创建Pod 都会重新拉取一次镜像
•Never:Pod 永远不会主动拉取这个镜像
查看拉取的镜像正常启动
[root@k8s-master1 tomcat]# kubectl get pod,svc,deploy NAME READY STATUS RESTARTS AGE pod/tomcat-deployment-6bb6864d4f-4xj82 1/1 Running 0 65s pod/tomcat-deployment-6bb6864d4f-drcjc 1/1 Running 0 47s pod/tomcat-deployment-6bb6864d4f-wmkxx 1/1 Running 0 45s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 44h service/tomcat-service NodePort 10.0.0.3 <none> 80:49014/TCP 8m20s NAME READY UP-TO-DATE AVAILABLE AGE deployment.extensions/tomcat-deployment 3/3 3 3 8m20s
资源限制
https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
创建Pod的时候,可以指定计算资源(目前支持的资源类型有CPU和内存),即指定每个容器的资源请求(Request)和资源限制(Limit),资源请求是容器所需的最小资源需求,资源限制则是容器不能超过的资源上限。它们的大小关系是:0<=request<=limit<=infinity
Pod的资源请求就是Pod中容器资源请求之和。Kubernetes在调度Pod时,会根据Node中的资源总量(通过cAdvisor接口获得),以及该Node上已使用的计算资源,来判断该Node是否满足需求。
资源请求能够保证Pod有足够的资源来运行,而资源限制则是防止某个Pod无限制地使用资源,导致其他Pod崩溃。特别是在公有云场景,往往会有恶意软件通过抢占内存来攻击平台。
原理:Docker 通过使用Linux Cgroup来实现对容器资源的控制,具体到启动参数上是--memory和--cpu-shares。Kubernetes中是通过控制这两个参数来实现对容器资源的控制。
Pod和Container的资源请求和限制:
•spec.containers[].resources.limits.cpu
•spec.containers[].resources.limits.memory
•spec.containers[].resources.requests.cpu
•spec.containers[].resources.requests.memory
示例
以下Pod有两个容器。每个Container都有0.25 cpu和64MiB内存的请求。每个Container的内存限制为0.5 cpu和128MiB。你可以说Pod有0.5 cpu和128 MiB内存的请求,并且限制为1 cpu和256MiB的内存。
[root@k8s-master1 ~]# vim pod1.yaml apiVersion: v1 kind: Pod metadata: name: frontend spec: containers: - name: db image: mysql env: - name: MYSQL_ROOT_PASSWORD value: "password" resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m" - name: wp image: wordpress resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m"
查看node节点资源使用情况
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
[root@k8s-master1 ~]# kubectl describe pod frontend | grep -A 3 Events Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 19m default-scheduler Successfully assigned default/frontend to 192.168.0.125 [root@k8s-master1 ~]# kubectl describe nodes 192.168.0.125 Name: 192.168.0.125 Roles: <none> Labels: beta.kubernetes.io/arch=amd64 beta.kubernetes.io/os=linux kubernetes.io/hostname=192.168.0.125 Annotations: node.alpha.kubernetes.io/ttl: 0 volumes.kubernetes.io/controller-managed-attach-detach: true CreationTimestamp: Wed, 19 Dec 2018 09:54:14 +0800 Taints: <none> Unschedulable: false Conditions: Type Status LastHeartbeatTime LastTransitionTime Reason Message ---- ------ ----------------- ------------------ ------ ------- MemoryPressure False Thu, 20 Dec 2018 17:26:03 +0800 Thu, 20 Dec 2018 10:29:48 +0800 KubeletHasSufficientMemory kubelet has sufficient memory available DiskPressure False Thu, 20 Dec 2018 17:26:03 +0800 Thu, 20 Dec 2018 10:29:48 +0800 KubeletHasNoDiskPressure kubelet has no disk pressure PIDPressure False Thu, 20 Dec 2018 17:26:03 +0800 Thu, 20 Dec 2018 10:29:48 +0800 KubeletHasSufficientPID kubelet has sufficient PID available Ready True Thu, 20 Dec 2018 17:26:03 +0800 Thu, 20 Dec 2018 10:29:48 +0800 KubeletReady kubelet is posting ready status OutOfDisk Unknown Wed, 19 Dec 2018 09:54:14 +0800 Wed, 19 Dec 2018 13:23:20 +0800 NodeStatusNeverUpdated Kubelet never posted node status. Addresses: InternalIP: 192.168.0.125 Hostname: 192.168.0.125 Capacity: cpu: 2 ephemeral-storage: 80699908Ki hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 3861520Ki pods: 110 Allocatable: cpu: 2 ephemeral-storage: 74373035090 hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 3759120Ki pods: 110 System Info: Machine ID: def36d2abcbe49839534858f6f1e13c5 System UUID: 86B24D56-709A-3467-6DDB-966B3B807949 Boot ID: 949f73c9-b14b-4e94-9137-78b2ac83d046 Kernel Version: 3.10.0-957.1.3.el7.x86_64 OS Image: CentOS Linux 7 (Core) Operating System: linux Architecture: amd64 Container Runtime Version: docker://18.9.0 Kubelet Version: v1.13.0 Kube-Proxy Version: v1.13.0 Non-terminated Pods: (3 in total) Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE --------- ---- ------------ ---------- --------------- ------------- --- default frontend 500m (25%) 1 (50%) 128Mi (3%) 256Mi (6%) 20m default tomcat-deployment-6bb6864d4f-drcjc 0 (0%) 0 (0%) 0 (0%) 0 (0%) 3h25m default tomcat-deployment-6bb6864d4f-wmkxx 0 (0%) 0 (0%) 0 (0%) 0 (0%) 3h25m Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted.) Resource Requests Limits -------- -------- ------ cpu 500m (25%) 1 (50%) memory 128Mi (3%) 256Mi (6%) ephemeral-storage 0 (0%) 0 (0%) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Starting 9m29s kube-proxy, 192.168.0.125 Starting kube-proxy. Normal Starting 8m42s kubelet, 192.168.0.125 Starting kubelet. Normal NodeHasSufficientMemory 8m42s kubelet, 192.168.0.125 Node 192.168.0.125 status is now: NodeHasSufficientMemory Normal NodeHasNoDiskPressure 8m42s kubelet, 192.168.0.125 Node 192.168.0.125 status is now: NodeHasNoDiskPressure Normal NodeHasSufficientPID 8m42s kubelet, 192.168.0.125 Node 192.168.0.125 status is now: NodeHasSufficientPID Normal NodeAllocatableEnforced 8m42s kubelet, 192.168.0.125 Updated Node Allocatable limit across pods Warning Rebooted 8m42s kubelet, 192.168.0.125 Node 192.168.0.125 has been rebooted, boot id: 949f73c9-b14b-4e94-9137-78b2ac83d046
健康检查(Probe)
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/
在实际生产环境中,想要使得开发的应用程序完全没有bug,在任何时候都运行正常,几乎 是不可能的任务。因此,我们需要一套管理系统,来对用户的应用程序执行周期性的健康检查和修复操作。这套管理系统必须运行在应用程序之外,这一点非常重要一一如果它是应用程序的一部分,极有可能会和应用程序一起崩溃。因此,在Kubernetes中,系统和应用程序的健康检查是由Kubelet来完成的。
1、进程级健康检查
最简单的健康检查是进程级的健康检查,即检验容器进程是否存活。这类健康检查的监控粒 度是在Kubernetes集群中运行的单一容器。Kubelet会定期通过Docker Daemon获取所有Docker进程的运行情况,如果发现某个Docker容器未正常运行,则重新启动该容器进程。目前,进程级的健康检查都是默认启用的。
2.业务级健康检查
在很多实际场景下,仅仅使用进程级健康检查还远远不够。有时,从Docker的角度来看,容器进程依旧在运行;但是如果从应用程序的角度来看,代码处于死锁状态,即容器永远都无法正常响应用户的业务为了解决以上问题,Kubernetes引人了一个在容器内执行的活性探针的概念,以支持用户自己实现应用业务级的健康检查。
Probe有以下两种类型:
livenessProbe:如果检查失败,将杀死容器,根据Pod的restartPolicy来操作。
readinessProbe:如果检查失败,Kubernetes会把Pod从service endpoints中剔除。
Probe支持以下三种检查方法:
- ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
- TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
- HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。
livenessProbe解析
[root@k8s-master1 ~]# kubectl explain pod.spec.containers.livenessProbe KIND: Pod VERSION: v1 RESOURCE: livenessProbe <Object> exec command 的方式探测 例如 ps 一个进程 failureThreshold 探测几次失败 才算失败 默认是连续三次 periodSeconds 每次的多长时间探测一次 默认10s timeoutSeconds 探测超市的秒数 默认1s initialDelaySeconds 初始化延迟探测,第一次探测的时候,因为主程序未必启动完成 tcpSocket 检测端口的探测 httpGet http请求探测
exec探针的示例:
[root@k8s-master1 ~]# vim exec-liveness.yaml apiVersion: v1 kind: Pod metadata: labels: test: liveness name: liveness-exec spec: containers: - name: liveness image: busybox args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600 livenessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 periodSeconds: 5 [root@k8s-master1 ~]# kubectl create -f exec-liveness.yaml pod/liveness-exec created [root@k8s-master1 ~]# kubectl get pod NAME READY STATUS RESTARTS AGE frontend 2/2 Running 106 16h liveness-exec 1/1 Running 0 16s
在配置文件中,您可以看到Pod具有单个Container。该periodSeconds
字段指定kubelet应每5秒执行一次活跃度探测。该initialDelaySeconds
字段告诉kubelet它应该在执行第一次探测之前等待5秒。要执行探测,kubelet将cat /tmp/healthy
在Container中执行命令。如果命令成功,则返回0,并且kubelet认为Container是活动且健康的。如果该命令返回非零值,则kubelet会终止Container并重新启动它。
再等30秒,确认Container已重新启动,RESTARTS
已增加
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 57s default-scheduler Successfully assigned default/liveness-exec to 192.168.0.126 Normal Pulling 55s kubelet, 192.168.0.126 pulling image "busybox" Normal Pulled 47s kubelet, 192.168.0.126 Successfully pulled image "busybox" Normal Created 47s kubelet, 192.168.0.126 Created container Normal Started 47s kubelet, 192.168.0.126 Started container Warning Unhealthy 5s (x3 over 15s) kubelet, 192.168.0.126 Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory [root@k8s-master1 ~]# kubectl get pod NAME READY STATUS RESTARTS AGE frontend 2/2 Running 106 16h liveness-exec 1/1 Running 1 107s
pod生命周期
https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/
Pod 的 status
在信息保存在 PodStatus 中定义,其中有一个 phase
字段。
Pod 的相位(phase)是 Pod 在其生命周期中的简单宏观概述。该阶段并不是对容器或 Pod 的综合汇总,也不是为了做为综合状态机。
Pod 相位的数量和含义是严格指定的。除了本文档中列举的状态外,不应该再假定 Pod 有其他的 phase
值。
下面是 phase
可能的值:
- 挂起(Pending):Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间。
- 运行中(Running):该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
- 成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。
- 失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
- 未知(Unknown):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。
下图是Pod的生命周期示意图,从图中可以看到Pod状态的变化。
故障排查
kubectl describe TYPE/NAME kubectl logs TYPE/NAME [-c CONTAINER] kubectl exec POD [-c CONTAINER] --COMMAND [args...]