kubectl接口风格

kubectl是一种RESTful风格的api,它把各种操作对象都一率当成资源来管理,并且可通过标准的http请求方法来处理,如: GET, PUT, DELETE, POST

资源:对象

资源实例化之后就是一个对象,类型于py的 , 如k8s资源: service, pod, deployment

  1. workload: 运行应用程序对外提供的服务,如Pod,

​ 工作负载型资源: ReplicaSet, Deployment, StatefulSet, DaemonSet, Job, Cronjob…

  1. 服务发现及服务均衡: Service, Ingress

  2. 配置与存储: Volume(存储卷), CSI (容器存储接口), PV, PVC

    属性 说明
    configMap 当配置中心使用
    Secret 与configMap一致,但这个工具用于保存敏感资源
    DownwardAPI 将外部环境信息输出给容器

    -------> 做为容器编排系统之上的应用程序,运行时需要用到存储,尤其是有状态的持久化存储的应用程序,其必然会用到Volume,以及几乎为了能够配置容器化应用也必然会用到的configMap与Secret

  3. 集群级资源

    资源名称 说明
    名称空间 不指定默认就是defalut 如 pod
    Node 节点自身也是资源
    Role 角色,应该属于名称空间namespace中的一种
    ClusterRole 集群角色
    RoleBinging 角色绑定
    CluseterRoleBinding 集群角色绑定
  4. 元数据型资源

    属性 说明
    HPA 水平pod的自主控制器,能自动调整其它资源的元数据信息 如replicas
    PodTemplate pod模板,用于让控制器创建pod使用的模板
    LimitRange pod资源限制, 在启动容器之前名称空间中设定, 如 cpu|内存

资源配置清单

查看清单详细状态: ~]# kubectl get pods myapp-64758bffd4-4kp5z -o yaml

  • apiVersion

    • 查看属于哪一个对象的版本或api组
    • apiVersion给定值一般格式为 group/version,如果不带group,那就表示为核心组之一,如apiVersion: v1
    • 查看api版本有哪些: ~]# kubectl api-versions
    • 三个级别: bata(开发), stable(稳定), alpha(测试)
  • kind

    • 资源类别,指定资源对象时使用 如: kind: Pod, workload, 服务发现及均衡
  • metadata

    ​ 指定元数据, 嵌套字段 如 {xx:[{'xx':xx},{'yy':yy}]}

    属性 说明
    labels 标签,每一种类型的资源都会有各自对应的标签, 当标签改变时会通知api server
    name 容器名称,name必须唯一
    namespace K8s概念的名称空间 如default, 通过 ~]# kubectl get ns 查看名称空间
    ownerReferences 属于哪个的资源
    selfLink /api/GROUP/VERSION/namespaces/NAMESPACE/TYPE/NAME
    如: /api/v1/namespaces/default/pods/myapp-64758bffd4-4kp5z
    uid 唯一标识,每个pod都不会相同
  • spec规格:

    ​ 定义创建对象时应当具备什么样的特性以及规范,如容器数量,容器镜像,容忍度, spec是资源对象中最重要的一个字段,使用该字段可以定义我们所期望的资源应当具体什么样的特性以及规范,而后靠控制器来确保它的特性能够被满足。

    • required: 必须要的字段 , 如pod资源类型 container是必要字段
  • status:

    ​ 用于显示当前容器的当前状态, 本字段由kubernetes集群维护, 副本个数,rollout,版本

  • 资源清单参数: ~]# kubectl explain pods

    属性 说明
    <string> 字符串
    <[]string> 字符串列表
    <object> 能嵌套两级字段
    <[]object> 对象列表,可以同时出现的多个列表
    <map> 键值组成的映射, 另外格式的json数组 k:v

创建资源方法

  • apiserver仅接收JSON格式的资源定义。
  • yaml格式提供配置清单,apiserver可自动将其转为json格式, 而后在提交之后在执行

yaml清单优势

  • 无需在检查pod是否存在, 可直接使用yaml删除
  • 复用效果
  • 创建比命令行更加快捷 kubectl create -f xx.yaml
  • 裸pod无需删除控制器,可自定义属性 存活性探测,就续状态探测,生命周期探测, 初始化时配置, 容器资源限定,资源最低需求

清单用法

命令 清单
kubectl run 命令式资源清单
kubectl create 配置清单
yaml 声明式资源清单

创建第一个yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  namespace: default
  labels:
    app: firstapp 
    title: demo
# spec <Object>
spec:
#  containers <[]Object>
  containers:    # 一个容器一个组
  - name: nginxs
    image: nginx
  - name: nginx2
    image: nginx

# labels用法
#  labels:
#    app: firstapp
#    title: demo
#  labels: {app:firstapp, title, demo}  

#  command的用法
#    command:  ['/bin/sh', 'nginx','-s', 'daemon off']
#    command:
#    - "/bin/sh"
#    - "-c"
#    - "sleep 5"

# 两个容器运行在同一个pod中, 如果A有目录而B没有,需要使用存储卷

创建: kubectl  create -f first.yaml
删除: kubectl  delete -f first.yaml

pod资源管理

​ 通过Pod运行容器,但Pod与容器并不是对应关系,Pod可以理解为容器的有一层外壳,Pod在容器之外增加了一层抽象封装,这个抽象封装叫Pod,而且在一个Pod内部可以有多个容器,而且这些容器本身将共享同一个网络名称空间,

​ 在Pod中会存在一个基础架构的容器,当我们来使用原始方式去部署k8s的时候,它用到的基础架构容器的对应的镜像叫pause,它创建以后一直处于暂停状态,我们甚至都看不见这么一个容器; 而后,任意一个Pod中的pause容器会为加入到此Pod中的其它容器来提供网络名称空间,提供存储卷的定义等功能;比如我们要定义存储卷, 那就意味着存储卷也属于该Pod或得Pod这个pause基础架构容器的,其它任何加入到此Pod的容器都将共享底层基础Pod的Pid、Mount、User、Ipc、Uts、Network等主要空间, 通过这种方式组织出来的多个容器,就像是运行在一个宿主机上的多个进程, 每一个容器就是一个进程 ,而进程与进程之间也就可以通过lo接口来进行通信了;

pod网络

​ Kubernetes之上存在三种类型的网络,分别的node网络这个才是能与外连网络通信的接口,第二个是service网络,service网络仅能出现在iptables或ipvs规则当中用于路由和调度请求流量,第三种网络是Pod网络,就相当于我们机房里面的Kubernetes内部网络,每一个Pod都处于这个网络当中,Pod的IP地址都是在这个网络动态分配的IP地址,因此各个Pod无论在跑在哪个node上,是可以直接通信的,Pod和Pod之间可以使用彼此的地址,互相之间通信,但是Pod是动态的,随之有可能被Pod控制器所重建,因此IP地址会发生变化的,那这个时候Pod和Pod之间直接使用IP地址进行通信就不是一种理想的状态的,我们因为让他借助于service地址通信;

​ 因此,在k8s之上运行应用程序,它就有一个特点,我们必须在Pod前增加一个抽象层(service),哪怕只有一个Pod我们也应该增加一个service前端,固定Service地址用于客户端能访问到这个应用程序, 而Service对象它表现在所有节点上的iptabels或ipvs规则,所以客户端在访问Pod的时候需要先到Service然后在后代或调度给Pod;

pod控制

​ 只要建构在k8s 之上的Pod都应该由于控制器来管理, 而且这个Pod一般不会由我们手动去创建,这种Pod叫做自助式Pod,它有一个特点,就是这个Pod一删除,它就不会被重建了,节点一宕机,在个Pod就没了,所以我们使用Pod虽然很多,但是绝对不会以手动的方式创建独立运行的Pod,而应该使用Pod控制器来创建Pod;

​ Pod控制器也是一类标准的Kubernetes资源,控制器有多种,不同的控制器有不同的功能和任务,控制器也是整个Kubernetes最核心的组成部分,整个集群的大脑,因为它主要通过和解循环,loop来完成确保用户所定义的每一个对象,它的当前状态和用户的期望值一致,如果不一致那么控制器就会通过一系列的逻辑操作来进行修复,所以说控制器里面包含的任务就像运维里面的发布、变更、故障处理等功能;

​ 所以从某种意义上来讲,控制器就是运维,因此有了Kubernetes之后我们运维工程师的日常任务,基本上就不需要再去人为的接入和管理了,至少对于现在的无状态应用来讲,已经做到了,你只需要管理Kubernetes集群自身是否运行正常就可以了;

Pod外部访问

我们怎么能把集群外部的流量在必要时接入到集群内部的Pod呢?

  1. 使用service的nodeport类型,它会在集群节点上的每一个node节点打开一个端口,而后你访问,集群中的任何一个节点的地址和端口都可以访问到Pod,它首先会DNAT到service,然后service再调度给Pod

  2. 使用service的hostPort类型,我们在定义Pod时候,使用hostPort的方式来将容器的端口映射到Node的端口,那这样的话这个容器跑在哪个节点,我们就可以使用哪个节点的地址和端口就行访问了,与nodeport的不同之处在于,hostPort仅在运行容器的节点打开端口,所以说它并不经由service;

  3. 使用hostNetwork,让Pod可以直接使用它所在主机的网络名称空间,因此,Pod的地址也就是主机的地址,Pod监听的端口也就是主机的端口,那这个时候直接访问Pod所在的node的地址和端口即可访问,那么很显然,Pod就不那么隐蔽了;

  4. ingress: k8s的核心目标就是去运行Pod, 而围绕在Pod之外,我们还有很多类型的资源,比如我们的Service, 像ipvs或iptables的规则都是四层会话,如果我们的服务是https,四层是不能卸载https会话的,那么所有的https证都都得安装在pod中,那就比较麻烦了,所以这里又有一个七层调度Ingress服务,类似于一个nginx或haproxy的组件

在这里插入图片描述

总结

  • ​ 当使用第一种方式nodeport类型时, 访问逻辑是最通透最直接的,访问任何一个节点都能到达, 但有一个缺陷就在于,我们创建的任何服务都要在所有节点上增加一个iptables或ipvs规则, 所以说如果服务使用同一个端口,都会导至端口冲突,所以nodeport只能是随机映射, 端口范围: 30000-32676;
  • ​ 所以说在这个时侯就不得不在K8s集群之外的前端,在人为的建立一个负载均衡器,用户访问这个LB将请求负载到后端的每一个物理节点所映射的端口, 那么一旦这个LB宕机了,对应的服务也就没了;
  • ​ 在必要的时候,我们还需要keepalived来给他做高可用,那这就背离了Kubernetes的使用初衷,因为还需要在Kubernetes集群之外再加一个不受Kubernetes管理的层,层层转发性能不是特别的好,更何况我们的Kubernetes集群外的负载均衡器也无法按需创建

labels 标签

​ 当pod数量过多时使用标签可以有效的将pod进行分组,控制器也需要使用标签来管控对应的pod资源,标签其实就是附加在pod之上的一个键值对,每一个标签都可以被标签选择器进行匹配度检查从而完成资源挑选, 一个资源可拥有多个标签,标签也可以同时添加到多个资源上, 标签可以在pod创建之前指定, 也可以在创建之后用命令来管理(增\删\改),

​ 实际当中通过不同纬度标签的标签来管理pod,也可通过分层 如application=nginx 指定应用程序为nginx, 使用标签时,一般会使用几种类型如: 应用程序版本 release (stable: 稳定版, bata:研发版 , alpha: 测试版), 环境标签(dev, test(qa), prodect), 使用功能 ( 存储, 应用程序, 分区标签 )

资源标签

# 格式:  key=value
# 标签中的键的名称通畅是由键前缀和键名组成的,其格式可以如KEY_NAME/KEY_PREFIX_NAME;

key:  字母、数字、下划线_、 横线-、点. 、5种类型开头,键名至多能使用63个字符,且只能以字母或数字开头

# 键前缀必须为DNS子域名格式,且不能超过253个字符,省略键前缀时,键将被视为用户的私有数据,不过由于Kuberetes系统组成,或第三方组件自动为用户资源添加的键必须使用前缀而"kubernetes/"前缀预留给kubernetes的核心组件使用;

value: 不能超过63个字符,可以为空, 只能以字母或数字开头及结尾,且中间仅使用了字母、数字、连接符号(-)、下划线或点号(.)等字符的数据;

标签选择器

  1. 等值关系
  • =, ==: # key=value的值
 ```bash
 ~]# kubectl  get pods -l release=stable   # 等值关系判断
 ~]# kubectl  get pods -l release=stable,app=firstapp --show-labels 
   NAME       READY   STATUS    RESTARTS   AGE   LABELS
   pod-demo   1/1     Running   0          28h   app=firstapp,release=stable,title=demo
 ```
  • !=: # key中不存在的值,取反
 ```bash
 # 取pods中不带stable的, 但 app=firstapp的资源
 ~]# kubectl get pods -l release!=stable,app=firstapp --show-labels 
 ```
  1. 集合关系
  • KEY in (value1, value2…) # key 存在于列表中值
 ```bash
 # 取出 run这个key中存在myapp与myapp2的values资源对象
  ~]# kubectl  get pods -l "run in (myapp, myapp2)" --show-labels
 ```
  • KEY notin (value1, value2,…) # key 不具有的值
 ```bash
 # 取出 run这个key中存在myapp与myapp2的values资源对象
  ~]# kubectl  get pods -l "run notin (myapp)" --show-labels
 ```
  1. 内嵌字段

​ kubernetes的诸多资源对象必须以标签选择器的方式关联到Pod资源对象,例如Service、Deployment和ReplicaSet类型的资源等,他们在spec字段中嵌套使用嵌套的selector字段通过matchLabels来指定标签选择器,有的甚至还支持使用matchExpressions来构造复杂的标签选择器机制;

标签选择器 说明
matchLabels 直接给定键值来进行选择
matchExpressions 基于给定的表达式来定义使用的标签选择器 {key:“KEY”, operator: “操作符”, values:[VAL1,VAL2]}, # values:[val1, val2] 与 operator进行对比
选择器操作符 说明
IN, NotIn values: 其值必须为非空列表
Exists, NotExists values: 必须为空列表
  1. 逻辑
# 许多资源支持内嵌字段定义其使用的标签选择器
# service 只支持 matchLabels
# deployment,replicas 两种都支持

使用标签选择器还能使用一下逻辑
    同时指定多个选择器之间的逻辑关系为与操作;
    使用"空值"的标签选择器意味着每个资源对象都将被选中;
    "空的"标签选择器将无法选出任何资源;

查看\显示标签

查看labels
 ~]# kubectl get pods --show-labels
 	pod-demo        1/1     Running   0   26h     app=firstapp,title=demo

# -L: 用于指定显示,指定资源对象类别下的所有资源对应的标签的值
 ~]# kubectl get pods -L app
     NAME                     READY   STATUS    RESTARTS   AGE     APP
    client-f44986c9-6mnvd    1/1     Running   0          5d21h   
    pod-demo                 1/1     Running   0          27h     firstapp
    
# -l  只显示有这个标签的资源
 ~]# kubectl get pods -l app --show-labels
NAME       READY   STATUS    RESTARTS   AGE   LABELS
pod-demo   1/1     Running   0          28h   app=firstapp,title=demo

# 过滤两种条件同时存在的pod
 ~]# kubectl get pods -l app,release --show-labels

打标签

 ~]# kubectl  get pods --show-labels
NAME          READY   STATUS    RESTARTS   AGE    LABELS
pod-demo      1/1     Running   0          28h    app=firstapp,title=demo

# 添加标签选择器
~]# kubectl label pods pod-demo release=base
pod/pod-demo labeled

~]# kubectl get pods --show-labels 
NAME             READY   STATUS    RESTARTS   AGE  LABELS
pod-demo         1/1     Running   0          28h  app=firstapp,release=base,title=demo

# 修改已存在的标签,  需要加上 --overwrite不加,会提示已存在的错误
~]# kubectl label pods pod-demo release=stable --overwrite
pod/pod-demo labeled

~]# kubectl get pods --show-labels 
NAME             READY   STATUS    RESTARTS   AGE  LABELS
pod-demo         1/1     Running   0          28h  app=firstapp,release=stable,title=demo

# 删除labels
]# kubectl label pods pod-demo -n qa release-

spec.nodeSelector

nodeSelector <map[string]string>:节点标签选择器, 限定pod运行在哪种类型的节点标签上

demo

  1. 查看节点

     ~]# kubectl get nodes --show-labels 
    NAME     STATUS   ROLES    AGE    VERSION   LABELS
    master   Ready    master   6d4h   v1.16.3   kubernetes.io/hostname=master
    node1    Ready    <none>   6d4h   v1.16.3   kubernetes.io/hostname=node1
    node2    Ready    <none>   6d4h   v1.16.3   kubernetes.io/hostname=node2
    
  2. 创建yaml

    ]# cat node.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-node     # craete -f 时pod的名称
      namespace: default  # 名称空间default
      labels:
        run: node    # 完成之后的label标签
    spec:
      containers:
      - name: cnode
        image: nginx:1.16.1   # 指定容器版本 默认imagePullPolicy就是IfNot
        imagePullPolicy: IfNotPresent
        ports:    # 暴露端口号
        - name: http
          containerPort: 80
        - name: https
          containerPort: 443
      nodeSelector:          # 限定pod运行在node2这个节点上
        kubernetes.io/hostname: node2
    
  3. 创建

     ]# kubectl create -f node.yaml 
    pod/pod-node created
    
  4. 查看创建的pod

     ]# kubectl describe pods pod-node
    Name:         pod-node
    Namespace:    default
    Priority:     0
    Node:         node2/192.168.9.32
    Start Time:   Wed, 04 Dec 2019 14:45:02 +0800
    Labels:       run=node
    Annotations:  <none>
    Status:       Running
    IP:           10.244.2.26
    IPs:
      IP:  10.244.2.26
    Containers:
      cnode:
        Container ID:   docker://xx
        Image:          nginx:1.16.1
        Ports:          80/TCP, 443/TCP
        Host Ports:     0/TCP, 0/TCP
        State:          Running
          Started:      Wed, 04 Dec 2019 14:45:27 +0800
        Ready:          True
    Node-Selectors:  kubernetes.io/hostname=node2
    Events:
      Type    Reason     Age   From               Message
      ----    ------     ----  ----               -------
      Normal  Scheduled  29s   default-scheduler  Successfully assigned default/pod-node to node2
      Normal  Pulling    28s   kubelet, node2     Pulling image "nginx:1.16.1"
      Normal  Pulled     4s    kubelet, node2     Successfully pulled image "nginx:1.16.1"
      Normal  Created    4s    kubelet, node2     Created container cnode
      Normal  Started    4s    kubelet, node2     Started container cnode
      
    ]# kubectl get pods -o wide
    NAME       READY   STATUS    RESTARTS   AGE     IP            NODE  
    pod-node   1/1     Running   0          4m48s   10.244.2.26   node2 
    

spec.nodeName

直接限定死运行在指定的节点之上

metadata.annotaions

资源注解,与lable不同的地方在于,它不能用于挑选资源对象,仅用于为对象提供“元数据”。 键值不受字符限制,如:前缀/组:value

apiVersion: v1
kind: Pod
metadata:
  name: mypod-nginx
  namespace: default
  labels:
    k8s.com/mypod: qa
spec:
  containers:
  - name: mypod-nginx
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80 
    - name: https
      containerPort: 443
  nodeSelector:
    kubernetes.io/hostname: slave2

pod生命周期

所谓Pod生命周期指的是,Pod从创建,退出结束终止之间经历的阶段;
在这里插入图片描述

**第一阶段:**在启动Pod主容器时, 可能需要先给它做一下环境初始化;

  • 比如: nginx在启动前需要先做一些文件操作, 那么在运行一个Nginx主容器之前,需要先启动一个容器, 然后创建一个目录并创建一个文件或挂载文件, 都完成之后才能启动主容器, 这个阶段过程我们称之为初始化阶段, 然后初始化容器就会退出, 但这个过程不是必须的, 而如果以后在创建Pod时有这种场景就可以使用, 这种术语叫: init container;

  • 且需要注意的是初始化容器也可能会存在多个, 比如多个容器都只干一件事,c1创建目录, c2创建访问文件, 只有两个容器都完成初始化工作, 主容器才会启动, 否则主容器是无法启动的, 并且需要注意的是如果初始化容器有多个,那么它们必须是串行, 不能并行

  • ]# kubectl explain pods.spec.initContainers
    

第二阶段,主容器的运行阶段,分为三个阶段,

  1. 第一个主容器刚启动之后;

  2. 第二是主容器正常运行;

  3. 第三是主容器结束之前,post start hook这个时候是你的容器刚刚启动完成,它是一个钩子,这个时候你可以触发你的定义的钩子命令,来帮你在这个容器中做一些启动后的设置,那么pre start hook就是结束之前做的操作,而这个两个主要是用于触发一些命令来执行的,让用户可以自定义操作的;

]# kubectl explain pods.spec.containers.lifecycle

​ 从pod被创建开始,一个容器实际上来说只运行一个进程, 这个进程称为主进程,一个pod可以运行多个容器,但一般只运行一个容器,容器在创建之前,有多个初始化容器(init container)用来进行初始化环境,init container执行完,它就退出了,接下来是主容器(main container)开始启动,主容器启动时也要初始化主容器里面的环境,在主容器刚启动时,用户可以手动嵌入一个操作叫 post start (启动后程序),启动执行完之后就会退出,在主容器结束前,也可以做一个收尾操作 pre stop (结束前),用来在主容器结束前做一个清理。

  1. 初始化容器完成初始化
  2. 主容器启动后可以做启动前钩子也可以在结束后做结束前钩子,还可以在运行过程中做容器探测(liveness probe、readiness probe);
  3. 在post start后,先做存活状态检测,再做就绪性检测;
  4. 程序操作完之后 执行一个pre stop(结束前)程序做结束前主容器的最后清理。

创建pod流程

  1. 当用户创建pod时请求会提交给apiserver, apiserver会将创建请求的目标状态保存到etcd;
  2. 接着请求scheduler进行调度(必须参与,挑选节点),将调度结果保存到etcd状态信息当中;
  3. 目标节点上的kubelet通过apiserver当中的状态位拿到用户提交的创建清单;
  4. 最后根据清单在当前节点上创建并运行这个Pod;
  5. 如果创建成功或失败,kubelet会将将状态结束返回给apiserver,再把结果存到etcd中
    在这里插入图片描述

Pod的状态

Pod生命周期中的重要行为: 初始化容器、容器探测、生命周期钩子(启动前、启动后)

状态 说明
Pending 挂起,调度尚未完成
Running 运行中
Failed 容器运行失败
Successed 成功
Unknown 未知状态

容器探测

健康检查分三个层次: 1.执行自定义命令; 2.直接向tcp端口发请求; 3.向http发get请求.

状态 说明
liveness probe 存活状态探测,用于判定主容器是否处于运行状态
readiness probe 就绪性探测: 用于判定容器中的主进程是否准备就绪以及能否对外提供服务

pod删除

​ 在提交删除pod时,程序不会直接kill删除,而是会往pod 内中的每一个容器发送终止信号,让pod中的容器正常终止,其会有一个平滑期比如2分钟,之后就会直接强行进行终止删除

spec.restartPolicy

重启策略, 一旦pod被调度到某一节点, 只要节点在pod就不会被重新调度到别的节点, 容器只会重启,除非pod被删除,节点故障等问题pod才会被重新调度,否则它就一直会存在于被调度的节目之上

选项 说明
Always 一旦pod中的容器挂了, 总是重启
OnFailure 只是其状态为错误时,才会重启,第一次立即,第二次会延时,
第三次及以上失败次数都是上一次的倍数
Never 从不重启
Default to Always 默认就是总是重启

探针类型

3种类型如果针对 liveness probe就是存活性探 针, 针对readiness probe就是就绪性探针

类型 说明
ExecAction 用户自定义命令, 需要是容器中存在的命令
TCPSocketAction 向tcp端口连接请求
HttpGetAction 向http发get请求

containers.livenessProbe

位置: spec.containers.livenessProbe
存活性探针, 定义探针只需要定义其中的一种即可,exec, httpGet, tcpsocket

选项 说明
failureThreshold 探测几次失败才算是失败,默认为3
periodSeconds 每次探测的时长是多少秒才算是失败, 默认10s
timeoutSeconds 每次探测之后的时长, 默认1秒
initialDelaySeconds 默认是容器一启动就开始探测,但是此时容器可能还没启动完,此时探测肯定是失败的, 所以initialDelaySeconds表示容器启动多长时间后才开始探测
exec 执行用户自定义的命令,命令必须是容器中存在的命令
command: 运行命令探测是否成功, 判断状态码

ExecAction

]# cat liveness_exec.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
  namespace: default
spec:
  containers:
  - name: liveness-exec
    image: ikubernetes/myapp:v1
    imagePullPolicy: IfNotPresent
    # 执行命令, 创建he.html文件, 睡眠2秒之后删除
    command: ['/bin/sh', '-c', 'touch /tmp/he.html; sleep 20; rm -f /tmp/he.html; sleep 60']
    ports:
      - name: http
        containerPort: 80
    livenessProbe:
      exec:  # 自定义命令探测
        # 存活性探测, 如果状态不为0那就说明该文件不存在 
        command: ['test', '-e', '/tmp/he.html']
      # 初始化三秒之后在进行探测
      initialDelaySeconds: 3
      # 3秒钟探测一次
      periodSeconds: 3
      # 失败3次就说明该容器的确是有问题
      failureThreshold: 3  
  nodeSelector:
    kubernetes.io/hostname: node2
    
    Command:
      /bin/sh
      -c
      touch /tmp/he.html; sleep 20; rm -f /tmp/he.html; sleep 60
    State:          Running      # 重启之后又恢复正常
    Last State:     Terminated   # 上一次的状态是失败的
      Reason:       Error
      Exit Code:    137
    Restart Count:  1    # 重启一次
    Liveness:       exec [test -e /tmp/he.html] delay=3s timeout=1s period=3s #success=1 #failure=3

HttpGetAction

]# cat liveness_html.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: liveness-html
  namespace: default
spec:
  containers:
  - name: liveness-html
    image: ikubernetes/myapp:v1
    imagePullPolicy: IfNotPresent
    ports:
      - name: http
        containerPort: 80
    livenessProbe:
      httpGet:
        port: http    # 如果暴露的端口有别名那就可以直接使用别名
        # 访问的路径
        path: /index.html
      # 启动后延迟3秒在进行探测
      initialDelaySeconds: 3
      # 3秒钟探测一次
      periodSeconds: 3
      failureThreshold: 3  
  nodeSelector:
    kubernetes.io/hostname: node2
    
# 检查状态, 如果删除容器中的 index.html文件, 如果探测访问不了那么就会直接重启容器 
~]# kubectl describe pods liveness-html 
Name:         liveness-html
Node:         node2/192.168.9.32
Containers:
  liveness-html:
    Image:          ikubernetes/myapp:v1
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Thu, 05 Dec 2019 13:44:17 +0800
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Thu, 05 Dec 2019 13:42:09 +0800
      Finished:     Thu, 05 Dec 2019 13:44:17 +0800
    Restart Count:  1
    Liveness:       http-get http://:http/index.html delay=3s timeout=1s period=3s #success=1 #failure=3

containers.readinessProbe

位置:spec.containers.readinessProbe
就绪性探针, 参数与存活性探针一样

​ service通过lables选择器关连至各pod资源, 当新建的pod符合service的lables选择器的选择条件, 那么pod将会立即做为service的后端对象pod之一, 当用户有新请求时将会被随机调度至新的pod中, 而新容器在启动之时启动是需要时间的(当容器在启动时,需要经过很多步骤,比如tomcat, 启动jvm展开war,启动tomcat, 启动过程不止一秒钟) 而就绪在开始之前就会直接显示成功,所以当新请求过来时必定会出现错误, 因此如果不做就绪性探测新容器创建的就绪准备,转发新请求都将会失败, 解决办法: 创建之后需要先做就绪性探测

HttpGetAction

]#  cat readline.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: readline-exec
  namespace: default
spec:
  containers:
  - name: readline-exec
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    readinessProbe:
      httpGet:
        port: http
        path: /index.html
      initialDelaySeconds: 3
      periodSeconds: 3

]# kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
readline-exec            1/1     Running   0          4s
      
# 如果 index.html无法访问 , 那么pod不会被删除, 而容器会进入非就绪状态,转发请求将会失败
]# kubectl  describe pods readline-exec
    Ready:          False
    Restart Count:  0
    Readiness:      http-get http://:http/index.html delay=3s timeout=1s period=3s #success=1 #failure=3
    Environment:    <none>
    
]# kubectl get pods  # pods 控制器 也会一直存在, 当容器服务正常它又会重新进入就绪状态
	readline-exec            0/1     Running   0          2m42s

lifecycle

位置: spec.containers.lifecycle
生命周期探针, 钩子(启动后,终止前探测)

  1. postStart: 启动后
  2. preStop: 终止前, 对应的pod在终止之前执行的命令 ,命令执行完之后才会被删除

资源需求及资源限制

CPU属于可压缩(compressible)型资源,即资源额度可按需收缩,而内存则是不可压缩型资源,对其执行收缩操作可能会导致某种程度的问题,所以我们需要资源进行一定的限制;
CPU的计量方式:一个核心相当于1000个微核心,即1=1000m,0.5=500m;
内存的计量方式:默认单位为字节,也可以使用E、P、T、G、M和K后缀单位,或Ei、Ei、Pi、Ti、Gi、Mi和Ki形式的单位为后缀;

Pod服务质量类别

根据Pod对象的requests和limits属性,Kubernetes把Pod对象归类到BesteFFort、Buaranteed三个服务质量类别,可以使用describe查看QoS Class属性;

  • Guaranteed:每个容器都为CPU资源设置了具有相同值的requests和limits属性,以及每个容器都为内存资源社会了具有相同值的requests和limits属性的pod资源会自动归类为此类别,这类Pod资源具有最高优先级;
  • Burstable:至少有一个容器设置了CPU或者内存资源的requests属性,但不满足Guaranteed类别要求的Pod资源自动归属此类,他们具有中等优先级;
  • BestEffort:未为任何一个容器设置requests或limits属性的Pod资源自动归属此类别,他们的优先级为最低级别;

spec.containers <[]object>

  1. name\image

    - name	<string>  -required-  # 必须要的参数
      image	<string>              # 指定镜像, 可以是顶级仓库|私有|其它,需要是有效镜像
    
  2. imagePullPolicy: 镜像获取策略, 一旦创建就不能被修改

    策略|选项 说明
    Always 不管有没有,总是去register中下载
    never 从不下载,如果本地有就用,没有就等待,需要手动下载
    ifNotPresent 如果本地存在就直接使用,不存在就下载, 如果标签是always那么总是去register上下载, 如果指定了版本,那么标签就是 ifNotPresent
  3. **ports <[]Object>: **暴露端口

    定义端口容器内要暴露的端口, 每一个端口可以有名称,端口号,协议,暴露的端口仅仅提供额外信息, ports一般需要指定的子参数,如下

    参数 说明
    containerPort <integer> -required- 只需要指定容器端口
    hostIP <string> 使用 0.0.0.0 所有端口
    name <string> 常使用 IANA_SVC_NAME格式
    protocol 指定协议 TCP|UDP 默认TCP
  4. args\command

    参数 说明
    args 传递给程序的参数 在args中 (VARNAME)表示变量引用,(VAR_NAME) 表示变量引用,(VARNAME)$(VAR_NAME)命令引用
    command 要运行的程序, 所给定的代码是不会运行在shell中的, 如果想要以sh运行需要手动指定, 如果没有指定命令,那就会先运行容器中的entrypoint的命令

    属性描述

    描述 Docker 字段名称 Kubernetes 字段名称
    容器运行的命令 Entrypoint command
    传递给命令的参数集合 Cmd args

    如果要覆盖默认的 Entrypoint 与 Cmd,需要遵循如下规则:

    • 如果在容器配置中没有设置command 或者 args,那么将使用Docker镜像自带的命令及其入参。
    • 如果在容器配置中只设置了command但是没有设置args,那么容器启动时只会执行该 命令,Docker镜像中自带的命令及其入参会被忽略。
    • 如果在容器配置中只设置了args,那么Docker镜像中自带的命令会使用该新入参作为 其执行时的入参。
    • 如果在容器配置中同时设置了commandargs,那么Docker镜像中自带的命令及 其入参会被忽略。容器启动时只会执行配置中设置的命令,并使用配置中设置的入参作为 命令的入参。

    下表涵盖了各类设置场景:

    镜像 Entrypoint 镜像 Cmd 容器 command 容器 args 运行的命令
    [/ep-1] [foo bar] [ep-1 foo bar]
    [/ep-1] [foo bar] [/ep-2] [ep-2]
    [/ep-1] [foo bar] [zoo boo] [ep-1 zoo boo]
    [/ep-1] [foo bar] [/ep-2] [zoo boo] [ep-2 zoo boo]

容器日志-logs

~]# kubectl  logs 容器名称,   # 检查容器的日志, 如果pod有多个容器需要 -c指定容器名称
 
# 如  先使用 kubectl describe deployments 查看容器名称
~]# kubectl  logs -c 容器名称

时设置了commandargs,那么Docker镜像中自带的命令及 其入参会被忽略。容器启动时只会执行配置中设置的命令,并使用配置中设置的入参作为 命令的入参。

下表涵盖了各类设置场景:

镜像 Entrypoint 镜像 Cmd 容器 command 容器 args 运行的命令
[/ep-1] [foo bar] [ep-1 foo bar]
[/ep-1] [foo bar] [/ep-2] [ep-2]
[/ep-1] [foo bar] [zoo boo] [ep-1 zoo boo]
[/ep-1] [foo bar] [/ep-2] [zoo boo] [ep-2 zoo boo]

容器日志-logs

~]# kubectl  logs 容器名称,   # 检查容器的日志, 如果pod有多个容器需要 -c指定容器名称
 
# 如  先使用 kubectl describe deployments 查看容器名称
~]# kubectl  logs -c 容器名称
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐