pod
- 1.为何使用pod?
- 2.容器设计模式
- 3. pod基本概念
- 3.1 pod仍需关注的字段
- 3.2 pod的生命周期
- 4.深入解析pod(四种Projected Volume,“投射数据卷)
- 4.1 Secret
- 4.2 ConfigMap
- 4.3 Downward API
- 4.4 ServiceAccountToken(特殊secret)
- 4.5 pod 的健康检查和恢复机制
1.为何使用pod?
容器的本质是进程。没错。容器,就是未来云计算系统中的进程;容器镜像就是这个系统里的“.exe”安装包。Kubernetes 就是操作系统!
[root@master ~]# pstree -g #展示当前系统中正在运行的进程的树状结构
Pod 是 Kubernetes 里的原子调度单位。这就意味着,Kubernetes 项目的调度器,是统一按照 Pod 而非容器的资源需求进行计算的。
像这样容器间的紧密协作,我们可以称为“超亲密关系”。这些具有“超亲密关系”容器的典型特征包括但不限于:互相之间会发生直接的文件交换、使用 localhost 或者 Socket 文件进行本地通信、会发生非常频繁的远程调用、需要共享某些 Linux Namespace(比如,一个容器要加入另一个容器的 Network Namespace)等等。
这也就意味着,并不是所有有“关系”的容器都属于同一个 Pod。比如,PHP 应用容器和 MySQL 虽然会发生访问关系,但并没有必要、也不应该部署在同一台机器上,它们更适合做成两个 Pod。
在 Kubernetes 项目里,Infra 容器一定要占用极少的资源,所以它使用的是一个非常特殊的镜像,叫作:k8s.gcr.io/pause。这个镜像是一个用汇编语言编写的、永远处于“暂停”状态的容器,解压后的大小也只有 100~200 KB 左右。
- pod原理:其只是一个逻辑概念,就是共享了某些资源的容器。最开始启动时infra容器,通过infra进行Network namespace的汇总,别的容器就可以通过Infra加入到Network namespace。pod生命周期是和infra一致的。一个pod启动之前首先启动的是infra容器。
2.容器设计模式
最常用的一种:sidecar,核心就是进行组合,提前启动一个辅助容器,下面是Init,完成独立于主容器之外的工作。比如说tomcat和所需的镜像包,同时进行更新。下面代码中的init容器先启动,启动之后进行cp操作,将需要的镜像进行复制到/app下。后续容器启动之后,所需的war包就可以直接被共享到volumes里面
apiVersion: v1
kind: Pod
metadata:name: javaweb-2
spec:initContainers:- image: geektime/sample:v2name: warcommand: ["cp", "/sample.war", "/app"]volumeMounts:- mountPath: /appname: app-volumecontainers:- image: geektime/tomcat:7.0name: tomcatcommand: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]volumeMounts:- mountPath: /root/apache-tomcat-7.0.42-v2/webappsname: app-volumeports:- containerPort: 8080hostPort: 8001 volumes:- name: app-volumeemptyDir: {}
3. pod基本概念
3.1 pod仍需关注的字段
-
pod 相当于是传统部署环境里面的虚拟机,而容器相当于是虚拟机里面的用户程序。所有的调度、网络、存储都是Pod级别的定义。
-
除了最常用的还需要关注的字段:
首先,是 ImagePullPolicy 字段。它定义了镜像拉取的策略。而它之所以是一个 Container 级别的属性,是因为容器镜像本来就是 Container 定义中的一部分。ImagePullPolicy 的值默认是 Always,即每次创建 Pod 都重新拉取一次镜像。另外,当容器的镜像是类似于 nginx 或者 nginx:latest 这样的名字时,ImagePullPolicy 也会被认为 Always。而如果它的值被定义为 Never 或者 IfNotPresent,则意味着 Pod 永远不会主动拉取这个镜像,或者只在宿主机上不存在这个镜像时才拉取。
其次,是 Lifecycle 字段。它定义的是 Container Lifecycle Hooks。顾名思义,Container Lifecycle Hooks 的作用,是在容器状态发生变化时触发一系列“钩子apiVersion: v1 kind: Pod metadata:name: lifecycle-demo spec:containers:- name: lifecycle-demo-containerimage: nginxlifecycle:postStart:exec:command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]preStop:exec:command: ["/usr/sbin/nginx","-s","quit"]
postStart指的是,在容器启动后,立刻执行一个指定的操作。需要明确的是,postStart 定义的操作,虽然是在 Docker 容器 ENTRYPOINT 执行之后,但它并不严格保证顺序。也就是说,在 postStart 启动时,ENTRYPOINT 有可能还没有结束。当然,如果 postStart 执行超时或者错误,Kubernetes 会在该 Pod 的 Events 中报出该容器启动失败的错误信息,导致 Pod 也处于失败的状态。而类似地,preStop 发生的时机,则是容器被杀死之前(比如,收到了 SIGKILL 信号)。而需要明确的是,preStop 操作的执行,是同步的。所以,它会阻塞当前的容器杀死流程,直到这个 Hook 定义操作完成之后,才允许容器被杀死,这跟 postStart 不一样。所以,在这个例子中,我们在容器成功启动之后,在 /usr/share/message 里写入了一句“欢迎信息”(即 postStart 定义的操作)。而在这个容器被删除之前,我们则先调用了 nginx 的退出指令(即 preStop 定义的操作),从而实现了容器的“优雅退出”。
3.2 pod的生命周期
- Pod 生命周期的变化,主要体现在 Pod API 对象的 Status 部分,这是它除了 Metadata 和 Spec 之外的第三个重要字段。其中,pod.status.phase,就是 Pod 的当前状态,它有如下几种可能的情况:
- Pending。这个状态意味着,Pod 的 YAML 文件已经提交给了 Kubernetes,API 对象已经被创建并保存在 Etcd 当中。但是,这个 Pod 里有些容器因为某种原因而不能被顺利创建。比如,调度不成功。
- Running。这个状态下,Pod 已经调度成功,跟一个具体的节点绑定。它包含的容器都已经创建成功,并且至少有一个正在运行中。
- Succeeded。这个状态意味着,Pod 里的所有容器都正常运行完毕,并且已经退出了。这种情况在运行一次性任务时最为常见。
- Failed。这个状态下,Pod 里至少有一个容器以不正常的状态(非 0 的返回码)退出。这个状态的出现,意味着你得想办法 Debug 这个容器的应用,比如查看 Pod 的 Events 和日志。
- Unknown。这是一个异常状态,意味着 Pod 的状态不能持续地被 kubelet 汇报给 kube-apiserver,这很有可能是主从节点(Master 和 Kubelet)间的通信出现了问题。
- 更进一步地,Pod 对象的 Status 字段,还可以再细分出一组 Conditions。这些细分状态的值包括:PodScheduled、Ready、Initialized,以及 Unschedulable。它们主要用于描述造成当前 Status 的具体原因是什么。比如,Pod 当前的 Status 是 Pending,对应的 Condition 是 Unschedulable,这就意味着它的调度出现了问题。
- 而其中,Ready 这个细分状态非常值得我们关注:它意味着 Pod 不仅已经正常启动(Running 状态),而且已经可以对外提供服务了。这两者之间(Running 和 Ready)是有区别的,你不妨仔细思考一下。Pod 的这些状态信息,是我们判断应用运行情况的重要标准,尤其是 Pod 进入了非“Running”状态后,你一定要能迅速做出反应,根据它所代表的异常情况开始跟踪和定位
4.深入解析pod(四种Projected Volume,“投射数据卷)
4.1 Secret
- 它的作用,是帮你把 Pod 想要访问的加密数据,存放到 Etcd 中。然后,你就可以通过在 Pod 的容器里挂载 Volume 的方式,访问到这些 Secret 里保存的信息了。
apiVersion: v1 kind: Pod metadata:name: test-projected-volume spec:containers:- name: test-secret-volumeimage: busyboxargs:- sleep- "86400"volumeMounts:- name: mysql-credmountPath: "/projected-volume"readOnly: truevolumes:- name: mysql-credprojected:sources:- secret:name: user- secret:name: pass #存储的用户和密码信息 $ cat ./username.txt admin $ cat ./password.txt c1oudc0w!$ kubectl create secret generic user --from-file=./username.txt $ kubectl create secret generic pass --from-file=./password.txt # 查看secret对象 $ kubectl get secrets NAME TYPE DATA AGE user Opaque 1 51s pass Opaque 1 51s ##除了直接创建的方式,还可以通过yaml文件apiVersion: v1kind: Secretmetadata:name: mysecrettype: Opaquedata:user: YWRtaW4= #echo -n 'admin' | base64 转码pass: MWYyZDFlMmU2N2Rm
4.2 ConfigMap
- 与 Secret 类似的是 ConfigMap,它与 Secret 的区别在于,ConfigMap 保存的是不需要加密的、应用所需的配置信息。而 ConfigMap 的用法几乎与 Secret 完全相同:你可以使用 kubectl create configmap 从文件或者目录创建 ConfigMap,也可以直接编写 ConfigMap 对象的 YAML 文件。
4.3 Downward API
- 让 Pod 里的容器能够直接获取到这个 Pod API 对象本身的信息。
apiVersion: v1
kind: Pod
metadata:name: test-downwardapi-volumelabels:zone: us-est-coastcluster: test-cluster1rack: rack-22
spec:containers:- name: client-containerimage: k8s.gcr.io/busyboxcommand: ["sh", "-c"]args:- while true; doif [[ -e /etc/podinfo/labels ]]; thenecho -en '\n\n'; cat /etc/podinfo/labels; fi;sleep 5;done;volumeMounts:- name: podinfomountPath: /etc/podinforeadOnly: falsevolumes:- name: podinfoprojected:sources:- downwardAPI:items:- path: "labels"fieldRef:fieldPath: metadata.labels$ kubectl create -f dapi-volume.yaml
$ kubectl logs test-downwardapi-volume
cluster="test-cluster1"
rack="rack-22"
zone="us-est-coast"
4.4 ServiceAccountToken(特殊secret)
$ kubectl describe pod nginx-deployment-5c678cfb6d-lg9lw #可以看到一个默认服务账户
Containers:...
Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-s8rbq (ro)Volumes:
default-token-s8rbq: Type:
Secret (a volume populated by a Secret)
SecretName: default-token-s8rbq Optional: false
4.5 pod 的健康检查和恢复机制
- Pod 恢复机制,也叫 restartPolicy,可以设置为三种值,Always:在任何情况下,只要容器不在运行状态,就自动重启容器;OnFailure: 只在容器 异常时才自动重启容器;Never: 从来不重启容器
- 在 Kubernetes 中,你可以为 Pod 里的容器定义一个健康检查“探针”(Probe)。这样,kubelet 就会根据这个 Probe 的返回值决定这个容器的状态,而不是直接以容器镜像是否运行(来自 Docker 返回的信息)作为依据。这种机制,是生产环境中保证应用健康存活的重要手段。
apiVersion: v1 kind: Pod metadata:labels:test: livenessname: test-liveness-exec spec:containers:- name: livenessimage: busyboxargs:- /bin/sh- -c- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600livenessProbe:exec:command:- cat- /tmp/healthy ##核心文件initialDelaySeconds: 5periodSeconds: 5