Kubernetes(K8s)系列——(一)关于Pod和Namespace


Kubernetes系列文章主要内容
菜鸟学Kubernetes(K8s)系列——(二)关于Deployment、StatefulSet、DaemonSet、Job、CronJob通过本文你将学习到:
(1)什么是Deployment,如何创建它、它的扩缩容能力是什么、自愈机制,滚动升级全过程、如何进行回滚
(2)什么是ReplicaSet、它和Deployment的关系是什么
(3)动态扩缩容能力(HPA)、蓝绿部署、金丝雀部署
(4)什么是DaemonSet/Job/CronJob、它们的功能是什么、如何创建使用等等
菜鸟学Kubernetes(K8s)系列——(三)关于Service、Ingress通过本文你将学习到:
(1)什么是Service,如何创建它、它的服务发现能力、对外暴露方式
(2)什么是NodePort类型的Service,它的使用方式、工作原理
(3)什么是Ingress,如何创建它、为什么需要Ingress
(4)什么的Ingress-Nginx、他和Nginx是什么关系、Ingress的各种功能
(5)什么是headless服务等等
菜鸟学Kubernetes(K8s)系列——(四)关于Volume卷(PV、PVC、StorageClass等)通过本文你将学习到:
(1)什么是Volume卷、它的几种类型(emptyDir、hostPath、NFS)、这几种类型是使用方式
(2)什么是PV-PVC、为什么要用他们、他们是怎么协作的、如何使用PV-PVC
(3)动态配置持久卷是什么,它是怎么工作的、如何实现动态的分配PV等等
菜鸟学Kubernetes(K8s)系列——(五)关于ConfigMap和Secret通过本文你将学习到:
(1)什么是ConfigMap,如何创建它、它能用来做什么事情、在实战中怎么使用ConfigMap
(2)什么是Secret,如何创建它,怎么使用它等等
菜鸟学Kubernetes(K8s)系列——(七)关于Kubernetes底层工作原理通过本文你将学习到:
(1)Kubernetes的核心组件:Etcd、Api-Server、Scheduler、Controller-Manager、Kubelet、Kube-proxy的工作方式,工作原理。
(2)Kubernetes集群中核心组件的协作方式、运行原理。等等
菜鸟学Kubernetes(K8s)系列——(八)关于Kubernetes的认证机制(RBAC)通过本文你将学习到:
(1)Api-Server的认证授权流程(2)什么是ServiceAccount(3)什么是Role、ClusterRole、RoleBinding、ClusterRoleBinding,如何使用他们,他们之间是如何关联协作的。等等
菜鸟学Kubernetes(K8s)系列——(番外)实现Deployment的动态扩缩容能力(HPA)通过本文你将学会实现Deployment的动态扩缩容能力(HPA)
菜鸟学Kubernetes(K8s)系列——(番外)安装Ingress-Nginx(工作原理)通过本文你将学会安装Ingress-Nginx

一、关于Pod

1、什么是Pod?

在Kubernetes中,她并不直接处理单个容器,而是直接操作Pod,Pod相当于是Kubernetes中最基本的部署单位。一个Pod中是可以包含多个容器的,容器中运行的是我们的应用程序。

一个Pod中是一组紧密相关的容器,这些容器一定是运行在同一个工作节点上的。每个Pod就像是一个独立的逻辑机器,拥有自己的IP、主机名、进程等。下面看看工作节点(Node)、Pod、容器、应用程序之间的关系。

在这里插入图片描述

1.1 为什么需要Pod?

为什么需要Pod?为什么不直接使用容器?为什么需要同时运行多个容器?为什么不能简单地把所有进程都放在一个单独的容器中?

一个由多个进程组成的应用程序往往是需要被运行在同一个台机器上。而我们知道,每个容器都非常像一台独立的机器,所以我们自然而然的就会认为,在单个容器中运行多个进程是合乎逻辑的。然而,在实践中这种做法并不合理。

我们建议,一个容器中运行一个进程。因为一个容器中运行一个进程会让水平扩缩容变的简单。这里举个例子:比如我们将一个前端服务和一个后端服务同时部署在同一个容器中,这时由于请求负载过大,我们只需要对后端服务进行扩容(一般情况下为了缓解请求压力只需要扩容后端服务,而不用过多的扩容前端服务),由于前后端服务部署在同一个容器中,这就让我们没办法去为一个单独容器(或者Pod)进行扩容(后面会讲解Deployment对Pod的扩缩容能力,很方便!),这就让扩缩容的过程变得非常复杂。一个容器中运行一个进程,这样才能够最好地应用容器编排来管理好容器和服务。因此建议一个容器中只运行一个进程。

由于不能将多个进程聚集在一个单独的容器中,所以就需要一种更高级的结构将容器绑定在一起,并将她们作为一个单元进行管理,这就产生了Pod。在一个Pod中,我们可以同时运行一些密切相关的进程,并为他们提供相同的环境,这时这些进程就好像全部运行于单个容器中一样,同时又保持着一定的隔离。

1.2 Pod的隔离特性

在Docker中我们知道每个容器之间是相互隔离的,每个容器都有属于自己的一组Namespace(指的是Linux的Namespace)。但是在K8s中,Pod之间是隔离的,而Pod中的一组容器是共享一些资源的。(意思让这些容器之间不用完全隔离)K8s通过配置Docker来让一个Pod内的所有容器共享相同的Namespace,而不是每个容器都有自己的一组Namespace。

由于一个Pod中的所有容器都在相同的Network Namespace下(他们还共享其他的一些Namespace),所以他们都共享相同的IP和端口。这就意味着在同一Pod中的容器运行的多个进程需要注意不能绑定到相同的端口号,否则会导致端口冲突。注意是同一Pod,而不同Pod间的容器是不用担心端口冲突的。此外,一个Pod中的所有容器也都具有相同的loopback网络接口,所以同一个Pod中的多个容器是可以通过localhost进行通信的。

上面提到了同一个Pod中的容器是不完全隔离的。当涉及到文件系统时,各个容器就是隔离的,因为大多数容器的文件系统来自容器镜像,因此默认情况下, 每个容器的文件系统与其他容器完全隔离。(但其实可以通过K8s的Volume来实现共享文件目录的操作,后面会提到这一功能。)

另外,在K8s集群中所有的Pod都在同一共享网络地址空间中,因此,整个集群中的每个Pod都可以通过其他Pod的IP地址实现相互访问。

在通过kubeadm安装Kubernetes集群的时候设置过一个配置:

kubeadm init \
--apiserver-advertise-address=xx.xx.xx.xx \
--image-repository xxx \
--kubernetes-version v1.21.0 \
--service-cidr=10.96.0.0/16 \
--pod-network-cidr=10.244.0.0/16   ### 这个就是集群中Pod的网络范围

1.3 通过Pod管理容器

一个Pod管理一个容器

我们将Pod视为独立的机器,其中每个机器只托管一个特定的应用。以前我们习惯于将各种应用程序塞进同一台主机,但是Pod不是这么玩的。我们将应用程序组织到多个Pod中,而每个Pod中只包含紧密相关的组件或进程。(注意,Pod是很轻量的,我们可以在几乎不导致任何额外开销的前提下拥有尽可能多的Pod,所以不用担心创建了太多的Pod)

这里继续以一个由前端应用和后端服务组成的多层应用程序为例。

前面我们提到,尽量让一个容器中运行一个进程,然后让一个Pod中运行多个容器,以这样的形式来实现前后端的部署。但是这样真的好吗?其实这种方式并不推荐。原因有两点:

  • 如果把前端和后端都部署在同一个Pod中,那么他们两个相当于是共生的,始终会部署在同一台机器上(一个Pod中的多个容器一定是运行在同一台机器上的)。这时如果我们集群具有多个节点,而整个前后端服务一直都部署在同一节点上,就不能对其他节点的资源进行充分利用。
  • 另一个原因和前面提到的一样,方便扩缩容。Pod是K8s中的基本操作单元,在K8s中实现动态扩缩容是对Pod进行扩缩容的。因此为了方便只扩容后端服务,更合理的做法就是把前后端服务拆分成两个Pod,方便的进行扩缩容。
何时在Pod中使用多个容器?

将多个容器添加到单个Pod中的主要原因是应用可能由一个主进程和多个辅助进程组成。在决定是将两个容器放入一个Pod还是两个单独的Pod时,我们需要问自己以下问题:

  • 他们需要一起运行还是可以在不同的主机上运行?
  • 他们代表的是一个整体还是相互独立的组件?
  • 他们必须一起进行扩缩容还是可以分别进行?

一般情况下,我们总是倾向于在单独的Pod中运行单独的容器。

2、几种不同的Pod(可暂时忽略)

每一个Pod中可以有三组容器:初始化容器组、应用容器组、临时容器组
在这里插入图片描述

应用容器
  • 应用容器就是我们用来运行应用程序的容器。
  • Pod启动,会先依次执行所有初始化容器,有一个失败,则Pod不能启动。接下来启动所有的应用容器(每一个应用容器都必须能一直运行起来),Pod开始正式工作,只要有一个容器启动失败就会尝试重启Pod内的这个容器,Pod只要是NotReady,Pod就不对外提供服务了
初始化容器
  • 应用容器必须一直运行,与应用容器不同的是,初始化容器必须要有终结的时刻,一般不要用一直启动的镜像。

  • 如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。 每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时, Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行。

创建一个初始化容器:(初始化容器一般用来准备好一些前置东西,然后其他容器再启动

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:    ### 应用容器
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:  ### Pod在启动containers之前,先要【运行完】initContainers的所有容器,所以这些容器必须有终结,不能一直运行
  - name: init-myservice
    image: busybox:1.28     ### 必须有终结的那个时刻,一般不要用一直启动的镜像,比如nginx
    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"]   ### 该命令表示他要等待myservice这个Service被创建了他才能启动成功
  - name: init-mydb
    image: busybox:1.28
    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"]       ### 该命令表示他要等待mydb这个Service被创建了他才能启动成功

初始化容器的状态如下:

NAME        READY     STATUS     RESTARTS   AGE
myapp-pod   0/1       Init:0/2   0          6m
临时容器

临时容器在当前版本还不太稳定,所以暂时不太用

临时容器用于线上排错。有些容器基础镜像。线上没法排错(比如一些容器里面的基础命令ip a、vim等命令都是没有的)。这时就可以使用临时容器进入这个Pod。临时容器共享了Pod的所有。临时容器 有Debug的一些命令,排错完成以后,只要exit退出容器,临时容器自动删除

3、创建一个Pod

3.1 从一个简单的Yaml开始

apiVersion: v1   ### 描述文件遵循v1版本的kubernetes API
kind: Pod		### 表示资源类型
metadata:
  name: test-pod   ### pod的名称
spec:
  containers:
  - name: zaq-container   ### 容器的名称
    image: nginx	### 创建容器所用的镜像
    ports:
    - containerPort: 80   ### 应用监听的端口
      protocol: TCP

通过kubectl apply -f mypod.yaml 即可部署这个Pod

这个文件表达的含义是:该文件遵循kubernetes API的v1版本,描述的资源类型是Pod类型,名称为test-pod,该Pod由基于nginx镜像的单个容器组成,该容器的名称为zaq-containers,他正在监听8080端口。

在Pod定义中指定的端口纯粹是展示性的,写不写无所谓。但是明确定义端口是有必要的,这样能让每个使用集群的人都可以快速查看每个Pod对外暴露的端口。后面我们还可以为每个端口指定一个名称,方便我们管理。

上面的这些属性我们不用特意去记,我们随时可以通过 kubectl explain 命令去查看每个字段的含义:

  • kubectl explain pods
  • kubectl explain pods.spec
  • kubectl explain pods.spec.containers

以后K8s的所有资源都可以通过一个Yaml文件来进行描述

注意:

我全文中提到的资源大部分指的是对Pod、Deploymen、Service、Ingress等等等等的统称,后面会一一介绍,小部分资源指的是机器的资源,如CPU、内存等,需要根据上下文环境区分。

3.2 对创建好的Pod进行一些操作

  • 获取所有的Pod:kubectl get pod -A

  • 查看Pod的完整定义:kubectl get pod test-pod -o yaml

  • 查看Pod的日志(这里说查看Pod的日志,其实更准确的说应该是查看容器的日志):kubectl logs test-pod

    • 如果Pod中存在多个容器,则只需要在命令后加 -c <容器名称> 参数即可

      kubectl logs test-pod -c zaq-containers

    • 注意:Pod被删除那他的日志也会被删除,如果希望在Pod删除之后仍然可以获取其日志,我们需要设置中心化的、集群范围的日志系统,将所有日志存储到中心存储中。

4、使用标签组织Pod

关于标签这个概念新手可能不好理解,如果看不懂可以先往后看,之后再回过头来看可能会恍然大悟。

4.1 什么是标签

标签是可以附加到资源的任意键值对,用来选择具有该确切标签的资源(通过标签选择器来选择)。只要标签的key在资源内是唯一的,一个资源便可以拥有多个标签。通常我们在创建资源时就会将标签附加到资源上。

标签不仅可以组织Pod,还能组织Kubernetes中的其他资源。他的主要功能就是为资源进行分组,方便管理。

以Pod资源为例,我们看看当K8s集群中的Pod没有打标签时:

在这里插入图片描述

这是我们一个微服务项目产生的多个Pod,他们有的Account服务部署的Pod,有的是Product服务部署的Pod,甚至有的是生产环境的,有的是stable环境的,他们在集群中杂乱无章。
而如果我们为这些Pod加上标签(进行分组),效果大不相同:

在这里插入图片描述

这是从两位维度上为他们分组:一个是按服务来分,一个是按环境来分。分别为各个Pod上打了两个标签:app和rel。

  • app:指定这个Pod属于哪个应用、组件或微服务。
  • rel:指定该Pod运行的应用程序属于什么环境。

4.2 为Pod指定标签

apiVersion: v1   ### 描述文件遵循v1版本的kubernetes API
kind: Pod		### 表示资源类型
metadata:
  name: test-pod   ### pod的名称
  namespace: default
  labels:
    env: prod        ###为pod指定 env:prod 标签
    app: testapp	 ###为pod指定 app:testapp 标签
spec:
  containers:
  - name: zaq-containers   ### 容器的名称
    image: nginx	### 创建容器所用的镜像
    ports:
    - containerPort: 80   ### 应用监听的端口
      protocol: TCP
  • 查看所有Pod具有的标签:kubectl get pod --show-labels

  • 查看具有指定标签的Pod:kubectl get pod -L env, app

  • 通过命令行为Pod新增标签:kubectl label pod test-pod key1=value1

  • 通过命令行修改Pod原有的标签的值:kubectl label pod test-pod env=debug --overwrite

4.3 标签选择器

单单为Pod创建一个标签并没有什么,他需要和标签选择器配合使用才能展现出强大的威力。标签选择器允许我们选择标记有特定标签的Pod子集,并对这些Pod执行操作。可以把标签选择器当作是我们用来过滤资源的过滤器。

标签和标签选择器在后面多处都会使用到,到时候也会再做介绍,这里说太多也无法很好的理解,所以就不再赘述

5、Pod的健康检查机制(Probe探针机制)

引言:

在Kubernetes中有一种自我修复能力。只要将 Pod 调度到某个节点, 该节点上的 Kubelet 就会运行 Pod 的容器,只要该 Pod 存在, 就会保持运行。 如果容器的主进程崩溃, Kubelet 将重启容器。 如果应用程序中有一个导致它每隔一段时间就会崩溃的bug, Kubemetes也会自动重启应用程序, 所以就算应用程序本身没有做任何特殊的处理,只要在Kubemetes 中运行,就能自动获得自我修复的能力。

那么会有一种情况,就算进程没有崩溃,有时一个应用程序也不能正常工作。比如应用发生内存泄漏抛出了OutOfMemoryErrors,但是JVM进程还一直运行。对于这种情况,就不能通过常规的机制判断是否健康,Kubernetes怎么检测这种情况,并重启容器呢?

对于这种问题有一种解决办法就是让应用程序给Kubernetes发送信号,告诉Kubernetes他运行异常并让Kubernetes重启他。但是这种解决办法不能解决所有问题。比如,你的应用因为无限循环或者死锁停止响应。为了保证应用程序在这种情况下也能被重启,必须从外部来检查应用的运行状况,而不是依赖内部检测。

这就引入了Kubernetes的存活探针(liveness probe),它可以用来检测容器是否还在允许。可以为Pod中的每个容器单独指定存活探针。如果探测失败,Kubernetes将定期执行探针并重新启动容器。

5.1 K8s中每个容器都可以都有三种探针

启动探针(startupProbe)

kubelet使用启动探针,来检测应用是否已经启动完成。如果提供了启动探针,则所有其他探针都会被禁用,直到此探针成功为止。如果启动探测失败,kubelet将杀死容器,而容器依其 重启策略进行重启。

比如有一个大型应用,可能会启动五分钟才算启动,仅调用了一个docker run是不能认为他就是启动的。对于这些启动时间长的应用就需要有一个启动探针,探测应用什么时候才算真正启动了

  • 慢容器一定指定启动探针。如果一直检测到未启动,则会一直在等待启动。
  • 启动探针是一个一次性探针。成功以后就不用了,剩下存活探针和就绪探针持续运行
存活探针(livenessProbe)

kubelet使用存活探针,来检测容器是否正常运行。(有些容器可能产生死锁【应用程序在运行,但是无法继续执行后面的步骤】), 如果检测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略决定未来。

  • 对于生产中运行的Pod,一定要定义一个存活探针
  • 如果在容器中运行的是Java应用程序,请确保使用HTTP GET存活探针,而不是启动全新JVM以获取存活信息的Exec探针。任何基于JVM或类似的应用程序也是如此,因为他们的启动过程需要大量的计算资源。
  • 如果容器不提供存活探针, 则默认状态为 Success
  • initialDelaySeconds: 3600(长了导致可能应用一段时间不可用) 5(短了陷入无限启动循环),为此引入启动探针(所以现有的存活探针,才有的启动探针)。
就绪探针(readinessProbe)

kubelet使用就绪探针,来检测容器是否准备好了可以接收客户端的请求(也就是是否能对外提供服务)。当一个Pod内的所有容器都准备好了,才能把这个Pod看作就绪了。

  • 就绪探针会定期调用,并确定特定的Pod是否接收客户端的请求。

  • 如果容器不提供就绪态探针,则默认状态为 Success

  • 与存活探针不同的是,如果就绪探针检测失败,是不会被终止或重新启动的。(这是存活探针和就绪探针之间的重要区别)存活探针通过杀死异常的容器并用新的正常容器代替他们来保持Pod正常工作,而就绪探针是从一个Endpoints中剔除异常的Pod,来保证请求一定访问到正常的Pod。

    如图, 如果一个容器的就绪探测失败, 则将该容器从Service负载均衡里面剔除,连接到该服务的客户端不会被重定向到Pod,等再次准备就绪才重新添加Pod。 这和Pod与服务的标签选择器完全不匹配的效果相同。

    在这里插入图片描述

    但是注意:不要用这一特性去实现从Service中移除Pod的功能,如果想要从某个Service中手动添加或删除Pod,请将enabled=true作为标签添加到Pod,以及Service的标签选择器中,当想要从Service中剔除Pod时,删除标签即可。

为什么要有就绪探针?

就绪探针确保客户端只与正常的pod交互, 并且永远不会知道系统存在问题。

如果没有将就绪探针添加到pod 中,它们几乎会立即成为服务端点。 如果应用程序需要很长时间才能开始监听传入连接,则在服务启动但尚未准备好接收传入连接时,客户端请求将被转发到该 pod。 因此,客户端会看到 “连接被拒绝 ” 类型的错误。

实例:

假设有一个订单服务在①号机器部署了一份,在②号机器部署了一份。会在两台机器上分别启动一个Pod,这时StartUp启动探针会探测Pod是否启动起来,如果成功了说明应用已经启动起来了。

应用启动后,可能会出现假死状态,不能提供服务。liveness存活探针会检查Pod在存活过程中是否还正常活着,所以他的检测可能会每隔一段时间去检测一个Pod是否正常活着。

Pod是活着的还不够,还会有Readiness就绪探针检测Pod是否准备就绪。两个Pod上层会由Service来做负载均衡,外部给Service发送请求,Service会将请求负载均衡到Pod①或者Pod②,而负载均衡网络要把请求发给哪个Pod,决定于Pod的就绪探针。如果哪个Pod的就绪探针提示他不能接收请求了,那这个Pod就会从Service的负载均衡网络中剔除,Service不在会给他发送请求。保证线上所有的应用能进行正常服务。

5.2 谁在利用这些探针探测?

  • 答:Kubelet,检测探针状态,重启容器这项任务是由承载Pod的节点上的Kubelet执行的,在Master节点上的Kubenetes Control Plane组件是不会参与此过程的。(Control Plane这一概念会在K8s的运行原理中讲解)

Kubelet检测的全过程:

Pod中会有多个容器,每个容器 都会配置三个探针(StartUp、Liveness、Readiness),这三个探针由Kubelet发起调用。

Kubelet首先会启动Pod,从而启动容器,Kubelet在底层docker run把容器启动起来,如果没有启动探针,只要docker run了kubelet就认为这个容器启动起来了。但是有些容器启动很慢,所以建议配一个启动探针。等容器真正启动完成了,再调用存活探针,不断的打电话问这个容器活着没活着没活着没,只要容器告诉他我活着我活着我活着,Kubelet就不会重启他。如果突然有个容器没反应了(比如三次没反应),这时Kubelet就会认为这个容器炸了,就会重启这个容器。直到容器一直活着,Kubelet就会调用就绪探针,每隔一段时间问容器有没有就绪,如果就绪,这时候请求流量就能发送到容器。

5.3 三种探针总结

  • 启动探针用来检查应用是否已经启动完成。(检测失败,则重启容器)

  • 存活探针会检查容器是否正常运行,如果不是就会重启他。(检测失败,则重启容器)

  • 就绪探针会检查容器是否能对外提供服务。如果不能,就会在Service负载均衡列表中被移除,客户端的请求就不会被再分配到这个就绪探针检测异常的容器上。

5.4 Kubemetes 对容器探测的三种机制

  • HTTP GET:对容器的 IP 地址(你指定的端口和路径)执行 HTTP GET 请求。

    如果探测器收到响应,并且响应状态码为200到400之间, 则认为探测成功。如果服务器返回错误响应状态码或者根本没有响应,那么探测就被认为是失败的,容器将被重新启动。

  • TCP Socket:TCP套接字探针尝试与容器指定端口建立TCP连接。如果连接成功建立,则探测成功。否则,容器重新启动。

  • Exec:探针在容器内执行任意命令,并检查命令的退出状态码。如果状态码是0, 则探测成功。所有其他状态码都被认为失败。

5.5 每个容器中每种探针Probe的附加功能

  • initialDelaySeconds :延时探测。容器启动后要等待多少秒后,探测器才被初始化,进行探测,默认是 0 秒后,最小值是 0。这是针对以前没有,即Kubelet第一次探测时生效。

    如果没有设置初始延迟,探针将在启动时立即开始探测容器, 这通常会导致探测失败,因为应用程序还没准备好开始接收请求。 如果失败次数超过阈值,在应用程序能正确响应请求之前, 容器就会重启。

    **提示:**务必记得设置一个初始延迟来说明应用程序的启动时间。

  • periodSeconds:执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1。

  • successThreshold:探测器在失败后,被视为探测成功的最小连续成功数。(换句话说:连续几次成功才算成功)默认值是 1。

    • 存活和启动探针的这个值必须是 1。最小值是 1。
  • failureThreshold:当探测失败时,Kubernetes 的重试次数。 (换句话说:连续几次失败才算失败)默认值是 3。最 小值是 1。

    • 存活探测情况下的放弃(失败)就意味着重新启动容器。
    • 就绪探测情况下的放弃(失败),Pod 会被打上未就绪的标签。
  • timeoutSeconds :探测超时。到了超时时间探测还没有返回结果说明失败。默认值是 1 秒。最小值是 1。

  • exechttpGettcpSocket,这三个表示用哪种方式探测

5.6 简单示例

创建一个包含HTTP GET存活探针的新Pod

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: luksa/kubia-unhealthy    ### 这是一个测试镜像,在发送第六次请求的时候都会返回一个500异常
    livenessProbe:
      httpGet:          ### 一个基于HTTP GET机制的存货探针
        path: /		### HTTP请求的路径
        port: 8080   ### 探针链接的网络端口

该Pod的描述文件定义了一个httpGet存活探针,该探针告诉Kubernetes定期在端口8080路径上执行HTTP GET请求,以确定该容器是否健康。当容器不健康了,K8s会认为探测失败,重启容器。

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 18; rm -rf /tmp/healthy; sleep 600    # 创建一个文件;睡30s;文件又删除,睡600秒
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5  #容器启动RUNNING 5秒以后再来探测
      periodSeconds: 5 #每隔5秒探测一次
apiVersion: v1
kind: Pod
metadata:
    name: "nginx-start-probe02"
    namespace: default
    labels:
        app: "nginx-start-probe02"
spec:
    volumes:
    - name: nginx-vol
      hostPath:
        path: /app
    - name: nginx-html
      hostPath:
        path: /html
    containers:
    - name: nginx
      image: "nginx"
      ports:
      - containerPort: 80
      
      volumeMounts:
      - name: nginx-vol
        mountPath: /app
      - name: nginx-html
        mountPath: /usr/share/nginx/html
        
      startupProbe:
        exec:
          command: ["/bin/sh","-c","cat /app/abc"] ## 对于Kubectl来说,只要返回不是0,那就是探测失败
# initialDelaySeconds: 20 ## 探测延时,即指定的这个 秒以后才执行探测
        periodSeconds: 5 ## 每隔几秒来运行这个探测
        timeoutSeconds: 5 ##探测超时,即到了超时时间探测还没返回结果说明失败
        successThreshold: 1 ## 成功阈值,连续几次成才算成功
        failureThreshold: 3 ## 失败阈值,连续几次失败才算真失败
        
      livenessProbe: ## nginx容器有没有 /abc.html,就绪探针
        exec:
          command: ["/bin/sh","-c","cat /usr/share/nginx/html/abc.html"] ## 返回不是0,那就是探测失败
# initialDelaySeconds: 20 ## 指定的这个秒以后才执行探测
        periodSeconds: 5 ## 每隔几秒来运行这个
        timeoutSeconds: 5 ##探测超时,到了超时时间探测还没返回结果说明失败
        successThreshold: 1 ## 成功阈值,连续几次成才算成功
        failureThreshold: 3 ## 失败阈值,连续几次失败才算真失败

      readinessProbe: # #就绪检测,都是http
        httpGet:
# host: 127.0.0.1 ###不行
          path: /abc.html ## 给容器发请求
          port: 80
          scheme: HTTP ## 返回不是0,那就是探测失败
        initialDelaySeconds: 2 ## 指定的这个秒以后才执行探测
        periodSeconds: 5 ## 每隔几秒来运行这个
        timeoutSeconds: 5 ##探测超时,到了超时时间探测还没返回结果说明失败
        successThreshold: 3 ## 成功阈值,连续几次成才算成功
        failureThreshold: 5 ## 失败阈值,连续几次失败才算真失败

二、关于Namespace(名称空间)

前面提到过通过标签可以将资源进行分组,但是他需要通过标签选择器去选择。在Kubernetes中还有另一种对资源进行分组的方式,就是通过Namespace进行分组。

**注意:**这里的Namespace和Docker中提到的基于Linux的Namespace实现资源隔离是不一样的。Kubernetes的Namespace简单地为资源名称提供了一个作用域,我们一定不会将所有的资源都放在同一个命名空间中,而是将她们组织到多个命名空间中,这样就可以允许我们在不同的名称空间中多次使用相同的资源名称。

1、Namespace能做什么?

我们可以通过Namespace将一个包含大量组件的复杂系统拆分为多个不同的组,这些组也可以用于在多租户环境中分配资源,将资源分配为生产、开发和QA环境。

如果有多个用户或用户组正在使用同一个Kubernetes集群,并且他们都各自管理自己独特的资源集合,那么他们就应该分别使用各自的名称空间。这样一来,他们就不用特别担心无意中修改或删除其他用户的资源,也无需关心名称冲突。在不同的用户看来,他们就好像在单独的使用这个Kubernetes集群。

除了隔离资源的作用,Namespace还可以用于仅允许某些用户访问某些特定资源,甚至限制单个用户可用的计算资源数量。后面会详细介绍。

注意,在Kubernetes中还有一些节点资源是不受命名空间的限制的,比如ClusterRole、ClusterRoleBinding等等。

2、Namespace不能做什么?

尽管Namespace将资源分割到不同的组,只允许你对属于特定Namespace的资源进行操作,但实际上Namespace之间并不提供对正在运行的资源的任何隔离。

比如,你可能会认为当不同的用户在不同的Namespace中部署Pod时,这些Pod应该彼此隔离,并且无法通信,但事实却并非如此。Namespace之间是否提供网络隔离取决于Kubernetes所使用的网络解决方案。当该解决方案不提供Namespace间的网络隔离时,那么如果namespaceA中的某个Pod知道namespaceB中Pod的IP地址,这时他就可以将流量发送到另一个Pod中。

3、通过Yaml创建Namespace

apiVersion: v1
kind: Namespace
metadata:
  name: custom-namespace      ### 指定名称空间的名称

4、通过命令行创建Namespace

kubectl create namespace test-ns

未完,待续>>>

参考:Kubernetes in Action

Logo

开源、云原生的融合云平台

更多推荐