“ Pod作为Kunernetes的原子调度单元,有必要深入认识下”
深入认识Pod
01.再次认识Pod
Pod,是Kubernetes项目中最小的API对象,是原子调度单元。
我们知道,容器的本质就是进程,那么就可以把Kubernetes类比为“操作系统“,因为它和操作系统类似,都是用来管理进程和进程之间关系的。
每一个Pod中都有一个中间容器,Infra容器。在一个Pod中,Infra容器永远都是第一个被创建的容器,而其他用户定义的容器,则通过Join Network Namespace的方式,与Infra容器关联在一起。
在Kubernetes项目中,Infra容器一定会占用极少的资源,所以它使用的是一个非常特殊的镜像,k8s.gcr.io/pause。这个镜像是一个用汇编语言写的、永远处于“暂停“状态的容器,大小也就200KB左右。
对与Pod中的容器A和容器B来说:
它们可以直接使用localhost进行通信;
它们看到的网络设备跟Infra容器看到的完全一样;
一个Pod只有一个IP地址,就是这个Pod的Network Namespace对应的IP地址;
其他所有网络资源,都是一个Pod一份,被Pod中的所有容器共享;
Pod的生命周期只跟Infra容器一致,而与容器A和容器B无关。
对于同一个Pod里面的所有用户容器来说,它们的进出流量,都是通过Infra容器完成的。
这样一来,共享Volume就简单很多,Kubernetes只要把所有Volume的定义都设计在Pod层级即可。这样,一个Volume对应的宿主机目录对于Pod来说就只有一个,Pod里的容器只要声明挂载这个Volume,就一定可以共享这个Volume对应的宿主机目录。
02.基本概念
NodeSelector,是一个供用户将Pod与Node进行绑定的字段,例如:
apiVersion: v1
kind: Pod
…
spec:
nodeSelector:
disktype: ssd
上面的配置意味着这个Pod只能运行在携带了标签“disktype: ssd“(Label)的节点上,否则将会调度失败。
NodeName,一旦Pod的这个字段被赋值,Kubernetes就会被认为这个Pod已经经过了调度,调度的结果就是赋值节点的名字。
HostAliases,定义了Pod的hosts文件里的内容,例如:
apiVersion: v1
kind: Pod
…
spec:
hostAliases:
- ip: “10.10.1.1”
hostnames:
- “foo.remote”
-“bar.remote”
在上面的配置中,当Pod启动后,/etc/hosts文件的内容会如下所示:
10.10.1.1foo.remote
10.10.1.1bar.remote
在Kubernetes项目中,一档要通过这种方法配置hosts文件,否则,如果直接修改了hosts文件,在Pod被删除重建之后,kubelet会自动覆盖掉被修改的内容。
Pod中还有一个非常重要的字段,那就是“Containers“。Kubernetes项目中对Container的定义,和Docker相比并没有太大的区别,Image(镜像)、Command(启动命令)、workDir(容器的工作目录)、Ports(容器要开放的端口)以及volumeMounts(容器要挂载的Volume)等都是构成Kubernetes项目中Container的主要字段,另外还有几个字段需要注意:
ImagePullPolicy,定义了镜像拉取的策略,默认值是Always,即每次创建Pod都重新拉取一次镜像,还有Never和ifNotPresent两个值。
Lifecycle,定义是Container Lifecycle Hooks。在容器状态放生变化时触发一系列“钩子“。
Status,Pod生命周期的变化,主要体现在Status上。它分为如下几种情况:
Pending,这个状态意味着,Pod的YAML文件已经提交给了Kubernetes,API对象已经被创建并保存在Etcd当中。但是这个Pod里有些容器因为某种原因而不能被顺利创建,比如调度不成功等。
Running,这个状态下,Pod已经调度成功,跟一个具体的节点绑定。它包含的容器都已经创建成功,并且至少有一个在运行中。
Succeeded,这个状态意味着,Pod里的所有容器都正常运行完毕,并且已经退出了。在运行一次性任务的情况常见。
Failed,这个状态下,Pod里至少有一个容器以不正常的状态退出。
Unknown,这是个异常状态,意味着Pod的状态不能持续的被Kubelet汇报给kube-apiserver,可能是主从节点间的通信出现了问题。
同时Pod对象的Status字段,还存在更细的一组Conditions,包括:PodScheduled,Ready,Initialized和Unschedulable,它们主要用于描述造成当前Status的具体原因。
03.特殊的Volume
特殊的Volume-Projected Volume,可以翻译为投射数据卷
在Kunernetes中,有几种特殊的Volume,它们存在的意义不是为了存放容器里的数据,也不是用来进行容器和宿主机之间的数据交换。这些特殊Volume的作用,是为容器提供预先定义好的数据。所以,从容器的角度来看,这些Volume里的信息就是仿佛是被Kubernetes“投射“(Projected)进入容器当中的。
目前Kubernetes支持的ProjectedVolume一共有四种:
-
Secret
-
ConfigMap
-
Downward API
-
ServiceAccountToken
Secret,它的作用是把Pod想要访问的加密数据,存放到etcd中。然后我们就可以通过在Pod的容器里挂载Volume的方式,访问到这些secret里保存的信息。
ConfigMap,保存的是不需要加密的、应用所需要的配置信息。
DownwardAPI,让Pod里的容器能够直接获取到这个Pod API对象本身的信息。
ServiceAccountToken,则是与secret密切相关的。Kubernetes系统内置了一种“服务账号“,就是service account对象。比如service account A可以只被允许对Kubernetes API进行GET操作,而service account B可以有Kubernetes API的所有操作权限。像这样的service account的授权信息和文件,保存在它所绑定的一个特殊的secret对象里。而这个特殊的secret对象就叫做ServiceAccountToken。任何运行在Kubernetes集群上的应用,都必须使用这个ServiceAccountToken里保存的授权信息(Token),才可以合法的访问API server。
- 健康检查与恢复机制
在Kubernetes中,可以为Pod里的容器定义一个健康检查“探针“,Probe。这样,kubelet就会根据这个Probe的返回值决定这个容器的状态,而不是直接以容器是否运行来作为依据。
简单的例子
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: test-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
在这个Pod中,定义了一个容器,它在启动之后做的第一件事就是在/tmp目录下创建了一个healthy文件,以此来作为自己已经正常运行的标志,而过30s之后就会把这个文件删除掉。
同时还定义了一个livenessProbe(健康检查),它的类型是exec,这意味着它会在容器启动后,在容器里面执行一句我们指定的命令,比如:“cat/tmp/healthy“。这时如果这个文件存在,这条命令的返回值就是0,Pod就会认为这个容器不仅已经启动,而且是健康的。这个健康检查在容器启动5S后开始执行(initialDelaySeconds:5),没5S执行一次(periodSeconds:5S)。
下面来实践下这个过程
创建这个Pod
kubectl create -f test-liveness.yaml
查看Pod状态
kubectl get po -n default
test-liveness-exec 1/1 Running 0 30s
30S后我们查看下Pod的事件信息
kubectl describe po test-liveness-exec -ndefault
有一个如下报错:
Warning Unhealthy 26s (x3 over 29s) kubelet, test5-0-0-storage-0.localdomain Liveness probe failed: cat: can’t open ‘/tmp/healthy’: No such file or directory
此时再次查看Podzhuangt
kubectl get po -n default
NAME READY STATUS RESTARTS AGE
test-liveness-exec 1/1 Running 1 2m
发现Pod已经重启(restarts=1),实际是重新创建了容器(Kubernetes中没有stop语义)。这个功能就是Kubernetes里的Pod恢复机制,也叫做restartPolicy。Pod的恢复过程,永远都是发生在当前节点上,不会跑到别的节点。一旦一个Pod与一个节点(Node)绑定,除非这个绑定发生了变化,否则它永远都不会离开这个节点。
restartPolicy策略:
always,在任何情况下,只要容器不在运行状态,就自动重启容器。
OnFailure,只在容器异常时才自动重启容器。
Never,从来不重启容器。
restartPolicy和Pod里容器的状态,以及Pod状态的对应关系:
-
只有Pod的restartPolicy指定的策略允许重启异常的容器,那么这个Pod就会保持Running状态,并进行容器重启。否则Pod就会进入Failed状态。
-
对于包含多个容器的Pod,只有它里面所有的容器都进入异常状态后,Pod才会进入Failed状态。在此之前,Pod都是Running状态。此时Pod的READY字段会显示正常容器的个数。
在Kubernetes中还有个叫readinessProbe的字段,虽然它的用法与liveinessProbe类似,但作用却大不一样。readinessProbe检查结果的成功与否,决定于这个Pod是不是能被通过Service的方式访问到,而并不影响Pod的生命周期。这部分后面再详细讨论。
随着学习的深入,理解起来越来越难了,但是一定要坚持下去!!!