k8s基本使用

149 阅读26分钟

k8s基本使用

核心概念

节点

从上面的图可以看出来,k8s 集群的节点有两个角色,分别为 Master 节点和 Node 节点,整个 K8s 集群Master 和 Node 节点关系如下图所示:

image.png

 

Master 节点

Master 节点也称为控制节点,每个 k8s 集群都有一个 Master 节点负责整个集群的管理控制,我们上面介绍的 k8s 三大能力都是经过 Master 节点发起的,Master 节点包含了以下几个组件:

image.png

  • API Server:提供了 HTTP Rest 接口的服务进程,所有资源对象的增、删、改、查等操作的唯一入口;
  • Controller Manager:k8s 集群所有资源对象的自动化控制中心;
  • Scheduler:k8s 集群所有资源对象自动化调度控制中心;
  • ETCD:k8s 集群注册服务发现中心,可以保存 k8s 集群中所有资源对象的数据。

Node

Node 节点的作用是承接 Master 分配的工作负载,它主要有以下几个关键组件:

  • kubelet:负责 Pod 对应容器的创建、启停等操作,与 Master 节点紧密协作;
  • kube-porxy:实现 k8s 集群通信与负载均衡的组件。

image.png

从图上可看出,在 Node 节点上面,还需要一个容器运行环境,如果使用 Docker 技术栈,则还需要在 Node 节点上面安装 Docker Engine,专门负责该节点容器管理工作。

Pod

Pod 是 k8s 最重要而且是最基本的一个资源对象,它的结构如下:

image.png

从以上 Pod 的结构图可以看出,它其实是容器的一个上层包装结构,这也就是为什么 K8s 可以支持多种容器类型的原因,基于这方面, k8s 的定位就是一个编排与调度工具,而容器只是它调度的一个资源对象而已。

Pod 可包含多个容器在里面,每个 Pod 至少会有一个 Pause 容器,其它用户定义的容器都共享该 Pause 容器,Pause 容器的主要作用是用于定义 Pod 的 ip 和 volume。

Pod 在 k8s 集群中的位置如下图所示:

image.png

Label

Label 在 k8s 中是一个非常核心的概念,我们可以将 Label 指定到对应的资源对象中

例如 Node、Pod、Replica Set、Service 等,一个资源可以绑定任意个 Label,k8s 通过 Label 可实现多维度的资源分组管理,后续可通过 Label Selector 查询和筛选拥有某些 Label 的资源对象,例如创建一个 Pod,给定一个 Label,workerid=123,后续可通过 workerid=123 删除拥有该标签的 Pod 资源。

image.png

Replica Set

Replica Set 目的是为了定义一个期望的场景,比如定义某种 Pod 的副本数量在任意时刻都处于 Peplica Set 期望的值

假设 Replica Set 定义 Pod 的副本数目为:replicas=2,当该 Replica Set 提交给 Master 后,Master 会定期巡检该 Pod 在集群中的数目,如果发现该 Pod 挂掉了一个,Master 就会尝试依据 Replica Set 设置的 Pod 模版创建 Pod,以维持 Pod 的数量与 Replica Set 预期的 Pod 数量相同。

通过 Replica Set,k8s 集群实现了用户应用的高可用性,而且大大减少了运维工作量。因此生产环境一般用 Deployment 或者 Replica Set 去控制 Pod 的生命周期和期望值,而不是直接单独创建 Pod。

image.png

类似 Replica Set 的还有 Deployment,它的内部实现也是通过 Replica Set 实现的,可以说 Deployment 是 Replica Set 的升级版,它们之间的 yaml 配置文件格式大部分都相同。

Service

Service 是 k8s 能够实现微服务集群的一个非常重要的概念

顾名思义,k8s 的 Service 就是我们平时所提及的微服务架构中的“微服务”,本文上面提及的 Pod、Replica Set 等都是为 Service 服务的资源, 如下图表示 Service、Pod、Replica Set 的关系:

image.png

从上图可看出,Service 定义了一个服务访问的入口,客户端通过这个入口即可访问服务背后的应用集群实例,而 Service 则是通过 Label Selector 实现关联与对接的,Replica Set 保证服务集群资源始终处于期望值。

以上只是一个微服务,通常来说一个应用项目会由多个不同业务能力而又彼此独立的微服务组成,多个微服务间组成了一个强大而又高可用的应用服务集群。

image.png

Namespace

Namespace 顾名思义是命名空间的意思,在 k8s 中主要用于实现资源隔离的目的

用户可根据不同项目创建不同的 Namespace,通过 k8s 将资源分配到不同 Namespace 中,即可实现不同项目的资源隔离:

image.png

k8s 组件介绍

整体架构

下图清晰表明了 Kubernetes 的架构设计以及组件之间的通信协议。

image.png

下面是更抽象的一个视图

image.png

Master 架构

image.png

Node 架构

image.png

k8s部署组件介绍

K8s 集群架构图

以下 K8s 架构图显示了 Kubernetes 集群的各部分之间的联系:

image.png

k8s控制组件

控制平面

K8s 集群的神经中枢

让我们从 Kubernetes 集群的神经中枢(即控制平面)开始说起。在这里,我们可以找到用于控制集群的 Kubernetes 组件以及一些有关集群状态和配置的数据,这些核心 Kubernetes 组件负责处理重要的工作,以确保容器以足够的数量和所需的资源运行。

控制平面会一直与您的计算机保持联系。集群已被配置为以特定的方式运行,而控制平面要做的就是确保万无一失。

kube-apiserver

K8s 集群API,如果需要与您的 Kubernetes 集群进行交互,就要通过 API

Kubernetes API 是 Kubernetes 控制平面的前端,用于处理内部和外部请求。API 服务器会确定请求是否有效,如果有效,则对其进行处理,您可以通过 REST 调用、kubectl 命令行界面或其他命令行工具(例如 kubeadm)来访问 API。

kube-scheduler

K8s 调度程序,您的集群是否状况良好?如果需要新的容器,要将它们放在哪里?这些是 Kubernetes 调度程序所要关注的问题。

调度程序会考虑容器集的资源需求(例如 CPU 或内存)以及集群的运行状况。随后,它会将容器集安排到适当的计算节点。

kube-controller-manager

K8s 控制器,控制器负责实际运行集群,而 Kubernetes 控制器管理器则是将多个控制器功能合而为一

控制器用于查询调度程序,并确保有正确数量的容器集在运行。如果有容器集停止运行,另一个控制器会发现并做出响应。控制器会将服务连接至容器集,以便让请求前往正确的端点。还有一些控制器用于创建帐户和 API 访问令牌。

etcd

键值存储数据库

配置数据以及有关集群状态的信息位于 etcd(一个键值存储数据库)中。etcd 采用分布式、容错设计,被视为集群的最终事实来源。

k8s运行组件

k8s节点

Kubernetes 集群中至少需要一个计算节点,但通常会有多个计算节点。

容器集经过调度和编排后,就会在节点上运行。如果需要扩展集群的容量,那就要添加更多的节点。

容器集

容器集是 Kubernetes 对象模型中最小、最简单的单元。

它代表了应用的单个实例。每个容器集都由一个容器(或一系列紧密耦合的容器)以及若干控制容器运行方式的选件组成。容器集可以连接至持久存储,以运行有状态应用。

容器运行时引擎

为了运行容器,每个计算节点都有一个容器运行时引擎。

比如 Docker,但 Kubernetes 也支持其他符合开源容器运动(OCI)标准的运行时,例如 rkt 和 CRI-O。

kubelet

每个计算节点中都包含一个 kubelet,这是一个与控制平面通信的微型应用。

kublet 可确保容器在容器集内运行,当控制平面需要在节点中执行某个操作时,kubelet 就会执行该操作。

kube-proxy

每个计算节点中还包含 kube-proxy,这是一个用于优化 Kubernetes 网络服务的网络代理。

kube-proxy 负责处理集群内部或外部的网络通信——靠操作系统的数据包过滤层,或者自行转发流量。

存储组件

持久存储

除了管理运行应用的容器外,Kubernetes 还可以管理附加在集群上的应用数据。

Kubernetes 允许用户请求存储资源,而无需了解底层存储基础架构的详细信息。持久卷是集群(而非容器集)所特有的,因此其寿命可以超过容器集。

容器镜像仓库

Kubernetes 所依赖的容器镜像存储于容器镜像仓库中。

这个镜像仓库可以由您自己配置的,也可以由第三方提供。

底层基础架构

您可以自己决定具体在哪里运行 Kubernetes。

答案可以是裸机服务器、虚拟机、公共云提供商、私有云和混合云环境。Kubernetes 的一大优势就是它可以在许多不同类型的基础架构上运行。

Pod使用

Pod是kubernetes中你可以创建和部署的最小也是最简的单位,一个Pod代表着集群中运行的一个进程。

Pod中封装着应用的容器(有的情况下是好几个容器),存储、独立的网络IP,管理容器如何运行的策略选项,Pod代表着部署的一个单位:kubernetes中应用的一个实例,可能由一个或者多个容器组合在一起共享资源。

Pod 特点

Pod有两个必须知道的特点

网络

每一个Pod都会被指派一个唯一的Ip地址,在Pod中的每一个容器共享网络命名空间,包括Ip地址和网络端口,在同一个Pod中的容器可以同locahost进行互相通信,当Pod中的容器需要与Pod外的实体进行通信时,则需要通过端口等共享的网络资源。

存储

Pod能够配置共享存储卷,在Pod中所有的容器能够访问共享存储卷,允许这些容器共享数据,存储卷也允许在一个Pod持久化数据,以防止其中的容器需要被重启。

使用方式

自主式Pod

这种Pod本身是不能自我修复的,当Pod被创建后(不论是由你直接创建还是被其他Controller),都会被Kuberentes调度到集群的Node上,直到Pod的进程终止、被删掉、因为缺少资源而被驱逐、或者Node故障之前这个Pod都会一直保持在那个Node上,Pod不会自愈。

如果Pod运行的Node故障,或者是调度器本身故障,这个Pod就会被删除,同样的,如果Pod所在Node缺少资源或者Pod处于维护状态,Pod也会被驱逐。

控制器管理的Pod

Kubernetes使用更高级的称为Controller的抽象层,来管理Pod实例,Controller可以创建和管理多个Pod,提供副本管理、滚动升级和集群级别的自愈能力。

例如,如果一个Node故障,Controller就能自动将该节点上的Pod调度到其他健康的Node上。虽然可以直接使用Pod,但是在Kubernetes中通常是使用Controller来管理Pod的

自主运行Pod

创建资源清单

通过yaml文件或者json描述Pod和其内容器的运行环境和期望状态,例如一个最简单的运行nginx应用的pod,定义如下

vi nginx-pod.yml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.12
    ports:
    - containerPort: 80
参数描述

下面简要分析一下上面的Pod定义文件:

  • apiVersion: 使用哪个版本的Kubernetes API来创建此对象
  • kind:要创建的对象类型,例如Pod,Deployment等
  • metadata:用于唯一区分对象的元数据,包括:name,UID和namespace
  • labels:是一个个的key/value对,定义这样的label到Pod后,其他控制器对象可以通过这样的label来定位到此Pod,从而对Pod进行管理。(参见Deployment等控制器对象)
  • spec: 其它描述信息,包含Pod中运行的容器,容器中运行的应用等等。不同类型的对象拥有不同的spec定义。详情参见API文档

创建Pod

使用kubectl创建pod

kubectl apply -f nginx-pod.yml

image.png

Pod操作

查看Pod列表
kubectl get pods

image.png

可以通过增加 -o wide查看详细信息

kubectl get pods -o wide

image.png

查看描述信息

可以通过describe查看pod的详细信息

kubectl describe pod nginx

image.png

访问pod

可以通过k8s创建的虚拟IP进行访问,可以在k8s的任何一个节点访问

 curl 10.244.1.10

image.png

删除Pod

可以使用delete删除Pod,删除后不能进行恢复

kubectl delete pod nginx

image.png

控制器运行Pod

Pod本身不具备容错性,这意味着如果Pod运行的Node宕机了,那么该Pod无法恢复,因此推荐使用Deployment等控制器来创建Pod并管理。

创建资源清单

通过yaml文件或者json描述Pod和其内容器的运行环境和期望状态,例如一个最简单的运行nginx应用的pod,定义如下

vi nginx-pod.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
        app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.12
        ports:
        - containerPort: 80

参数描述(了解)

下面简要分析一下上面的Pod定义文件:

Replicas

副本数量

spec.replicas 是可以选字段,指定期望的pod数量,默认是1。

Selector

标签选择器

.spec.selector是可选字段,用来指定 label selector ,圈定Deployment管理的pod范围。如果被指定, .spec.selector 必须匹配 .spec.template.metadata.labels,否则它将被API拒绝。如果 .spec.selector 没有被指定, .spec.selector.matchLabels 默认是.spec.template.metadata.labels。

在Pod的template跟.spec.template不同或者数量超过了.spec.replicas规定的数量的情况下,Deployment会杀掉label跟selector不同的Pod。

Pod Template

Pod模板,.spec.template 是 .spec中唯一要求的字段。

.spec.template 是 pod template,它跟 Pod有一模一样的schema,除了它是嵌套的并且不需要apiVersion 和 kind字段。

另外为了划分Pod的范围,Deployment中的pod template必须指定适当的label(不要跟其他controller重复了,参考selector)和适当的重启策略。

.spec.template.spec.restartPolicy 可以设置为 Always , 如果不指定的话这就是默认配置。

创建Pod

kubectl apply -f nginx-pod.yml


kubectl get pods -o wide

创建后发现,有两个nginx的pod在运行,符合我们的预期

image.png

Pod操作

删除Pod

这里可以尝试删除Pod

kubectl delete pod nginx-deployment-f77774fc5-cgs82
# 查看Pod详情
kubectl get pods -o wide

删除Pod后发现重新新建了一个Pod,这是因为有控制器发现少了一个Pod就会进行重新拉起来一个

image.png

镜像拉取策略

pod的镜像拉取策略分为三种:

  • always(总是从官方下载镜像)
  • never(从不下载镜像)
  • ifnotpresent(如果本地没有镜像就从官方下载镜像)。

Kubernetes集群默认使用IfNotPresent策略

always

不管是否存在本地镜像,总是从远程仓库下载

修改资源清单

我们可以通过修改配置清单来配置不同的策略

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
        app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.12
        imagePullPolicy: Always
        ports:
        - containerPort: 80
生效配置
kubectl apply -f nginx-pod.yml

image.png

查看创建过程
kubectl describe pod nginx-deployment

可以清楚的看到重新下载而没有使用本地镜像

image.png

IfNotPresent

Kubernetes集群的默认策略,如果有本地镜像就使用,没有则从远程仓库下载

修改资源清单

我们可以通过修改配置清单来配置不同的策略

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
        app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.12
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
生效配置
kubectl apply -f nginx-pod.yml

image.png

查看创建过程
kubectl describe pod nginx-deployment

可以清楚的看到没有重新下载镜像而是使用本地的镜像。

image.png

Pod生命周期

各个阶段

POD中明确规定了如下几个阶段

状态值说明
挂起(Pending)Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建,等待时间包括调度 Pod 的时间和通过网络下载镜像的时间。
运行中(Running)该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
成功(Succeeded)Pod 中的所有容器都被成功终止,并且不会再重启。
失败(Failed)Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
未知(Unknown)因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。

实际上还有一中状态Terminating,在代码和文档中都没有说明,但却是存在。这种情况出现杂无法获取所在主机的资源情况,一直在尝试建立连接。

Pod重启策略

在Pod中的容器可能会由于异常等原因导致其终止退出,Kubernetes提供了重启策略以重启容器。

Pod通过restartPolicy字段指定重启策略,重启策略类型为:Always、OnFailure 和 Never,默认为 Always。

重启策略对同一个Pod的所有容器起作用,容器的重启由Node上的kubelet执行。Pod支持三种重启策略,在配置文件中通过restartPolicy字段设置重启策略:

重启策略说明
Always当容器失效时,由kubelet自动重启该容器
OnFailure当容器终止运行且退出码不为0时,由kubelet自动重启该容器
Never不论容器运行状态如何,kubelet都不会重启该容器

注意:这里的重启是指在Pod的宿主Node上进行本地重启,而不是调度到其它Node上。

Pod状态转换

Pod的容器数Pod当前状态发生的事件Pod结果状态  
   RestartPolicy=AlwaysRestartPolicy=OnFailureRestartPolicy=Never
包含一个容器Running容器成功退出RunningSucceededSucceeded
包含一个容器Running容器失败退出RunningRunningFailure
包含两个容器Running1个容器失败退出RunningRunningRunning
包含两个容器Running容器被OOM杀掉RunningRunningFailure

生命周期行为

初始化容器

初始化容器(init container)即应用程序的主容器启动之前要运行的容器,常用于为主容器执行一些预置操作,它们具有两种典型特征。

  1. 初始化容器必须运行完成直至结束,若某初始化容器运行失败,那么kubernetes需要重启它直到成功完成。(注意:如果podspec.restartPolicy字段值为“Never”,那么运行失败的初始化容器不会被重启。)
  2. 每个初始化容器都必须按定义的顺序串行运行。

容器探测

容器探测(container probe)是Pod对象生命周期中的一项重要的日常任务,它是kubelet对容器周期性执行的健康状态诊断,诊断操作由容器的处理器(handler)进行定义,Kubernetes支持三种处理器用于Pod探测:

  • ExecAction:在容器内执行指定命令,并根据其返回的状态码进行诊断的操作称为Exec探测,状态码为0表示成功,否则即为不健康状态。
  • TCPSocketAction:通过与容器的某TCP端口尝试建立连接进行诊断,端口能够成功打开即为正常,否则为不健康状态。
  • HTTPGetAction:通过向容器IP地址的某指定端口的指定path发起HTTP GET请求进行诊断,响应码为2xx3xx时即为成功,否则为失败。

任何一种探测方式都可能存在三种结果:“Success”(成功)“Failure”(失败)“Unknown”(未知),只有success表示成功通过检测。

健康检查

强大的自愈能力是Kubernetes这类容器编排引擎的一个重要特性,自愈的默认实现方式是自动重启发生故障的容器。

为什么需要健康检查

用户还可以利用Liveness和Readiness探测机制设置更精细的健康检查,进而实现如下需求:

  • 零停机部署。
  • 避免部署无效的镜像。
  • 更加安全的滚动升级。

检查策略

在Pod部署到Kubernetes集群中以后,为了确保Pod处于健康正常的运行状态,Kubernetes提供了两种探针,用于检测容器的状态:

存活探测

Liveness是检查容器是否处于运行状态,如果检测失败,kubelet将会杀掉掉容器,并根据重启策略进行下一步的操作,如果容器没有提供Liveness Probe,则默认状态为Success;

Liveness探测器是让Kubernetes知道你的应用是否活着,如果你的应用还活着,那么Kubernetes就让它继续存在,如果你的应用程序已经死了,Kubernetes将移除Pod并重新启动一个来替换它。

让我们想象另一种情况,当我们的应用在成功启动以后因为一些原因“宕机”,或者遇到死锁情况,导致它无法响应用户请求。 ​ 在默认情况下,Kubernetes会继续向Pod发送请求,通过使用存活探针来检测,当发现服务不能在限定时间内处理请求(请求错误或者超时),就会重新启动有问题的pod。

image.png

就绪探测

Readiness 是检查容器是否已经处于可接受服务请求的状态,如果Readiness Probe失败,端点控制器将会从服务端点(与Pod匹配的)中移除容器的IP地址,Readiness的默认值为Failure,如果一个容器未提供Readiness,则默认是Success。

就绪探针旨在让Kubernetes知道你的应用是否准备好为请求提供服务,Kubernetes只有在就绪探针通过才会把流量转发到Pod,如果就绪探针检测失败,Kubernetes将停止向该容器发送流量,直到它通过。

一个应用往往需要一段时间来预热和启动,比如一个后端项目的启动需要连接数据库执行数据库迁移等等,一个Spring项目的启动也需要依赖Java虚拟机。即使该过程已启动,您的服务在启动并运行之前也无法运行。应用在完全就绪之前不应接收流量,但默认情况下,Kubernetes会在容器内的进程启动后立即开始发送流量。通过就绪探针探测,直到应用程序完全启动,然后才允许将流量发送到新副本。

image.png

两者对比

  • Liveness探测和Readiness探测是两种Health Check机制,如果不特意配置,Kubernetes将对两种探测采取相同的默认行为,即通过判断容器启动进程的返回值是否为零来判断探测是否成功。
  • 两种探测的配置方法完全一样,支持的配置参数也一样,不同之处在于探测失败后的行为:Liveness探测是重启容器;Readiness探测则是将容器设置为不可用,不接收Service转发的请求。
  • Liveness探测和Readiness探测是独立执行的,二者之间没有依赖,所以可以单独使用,也可以同时使用,用Liveness探测判断容器是否需要重启以实现自愈;用Readiness探测判断容器是否已经准备好对外提供服务

如何配置

对于LivenessProbe和ReadinessProbe用法都一样,拥有相同的参数和相同的监测方式。

  • initialDelaySeconds:用来表示初始化延迟的时间,也就是告诉监测从多久之后开始运行,单位是秒
  • timeoutSeconds: 用来表示监测的超时时间,如果超过这个时长后,则认为监测失败
  • periodSeconds:指定每多少秒执行一次探测,Kubernetes如果连续执行3次Liveness探测均失败,则会杀掉并重启容器

使用场景

  • 如果容器中的进程能够在遇到问题或不健康的情况下自行崩溃,则不一定需要存活探针; kubelet 将根据 Pod 的restartPolicy 自动执行正确的操作。
  • 如果希望容器在探测失败时被杀死并重新启动,那么请指定一个存活探针,并指定restartPolicy 为 Always 或 OnFailure。
  • 如果要仅在探测成功时才开始向 Pod 发送流量,请指定就绪探针,在这种情况下,就绪探针可能与存活探针相同,但是 spec 中的就绪探针的存在意味着 Pod 将在没有接收到任何流量的情况下启动,并且只有在探针探测成功后才开始接收流量。
  • 如果您希望容器能够自行维护,您可以指定一个就绪探针,该探针检查与存活探针不同的端点。
  • 如果您只想在 Pod 被删除时能够排除请求,则不一定需要使用就绪探针;在删除 Pod 时,Pod 会自动将自身置于未完成状态,无论就绪探针是否存在,当等待 Pod 中的容器停止时,Pod 仍处于未完成状态。

默认的健康检查

我们首先学习Kubernetes默认的健康检查机制:每个容器启动时都会执行一个进程,此进程由Dockerfile的CMD或ENTRYPOINT指定。

如果进程退出时返回码非零,则认为容器发生故障,Kubernetes就会根据restartPolicy重启容器

创建资源清单

Pod的restartPolicy设置为OnFailure,默认为Always,sleep 10; exit 1模拟容器启动10秒后发生故障

vi pod-default-health.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-default-health
  namespace: default
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.12
    ports: 
    - containerPort: 80
    args: ["/bin/sh","-c"," sleep 10;exit 1"]

创建容器

kubectl apply -f pod-default-health.yml

image.png

监控Pod变化

kubectl get pods -o wide -w

该命令可以不断显示容器的因为失败不断重启

image.png

在上面的例子中,容器进程返回值非零,Kubernetes则认为容器发生故障,需要重启。

有不少情况是发生了故障,但进程并不会退出,比如访问Web服务器时显示500内部错误,可能是系统超载,也可能是资源死锁,此时httpd进程并没有异常退出,在这种情况下重启容器可能是最直接、最有效的解决方案,那我们如何利用HealthCheck机制来处理这类场景呢?

探针类型

探针类型是指通过何种方式来进行健康检查,K8S有三种类型的探测:HTTP,Command和TCP。

exec存活探针

对于命令探测,是指Kubernetes在容器内运行命令,如果命令以退出代码0返回,则容器将标记为正常。否则,它被标记为不健康

下面的资源会在先创建一个nginx的任务,生存测试探针livenessProbe会执行test -e /tmp/healthy命令检查文件是否存在, 若文件存在则返回状态码 0,表示成功通过测试。

apiVersion: v1
kind: Pod
metadata:
  name: pod-nginx-demo
  namespace: default
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.12
    ports: 
    - containerPort: 80
    livenessProbe:
      initialDelaySeconds: 5
      periodSeconds: 3
      exec:
        command: ["test","-e","/tmp/healthy"]
创建pod

创建pod

kubectl create -f pod-demo.yaml
kubectl get pod -w -o wide

启动后不断检测/tmp/healthy是否存在,不存在重启容器

image.png

创建文件

新开一个窗口写入登录pod容器,写入healthy文件

# 登录pod容器
kubectl exec pod-nginx-demo -it /bin/bash
echo healthy > /tmp/healthy
# 在html目录写入healthy文件
echo healthy > /tmp/healthy

image.png

查看原来的pod状态

kubectl get pods -o wide -w

我们发现pod不在不断地重启了

image.png

HTTP就绪探针

HTTP探测可能是最常见的探针类型,即使应用不是HTTP服务,也可以创建一个轻量级HTTP服务器来响应探测,比如让Kubernetes通过HTTP访问一个URL,如果返回码在200到300范围内,就将应用程序标记为健康状态,否则它被标记为不健康。

上面 清单 文件 中 定义 的 httpGet 测试 中, 请求的资源路径 为/healthy, 地址 默认 为 Pod IP, 端口使用了容器中定义的端口名称 HTTP, 这也是明确为容器指明要暴露的端口的用途之一。

apiVersion: v1
kind: Pod
metadata:
  name: pod-nginx-demo
  namespace: default
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.12
    ports: 
    - containerPort: 80
    readinessProbe:
      initialDelaySeconds: 5
      periodSeconds: 3
      httpGet:
        port: 80
        path: /healthy
        scheme: HTTP
创建pod
kubectl create -f pod-demo.yaml
#查看pod状态
kubectl get pods -o wide -w

我们发现nginx 一致处于未未就绪状态

image.png

查看pod详情
 kubectl describe pod pod-nginx-demo

image.png

创建文件

新开一个窗口写入登录pod容器,写入healthy文件

# 登录pod容器
kubectl exec pod-nginx-demo -it /bin/bash
# 在html目录写入healthy文件
echo healthy > /usr/share/nginx/html/healthy

查看原来的pod状态

kubectl get pods -o wide -w

image.png

访问
curl 10.244.1.30/healthy

再次删除healthy文件

rm -f /usr/share/nginx/html/healthy

image.png

再次查看pod状态,进入未就绪状态

 kubectl get pods -o wide -w

image.png

TCP探针

TCP探测是指Kubernetes尝试在指定端口上建立TCP连接。

如果它可以建立连接,容器被认为是健康的; 如果它不能被认为是不健康的。

这常用于对gRPC或FTP服务的探测。

下面的资源清单文件,向Pod IP的80/tcp端口发起连接请求,并根据连接建立的状态判断Pod存活状态。

apiVersion: v1
kind: Pod
metadata:
  name: pod-nginx-demo
  namespace: default
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.12
    ports: 
    - containerPort: 80
    livenessProbe:
      tcpSocket:
        port: 80
探测结果

每次探测都将获得以下三种结果之一:

  • 成功:容器通过了诊断。
  • 失败:容器未通过诊断。
  • 未知:诊断失败,因此不会采取任何行动。
创建pod
kubectl create -f pod-demo.yaml
#查看pod状态
kubectl get pods -o wide -w

只要80端口正常一致就是正常状态

image.png