kubernetes(k8s)资源对象pod
kubernetes资源对象pod介绍
kubernetes(k8s)资源对象pod
概述
Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
Pod(就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) ; 这些容器共享存储、网络、以及怎样运行这些容器的声明。 Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。 Pod 所建模的是特定于应用的 “逻辑主机”,其中包含一个或多个应用容器, 这些容器相对紧密地耦合在一起。 在非云环境中,在相同的物理机或虚拟机上运行的应用类似于在同一逻辑主机上运行的云应用。
除了应用容器,Pod 还可以包含在 Pod 启动期间运行的 [Init 容器]。 也可以在集群中支持[临时性容器]的情况下,为调试的目的注入临时性容器。
pod生命周期
pod生命期
Pod 也被认为是相对临时性(而不是长期存在)的实体。 Pod 在其生命周期中只会被[调度]一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者 被[终止]。如果一个节点死掉了,调度到该节点 的 Pod 也被计划在给定超时期限结束后[删除]。Kubernetes 使用一种高级抽象 来管理这些相对而言可随时丢弃的 Pod 实例,称作 [控制器]。
如果某物声称其生命期与某 Pod 相同,例如存储卷, 这就意味着该对象在此 Pod (UID 亦相同)存在期间也一直存在。 如果 Pod 因为任何原因被删除,甚至某完全相同的替代 Pod 被创建时, 这个相关的对象(例如这里的卷)也会被删除并重建。
pod阶段
Pod 的阶段(Phase)是 Pod 在其生命周期中所处位置的简单宏观概述。 该阶段并不是对容器或 Pod 状态的综合汇总,也不是为了成为完整的状态机。
取值 | 描述 |
---|---|
pending(挂起) | Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。 |
running(运行中) | Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。 |
succeeded(成功) | Pod 中的所有容器都已成功终止,并且不会再重启。 |
failed(失败) | Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。 |
unknown(未知) | 因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。 |
说明: 当一个 Pod 被删除时,执行一些 kubectl 命令会展示这个 Pod 的状态为 Terminating
(终止)。 这个 Terminating
状态并不是 Pod 阶段之一。 Pod 被赋予一个可以体面终止的期限,默认为 30 秒。 你可以使用 --force
参数来强制终止 Pod。
如果某节点死掉或者与集群中其他节点失联,Kubernetes 会实施一种策略,将失去的节点上运行的所有 Pod 的 phase
设置为 Failed
。
容器状态
Kubernetes 会跟踪 Pod 中每个容器的状态,就像它跟踪 Pod 总体上的阶段一样。 你可以使用[容器生命周期回调]来在容器生命周期中的特定时间点触发事件。
状态 | 描述 |
---|---|
waiting(等待) | 处于 Waiting 状态的容器仍在运行它完成启动所需要的操作:例如,从某个容器镜像 仓库拉取容器镜像,或者向容器应用 [Secret]数据等等。 当你使用 kubectl 来查询包含 Waiting 状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因。 |
running(运行中) | Running 状态表明容器正在执行状态并且没有问题发生。 如果配置了 postStart 回调,那么该回调已经执行且已完成。 如果你使用 kubectl 来查询包含 Running 状态的容器的 Pod 时,你也会看到 关于容器进入 Running 状态的信息。 |
terminated(已终止) | 处于 Terminated 状态的容器已经开始执行并且或者正常结束或者因为某些原因失败。 如果你使用 kubectl 来查询包含 Terminated 状态的容器的 Pod 时,你会看到 容器进入此状态的原因、退出代码以及容器执行期间的起止时间。如果容器配置了 preStop 回调,则该回调会在容器进入 Terminated 状态之前执行。 |
pod重启策略在 Pod 的 spec
中包含一个 restartPolicy
字段设置,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。
pod状态
Pod 有一个 PodStatus 对象,其中包含一个 [PodConditions]数组。Pod 可能通过也可能未通过其中的一些状况测试。
状态 | |
---|---|
PodScheduled | Pod 已经被调度到某节点; |
ContainersReady | Pod 中所有容器都已就绪; |
Initialized | 所有的 Init 容器都已成功完成; |
Ready | Pod 可以为请求提供服务,并且应该被添加到对应服务的负载均衡池中。 |
init容器
理解init容器
init容器是一种特殊的容器,在pod 内应用容器启动前运行。每个 [Pod]中可以包含多个容器, 应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。
如果 Pod 的 Init 容器失败,kubelet 会不断地重启该 Init 容器直到该容器成功为止。 然而,如果 Pod 对应的 restartPolicy
值为 “Never”,并且 Pod 的 Init 容器失败, 则 Kubernetes 会将整个 Pod 状态设置为失败。
为 Pod 设置 Init 容器需要在 [Pod 规约]中添加 initContainers
字段, 该字段以 [Container]类型对象数组的形式组织,和应用的 containers
数组同级相邻。
如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。 每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时, Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行 。
使用init容器
因为 Init 容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势:
- Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。 例如,没有必要仅为了在安装过程中使用类似
sed
、awk
、python
或dig
这样的工具而去FROM
一个镜像来生成一个新的镜像。 - Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。
- 应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
- Init 容器能以不同于 Pod 内应用容器的文件系统视图运行。因此,Init 容器可以访问 应用容器不能访问的 [Secret]的权限。
- 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。 一旦前置条件满足,Pod 内的所有的应用容器会并行启动。
编写myapp-pod.yaml 文件
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
spec:
containers:
- name: myapp-pod
image: busybox:1.28
command: ['sh','-c','echo the myapp-pod is running! && sleep 360']
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"]
运行myapp-pod.yaml 文件
# kubectl apply -f myapp-pod.yaml
pod/myapp-pod created
查看pod状态
# kubectl get -f myapp-pod.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 3m47s
# kubectl describe -f myapp-pod.yaml
Name: myapp-pod
Namespace: default
Priority: 0
Node: node02/192.168.4.225
Start Time: Mon, 05 Sep 2022 16:42:39 +0800
Labels: <none>
Annotations: cni.projectcalico.org/containerID: 332e652dfe216bb3b61046e9f99c5fcdfd48ca01264bd34dd4ca4b92ea16543e
cni.projectcalico.org/podIP: 172.19.140.91/32
cni.projectcalico.org/podIPs: 172.19.140.91/32
Status: Pending
IP: 172.19.140.91
IPs:
IP: 172.19.140.91
Init Containers:
init-myservice:
Container ID: docker://395602041aed52bf3068b07bb0e9f001577e637ef46333bbd98b59484cb444d2
Image: busybox:1.28
Image ID: docker-pullable://busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
Port: <none>
Host Port: <none>
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
State: Running
Started: Mon, 05 Sep 2022 16:42:58 +0800
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-8r7sj (ro)
init-mydb:
Container ID:
Image: busybox:1.28
Image ID:
Port: <none>
Host Port: <none>
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
State: Waiting
Reason: PodInitializing
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-8r7sj (ro)
Containers:
myapp-pod:
Container ID:
Image: busybox:1.28
Image ID:
Port: <none>
Host Port: <none>
Command:
sh
-c
echo the myapp-pod is running! && sleep 360
State: Waiting
Reason: PodInitializing
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-8r7sj (ro)
Conditions:
Type Status
Initialized False
Ready False
ContainersReady False
PodScheduled True
Volumes:
default-token-8r7sj:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-8r7sj
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 4m13s default-scheduler Successfully assigned default/myapp-pod to node02
Normal Pulling 4m11s kubelet Pulling image "busybox:1.28"
Normal Pulled 3m54s kubelet Successfully pulled image "busybox:1.28" in 16.602216282s
Normal Created 3m54s kubelet Created container init-myservice
Normal Started 3m54s kubelet Started container init-myservice
查看日志
# kubectl logs myapp-pod -c init-myservice
nslookup: can't resolve 'myservice.default.svc.cluster.local'
Server: 10.0.0.2
Address 1: 10.0.0.2
waiting for myservice
Server: 10.0.0.2
Address 1: 10.0.0.2
nslookup: can't resolve 'myservice.default.svc.cluster.local'
waiting for myservice
nslookup: can't resolve 'myservice.default.svc.cluster.local'
Server: 10.0.0.2
Address 1: 10.0.0.2
waiting for myservice
nslookup: can't resolve 'myservice.default.svc.cluster.local'
Server: 10.0.0.2
Address 1: 10.0.0.2
waiting for myservice
Server: 10.0.0.2
Address 1: 10.0.0.2
nslookup: can't resolve 'myservice.default.svc.cluster.local'
waiting for myservice
nslookup: can't resolve 'myservice.default.svc.cluster.local'
Server: 10.0.0.2
Address 1: 10.0.0.2
waiting for myservice
# kubectl logs myapp-pod -c init-mydb
Error from server (BadRequest): container "init-mydb" in pod "myapp-pod" is waiting to start: PodInitializing
可以看到第一个init容器失败,导致第二个init容器没有启动,在这一刻,Init 容器将会等待至发现名称为 mydb
和 myservice
的 Service。
添加service到myapp-pod.yaml 文件中
---
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
运行并查看
# kubectl apply -f myapp-pod.yaml
pod/myapp-pod unchanged
service/myservice created
service/mydb created
# kubectl get -f myapp-pod.yaml
NAME READY STATUS RESTARTS AGE
pod/myapp-pod 1/1 Running 0 9m48s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/myservice ClusterIP 10.0.0.120 <none> 80/TCP 9m47s
service/mydb ClusterIP 10.0.0.111 <none> 80/TCP 9m47s
配置探针
kubelet使用存活探针来确定什么时候要重启容器。 例如,存活探针可以探测到应用死锁(应用程序在运行,但是无法继续执行后面的步骤)情况。 重启这种状态下的容器有助于提高应用的可用性,即使其中存在缺陷。
kubelet 使用就绪探针可以知道容器何时准备好接受请求流量,当一个 Pod 内的所有容器都就绪时,才能认为该 Pod 就绪。 这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。 若 Pod 尚未就绪,会被从 Service 的负载均衡器中剔除。
kubelet 使用启动探针来了解应用容器何时启动。 如果配置了这类探针,你就可以控制容器在启动成功后再进行存活性和就绪态检查, 确保这些存活、就绪探针不会影响应用的启动。 启动探针可以用于对慢启动容器进行存活性检测,避免它们在启动运行之前就被杀掉。
存活探针
许多长时间运行的应用最终会进入损坏状态,除非重新启动,否则无法被恢复。 Kubernetes 提供了存活探针来发现并处理这种情况。
存活命令
编写exec-liveness.yaml 文件
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: busybox:latest
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
在这个配置文件中,可以看到 Pod 中只有一个 Container
。 periodSeconds
字段指定了 kubelet 应该每 5 秒执行一次存活探测。 initialDelaySeconds
字段告诉 kubelet 在执行第一次探测前应该等待 5 秒。 kubelet 在容器内执行命令 cat /tmp/healthy
来进行探测。 如果命令执行成功并且返回值为 0,kubelet 就会认为这个容器是健康存活的。 如果这个命令返回非 0 值,kubelet 会杀死这个容器并重新启动它。
当容器启动时,执行如下的命令:
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600"
这个容器生命的前 30 秒,/tmp/healthy
文件是存在的。 所以在这最开始的 30 秒内,执行命令 cat /tmp/healthy
会返回成功代码。 30 秒之后,执行命令 cat /tmp/healthy
就会返回失败代码。
创建pod
# kubectl apply -f exec-liveness.yaml
pod/liveness-exec created
在 30 秒内,查看 Pod 的事件:
# kubectl describe pod liveness-exec
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 36s default-scheduler Successfully assigned default/liveness-exec to node02
Normal Pulling 36s kubelet Pulling image "busybox:latest"
Normal Pulled 20s kubelet Successfully pulled image "busybox:latest" in 15.435591611s
Normal Created 20s kubelet Created container liveness
Normal Started 20s kubelet Started container liveness
35 秒之后,再来看 Pod 的事件:
# kubectl describe pod liveness-exec
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 51s default-scheduler Successfully assigned default/liveness-exec to node02
Normal Pulling 51s kubelet Pulling image "busybox:latest"
Normal Pulled 35s kubelet Successfully pulled image "busybox:latest" in 15.435591611s
Normal Created 35s kubelet Created container liveness
Normal Started 35s kubelet Started container liveness
Warning Unhealthy 4s kubelet Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
在输出结果的最下面,有信息显示存活探针失败了,这个失败的容器被杀死并且被重建了。
存活HTTP请求接口
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: liveness
args:
- /server
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
更多推荐
所有评论(0)