01k8s--pod入门

pod概念

pod概念



Pod是Kubernetes中的最小调度单元,k8s是通过定义一个Pod的资源,然后在Pod里面运行容器,容器需要指定一个镜像,这样就可以用来运行具体的服务。一个Pod封装一个容器(也可以封装多个容器),Pod里的容器共享存储、网络等。也就是说,应该把整个pod看作虚拟机,然后每个容器相当于运行在虚拟机的进程。

  Pod中可以同时运行多个容器。同一个Pod中的容器会自动的分配到同一个 node 上。同一个Pod中的容器共享资源、网络环境,它们总是被同时调度,

pod网络

  Pod是有IP地址的,每个pod都被分配唯一的IP地址(IP地址是靠网络插件calico、flannel、weave等分配的),POD中的容器共享网络名称空间,包括IP地址和网络端口。 Pod内部的容器可以使用localhost相互通信。 Pod中的容器也可以通过网络插件calico与其他节点的Pod通信。

pod存储

  创建Pod的时候可以指定挂载的存储卷。 POD中的所有容器都可以访问共享卷,允许这些容器共享数据。 Pod只要挂载持久化数据卷,Pod重启之后数据还是会存在的。

初识pod

[root@master ~]# cat pod-new.yaml 
apiVersion: v1          ##版本,v1代表稳定版
kind: Pod                       ##类型
metadata:                       ##元数据
  name: pod-new         ##pod的名字
spec:                           ##pod中容器的详细定义
  containers:           ##pod中容器列表,
  - name: con-pod       ##容器名称
    image: nginx        ##容器的镜像

运行

[root@master ~]# kubectl apply -f pod-new.yaml 

pod工作方式

  在K8s中,所有的资源都可以使用一个yaml文件来创建,创建Pod也可以使用yaml配置文件。或者使用kubectl run在命令行创建Pod(不常用)。
自主式pod
所谓的自主式Pod,就是直接定义一个Pod资源
[root@master ~]# vi pod-tomcal.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: tomcat-test
  namespace: default
  labels:
    app: tomcat
spec:
  containers:
  - name: tomcat-java
    ports:
    - containerPort: 8080
    image: xianchao/tomcat-8.5-jre8:v1
    imagePullPolicy: IfNotPresent
    
###导入镜像
[root@node1 ~]# docker load -i tomcat.tar.gz    
[root@node2 ~]# docker load -i tomcat.tar.gz

###更新资源文件
[root@master ~]# kubectl apply -f pod-tomcal.yaml 
pod/tomcat-test created

###查看是否创建成功
[root@master ~]# kubectl get pods -o wide -l app=tomcat
NAME          READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
tomcat-test   1/1     Running   0          51s   10.122.104.4   node2   <none>           <none>

但是自主式Pod是存在一个问题的,假如我们不小心删除了pod:
[root@master ~]# kubectl delete pods tomcat-test
pod "tomcat-test" deleted

#查看pod是否还在
[root@master ~]# kubectl get pods -o wide -l app=tomcat
No resources found in default namespace
###结果是空,说明pod已经被删除

  通过上面可以看到,如果直接定义一个Pod资源,那Pod被删除,就彻底被删除了,不会再创建一个新的Pod,这在生产环境还是具有非常大风险的,所以今后我们接触的Pod,都是控制器管理的。
控制器管理的pod
常见的管理Pod的控制器:Replicaset、Deployment、Job、CronJob、Daemonset、Statefulset。
控制器管理的Pod可以确保Pod始终维持在指定的副本数运行。
如,通过Deployment管理Pod

[root@master ~]# vi tomcat-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-test
  labels:
    app: tomcat-deploy
spec:
  selector:
    matchLabels:
      app: tomcat
  replicas: 2
  template:
    metadata:
      labels:
        app: tomcat
    spec:
      containers:
      - name: my-tomcat
        image: xianchao/tomcat-8.5-jre8:v1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        
        
###更新资源清单
[root@master ~]# kubectl apply -f tomcat-deploy.yaml 
deployment.apps/tomcat-test created

查看deployment
[root@master ~]# kubectl  get deploy -l app=tomcat-deploy
NAME          READY   UP-TO-DATE   AVAILABLE   AGE
tomcat-test   2/2     2            2           67s

查看Replicaset
[root@master ~]# kubectl get rs -l  app=tomcat
NAME                     DESIRED   CURRENT   READY   AGE
tomcat-test-55946f7dbc   2         2         2       89s

##查看pod
[root@master ~]# kubectl get pods -o wide -l app=tomcat
NAME                           READY   STATUS    RESTARTS   AGE    IP             NODE    NOMINATED NODE   READINESS GATES
tomcat-test-55946f7dbc-5dnlc   1/1     Running   0          115s   10.122.104.6   node2   <none>           <none>
tomcat-test-55946f7dbc-z6nld   1/1     Running   0          115s   10.122.104.5   node2   <none>           <none>

###删除tomcat-test-55946f7dbc-5dnlc这个
[root@master ~]# kubectl delete pods tomcat-test-55946f7dbc-5dnlc
pod "tomcat-test-55946f7dbc-5dnlc" deleted

##
[root@master ~]# kubectl get pods -o wide -l app=tomcat
发现重新创建一个新的pod
通过上面可以发现通过deployment管理的pod,可以确保pod始终维持在指定副本数量

###删除之前所有创建的
[root@master ~]# kubectl delete  -f tomcat-deploy.yaml 
deployment.apps "tomcat-test" deleted

pod基本操作

pod帮助

[root@master ~]# kubectl  --help 

###实战--创建命名空间

####创建大部分命令都是create,所以现使用下面命令尝试是否能成功
[root@master ~]# kubectl create --help

####可以看到成功说明此命令正确,可看到命名空间是namespace
[root@master ~]# kubectl create namespace --help
Create a namespace with the specified name.
Aliases:
namespace, ns	##
Examples:
  # Create a new namespace named my-namespace
  kubectl create namespace my-namespace	####创建命令
Usage:		###下面是创建格式
  kubectl create namespace NAME [--dry-run=server|client|none] [options]
  
####可看到上面命令很详细,创建名为test命名空间
[root@master ~]# kubectl create namespace test 
namespace/test created
###上面创建命令可简写
[root@master ~]# kubectl create ns test 
###查看
[root@master ~]# kubectl get  namespace 

创建pod

通过kubectl run创建
[root@master ~]# kubectl run tomcat --image=tomcat --image-pull-policy='IfNotPresent'  --port=8080

默认会在node节点创建所以要在node节点拉取镜像

[root@node1 ~]# docker pull tomcat

查看状态

[root@master ~]# kubectl get pods 
NAME     READY   STATUS    RESTARTS   AGE
tomcat   1/1     Running   0          2m11s
资源清单yum创建
yum书写技巧
###查看api版本
[root@master ~]# kubectl  --help  api.versions
####查看pod资源有哪些字段
[root@master ~]# kubectl explain pod
KIND:     Pod
VERSION:  v1	####kubectl api-versions可查看所以版本

FIELDS:
   apiVersion   <string>	####版本
   
   kind <string>	###Kind是字符串类型的值,代表了要创建的资源
   metadata     <Object>###metadata是对象,定义元数据属性信息
   spec <Object>	###spec制定了定义Pod的规格,里面包含容器的信息
   status   <Object>  ####表示状态,这个不可以修改,定义pod的时候也不需要定义这个字段
   ......
##查看上面pod.metadata字段如何定义
[root@master ~]# kubectl explain pod.metadata
KIND:     Pod
VERSION:  v1

RESOURCE: metadata <Object> ####metadata是对象<Object>,下面可以有多个字段

FIELDS:
   annotations  <map[string]string>	###用来记录信息(build信息、release信息、Docker镜像信息等)
   clusterName  <string>####对象所属群集的名称。这是用来区分不同集群中具有相同名称和命名空间的资源。
   creationTimestamp    <string>
   deletionGracePeriodSeconds   <integer>
   .....
   labels       <map[string]string>		###创建的资源具有的标签,labels是map类型,map类型表示对应的值是key-value键值对,
   name	<string>           #创建的资源的名字
   namespace    <string>	####创建的资源所属的名称空间
   		#### namespaces划分了一个空间,在同一个namesace下的资源名字是唯一的,默认的名称空间是default。
   

###查看pod.spec字段定义
#Pod的spec字段是用来描述Pod的
[root@master ~]# kubectl explain pod.spec
KIND:     Pod
VERSION:  v1

RESOURCE: spec <Object>
	activeDeadlineSeconds        <integer>	####表示Pod可以运行的最长时间,达到设置的值后,Pod会自动停止
	affinity     <Object>		### #定义亲和性的
	automountServiceAccountToken <boolean> 
	containers   <[]Object> -required-	##containers是对象列表,用来定义容器的,是必须字段。对象列表下面的内容用 - 连接。
	
###查看pod.spec.containers字段如何定义
#container是定义在pod里面的,一个pod至少要有一个容器。
[root@master ~]# kubectl explain pod.spec.containers
KIND:     Pod
VERSION:  v1

RESOURCE: containers <[]Object>

	image        <string>	###image是用来指定容器需要的镜像的
	imagePullPolicy      <string>	#镜像拉取策略,pod是要调度到node节点的,那pod启动需要镜像,可以根据这个字段设置镜像拉取策略,支持如下三种:
		Always:不管本地是否存在镜像,都要重新拉取镜像
		Never: 从不拉取镜像
		IfNotPresent:如果本地存在,使用本地的镜像,本地不存在,从官方拉取镜像
	name <string> -required-	#name是必须字段,用来指定容器名字的
	ports        <[]Object>		#port是端口,属于对象列表
	
###查看pod.spec.container.ports字段如何定义
[root@master ~]# kubectl explain pod.spec.containers.ports
KIND:     Pod
VERSION:  v1

RESOURCE: ports <[]Object>
   containerPort        <integer> -required-	#containerPort是必须字段, pod中的容器需要暴露的端口。
   hostIP       <string>	#将容器中的服务暴露到宿主机的端口上时,可以指定绑定的宿主机 IP。
   hostPort     <integer>	#容器中的服务在宿主机上映射的端口
   name <string>	#端口的名字
创建pod
[root@master ~]# cat pod-first.yaml 
apiVersion: v1	#api版本
kind: Pod	#创建的资源
metadata:
  name: pod-first	#Pod的名字
  namespace: default	#Pod所在的名称空间
  labels:
    app: tomcat-pod-first	#Pod具有的标签
spec:
  containers:
  - name: tomcat-first	#Pod里容器的名字
    ports:
    - containerPort: 8080	#容器暴露的端口
    image: tomcat:8.5-jre8-alpine	#容器使用的镜像
    imagePullPolicy: IfNotPresent 	#镜像拉取策略

导入镜像

####创建的pod默认会创建在工作节点node节点上所以在node节点拉取镜像
[root@node1 ~]# docker load -i tomcat.tar.gz

创建

[root@master ~]# kubectl apply -f pod-first.yaml 
pod/pod-first created

查看是否创建成功

[root@master ~]# kubectl get pods
NAME        READY   STATUS    RESTARTS   AGE
pod-first   1/1     Running   0          9s

[root@master ~]# kubectl get pods -o wide -l app=tomcat-pod-first  
NAME        READY   STATUS    RESTARTS   AGE     IP           NODE    NOMINATED NODE   READINESS GATES
pod-first   1/1     Running   0          6m50s   10.244.1.2   node1   <none>           <none>

查看日志

[root@master ~]# kubectl logs pod-first

查看pod里指定容器的日志

[root@master ~]# kubectl logs pod-first -c tomcat-first

进入刚刚创建的容器

[root@master ~]# kubectl exec -it pod-first -- /bin/bash
bash-4.4#

假如pod里有多个容器,进入到pod里的指定容器

[root@master ~]# kubectl exec -it pod-first -c tomcat-first -- /bin/bash
bash-4.4# 

查看pod

###查看pod状态

[root@master ~]# kubectl get pods
NAME            READY   STATUS       RESTARTS   AGE
liveness-exec   1/1     Running      105        98d

###查看指定pod
[root@master ~]# kubectl get pods myapp-pod
###查看所有命名空间下的pod
[root@master yam]# kubectl get pods -A
###持续查看

[root@master ~]# kubectl get pods  -w
###查看指定命名空间下的pod

[root@master ~]# kubectl get pods -n kube-system

###查看有哪些命名空间
[root@master yam]# kubectl get namespace
###查看更多概要信息

[root@master ~]# kubectl get pods -o wide

[root@master ~]# kubectl get pods pod-first -o wide
###多种格式输出

[root@master ~]# kubectl get pods pod-first --output yaml
[root@master ~]# kubectl get pods pod-first --output json
###pod-first:pod名称
###查看详细信息

[root@master ~]# kubectl describe pod pod-first 
###过滤查看

###kubectl get 支持go tempalte方式过滤出指定的信息
###查询pod的完整状态
[root@master ~]# kubectl get pod pod-first --output=go-template --template={{.status.phase}} 
Running
###查看日志
[root@master ~]# kubectl logs pod-first
#持续查看
[root@master ~]# kubectl attach pod-first
##查看pod下容器日志
[root@master ~]# kubectl attach pod-first confirst
###confirst:是创建的容器名称,containers:参数下的
###查看pod支持的字段
[root@master ~]# kubectl explain pod
###继续查看pod中的字段
[root@master ~]# kubectl explain pod.spec 

修改pod

pod中有很多属性不可修改,如containers的image属性,spec下的activeDeadline..等,若一定要修改要加上 --force参数

###更改文件内容
强制执行
[root@master ~]# kubectl apply -f pod-first.yaml --force #强制修改

删除

[root@master ~]# kubectl delete  pod-first

###若有依赖关系可直接使用文件进行删除
[root@master ~]# kubectl delete -f pod-first.yaml 

###删除全部
[root@master ~]# kubectl delete pod --all

登入

[root@master ~]# kubectl get pods 
NAME                          READY   STATUS    RESTARTS   AGE
pod-first                     1/1     Running   0          4s

[root@master ~]# kubectl exec -it  pod-first  -- bash

###登入到pod中的指定容器
[root@master ~]# kubectl exec -it   pod-first -c tomcat-first -- bash 
bash-4.4# 

拷贝

#####从本地中拷贝文件到容器中
[root@master ~]# kubectl cp pod-first:/root /bach
tar: removing leading '/' from member names	###报错



###本地拷贝到容器
# kubectl cp /tmp/nginx.log nginx:/tmp/nginx.log
# kubectl exec nginx cat /tmp/nginx.log

pod与容器

(1)volumeMounts配置信息

pod中的容器可以访问共同的数据卷来实现文件系统的共享。所以kubernetes中的数据卷是pod级别的,而不是容器级别的。pod中的容器可以访问共同的数据卷,实现容器间的数据共享。

EmptyDir

[root@master ~]# cat pod-volume.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: exam-volume
spec:
  containers:
  - name: con-write		#容器1,向数据卷写入数据------
    image: mysql:5.7
    imagePullPolicy: IfNotPresent
    command: ['sh','-c']
    args: ['echo "test data!"; > /write_dir/data ; sleep 3600']
    volumeMounts:
    - name: filedata		#引用下面存储卷
      mountPath: /write_dir		#存储卷在容器内挂载的绝对路径

  - name: con-read			#容器2----------------
    image: mysql:5.7
    imagePullPolicy: IfNotPresent
    command: ['sh','-c']
    args: ['cat /read_dir/data; sleep 3600']
    volumeMounts:
    - name: filedata		#引用下面
      mountPath: /read_dir		#容器内数据卷地址
  volumes:			#创建存储卷-----------------------
  - name: filedata	#被容器设置中的数据卷所引用
    emptyDir: {}	#类型emptyDir
[root@master ~]# kubectl apply -f pod-volume.yaml 
[root@master ~]# kubectl get pods 
NAME                          READY   STATUS    RESTARTS   AGE
exam-volume                   2/2     Running   0          5s

###查看pod中con-write容器
[root@master ~]# kubectl logs  exam-volume con-write
test data!

[root@master ~]# kubectl logs  exam-volume con-read
####此实验没有共享一个目录所有目的只是实现一个容器读一个容器写,而不是第一个容器写入第二个容器读取

----本列创建了两个容器。一个存储卷

​ 1con-write,它向数据卷写入数据,会向/write_dir/data文件写入test data文本,

创建pod容器内数据卷地址为/write_dir,它引用的存储卷为filedata

​ 2con-read,会从/read_dir/data文件中读取文本,并将其输出到控制台,容器内数据卷地址为/read_dir,它引用的存储卷为filedata

进入容器

root@master ~]# kubectl  exec -it  exam-volume   con-write -- /bin/bash  

在宿主机中查看

###在pod所创建在的主机上查看此处是node1
###在/var/lib/kubelet/pods目录中查看


实例2

HostDir

在宿主机上指定一个目录,挂载到Pod的容器中

[root@master ~]# cat pod-volume2.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: con-volume2
spec:
  containers:
  - name: con-writer2
    image: mysql:5.7
    imagePullPolicy: IfNotPresent
    command: ['sh','-c']
    args: ['echo "hello worlds"; >> /data/hello ; sleep 3600']
    volumeMounts:
      - name: data
        mountPath: /data

  - name: con-read2
    image: mysql:5.7
    imagePullPolicy: IfNotPresent
    command: ['sh','-c']
    args: ['cat /data/hello; sleep 3600']
    volumeMounts:
      - name: data
        mountPath: /data
  volumes:
  - name: data
    hostPath:
      path: /home
[root@master ~]# kubectl apply -f pod-volume2.yaml 

###
###此处是挂载在物理机中,挂载在pod所创建的节点本处是node1的/home节点

问题:共享的数据卷,和con-writer2没什么关系,使用lkubectl logs查看输出之前输入的内容,而查看con-read2却查看不到,对挂载在/home的卷操作,进如两个容器中查看,可以查看到但使用logs查看又是显示之前输入的内容

(2)ports配置信息

使用宿主机端口需要考虑端口冲突,幸运的是kubernetes在调度pod的时候,会检查宿主机端口是否冲突。若端口冲突,调度时就会将这两个pod调度到不同node上。若所以node端口都被占用,那么pod调度就会失败。

暴露端口,并映射到主机

[root@master ~]# cat pod-port.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: exam-port2
spec:
  containers:
  - name: exam-nginx2
    image: daocloud.io/library/nginx:1.13.2
    imagePullPolicy: IfNotPresent
    ports:
    - name: portfoxnginx
      containerPort: 80
      hostPort: 8088
      protocol: TCP
[root@master ~]# kubectl apply -f pod-port.yaml  

查看运行

[root@master ~]# kubectl get pods -o wide
NAME         READY   STATUS        RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATES
exam-port2   1/1     Running       0          4m47s   10.244.0.6   master   <none>           <none>
###此处运行在master节点上,因为node节点上8088端口已使用

查看详细信息

[root@master ~]# kubectl describe  pods  exam-port2

访问

[root@master ~]# curl 192.168.200.80:8088 

(3)env配置信息

[root@master ~]# cat pod-env.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: exam-env
spec:
  containers:
  - name: con-env
    image: mysql:5.7
    imagePullPolicy: IfNotPresent
    env:		###环境变量
    - name: para1
      value: "good moring!"
    - name: para2
      value: "good might"
    command: ['sh','-c']
    args: ['echo "${para1} ${para2}";sleep 3600']
##上面环境变量类似于:
parameter1=good morning!
parameter2=good might!

----模板中定义了一个名为containerforenv的容器,向他传入了两个环境变量,

---将传入的两个环境变量拼接到一起

[root@master ~]# kubectl apply -f pod-env.yaml 

查看输出日志

[root@master ~]# kubectl get pods 
NAME       READY   STATUS    RESTARTS   AGE
exam-env   1/1     Running   0          5m25s

[root@master ~]# kubectl logs exam-env
good moring! good might

过滤环境变量

[root@master ~]# kubectl exec exam-env env | grep para
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
para2=good might
para1=good moring!
[root@master ~]# kubectl describe pod exam-env
    Environment:
      para1:  good moring!
      para2:  good might

(4)pod的网络

[root@master ~]# kubectl get pod exam-env --template={{.status.podIP}}
10.244.1.3
#####exam-env pod名称

定义的pod设置为host网络模式

[root@master ~]# cat pod-host.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: exam-host
spec:
  containers:
  - name: cont-host
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - name: web
      containerPort: 80
      protocol: TCP
  hostNetwork: true
[root@master ~]# kubectl apply -f pod-host.yaml 
[root@master ~]# kubectl get pod exam-host --template={{.status.podIP}}
192.168.200.30
###此pod使用的是node节点宿主机的ip

命名空间

概念

Kubernetes 支持多个虚拟集群,它们底层依赖于同一个物理集群。 这些虚拟集群被称为命名空间。

命名空间namespace是k8s集群级别的资源,可以给不同的用户、租户、环境或项目创建对应的命名空间,例如,可以为test、devlopment、production环境分别创建各自的命名空间。

namespace应用场景

命名空间适用于存在很多跨多个团队或项目的用户的场景。

名称空间及其资源对象

k8s集群默认提供了几个名称空间用于特定目的,例如,kube-system主要用于运行系统级资源,存放k8s一些组件的。而default则为那些未指定名称空间的资源操作提供一个默认值。

查看namespace资源

[root@master ~]# kubectl get namespace
#namespace:可简写为ns

查看特定的命名空间详细信息

[root@master ~]# kubectl describe namespace $NAME 

查看指定命名空间

[root@master ~]# kubectl get pods -n kube-system

删除命名空间

###test是要自己手动创建的
[root@master ~]# kubectl delete ns test

管理namespace资源

namespace资源属性较少,通常只需要指定名称即可创建,如“kubectl create namespace qa”。namespace资源的名称仅能由字母、数字、下划线、连接线等字符组成。删除namespace资源会级联删除其包含的所有其他资源对象。

namespace使用案例

创建一个test命名空间

[root@master ~]# kubectl  create ns test
namespace/test created

切换命名空间

####切换到kube-system的命名空间
[root@master ~]# kubectl config set-context --current --namespace=kube-system
Context "kubernetes-admin@kubernetes" modified.
####切换命名空间后,kubectl get pods 如果不指定-n,查看的就是kube-system命名空间的资源了。

查看哪些资源属于命名空间级别的

[root@master ~]# kubectl api-resources --namespace=true

使用yaml文件创建命名空间

[root@master ~]# cat kube-name.yaml 
kind: Namespace
apiVersion: v1
metadata:
  name: kube-logging
[root@master ~]# kubectl apply -f kube-name.yaml 

###查看
[root@master ~]# kubectl get ns 

namespace资源限额

namespace是命名空间,里面有很多资源,那么我们可以对命名空间资源做个限制,防止该命名空间部署的资源超过限制。

[root@master ~]# cat namespace-quota.yaml 
apiVersion: v1
kind: ResourceQuota
metadata:
  name: mem-cpu-quota
  namespace: test	###使用命名空间
spec:
  hard:
    requests.cpu: "2"
    requests.memory: 2Gi
    limits.cpu: "4"
    limits.memory: 4Gi
    

####创建前要先有test不然可能会出错
    
-----
#创建的ResourceQuota对象将在test命名空间中添加以下限制:
每个容器必须设置内存请求(memory request),内存限额(memory limit),cpu请求(cpu request)和cpu限额(cpu limit)。
  所有容器的CPU请求总额不得超过2 CPU。
  所有容器的内存请求总额不得超过2GiB。
  所有容器的CPU限额总额不得超过4CPU。
  所有容器的内存限额总额不得超过4 GiB。

创建pod时候必须设置资源限额,否则创建失败,

[root@master ~]# cat pod-first.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  namespace: test	###使用上面做了限制的命名空间
  labels:
    app: tomcat-pod-first
spec:
  containers:
  - name: tomcat-first
    ports:
    - containerPort: 8080
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent  
[root@master ~]# kubectl apply -f pod-first.yaml 
pod/pod-first created

[root@master ~]# kubectl get pods -n test
NAME        READY   STATUS    RESTARTS   AGE
pod-first   1/1     Running   0          25s

标签

概念

标签其实就一对 key/value ,被关联到对象上,标签可以在创建一个对象的时候直接定义,也可以在后期随时修改,每一个对象可以拥有多个标签,但是,key值必须是唯一的。创建标签之后也可以方便我们对资源进行分组管理。如果对pod打标签,之后就可以使用标签来查看、删除指定的pod。

给pod打上标签

######因为上面给这个pod更改默认命名空间了所以查看要加-n test
###查看
[root@master ~]# kubectl get pods -n test
NAME        READY   STATUS    RESTARTS   AGE
pod-first   1/1     Running   0          6m35s

####打标签(给pod-first打上标签)
[root@master ~]# kubectl label pods pod-first release=v1 -n test
pod/pod-first labeled

####若没加命名空间默认命名空间
[root@master ~]# kubectl label pods pod-first release=v1

查看标签

#####若时默认命名空间此处不用加上-n test
[root@master ~]# kubectl get pods pod-first --show-labels -n test
NAME        READY   STATUS    RESTARTS   AGE     LABELS
pod-first   1/1     Running   0          7m54s   app=tomcat-pod-first,release=v1

创建pod时打标签

[root@master ~]# cat pod-label.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-nginx
  labels:
     version: "3.0"
     env: "test"
spec:
  containers:
  - image: nginx
    name: con-pod
    ports:
    - name: nginx-port
      containerPort: 801
      protocol: TCP
[root@master ~]# kubectl apply -f pod-label.yaml 

查看此pod标签

[root@master ~]# kubectl get pods 
NAME        READY   STATUS             RESTARTS   AGE
pod-nginx   1/1     Running            0          5m51s
###查看所以pod标签
[root@master ~]# kubectl get pods --show-labels 
NAME        READY   STATUS             RESTARTS   AGE     LABELS
pod-nginx   1/1     Running            0          2m20s   env=test,version=3.0
##查看指定标签
[root@master ~]# kubectl get pods pod-nginx  --show-labels  

查看资源标签

更换默认命名空间

此步可不做
[root@master ~]# kubectl config set-context --current --namespace=test
Context "kubernetes-admin@kubernetes" modified.

查看节点命名空间

[root@master ~]# kubectl get nodes --show-labels 

查看默认命名空间下所有资源pod标签

[root@master ~]# kubectl get pods --show-labels

#查看默认名称空间下指定pod具有的所有标签

#####上面更换了默认命名空间所以此处执行会报错,正确要加:-n test
[root@master ~]# kubectl get pods pod-first --show-labels 

#列出默认名称空间下标签key是release的pod,不显示标签

[root@master ~]# kubectl get pods -l release

#列出默认名称空间下标签key是release、值是v1的pod,不显示标签

[root@master ~]# kubectl get pods -l release=v1

列出默认名称空间下标签key是release的所有pod

[root@master ~]# kubectl get pods -L release

#查看所有名称空间下的所有pod的标签

[root@master ~]# kubectl get pods --all-namespaces --show-labels
[root@master ~]# kubectl get pods -l release=v1 -L release

pod资源清单详细解读

apiVersion: v1       #版本号,例如v1
kind: Pod       #资源类型,如Pod
metadata:       #元数据
  name: string       # Pod名字
  namespace: string    # Pod所属的命名空间
  labels:      #自定义标签
    - name: string     #自定义标签名字
  annotations:       #自定义注释列表
    - name: string
    
spec:         # Pod中容器的详细定义
  containers:      # Pod中容器列表
  - name: string     #容器名称
    image: string    #容器的镜像名称
    imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
    command: [string]    #容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]     #容器的启动命令参数列表
    workingDir: string     #容器的工作目录
    volumeMounts:    #挂载到容器内部的存储卷配置
    - name: string     #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string    #存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean    #是否为只读模式
    ports:       #需要暴露的端口库号
    - name: string     #端口号名称
      containerPort: int   #容器需要监听的端口号
      hostPort: int    #容器所在主机需要监听的端口号,默认与Container相同
      protocol: string     #端口协议,支持TCP和UDP,默认TCP
    env:       #容器运行前需设置的环境变量列表
    - name: string     #环境变量名称
      value: string    #环境变量的值
    resources:       #资源限制和请求的设置
      limits:      #资源限制的设置
        cpu: string    #cpu的限制,单位为core数
        memory: string     #内存限制,单位可以为Mib/Gib
      requests:      #资源请求的设置
        cpu: string    #cpu请求,容器启动的初始可用数量
        memory: string     #内存请求,容器启动的初始可用内存
    livenessProbe:     #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
      exec:      #对Pod容器内检查方式设置为exec方式
        command: [string]  #exec方式需要制定的命令或脚本
      httpGet:       #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:     #对Pod内个容器健康检查方式设置为tcpSocket方式
         port: number
       initialDelaySeconds: 0  #容器启动完成后首次探测的时间,单位为秒
       timeoutSeconds: 0   #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
       periodSeconds: 0    #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged:false
    restartPolicy: [Always | Never | OnFailure]#Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
    nodeSelector: obeject  #设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
    imagePullSecrets:    #Pull镜像时使用的secret名称,以key:secretkey格式指定
    - name: string
    hostNetwork:false      #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
    volumes:       #在该pod上定义共享存储卷列表
    - name: string     #共享存储卷名称 (volumes类型有很多种)
      emptyDir: {}     #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
      hostPath: string     #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
        path: string     #Pod所在宿主机的目录,将被用于同期中mount的目录
      secret:      #类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
        scretname: string  
        items:     
        - key: string
          path: string
      configMap:     #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
        name: string
        items:
        - key: string
          path: string

node节点选择器

在创建pod资源的时候,pod会根据schduler进行调度,那么默认会调度到随机的一个工作节点,如果我们想要pod调度到指定节点或者调度到一些具有相同特点的node节点,可以使用pod中的nodeName或者nodeSelector字段指定要调度到的node节点

nodeName

查看节点

[root@master ~]# kubectl get nodes
NAME     STATUS   ROLES    AGE   VERSION
master   Ready    master   16d   v1.18.1
node1    Ready    <none>   16d   v1.18.1

编写文件指定运行在master节点

[root@master ~]# cat pod-master.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: demo-pod
  namespace: default
  labels:
    app: myapp
    env: dev
spec:
  nodeName: master	###指定在master节点
  containers:
  - name: tomcat-pod-java
    ports:
    - containerPort: 8081
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
  - name: busybox
    image: busybox:latest
    command:
    - "/bin/sh"
    - "-c"
    - "sleep 3600"

拉取镜像

###在master节点拉取:因为文件中指定在master中创建
[root@master ~]# docker load -i busybox.tar.gz
[root@master ~]# docker load -i tomcat.tar.gz 
[root@master yam]# kubectl apply -f pod-master.yaml 

查看

##可看到上面创建的在master节点
[root@master ~]# kubectl  get pods -o wide
NAME        READY   STATUS    RESTARTS   AGE    IP           NODE     NOMINATED NODE   READINESS GATES
demo-pod    2/2     Running   0          2m2s   10.244.0.6   master   <none>           <none>

nodeSelector

指定pod调度到具有哪些标签的node节点上

查看节点

[root@master ~]# kubectl get nodes                  
NAME     STATUS   ROLES    AGE   VERSION
master   Ready    master   16d   v1.18.1
node1    Ready    <none>   16d   v1.18.1

#给node节点打标签,打个具有disk=ceph的标签

[root@master ~]# kubectl label nodes node1 disk=ceph
node/node1 labeled

#定义pod的时候指定要调度到具有disk=ceph标签的node上

[root@master ~]# cat pod-node1.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: demo-pod-1
  namespace: default
  labels:
    app: myapp
    env: dev
spec:
  nodeSelector:
    disk: ceph	###指定到含有ceph标签的节点上
  containers:
  - name: tomcat-pod-java
    ports:
    - containerPort: 8083
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
[root@master ~]# kubectl apply -f pod-node1.yaml 
pod/demo-pod-1 created

查看

[root@master ~]# kubectl get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE    IP           NODE     NOMINATED NODE   READINESS GATES
demo-pod-1   1/1     Running   0          13s    10.244.1.4   node1    <none>           <none>

污点和容忍度

node节点亲和性

node节点亲和性调度:nodeAffinity

###查看文档
[root@master ~]# kubectl explain pods.spec.affinity
KIND:     Pod
VERSION:  v1

RESOURCE: affinity <Object>
FIELDS:
   nodeAffinity <Object>
   podAffinity  <Object>
   podAntiAffinity      <Object>
[root@master ~]# kubectl explain pods.spec.affinity.nodeAffinity
KIND:     Pod
VERSION:  v1

RESOURCE: nodeAffinity <Object>

DESCRIPTION:
   preferredDuringSchedulingIgnoredDuringExecution      <[]Object>
   requiredDuringSchedulingIgnoredDuringExecution       <Object>
   
   prefered表示有节点尽量满足这个位置定义的亲和性,这不是一个必须的条件,软亲和性
   require表示必须有节点满足这个位置定义的亲和性,这是个硬性条件,硬亲和性

[root@master ~]# kubectl  explain pods.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution
KIND:     Pod
VERSION:  v1
FIELDS:
   nodeSelectorTerms    <[]Object> -required-
[root@master ~]# kubectl  explain pods.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms
KIND:     Pod
VERSION:  v1
FIELDS:
   matchExpressions     <[]Object>
   matchFields  <[]Object>
[root@master ~]# kubectl  explain pods.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms.matchFields
KIND:     Pod
VERSION:  v1
FIELDS:
   key  <string> -required-
   operator     <string> -required-
   values       <[]string>
   
[root@master ~]# kubectl  explain pods.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms.matchExpressions
KIND:     Pod
VERSION:  v1
FIELDS:
   key  <string> -required-		###检查label
   operator     <string> -required-	###做等值选则还是不等值选则
   values       <[]string>	###给定值
   

例1:使用requiredDuringSchedulingIgnoredDuringExecution硬亲和性

​ 硬亲和:若节点没有和标签相同的则不运行

在node1节点拉取镜像

[root@node1 ~]# docker load -i myapp-v1.tar.gz
[root@master ~]# cat pod-nodeaffinity-demo.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-node-affinity-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
  affinity:					#####
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: zone	###检查zone标签
            operator: In
            values:
            - foo	###值
            - bar	###值
            
#####我们检查当前节点中有任意一个节点拥有zone标签的值是foo或者bar,就可以把pod调度到这个node节点的foo或者bar标签上的节点上
[root@master ~]# kubectl apply -f pod-nodeaffinity-demo.yaml 
pod/pod-node-affinity-demo created

查看

[root@master ~]# kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
pod-node-affinity-demo   0/1     Pending   0          7s    <none>   <none>   <none>           <none>

status的状态是pending,上面说明没有完成调度,因为没有一个拥有zone的标签的值是foo或者bar,而且使用的是硬亲和性,必须满足条件才能完成调度

###给node1节点打zone标签,值为foo
[root@master ~]# kubectl label nodes node1 zone=foo
node/node1 labeled

[root@master ~]# kubectl get pods -o wide          
NAME                     READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
pod-node-affinity-demo   1/1     Running   0          58s   10.244.1.5   node1   <none>           <none>

扩展--参数编写技巧

[root@master ~]# kubectl explain pod.spec| grep affi

例2:使用preferredDuringSchedulingIgnoredDuringExecution软亲和性

​ 软亲和:优先在节点找和标签相同的没有也会运行

[root@master ~]# cat pod-nodeaffinity-demo-2.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-node-affinity-demo-2
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - preference:
          matchExpressions:
          - key: zone1
            operator: In
            values:
            - fool
            - barl
        weight: 60
[root@master ~]# kubectl apply -f pod-nodeaffinity-demo-2.yaml
pod/pod-node-affinity-demo-2 created
[root@master ~]# kubectl get pods -o wide 
NAME                       READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
pod-node-affinity-demo-2   1/1     Running   0          17s   10.244.1.6   node1   <none>           <none>

####上面说明软亲和性是可以运行这个pod的,尽管没有运行这个pod的节点定义的zone1标签

Node节点亲和性针对的是pod和node的关系,Pod调度到node节点的时候匹配的条件

pod节点亲和性

pod自身的亲和性调度有两种表示形式

podaffinity:pod和pod更倾向腻在一起,把相近的pod结合到相近的位置,如同一区域,同一机架,这样的话pod和pod之间更好通信

podunaffinity:pod和pod更倾向不腻在一起,如果部署两套程序,那么这两套程序更倾向于反亲和性,这样相互之间不会有影响。

第一个pod随机选则一个节点,做为评判后续的pod能否到达这个pod所在的节点上的运行方式,这就称为pod亲和性;

以节点名称为标准,这个节点名称相同的表示是同一个位置,节点名称不相同的表示不是一个位置。

[root@master ~]#  kubectl explain pods.spec.affinity.podAffinity
KIND:     Pod
VERSION:  v1
FIELDS:
   preferredDuringSchedulingIgnoredDuringExecution      <[]Object>
   requiredDuringSchedulingIgnoredDuringExecution       <[]Object>
   
   
   requiredDuringSchedulingIgnoredDuringExecution: 硬亲和性
   preferredDuringSchedulingIgnoredDuringExecution:软亲和性
[root@master ~]# kubectl explain pods.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution
KIND:     Pod
VERSION:  v1
FIELDS:
   labelSelector        <Object>
   namespaces   <[]string>
   topologyKey  <string> -required-		###位置拓扑的键,这个是必须字段

怎么判断是不是同一个位置:
rack=rack1
row=row1
使用rack的键是同一个位置
使用row的键是同一个位置

labelSelector:
我们要判断pod跟别的pod亲和,跟哪个pod亲和,需要靠labelSelector,通过labelSelector选则一组能作为亲和对象的pod资源

namespace:
labelSelector需要选则一组资源,那么这组资源是在哪个名称空间中呢,通过namespace指定,如果不指定namespaces,那么就是当前创建pod的名称空间

[root@master ~]# kubectl explain pods.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.labelSelector 
KIND:     Pod
VERSION:  v1
FIELDS:
   matchExpressions     <[]Object>
   matchLabels  <map[string]string>

例1:pod节点亲和性

定义两个pod,第一个pod做为基准,第二个pod跟着它走

[root@master ~]# kubectl delete pods pod-first                         
[root@master ~]# cat pod-required-affinity-demo.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  labels:
    app2: myapp2
    tier: frontend
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1

---
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
  labels:
    app: backup
    tier: db
spec:
    containers:
    - name: busybox
      image: busybox:latest
      imagePullPolicy: IfNotPresent
      command: ["sh","-c","sleep 3600"]
    affinity:
      podAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
            - {key: app2, operator: In, values: ["myapp2"]}
          topologyKey: kubernetes.io/hostname

#上面表示创建的pod必须与拥有app=myapp标签的pod在一个节点上

[root@master ~]# kubectl apply -f pod-required-affinity-demo.yaml 
pod/pod-first created
pod/pod-second created

查看

[root@master ~]# kubectl get pods -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
pod-first                  1/1     Running   0          15s   10.244.1.7   node1   <none>           <none>
pod-second                 1/1     Running   0          15s   10.244.1.8   node1   <none>           <none>

###查看标签
[root@master ~]# kubectl get pods --show-labels
NAME                       READY   STATUS    RESTARTS   AGE   LABELS
pod-first                  1/1     Running   0          80s   app2=myapp2,tier=frontend
pod-second                 1/1     Running   0          80s   app=backup,tier=db

上面说明第一个pod调度到哪,第二个pod也调度到哪,这就是pod节点亲和性

####删除
[root@master ~]# kubectl delete -f pod-required-affinity-demo.yaml 

例2:pod节点反亲和性

定义两个pod,第一个pod做为基准,第二个pod跟它调度节点相反

[root@master ~]# cat pod-required-anti-affinity-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  labels:
    app1: myapp1
    tier: frontend
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1

---
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
  labels:
    app: backend
    tier: db
spec:
  containers:
  - name: busybox
    image: busybox:latest
    command: ["sh","-c","sleep 3600"]
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - {key: app1, operator: In, values: ["myapp1"]}
        topologyKey: kubernetes.io/hostname
[root@master ~]# kubectl apply -f pod-required-anti-affinity-demo.yaml 
pod/pod-first unchanged
pod/pod-second created
[root@master ~]# kubectl get pods -o wide
NAME                       READY   STATUS              RESTARTS   AGE    IP           NODE     NOMINATED NODE   READINESS GATES
pod-first                  1/1     Running             0          113s   10.244.1.9   node1    <none>           <none>
pod-second                 0/1     ContainerCreating   0          11s    <none>       master   <none>           <none>
#####删除
[root@master ~]# kubectl delete -f pod-required-anti-affinity-demo.yaml 

例3:换一个topologykey

[root@master ~]# kubectl label nodes node1 zone=foo
[root@master ~]# kubectl label nodes master zone=foo --overwrite

[root@master ~]# kubectl get nodes --show-labels 
[root@master ~]# cat pod-first-required-anti-affinity-demo-1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  labels:
    app3: myapp3
    tier: frontend
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
[root@master ~]#  cat pod-second-required-anti-affinity-demo-1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
  labels:
    app: backend
    tier: db
spec:
  containers:
  - name: busybox
    image: busybox:latest
    imagePullPolicy: IfNotPresent
    command: ["sh","-c","sleep 3600"]
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - {key: app3 ,operator: In, values: ["myapp3"]}
        topologyKey:  zone
[root@master ~]# kubectl apply -f pod-first-required-anti-affinity-demo-1.yaml 
pod/pod-first created
[root@master ~]# kubectl apply -f pod-second-required-anti-affinity-demo-1.yaml 
pod/pod-second created
[root@master ~]# kubectl get pods -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-first                  1/1     Running   0          19s   10.244.1.10   node1    <none>           <none>
pod-second                 0/1     Pending   0          9s    <none>        <none>   <none>           <none>

第二个节点现是pending,因为两个节点是同一个位置,现在没有不是同一个位置的了,而且我们要求反亲和性,所以就会处于pending状态,如果在反亲和性这个位置把required改成preferred,那么也会运行。

podaffinity:pod节点亲和性,pod倾向于哪个pod

nodeaffinity:node节点亲和性,pod倾向于哪个node

污点,容忍度

给了节点选则的主动权,我们给节点打一个污点,不容忍的pod就运行不上来,污点就是定义在节点上的键值属性数据,可以决定拒绝那些pod;

taints是键值数据,用在节点上,定义污点;

tolerations是键值数据,用在pod上,定义容忍度,能容忍哪些污点

pod亲和性是pod属性;但是污点是节点的属性,污点定义在nodeSelector上

查看master节点是否有污点

[root@master ~]# kubectl describe nodes master
Taints:             <none>	###可看到master节点没有污点

[root@master ~]# kubectl explain node.spec.taints
KIND:     Node
VERSION:  v1
FIELDS:
   effect       <string> -required-
   key  <string> -required-
   timeAdded    <string>
   value        <string>

在pod对象定义容忍度的时候支持两种操作:

1.等值密钥:key和value上完全匹配

2.存在性判断:key和effect必须同时匹配,value可以是空

在pod上定义的容忍度可能不止一个,在节点上定义的污点可能多个,需要琢个检查容忍度和污点能否匹配,每一个污点都能被容忍,才能完成调度,如果不能容忍,那就需要看pod的容忍度了

查看pod容忍度

[root@master ~]# kubectl describe pods kube-apiserver-master -n kube-system
Node-Selectors:    <none>
Tolerations:       :NoExecute
Events:

可以看到这个pod的容忍度是NoExecute,则可以调度到master上

管理节点污点

[root@master ~]# kubectl taint --help

例1:把node1当成是生产环境专用的,其他node是测试的

[root@master ~]# kubectl taint node node1 node-type=production:NoSchedule
node/node1 tainted

给node1打污点,pod如果不能容忍就不会调度过来)

[root@master ~]# cat pod-taint.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: taint-pod
  namespace: default
  labels:
    tomcat: tomcat-pod
spec:
  containers:
  - name: taint-pod
    ports:
    - containerPort: 8083
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
[root@master ~]# kubectl apply -f pod-taint.yaml

[root@master ~]# kubectl get pods -o wide        
NAME        READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
taint-pod   1/1     Running   0          74s   10.244.0.6   master   <none>           <none>

可以看到都被调度到master上了,因为node1这个节点打了污点,而我们在创建pod的时候没有容忍度,所以node1上不会有pod调度上去的

例2:给master也打上污点

[root@master ~]# kubectl taint node master node-type=dev:NoExecute
node/master tainted
[root@master ~]# kubectl get pods -o wide
可以看到已经存在的pod节点都被撵走了
[root@master ~]# cat pod-demo-1.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: myapp-deploy
  namespace: default
  labels:
    app: myapp
    release: canary
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 83
  tolerations:
  - key: "node-type"
    operator: "Equal"
    value: "production"
    effect: "NoExecute"
    tolerationSeconds: 3600
[root@master ~]# kubectl apply -f pod-demo-1.yaml  
pod/myapp-deploy created
[root@master ~]# kubectl get pods 
NAME           READY   STATUS    RESTARTS   AGE
myapp-deploy   0/1     Pending   0 

还是显示pending,因为我们使用的是equal(等值匹配),所以key和value,effect必须和node节点定义的污点完全匹配才可以,把上面配置effect: "NoExecute"变成

effect: "NoSchedule"; tolerationSeconds: 3600这行去掉

[root@master ~]# kubectl delete -f pod-demo-1.yaml 
[root@master ~]# vi pod-demo-1.yaml
...
    value: "production"
    effect: "NoSchedule"
[root@master ~]# kubectl apply -f pod-demo-1.yaml

[root@master ~]# kubectl get pods 
NAME           READY   STATUS    RESTARTS   AGE
myapp-deploy   1/1     Running   0          5s

上面就可以调度到node上了,因为在pod中定义的容忍度能容忍node节点上的污点

例3:再次修改

[root@master ~]# kubectl delete -f pod-demo-1.yaml
[root@master ~]# vi pod-demo-1.yaml 
  tolerations:
  - key: "node-type"
    operator: "Exists"
    value: ""
    effect: "NoSchedule"

只要对应的键是存在的,exists,其值被自动定义成通配符

[root@master ~]# kubectl apply -f pod-demo-1.yaml 


[root@master ~]# kubectl get pods -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
myapp-deploy   1/1     Running   0          19s   10.244.1.3   node1   <none>           <none>

发现还是调度到node1上

再次修改:

[root@master ~]# kubectl delete -f pod-demo-1.yaml 
[root@master ~]# vi pod-demo-1.yaml 
  tolerations:
  - key: "node-type"
    operator: "Exists"
    value: ""
    effect: ""

有一个node-type的键,不管值是什么,不管是什么效果,都能容忍

[root@master ~]# kubectl apply -f pod-demo-1.yaml 

[root@master ~]# kubectl get pods -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
myapp-deploy   1/1     Running   0          8s    10.244.1.4   node1   <none>           <none>

node1和master节点都有可能有pod被调度

删除污点

查看

[root@master ~]# kubectl describe nodes master | grep Taints
Taints:             node-type=dev:NoExecute

删除

[root@master ~]# kubectl taint nodes master node-type=dev:NoExecute-

[root@master ~]# kubectl taint nodes node1 node-type-

pod常见状态和重启策略

常见状态

Pod的status定义在PodStatus对象中,其中有一个phase字段。它简单描述了Pod在其生命周期的阶段。

挂起(Pending):我们在请求创建pod时,条件不满足,调度没有完成,没有任何一个节点能满足调度条件,已经创建了pod但是没有适合它运行的节点叫做挂起,调度没有完成,处于pending的状态会持续一段时间:包括调度Pod的时间和通过网络下载镜像的时间。

运行中(Running):Pod已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。

成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。

失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。

未知(Unknown):未知状态,所谓pod是什么状态是apiserver和运行在pod节点的kubelet进行通信获取状态信息的,如果节点之上的kubelet本身出故障,那么apiserver就连不上kubelet,得不到信息了,就会看Unknown

扩展

Evicted状态:出现这种情况,多见于系统内存或硬盘资源不足,可df-h查看docker存储所在目录的资源使用情况,如果百分比大于85%,就要及时清理下资源,尤其是一些大文件、docker镜像。

CrashLoopBackOff:容器曾经启动了,但可能又异常退出了

Error 状态:Pod 启动过程中发生了错误

重启策略

pod的重启策略是指当pod中的容器中终止退出后,重启容器的策略。
重器容器的做法实际上就是重建容器,所有容器中数据会丢失。

Pod的重启策略(RestartPolicy)应用于Pod内的所有容器,并且仅在Pod所处的Node上由kubelet进行判断和重启操作。

Pod的重启策略包括:Always、OnFailure和Never,默认值为Always

Always:当容器失败时,由kubelet自动重启该容器。

OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启该容器。

Never:不论容器运行状态如何,kubelet都不会重启该容器。

[root@master ~]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: demo-pod
  namespace: default
  labels:
    app: myapp
spec:
  restartPolicy: Always		#####重启策略
  containers:
  - name: tomcat-pod-java
    ports:
    - containerPort: 8084
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
[root@master ~]# kubectl apply -f pod.yaml

创建一个pod,其中的容器将异常退出(exit 1)

[root@master ~]# cat pod-exit.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: exam-exit
spec:
  containers:
  - name: con-exit
    image: mysql:5.7
    command: ["bash","-c","exit 1"]
  restartPolicy: OnFailure
[root@master ~]# kubectl apply -f pod-exit.yaml
[root@master ~]# kubectl get pods  -w
NAME        READY   STATUS             RESTARTS   AGE
exam-exit   0/1     CrashLoopBackOff   1          7s
exam-exit   0/1     Error              2          19s
exam-exit   0/1     CrashLoopBackOff   2          33s

查询每个容器的重启次数

[root@master ~]# kubectl get pod  exam-exit --template="{{range .status.containerStatuses}}{{.name}}:{{.restartCount}}{{end}}"  
con-exit:5

pod生命周期

pod的生命周期可用简单描述为,首先pod被创建,接着pod被调度到node进行部署运行。

Init容器

Pod 里面可以有一个或者多个容器,部署应用的容器可以称为主容器,在创建Pod时候,Pod 中可以有一个或多个先于主容器启动的Init容器,这个init容器就可以成为初始化容器,初始化容器一旦执行完,它从启动开始到初始化代码执行完就退出了,它不会一直存在,所以在主容器启动之前执行初始化,初始化容器可以有多个,多个初始化容器是要串行执行的,先执行初始化容器1,在执行初始化容器2等,等初始化容器执行完初始化就退出了,然后再执行主容器,主容器一退出,pod就结束了,主容器退出的时间点就是pod的结束点,它俩时间轴是一致的;

Init容器就是做初始化工作的容器。可以有一个或多个,如果多个按照定义的顺序依次执行,只有所有的初始化容器执行完后,主容器才启动。由于一个Pod里的存储卷是共享的,所以Init Container里产生的数据可以被主容器使用到,Init Container可以在多种K8S资源里被使用到,如Deployment、DaemonSet, StatefulSet、Job等,但都是在Pod启动时,在主容器启动前执行,做初始化工作。

Init容器与普通的容器区别是:

1、Init 容器不支持 Readiness,因为它们必须在Pod就绪之前运行完成

2、每个Init容器必须运行成功,下一个才能够运行

3、如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止,然而,如果Pod对应的restartPolicy值为 Never,它不会重新启动。

初始化容器的官方地址:

https://kubernetes.io/docs/concepts/workloads/pods/init-containers/#init-containers-in-use
[root@master init]# cat init.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox:latest
    command: ['sh','-c','echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:latest
    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:latest
    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"]

本例pod中包含一个名为myapp-container的容器和二个名为init-my..的初始化容器,其中初始化容器用于执行初始化脚本,会执行2s

[root@master init]# kubectl apply -f init.yaml

[root@master init]# kubectl get pods 
NAME           READY   STATUS     RESTARTS   AGE
myapp-pod      0/1     Init:0/2   0          4s
[root@master init]# cat service.yaml 
---
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
  - protocol: TCP
    port: 84
    targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
  name: mydb
spec:
  ports:
  - protocol: TCP
    port: 84
    targetPort: 9377
[root@master init]# kubectl apply -f service.yaml 
service/myservice created
service/mydb created

[root@master init]# kubectl get pods  -w
NAME           READY   STATUS     RESTARTS   AGE
myapp-pod      0/1     Init:1/2   0          13m
myapp-pod      0/1     Init:1/2   0          14m
myapp-pod      0/1     PodInitializing   0          14m
myapp-pod      1/1     Running           0          14m

查询pod处于生命周期哪个阶段

[root@master ~]# kubectl get pods myapp-pod  --template="{{.status.phase}}"
Running

主容器

容器钩子

初始化容器启动之后,开始启动主容器,在主容器启动之前有一个post start hook(容器启动后钩子)和pre stop hook(容器结束前钩子),无论启动后还是结束前所做的事我们可以把它放两个钩子,这个钩子就表示用户可以用它来钩住一些命令,来执行它,做开场前的预设,结束前的清理,如awk有begin,end,和这个效果类似;

postStart:该钩子在容器被创建后立刻触发,通知容器它已经被创建。如果该钩子对应的hook handler执行失败,则该容器会被杀死,并根据该容器的重启策略决定是否要重启该容器,这个钩子不需要传递任何参数。

preStop:该钩子在容器被删除前触发,其所对应的hook handler必须在删除该容器的请求发送给Docker daemon之前完成。在该钩子对应的hook handler完成后不论执行的结果如何,Docker daemon会发送一个SGTERN信号量给Docker daemon来删除该容器,这个钩子不需要传递任何参数。

在k8s中支持两类对pod的检测,第一类叫做livenessprobe(pod存活性探测):

存活探针主要作用是,用指定的方式检测pod中的容器应用是否正常运行,如果检测失败,则认为容器不健康,那么Kubelet将根据Pod中设置的 restartPolicy来判断Pod 是否要进行重启操作,如果容器配置中没有配置 livenessProbe,Kubelet 将认为存活探针探测一直为成功状态。

第二类是状态检readinessprobe(pod就绪性探测):用于判断容器中应用是否启动完成,当探测成功后才使Pod对外提供网络访问,设置容器Ready状态为true,如果探测失败,则设置容器的Ready状态为false。

pod容器探测和钩子

容器钩子

postStart:容器创建成功后,运行前的任务,用于资源部署、环境准备等。

preStop:在容器被终止前的任务,用于优雅关闭应用程序、通知其他系统等。

演示postStart和preStop用法


containers:
- image: sample:v2  
     name: war
     lifecycle:
      postStart:
       exec:		#在容器中执行指定的命令
         command:	#需要执行的命令
          - “cp”
          - “/sample.war”
          - “/app”
      prestop:
       httpGet:
        host: monitor.com	#请求的ip
        path: /waring	#请求的URL路径
        port: 8080		#请求的端口
        scheme: HTTP	#请求的协议


以上示例中,定义了一个Pod,包含一个JAVA的web应用容器,其中设置了PostStart和PreStop回调函数。即在容器创建成功后,复制/sample.war到/app文件夹中。而在容器终止之前,发送HTTP请求到http://monitor.com:8080/waring,即向监控系统发送警告。

优雅的删除资源对象

当用户请求删除含有pod的资源对象时(如RC、deployment等),K8S为了让应用程序优雅关闭(即让应用程序完成正在处理的请求后,再关闭软件),K8S提供两种信息通知:

1)、默认:K8S通知node执行docker stop命令,docker会先向容器中PID为1的进程发送系统信号SIGTERM,然后等待容器中的应用程序终止执行,如果等待时间达到设定的超时时间,或者默认超时时间(30s),会继续发送SIGKILL的系统信号强行kill掉进程。

2)、使用pod生命周期(利用PreStop回调函数),它执行在发送终止信号之前。

默认情况下,所有的删除操作的优雅退出时间都在30秒以内。kubectl delete命令支持--grace-period=的选项,以运行用户来修改默认值。0表示删除立即执行,并且立即从API中删除pod。在节点上,被设置了立即结束的的pod,仍然会给一个很短的优雅退出时间段,才会开始被强制杀死。如下:

    spec:
      containers:
      - name: nginx-demo
        image: centos:nginx
        lifecycle:		###用于在容器运行前或关闭前的一些动作
          preStop:		####容器被终止前,用于关闭应用程序,通知其他系统等
            exec:
              # nginx -s quit gracefully terminate while SIGTERM triggers a quick exit
              command: ["/usr/local/nginx/sbin/nginx","-s","quit"]
        ports:
          - name: http
            containerPort: 80

[root@master ~]# cat pod-prestop.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: exam-prestart.yaml
spec:
  containers:
  - name: con-start
    image: busybox
    imagePullPolicy: IfNotPresent
    command: ['sh','-c']
    args: ['echo "Hello kubernetes!"; sleep 3600']
    lifecycle:		###用于在容器运行前或关闭前的一些动作
      postStart:	###容器创建成功后,运行前的任务
        httpGet:
          host: www.baidu.com	##请求的ip
          path: /		##请求的URL路径
          port: 80		##请求的端口
          scheme: HTTP	##请求的协议
      preStop:		####容器被终止前,用于关闭应用程序,通知其他系统等
        exec:
          command: ['sh','-c','echo "preStop callback done!";sleep 60']

----本实验使用了postStart事件执行HttpGet回调,postStart执行命令并输入一段文本,之后停留60s

开启新终端持续查看

[root@master ~]# kubectl get pods -w
NAME        READY   STATUS             RESTARTS   AGE
exam-prestart.yaml   0/1     Pending            0          0s
exam-prestart.yaml   0/1     ContainerCreating   0          0s
exam-prestart.yaml   1/1     Running             0          18s
exam-prestart.yaml   1/1     Terminating         0          69s
exam-prestart.yaml   0/1     Terminating         0          102s
exam-prestart.yaml   0/1     Terminating         0          107s
exam-prestart.yaml   0/1     Terminating         0          107s
exam-exit            0/1     Error               10         26m
exam-exit            0/1     CrashLoopBackOff    10         26m
[root@master ~]# kubectl apply -f pod-prestop.yaml 

---设置了60s的等待时间,在执行删除命令时,由于要回调,因此要等60s才正式开始删除pod,在这段时间内,pod仍然处于可访问的运行状态

[root@master ~]# kubectl delete -f pod-prestop.yaml

###执行删除命令后查看日志文件依然可以查看到
[root@master ~]# kubectl logs exam-prestart.yaml
Hello kubernetes!

存活性探测livenessProbe和就绪性探测readinessProbe

livenessProbe:存活性探测

许多应用程序经过长时间运行,最终过渡到无法运行的状态,除了重启,无法恢复。K8S提供livenessProbe来检测容器是否正常运行,并且对相应状况进行相应的补救措施。

readinessProbe:就绪性探测

在没有配置readinessProbe的资源对象中,pod中的容器启动完成后,就认为pod中的应用程序可以对外提供服务,该pod就会加入相对应的service,对外提供服务。但有时一些应用程序启动后,需要较长时间的加载才能对外服务,如果这时对外提供服务,执行结果必然无法达到预期效果,影响用户体验。

目前LivenessProbe和ReadinessProbe两种探针都支持下面三种探测方法:

1、ExecAction:在容器中执行指定的命令,如果执行成功,退出码为 0 则探测成功。

2、TCPSocketAction:通过容器的 IP 地址和端口号执行 TCP 检 查,如果能够建立 TCP 连接,则表明容器健康。

3、HTTPGetAction:通过容器的IP地址、端口号及路径调用 HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器健康

探针探测结果有以下值:

1、Success:表示通过检测。

2、Failure:表示未通过检测。

3、Unknown:表示检测没有正常进行。

Pod探针相关的属性:

探针(Probe)有许多可选字段,可以用来更加精确的控制Liveness和Readiness两种探针的行为

initialDelaySeconds: Pod启动后首次进行检查的等待时间,单位“秒”。

periodSeconds: 检查的间隔时间,默认为10s,单位“秒”。

timeoutSeconds: 探针执行检测请求后,等待响应的超时时间,默认为1s,单位“秒”。

successThreshold:连续探测几次成功,才认为探测成功,默认为 1,在 Liveness 探针中必须为1,最小值为1。

failureThreshold: 探测失败的重试次数,重试一定次数后将认为失败,在 readiness 探针中,Pod会被标记为未就绪,默认为 3,最小值为 1

两种探针区别:

ReadinessProbe 和 livenessProbe 可以使用相同探测方式,只是对 Pod 的处置方式不同:

readinessProbe 当检测失败后,将 Pod 的 IP:Port 从对应的 EndPoint 列表中删除。

livenessProbe 当检测失败后,将杀死容器并根据 Pod 的重启策略来决定作出对应的措施。

Pod探针使用示例:

1、LivenessProbe 探针使用示例
(1)、通过exec方式做健康探测

ExecAction:在容器内部执行指定命令。若状态码为0退出,则测定为诊断成功

[root@master ~]# cat liveness-exec.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
  labels:
    app: liveness
spec:
  containers:
  - name: liveness
    image: busybox
    args:			####创建测试探针探测的文件
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      initialDelaySeconds: 10		####延迟检测时间
      periodSeconds: 5				####检测时间间隔
      exec:
        command:	#命令列表
        - cat
        - /tmp/healthy

打开一个新终端执行持续查看

[root@master ~]# kubectl get pods -w
NAME           READY   STATUS    RESTARTS   AGE
#####执行后的结果
liveness-exec   0/1     Pending   0          0s
liveness-exec   0/1     Pending   0          0s
liveness-exec   0/1     ContainerCreating   0          0s
liveness-exec   1/1     Running             0          17s
liveness-exec   1/1     Running             1          117s

执行

[root@master ~]# kubectl apply -f liveness-exec.yaml 
pod/liveness-exec created

容器启动设置执行的命令:

/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"

容器在初始化后,首先创建一个 /tmp/healthy 文件,然后执行睡眠命令,睡眠 30 秒,到时间后执行删除 /tmp/healthy 文件命令。而设置的存活探针检检测方式为执行 shell 命令,用 cat 命令输出 healthy 文件的内容,如果能成功执行这条命令,存活探针就认为探测成功,否则探测失败。在前 30 秒内,由于文件存在,所以存活探针探测时执行 cat /tmp/healthy 命令成功执行。30 秒后 healthy 文件被删除,所以执行命令失败,Kubernetes 会根据 Pod 设置的重启策略来判断,是否重启 Pod。

(2)、通过HTTP方式做健康探测

HTTPGetAction对容器IP地址的指定端口和执行HttpGet请求,若范围为200~400则检测成功

[root@master ~]# cat liveness-http.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: liveness-http
  labels:
    test: liveness
spec:
  containers:
  - name: liveness
    image: mydlqclub/springboot-helloworld:0.0.1
    livenessProbe:
      initialDelaySeconds: 20		#####延迟加载时间
      periodSeconds: 5				#####重试时间间隔
      timeoutSeconds: 10			#####超时时间设置
      httpGet:
        scheme: HTTP	##请求的协议
        port: 8085		#指定端口号
        path: /actuator/health		#指定的路径

新开起一个终端持续查看

[root@master ~]# kubectl get pods -w
NAME            READY   STATUS    RESTARTS   AGE
liveness-http   0/1     Pending            0          0s
liveness-http   0/1     Pending            0          0s
liveness-http   0/1     ContainerCreating   0          0s
liveness-http   1/1     Running             0          2s
liveness-http   1/1     Running             1          35s
liveness-http   1/1     Running             2          65s
liveness-http   0/1     CrashLoopBackOff    4          2m35s
[root@master ~]# kubectl apply -f liveness-http.yaml 

上面 Pod 中启动的容器是一个 SpringBoot 应用,其中引用了 Actuator 组件,提供了 /actuator/health 健康检查地址,存活探针可以使用 HTTPGet 方式向服务发起请求,请求 8081 端口的 /actuator/health 路径来进行存活判断:

任何大于或等于200且小于400的代码表示探测成功。

任何其他代码表示失败。

如果探测失败,则会杀死 Pod 进行重启操作。

httpGet探测方式有如下可选的控制字段:

scheme: 用于连接host的协议,默认为HTTP。

host:要连接的主机名,默认为Pod IP,可以在http request head中设置host头部。

port:容器上要访问端口号或名称。

path:http服务器上的访问URI。

httpHeaders:自定义HTTP请求headers,HTTP允许重复headers。

(3)、通过TCP方式做健康探测

TCPSocketAction对容器ip地址的指定端口执行TCP检测,若端口是打开的,则测定成功

[root@master ~]# cat liveness-tcp.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: liveness-tcp
  labels:
    app: liveness
spec:
  containers:
  - name: liveness
    image: nginx
    livenessProbe:
      initialDelaySeconds: 15
      periodSeconds: 20
      tcpSocket:
        port: 87	#检查的TCP端口

新开一个终端持续查看

[root@master ~]# kubectl get pods -w
NAME            READY   STATUS      RESTARTS   AGE
liveness-tcp    0/1     Pending            0          0s
liveness-tcp    0/1     Pending            0          0s
liveness-tcp    0/1     ContainerCreating   0          1s
liveness-tcp    1/1     Running             0          40s
liveness-tcp    1/1     Running             1          2m
liveness-tcp    1/1     Running             1          2m
[root@master ~]# kubectl apply -f liveness-tcp.yaml 

TCP 检查方式和 HTTP 检查方式非常相似,在容器启动 initialDelaySeconds 参数设定的时间后,kubelet 将发送第一个 livenessProbe 探针,尝试连接容器的 80 端口,如果连接失败则将杀死 Pod 重启容器。

2、ReadinessProbe 探针使用示例

Pod 的ReadinessProbe 探针使用方式和 LivenessProbe 探针探测方法一样,也是支持三种,只是一个是用于探测应用的存活,一个是判断是否对外提供流量的条件。这里用一个 Springboot 项目,设置 ReadinessProbe 探测 SpringBoot 项目的 8081 端口下的 /actuator/health 接口,如果探测成功则代表内部程序以及启动,就开放对外提供接口访问,否则内部应用没有成功启动,暂不对外提供访问,直到就绪探针探测成功。

[root@master ~]# cat readiness-exec.yaml 
apiVersion: v1
kind: Service
metadata:
  name: springboot
  labels:
    app: springboot
spec:
  type: NodePort
  ports:
  - name: server
    port: 8082
    targetPort: 8082
    nodePort: 31180
  - name: management
    port: 8083
    targetPort: 8083
    nodePort: 31181
  selector:
    app: springboot
---
apiVersion: v1
kind: Pod
metadata:
  name: springboot
  labels:
    app: apringboot
spec:
  containers:
  - name: springboot
    image: mydlqclub/springboot-helloworld:0.0.1
    ports:
    - name: server
      containerPort: 8082
    - name: management
      containerPort: 8083
    readinessProbe:
      initialDelaySeconds: 20
      periodSeconds: 5
      timeoutSeconds: 10
      httpGet:
        scheme: HTTP
        port: 8083
        path: /actuator/health
[root@master ~]# kubectl apply -f readiness-exec.yaml 
service/springboot created
pod/springboot created

3、ReadinessProbe + LivenessProbe 配合使用示例
一般程序中需要设置两种探针结合使用,并且也要结合实际情况,来配置初始化检查时间和检测间隔,下面列一个简单的 SpringBoot 项目的 Deployment 例子。

[root@master ~]# cat readiness-libe.yaml 
apiVersion: v1
kind: Service
metadata:
  name: springboot
  labels:
    app: springboot
spec:
  type: NodePort
  ports:
  - name: server
    port: 8082
    targetPort: 8082
    nodePort: 31180
  - name: management
    port: 8083
    targetPort: 8083
    nodePort: 31181
  selector:
    app: springboot

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: springboot
  labels:
    app: springboot
spec:
  replicas: 1
  selector:
    matchLabels:
      app: springboot
  template:
    metadata:
      name: springboot
      labels:
        app: springboot
    spec:
      containers:
      - name: readiness
        image: mydlqclub/springboot-helloworld:0.0.1
        ports:
        - name: server
          containerPort: 8082
        - name: management
          containerPort: 8083
        readinessProbe:
          initialDelaySeconds: 20
          periodSeconds: 5
          timeoutSeconds: 10
          httpGet:
            scheme: HTTP
            port: 8083
            path: /actuator/health
        livenessProbe:
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 5
            httpGet:
              scheme: HTTP
              port: 8083
              path: /actuator/health
[root@master ~]# kubectl apply -f readiness-libe.yaml 
service/springboot unchanged
deployment.apps/springboot created


pod模板

# yaml格式的pod定义文件完整内容:
apiVersion: v1       #必选,版本号,例如v1
kind: Pod       #必选,Pod
metadata:       #必选,元数据
  name: string       #必选,Pod名称
  namespace: string    #必选,Pod所属的命名空间
  labels:      #自定义标签
    - name: string     #自定义标签名字
  annotations:       #自定义注释列表
    - name: string
spec:         #必选,Pod中容器的详细定义
  containers:      #必选,Pod中容器列表
  - name: string     #必选,容器名称
    image: string    #必选,容器的镜像名称
    imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
    command: [string]    #容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]     #容器的启动命令参数列表
    workingDir: string     #容器的工作目录
    volumeMounts:    #挂载到容器内部的存储卷配置
    - name: string     #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string    #存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean    #是否为只读模式
    ports:       #需要暴露的端口库号列表
    - name: string     #端口号名称
      containerPort: int   #容器需要监听的端口号
      hostPort: int    #容器所在主机需要监听的端口号,默认与Container相同
      protocol: string     #端口协议,支持TCP和UDP,默认TCP
    env:       #容器运行前需设置的环境变量列表
    - name: string     #环境变量名称
      value: string    #环境变量的值
    resources:       #资源限制和请求的设置
      limits:      #资源限制的设置
        cpu: string    #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
        memory: string     #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
      requests:      #资源请求的设置
        cpu: string    #Cpu请求,容器启动的初始可用数量
        memory: string     #内存清楚,容器启动的初始可用数量
    livenessProbe:     #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
      exec:      #对Pod容器内检查方式设置为exec方式
        command: [string]  #exec方式需要制定的命令或脚本
      httpGet:       #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:     #对Pod内个容器健康检查方式设置为tcpSocket方式
         port: number
       initialDelaySeconds: 0  #容器启动完成后首次探测的时间,单位为秒
       timeoutSeconds: 0   #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
       periodSeconds: 0    #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged:false
    restartPolicy: [Always | Never | OnFailure]#Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
    nodeSelector: obeject  #设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
    imagePullSecrets:    #Pull镜像时使用的secret名称,以key:secretkey格式指定
    - name: string
    hostNetwork:false      #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
    volumes:       #在该pod上定义共享存储卷列表
    - name: string     #共享存储卷名称 (volumes类型有很多种)
      emptyDir: {}     #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
      hostPath: string     #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
        path: string     #Pod所在宿主机的目录,将被用于同期中mount的目录
      secret:      #类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
        scretname: string  
        items:     
        - key: string
          path: string
      configMap:     #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
        name: string
        items:
        - key: string
          path: string

编辑日期:2021-12-26

posted @ 2023-04-05 21:14  idazhi  阅读(33)  评论(0编辑  收藏  举报