小编在这里向各位博友道个歉,上篇文章确实写的有些应付,但怎么说,部署确实因人而异,并且不多有刚刚进公司就让你搭建一个集群,通常公司都有本身的集群,因此小编以为,侧重点不该该在安装,应该在维护!虽然有些牵强,但小编保证,这一篇绝对有质量!但愿看了小编的博客,你们对pod有更深刻的认识。
这篇文章,小编打算介绍关于pod的11个重要的知识点,你们要有耐心的看下去哦!虽然内容比较多,有兴趣的朋友能够细细阅读,小编会尽量的用比较容易理解的话和图,去介绍比较重要而且难以理解的地方。php
首先咱们经过yaml定义的方式看看pod中能够定义哪些内容:node
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的:nginx
#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
[root@zy yaml_file]# kubectl create -f frontend-pod.yaml #建立这个pod
建立一个两个container组合成一个总体的pod对外提供服务:web
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中有兴趣的能够解决一下这个问题:redis
所谓的静态的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.yamldocker
#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
[root@zy yaml_file]# systemctl restart kubelet #重启kubelet服务 [root@zy 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。json
这里的配置管理,就是将程序和配置分离,使程序更加灵活,通常的咱们在打包应用程序为镜像,能够经过环境变量或者外挂volume的方式在建立容器的时候进行配置注入,可是若是机器规模比较大的时候,对多容器进行不一样的配置注入将十分复杂,因此这里咱们介绍一种便捷方式configMap。
configMap典型使用场景:
生成容器内部的环境变量
设置容器的启动命令的参数
以volume的形式挂载为容器内部的文件或者目录
在同一个pod中的多个容器之间可以共享pod级别的存储卷volume,volume能够被定义为各类类型,多个容器之间进行各自挂载,将一个volume挂载为容器内部的目录:
上图就是一个pod中有两个容器同时挂载一个volume共享,其中实现的功能为:tomcat用于向其中写日志,busybox用于向其中读取日志:api
#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容器生成的日志,咱们经过命令查看:数组
[root@zy yaml_file]# kubectl logs volume-pod -c logreader
这里的配置管理,就是将程序和配置分离,使程序更加灵活,通常的咱们在打包应用程序为镜像,能够经过环境变量或者外挂volume的方式在建立容器的时候进行配置注入,可是若是机器规模比较大的时候,对多容器进行不一样的配置注入将十分复杂,因此这里咱们介绍一种便捷方式configMap。
configMap典型使用场景:
生成容器内部的环境变量
设置容器的启动命令的参数
以volume的形式挂载为容器内部的文件或者目录
configMap用法:configMap以key-value的形式定义,这里的value能够是string也能够是一个文件内容,经过kubectl create configmap 的方式建立configMap。
这里小编经过这个几个方面去介绍configMap的用法:
configMap的两种建立方式:基于yaml文件或者基于命令。
configMap的两种使用方式:环境变量和volume挂载。
configMap的建立:
① 基于yaml文件tomcat
#cm-appvars.yaml apiVersion: v1 kind: ConfigMap metadata: name: cm-aoovars data: apploglevel: info appdatadir: /var/data
[root@zy yaml_file]# kubectl create -f cm-appvars.yaml #建立configmap [root@zy yaml_file]# kubectl get configmap #查看建立的configmap
[root@zy 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: "配置文件内容"
[root@zy yaml_file]# kubectl get configmap cm-appconfigfiles -o yaml #查看详细内容
② 基于命令
[root@zy yaml_file]# kubectl create configmap cm-figmap --from-file=server.xml
注意:这里会将文件的名称为key,内容为value,若是目录下有多个文件,则同时建立,而且文件的名称为key,内容为value。
[root@zy 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建立的文件会总体的将挂载数据卷的容器的目录下的文件所有覆盖
在咱们建立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
[root@zy 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
[root@zy yaml_file]# kubectl logs daip-test-pod-container-vars
② Volume挂载方式
#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的名称生成文件。
[root@zy yaml_file]# kubectl logs dapi-test-pod-volume
Downward API的做用:在某些集群中,集群中的节点须要将自身标识以及进程绑定的IP地址等信息预习写入配置文件,进程启动时读取这些信息,而后发布到相似于服务注册中心中,作集群的节点的自动发现功能。那么Downward API就大有用处,它能够先编写一个预启动脚本或者init container,经过环境变量或者文件的方式获取pod自身的名称、IP地址等信息,而后写入主程序配置中。
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不会被健康检查)
就像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介绍分为两篇博文向你们介绍,
文章参考至《kubernetes权威指南》