kubernetes之pod超详细解读--第一篇
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kubernetes之pod超详细解读--第一篇相关的知识,希望对你有一定的参考价值。
小编在这里向各位博友道个歉,上篇文章确实写的有些应付,但怎么说,部署确实因人而异,而且很少有刚刚进公司就让你搭建一个集群,一般公司都有自己的集群,所以小编觉得,侧重点不应该在安装,应该在维护!虽然有些牵强,但小编保证,这一篇绝对有质量!希望看了小编的博客,大家对pod有更深入的认识。这篇文章,小编打算介绍关于pod的11个重要的知识点,大家要有耐心的看下去哦!虽然内容比较多,有兴趣的朋友可以细细阅读,小编会尽可能的用比较容易理解的话和图,去介绍比较重要并且难以理解的地方。
1. pod的基本定义和用法
首先我们通过yaml定义的方式看看pod中可以定义哪些内容:
apiVersion: v1 #版本号
kind: Pod #资源对象类型
metadata: #元数据
name: string #pod的名称
namespace: string #pod所属的命名空间
labels: #自定义标签列表
- name: string
annotations: #自定义注解列表
- name: string
spec: #pod的容器的详细定义
containers:
- name: string #容器的名称
image: string #容器的镜像
imagePullPolicy: [Always|Never|IfNotPresent] #镜像获取策略
command: [string] #容器的启动命令列表
args: [string] #启动命令参数
workingDir: string #容器的工作目录
volumeMounts: #挂载到容器内部的存储卷配置
- name: string
mountPath: string #挂载的目录
readOnly: boolean #是否只读挂载
ports: #容器暴露的端口列表
- name: string #端口名称
containerPort: int #容器监听的端口
hostPort: int #容器所在主机需要监听的端口
protocol: string #端口协议
env: #容器中的环境变量
- name: string
value: string
resources: #资源限制设置
limits: #最大使用资源
cpu: string
memory: string
requests: #请求时资源设置
cpu: string
memory: string
livenessProbe: #对容器的健康检查
exec: #通过命令的返回值
command: [string]
httpGet: #通过访问容器的端口的返回的状态码
path: string
port: number
host: string
scheme: string
httpHeaders:
- name: string
value: string
tcpSocket: #通过tcpSocket
port: number
initialDelaySeconds: 0 #首次健康检查时间
timeoutSeconds: 0 #健康检查的超时时间
periodSeconds: 0 #每次健康检查的时间间隔
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always|Never|OnFailure] #pod的重启策略
nodeSelector: object #指定的运行pod的node标签
imagePullSecrets:
- name: string
hostNetwork: false #是否使用主机网络模式
volumes: #该pod上定义的共享存储卷列表
- name: string
emptyDir: {} #临时挂载
hostPath: #挂载宿主机目录
path: string
secret: #类型为secret存储卷
secretName: string
items:
- key: string
path: string
configMap: #类型为configMap的存储卷
name: string
items:
- key: string
path: string
是不是一下子看了这么多配置,感觉有点蒙蒙的,不要着急,先苦后甜,小编接下来会一一介绍如何使用这些配置,以及这些配置有什么作用。
Pod的基本用法:
当然这里小编要强调的是,如果自己定义的image,并且image运行的程序的脚本是后台调度运行的例:nohup ./start.sh,类似这样的,如果是在docker中可以使用docker run的方式创建并启动这个容器,当时在kubernetes中,类似这样后台的程序,kubelet创建这个容器的pod之后,运行完该命令,就认为pod执行结束,将立刻销毁这个pod,如果给这个pod绑定了RC,那么系统将会根据RC中的pod的副本数重新启动这个pod,这样下去会进入无限的死循环中,当然问题出现了肯定会有解决办法,这里小编向大家介绍一个服务supervisor,说实话,小编也不是很懂它,有时间再把它玩一玩,这里小编先介绍一下它是如何让这些后台启动的容器持续运行,并满足kubernetes对容器启动的要求:supervisor提供了一种可以同时启动多个后台进程,并保持supervisor自身在前台执行的机制。(好吧我知道是废话,但是很通俗易懂,能就这样,强行安慰自己,感觉很nice)。
接下来创建几个pod,看看效果,这里pod可以由一个或者多个container组成,先创建一个只有一个container的:
#frontend-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: frontend
labels:
name: frontend
spec:
containers:
- name: frontend
image: docker.io/kubeguide/guestbook-php-frontend
env:
- name: GET_HOSTS_FROM
value: env
ports:
- containerPort: 80
hostNetwork: true
[[email protected] yaml_file]# kubectl create -f frontend-pod.yaml #创建这个pod
创建一个两个container组合成一个整体的pod对外提供服务:
apiVersion: v1
kind: Pod
metadata:
name: redis-php
labels:
name: redis-php
spec:
containers:
- name: frontend
image: docker.io/kubeguide/guestbook-php-frontend:localredis
ports:
- containerPort: 80
- name: redis
image: docker.io/kubeguide/redis-master
ports:
- containerPort: 6379
这里有一个container,死了,可能是镜像出了问题,当然重点不在这里,主要是演示如何运行2个容器在一个pod中有兴趣的可以解决一下这个问题:
2. 静态pod
所谓的静态的pod就是通过kubelet管理并且仅存在于特定的node上的pod,它们不能通过API server 进行管理,也无法与RC、deployment、daemonSet进行关联,并且kubelet也不能对其进行健康检查。他们总是由kubelet创建,并且总在kubelet所在node上运行。其中创建静态的pod有两种方式:配置文件方式和HTTP方式。
① 配置文件方式
这里我的kubelet的配置文件在/etc/kubernetes/kubelet
然后在配置文件中加入:--config=/k8s/yaml_file/static-web.yaml
#static-web.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
name: static-web
spec:
containers:
- name: static-web
image: nginx
ports:
- name: web
containerPort: 80
[[email protected] yaml_file]# systemctl restart kubelet #重启kubelet服务
[[email protected] yaml_file]# docker ps #查看本机的容器:docker ps
此时这个静态的pod就正在创建,并且使用kubectl delete pod pod_name删除不了这个pod的,只能让这个pod处于pending状态,当然只要将该node上的定义这个pod的文件删除,就能将这个pod从这个node上删除了。
② HTTP方式:因为简单这里就不在演示,只要在kubelet的配置文件中加入:--manifest-url=xxx,kubelet就会定期的从指定的URL中下载pod的定义文件(yaml|json),然后根据定义在自己的node上创建pod。
3.pod容器共享volume
这里的配置管理,就是将程序和配置分离,使程序更加灵活,一般的我们在打包应用程序为镜像,可以通过环境变量或者外挂volume的方式在创建容器的时候进行配置注入,但是如果机器规模比较大的时候,对多容器进行不同的配置注入将十分复杂,所以这里我们介绍一种便捷方式configMap。
configMap典型使用场景:
? 生成容器内部的环境变量
? 设置容器的启动命令的参数
? 以volume的形式挂载为容器内部的文件或者目录
在同一个pod中的多个容器之间能够共享pod级别的存储卷volume,volume可以被定义为各种类型,多个容器之间进行各自挂载,将一个volume挂载为容器内部的目录:
上图就是一个pod中有两个容器同时挂载一个volume共享,其中实现的功能为:tomcat用于向其中写日志,busybox用于向其中读取日志:
#pod-volume-applogs.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-pod
spec:
containers:
- name: tomcat
imagePullPolicy: IfNotPresent
image: docker.io/tomcat
ports:
- containerPort: 8080
volumeMounts:
- name: app-logs
mountPath: /usr/local/tomcat/logs
- name: logreader
image: docker.io/busybox
imagePullPolicy: IfNotPresent
command: ["sh","-c","tail -f /logs/catalina*.log"]
volumeMounts:
- name: app-logs
mountPath: /logs
volumes:
- name: app-logs
emptyDir: {}
注意 :这里名称为volume-pod的pod中的两个容器,同时挂载了类型为emptyDir这种临时目录,并且在容器logreader中打印Tomcat容器生成的日志,我们通过命令查看:
[[email protected] yaml_file]# kubectl logs volume-pod -c logreader
4. pod的配置管理
这里的配置管理,就是将程序和配置分离,使程序更加灵活,一般的我们在打包应用程序为镜像,可以通过环境变量或者外挂volume的方式在创建容器的时候进行配置注入,但是如果机器规模比较大的时候,对多容器进行不同的配置注入将十分复杂,所以这里我们介绍一种便捷方式configMap。
configMap典型使用场景:
? 生成容器内部的环境变量
? 设置容器的启动命令的参数
? 以volume的形式挂载为容器内部的文件或者目录
configMap用法:configMap以key-value的形式定义,这里的value可以是string也可以是一个文件内容,通过kubectl create configmap 的方式创建configMap。
这里小编通过这个几个方面去介绍configMap的用法:
? configMap的两种创建方式:基于yaml文件或者基于命令。
? configMap的两种使用方式:环境变量和volume挂载。
configMap的创建:
① 基于yaml文件
#cm-appvars.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-aoovars
data:
apploglevel: info
appdatadir: /var/data
[[email protected] yaml_file]# kubectl create -f cm-appvars.yaml #创建configmap
[[email protected] yaml_file]# kubectl get configmap #查看创建的configmap
[[email protected] yaml_file]# kubectl describe configmap cm-aoovars #查看configmap定义的内容
#cm-appconfigfiles.yaml(value为文件内容)
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-appconfigfiles
data:
key-serverxml: |
xml文件内容
key-loggingproperties: "配置文件内容"
[[email protected] yaml_file]# kubectl get configmap cm-appconfigfiles -o yaml #查看详细内容
② 基于命令
[[email protected] yaml_file]# kubectl create configmap cm-figmap --from-file=server.xml
注意:这里会将文件的名称为key,内容为value,如果目录下有多个文件,则同时创建,并且文件的名称为key,内容为value。
[[email protected] yaml_file]# kubectl create configmap cm-figmap --from-literal=loglevel=info --fromliteral=appdatadir=/var/data
注意:这种方式是指定具体的key-value创建configmap
configMap的使用:
① 通过环境变量的方式使用configmap
apiVersion: v1
kind: Pod
metadata:
name: cm-test-pod
spec:
containers:
- name: busybox
image: docker.io/busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","env|grep APP"]
env:
- name: APPLOGLEVEL #定义环境变量
valueFrom:
configMapKeyRef:
name: configMapNAME
key: configMap_KEY
- name: APPLOGLEVEL #定义环境变量
valueFrom:
configMapKeyRef:
name: configMapNAME
key: configMap_KEY
在kubernetes1.6之后,有一种简单的定义env的方式:
envFrom:
- configMapRef:
name: configMapNAME
② 通过volumeMount使用configmap
上面我们定义了一个基于文件的configmap,接下来看如何使用基于文件的configmap,挂载到具体的pod的容器的目录下:
#cm-test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: cm-test-pod
spec:
containers:
- name: busybox
image: kubeguide/tomcat-app:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
volumeMounts:
- name: serverxml #引用volumes名称
mountPath: /configfiles #将confimap中的文件挂载到容器的目录中
volumes:
- name: serverxml
configMap:
name: configMapName #定义的configmap的名称
items: #需要挂载的文件的列表
- key: key-serverxml #configmap中定义的key
path: server.xml #挂载后的文件名
- key: key-loggingproperties
path: logging.properties
注意:如果在定义volume中的configmap时不指定items,那么volumeMount会在容器的指定目录下为每一个items生产一个文件名为key,内容为value的文件。
ConfigMap的使用限制说明:
? Configmap必须在pod创建之间创建
? ConfigMap受到namespace的限制,只有同一个命名空间下才能引用
? 静态的pod无法使用ConfigMap
? 在使用volumeMount挂载的时候,configMap基于items创建的文件会整体的将挂载数据卷的容器的目录下的文件全部覆盖
5.在容器中获取pod的信息
在我们创建pod后,系统就会给其分配唯一的名字、IP、并且处于某个namspace下面,那么这些信息我们如何获取呢?通过Downward API的方式。
Downward API可以通过以下得到两种方式将pod的信息导入到container中:
? 环境变量,用于单个变量,可以将pod信息和container信息注入到容器中
? Volume挂载:将数组类信息生成文件挂载到容器内部。
实例:
① 环境变量的方式
#将pod信息注入为环境变量
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","env"]
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
[[email protected] yaml_file]# kubectl log dapi-test-pod #查看
#daip-test-pod-container-vars.yaml将容器资源信息注入为环境变量
apiVersion: v1
kind: Pod
metadata:
name: daip-test-pod-container-vars
spec:
containers:
- name: test-container
image: busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c"]
args:
- while true; do
echo -en "\n";
printenv MY_CPU_REQUEST MY_CPU_LIMIT;
printenv MY_MEM_REQUEST MY_MEM_LIMIT;
sleep 60;
done;
resources:
requests:
memory: "32Mi"
cpu: "125m"
limits:
memory: "40Mi"
cpu: "130m"
env:
- name: MY_CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: requests.cpu
- name: MY_CPU_LIMIT
valueFrom:
resourceFieldRef:
containerName: test-container
resource: requests.cpu
- name: MY_CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: limits.cpu
- name: MY_MEM_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: requests.memory
- name: MY_MEM_LIMIT
valueFrom:
resourceFieldRef:
containerName: test-container
resource: limits.memory
[[email protected] yaml_file]# kubectl logs daip-test-pod-container-vars
② Volume挂载方式
![](https://s1.51cto.com/images/blog/201905/18/33b1db246d451ae70c8bc2738341fea9.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)#dapi-test-pod-volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod-volume
labels:
zone: us-est-coast
cluster: test-cluster
rack: rack-22
annotations:
build: two
builder: john-doe
spec:
containers:
- name: test-container
image: busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c"]
args:
- while true;do
if [[ -e /etc/labels ]];then
echo -en "\n\n";cat /etc/labels; fi;
if [[ -e /etc/annotations ]];then
echo -en "\n\n";cat /etc/annotations; fi;
sleep 60;
done;
volumeMounts:
- name: podinfo
mountPath: /etc
readOnly: false
volumes:
- name: podinfo
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotations
注意:通过设置items,将会以path的名称生成文件。
[[email protected] yaml_file]# kubectl logs dapi-test-pod-volume
Downward API的作用:在某些集群中,集群中的节点需要将自身标识以及进程绑定的IP地址等信息预习写入配置文件,进程启动时读取这些信息,然后发布到类似于服务注册中心中,做集群的节点的自动发现功能。那么Downward API就大有用处,它可以先编写一个预启动脚本或者init container,通过环境变量或者文件的方式获取pod自身的名称、IP地址等信息,然后写入主程序配置中。
6.pod的声明周期和重启策略
pod在整个声明周期中有很多状态,了解其各种状态对于集群排错大有帮助:
当某个pod异常退出或者健康检查失败的时候,kubelet会根据pod定义中的spec.RestartPolicy的设置来进行相应的操作。
Pod的重启策略包括:
? Always:当容器失效时,由kubelet自动重启
? OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启
? Nerver:永远不重启
Pod的重启策略,与管理其的资源对象息息相关,RC、job、Daemonset以及通过kubelet直接管理的静态的pod,每一种控制器对pod的重启策略都有要求:
? RC和Daemonset:必须设置为Always。
? Job:OnFailure或者Nerver,确保容器执行完成不在重启
? 静态pod:在pod失效时自动重启。(注意静态pod不会被健康检查)
7 .Pod的健康检查
就像HDFS中的DataNode会定时发送心跳给namenode一样,k8s集群中通过探针的方式给Pod定时做健康检查,一旦符合定义的情况,就执行相应的重启策略。
健康检查分为以下两种探针:
? LivenessProbe探针: 判断容器是否存活(runnning状态),如果探测到容器不健康,则kubelet杀死该容器,并且根据重启策略做相应处理,如果容器中没有LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针一直返回“Success”
? ReadinessProbe探针: 用于判断容器是否启动完成(ready状态),可以接受请求。如果ReadinessProbe探针探测到失败,则pod的状态被修改。并且EndPoint Controller将从service的EndPoint中删除包含该容器所在pod的EndPoint。
接下来我们重点介绍一下LivenessProbe探针如何判断pod是否健康,这里有三种实现方式:
? ExecAction:在容器中执行一个命令,如果该命令返回的状态码为0,表示该容器正常
? TCPSocketAction:通过容器的IP地址和端口执行TCP检查,能够建立TCP连接,表示该容器正常
? HTTPGetAction:通过容器的IP和端口以及路径调用HTTP get方法,如果相应的状态码大于等于200并且小于400,则认为该容器正常
实例演示:
① ExecAction
apiVersion: v1
kind: Pod
metadata:
labels:
test:liveness
name: liveness-exec
spec:
containers:
- name: liveness
images: gcr.io/google_containers/busybox
args:
- /bin/sh
- -c
- echo ok > /tmp/health; sleep 10 ;rm -rf /tmp/health;sleep 10 ;
livenessProbe:
exec:
command:
- cat
- /tmp/health
initialDelaySeconds: 15 #初次健康检查时间
timeoutSeconds: 1 #超时时间
这里注意:我们设置了livenessProbe探针初次检查时间为15秒,但是程序中将10之后删除检查的文件,这里cat /tmp/health 这个命令执行失败,状态码返回不为0,导致kubelet杀掉该进程,并根据相应的重启策略进行操作。
② TCPSocketAction
apiVersion: v1
kind: Pod
metadata:
labels:
test:liveness
name: liveness-exec
spec:
containers:
- name: nginx
images: nginx
ports:
- containerPort: 80
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 15 #初次健康检查时间
timeoutSeconds: 1 #超时时间
③ HTTPGetAction
apiVersion: v1
kind: Pod
metadata:
labels:
test:liveness
name: liveness-exec
spec:
containers:
- name: nginx
images: nginx
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /_status/helthz
port: 80
initialDelaySeconds: 30 #初次健康检查时间
timeoutSeconds: 1 #超时时间
这里小编强调一下:
initialDelaySeconds:启动容器后首次健康检查的时间
timeoutSeconds:健康检查发送请求后等待相应的时间
看到这里大家一定脑子都炸了,这里小编想说一下,后面还有很多,这里小编把pod介绍分为两篇博文向大家介绍,
后续部分URL:
文章参考至《kubernetes权威指南》
以上是关于kubernetes之pod超详细解读--第一篇的主要内容,如果未能解决你的问题,请参考以下文章
Jenkins-Kubernetes插件实现使用Pod作为 Agent-超详细