• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Kubernetes学习(二)

武飞扬头像
种棵马拉松
帮助1

二 开始使用Kubernetes和Docker

(一)创建、运行、共享容器镜像

使用DockerFile来创建一个简单的Web容器镜像,并将其发布到DockerHub中以共享镜像

  • 使用DockerFile创建一个镜像
  • docker run创建容器并进行测试
  • 使用docker tag修改镜像标签,并使用docker push镜像推送到DockerHub
  • 在其他服务或者机器中拉取该镜像进行运行
(二)部署K8S集群
1. 使用Google Kubernetes Engine(GKE)托管K8S集群
  • 在GKE上创建一个三节点集群gcloud container clusters create-auto hello-cluster \ --region=COMPUTE_REGION,创建后可以使用kubectl get nodes来查看节点,还可以使用kubectl describe node [node-id]来查看节点的详细信息
  • 现在已经创建了一个K8S集群,可以向其部署容器化服务了,创建一个deployment来托管容器服务:kubectl create deployment hello-server \ --image=us-docker.pkg.dev/谷歌-samples/containers/gke/hello-app:1.0
  • 公开deployment
    部署应用后,应该将其公开给外网,可以通过创建service资源将其开放给外部网络访问kubectl expose deployment hello-server --type LoadBalancer --port 80 --target-port 8080
  • 水平伸缩应用
    通过调度deploment可以轻松实现容器服务的扩展部署,kubectl scale deployment/hello-server --replicas=3 -n default将容器服务的运行实例增加到三个。目前应用正在三个实例上运行,当外部访问该web服务时,将在这三个pod之间进行切换
  • 可以使用kubectl get pod -o wide获取pod运行的节点信息,还可以使用kubectl describe pod [pod-id]来获取指定pod更加详细的信息

三 POD — 运行于K8S中的容器

       POD是一组并置的容器,组成了K8S中最基本的构建单元,实际应用中我们不会对容器进行直接操作,而是对POD进行处理。这并不意味着POD中一定需要包含多个容器服务,但是当一个POD包含多个容器时,这些容器总会是在同一个工作节点上。
       为何多个容器比单个容器中包含多个进程要好?想象一个由多个进程组成的应用程序, 无论是通过ipc (进程间通信)还是本地存储文件进行通信, 都要求它们运行于同一 台机器上。 在Kubernetes中, 我们经常在容器中运行进程, 由于每一个容器都非常像一台独立的机器, 此时你可能认为在单个容器中运行多个进程是合乎逻辑的, 然而在实践中这种做法并不合理。容器设计为每个容器只运行一个进程(除非进程本身产生子进程)。 如果在单个容器中运行多个不相关的进程, 那么保持所有进程运行、 管理它们的日志等将会是我们的责任。 例如, 我们需要包含一种在进程崩溃时能够自动重启的机制。 同时这些进程都将记录到相同的标准输出中, 而此时我们将很难确定每个进程分别记录了什么。

使用YAML或者JSON文件创建pod

       Pod和其他K8S资源通常是向K8S REST API提供YAML文件的方式创建,当然也可以使用kubectl run命令,但是这样简单的方式通常只支持一组有限的配置。另外当使用YAML文件创建时,还可以基于版本控制来更方便的控制K8S的资源。

  • 介绍YAML中pod定义的主要部分(在从头构建manifest时,可以使用kubectl explain来发现可能的API对象字段,如kubectl explain pods , kubectl explain pod.spec
    • metadata:包括pod名称、命名空间、标签和关于该pod的其他信息
    • spec:包含pod内容的详细说明,比如pod的容器、卷和其他数据等
    • status:包含运行中的pod的当前信息,例如容器的内部IP、每个容器的描述状态等。当需要新建pod时,不需要提供status相关的信息
  • 在处理好YAML文件后,可以使用kubectl create -f kubia-manual.yaml命令以YAML文件的方式创建Pod,当然也可以创建一切其他资源
apiVersion: v1 // 描述文件遵循V1版本的K8S API
kind: pod
metadata: 
	name: kubia-manual //pod名称
spec:
	containers:
	- image: jarvis/kubia //创建容器所需的镜像
	  name: kubia
	  ports:
	  - containerPort: 8080 // 监听的端口
	    protocol: TCP
查看pod以及获取容器运行日志
  • 使用kubectl get pods获取运行中的pod信息
  • 使用kubectl logs [pod-id] -c [container-id]获取指定容器日志
  • kubectl logs命令将显示当前容器的日志,如果容器重启过,当想要看前一个容器的日志时,可以使用kubectl logs [pod-id] --previous指令
使用标签组织pod

       在我们的测试集群中目前只存在寥寥数个pod,但是在微服务架构以及多版本构建时,pod会轻松的超过上百个,这将使得我们在管理pod时非常麻烦。因此K8S引入标签来处理这种场景。

  • 在pod创建时添加标签
apiVersion: v1 // 描述文件遵循V1版本的K8S API
kind: pod
metadata: 
	name: kubia-manual //pod名称
	labels:
		creation_method: manual
		env: production  //为资源指定的两个标签
spec:
	containers:
	- image: jarvis/kubia //创建容器所需的镜像
	  name: kubia
	  ports:
	  - containerPort: 8080 // 监听的端口
	    protocol: TCP
  • 在获取pod信息时带上标签信息
    kubectl get pods --show-labelskubectl get pods -L creation_method ,env
  • 修改现有的标签
    kubectl label po kubia-manual creation method=manual添加新标签
    kubectl label pod kubia-manual env =debug --overwrite更新pod的标签
  • 通过标签选择器列出pod
    kubectl get pods -l creation_method=manual:列出所有creation_method=manual的pod
    kubectl get pods -l env:列出所有包含env标签的pod
    kubectl get pods -l '!env':列出所有不包含env标签的pod
    kubectl get pods -l env in (prod,devel)
  • 使用标签选择器分类工作节点
           pod并不是唯一可以附加标签的K8S资。表亲啊可以附加到任何K8S对象上,包括工作节点node。因此可以使用同样的方式来调度处理节点。同样的,可以使用标签选择器将pod调度到特定节点。
apiVersion: v1 // 描述文件遵循V1版本的K8S API
kind: pod
metadata: 
	name: kubia-manual //pod名称
	labels:
		creation_method: manual
		env: production  //为资源指定的两个标签
spec:
	nodeSelector:
		gpu: "true" //通过节点选择器将pod只部署到包含标签gpu=true的节点上
	containers:
	- image: jarvis/kubia //创建容器所需的镜像
	  name: kubia
	  ports:
	  - containerPort: 8080 // 监听的端口
	    protocol: TCP
学新通
注解

       除了标签之外,pod或者其他资源对象还可以包含注解。注解同样的也是键值对,但是并不是为了保存标识信息而存在的,它们不能像标签一样用于对对象进行分组,当然也就不存在注解选择器。注解可以容纳更多的信息,主要是用于工具使用,用户可以手动添加需要的注解,K8S也会将一些注解自动添加到对象上。注解中的元数据,可以很小,也可以很大,可以是结构化的,也可以是非结构化的,能够包含标签不允许的字符。大量的使用注解可以为K8S资源添加说明,以便快速查阅每个对象的信息。

  • 以下是一些例子,用来说明哪些信息可以使用注解来记录:(你可以将这类信息存储在外部数据库或目录中而不使用注解, 但这样做就使得开发人员很难生成用于部署、管理、自检的客户端共享库和工具。)

    • 由声明性配置所管理的字段。 将这些字段附加为注解,能够将它们与客户端或服务端设置的默认值、 自动生成的字段以及通过自动调整大小或自动伸缩系统设置的字段区分开来。
    • 构建、发布或镜像信息(如时间戳、发布 ID、Git 分支、PR 数量、镜像哈希、仓库地址)。
    • 指向日志记录、监控、分析或审计仓库的指针。
    • 可用于调试目的的客户端库或工具信息:例如,名称、版本和构建信息。
    • 用户或者工具/系统的来源信息,例如来自其他生态系统组件的相关对象的 URL。
    • 轻量级上线工具的元数据信息:例如,配置或检查点。
    • 负责人员的电话或呼机号码,或指定在何处可以找到该信息的目录条目,如团队网站。
    • 从用户到最终运行的指令,以修改行为或使用非标准功能。
  • 查看对象的注解
    可以使用kubectl describe -o yaml命令来查看添加到资源上的注解

  • 添加或者修改注解
    可以使用kubectl annotate [type] [id] [annotationkey=annotationValue]

命名空间

       标签可以实现将资源进行分组,但是这样的资源分组可以重叠,如果不使用标签选择器时,将获取所有的同类资源。因此为了将资源分割成完全独立且不重合的组,引入了命名空间的概念。K8S命名空间简单的为对象名称提供了一个作用域,允许我们将资源组织到不同的作用域中。

  • 列出所有的命名空间
    kubectl get namespaces , kubectl get ns
  • 列出指定命名空间内的资源
    kubectl get pods --namespace [ns]kubectl get pods -n [ns]
  • 创建一个命名空间
    可以简单的使用kubectl create namespace custom-namespace来创建命名空间,同样的我们也可以使用YAML文件的方式创建——这表明K8S中的所有内容都是一个API对象
apiVersion: v1
kind: Namespace
metadata:
	name: custom-namespace
  • 命名空间提供的隔离
           尽管命名空间可以提供一个作用域,但是命名空间并不提供任何对正在运行的对象的隔离,如命名空间之间是否提供网络隔离取决于K8S所使用的网络解决方案,如果该网络解决方案不提供网络隔离时,那它就可以将流量发送到另外的命名空间的资源中。
停止和移除pod
  • 根据名称删除pod kubectl delete pod [pod-id]
  • 基于标签选择器删除podkubectl dedlete pod -l creation_method=manual
  • 通过删除命名空间来删除podkubectl delete ns [ns]
  • 删除命名空间的pod但保留namespacekubectl delete pod --all
  • 删除命名空间的几乎所有资源kubectl delete all --all
    注意,由于replicationController(replicaSet|Deployment)的存在,被托管的pod被删除后会自动重建,并且使用kubectl delete all --all无法删除Secret资源——这将在后续的部分描述。

四 部署托管的pod(从ReplicationController到Deployment)

ReplicationController 的替代方案
ReplicaSet
ReplicaSet 是下一代 ReplicationController, 支持新的基于集合的标签选择算符。 它主要被 Deployment 用来作为一种编排 Pod 创建、删除及更新的机制。 请注意,推荐使用 Deployment 而不是直接使用 ReplicaSet,除非你需要自定义更新编排或根本不需要更新。

Deployment (推荐)
Deployment 是一种更高级别的 API 对象,用于更新其底层 ReplicaSet 及其 Pod。 如果你想要这种滚动更新功能,那么推荐使用 Deployment,因为它们是声明式的、服务端的,并且具有其它特性。这将在后续内容中介绍。

       在实际使用K8S时,通常希望我们的部署能够保持运行与健康,无需手动对其进行干预。因此我们基本上不会直接创建pod,而是通过创建ReplicationController或者Deployment这样的资源,由他们来处理Pod的部署和管理。

保持Pod的健康

       使用K8S的好处之一是,K8S能够自己处理Pod的生命周期。我们可以给K8S提供一组容器列表,K8S能够自己在节点上创建部署Pod,并对其生命状态进行监控。比如当节点崩溃时,K8S可以在其他节点上部署出新的Pod,当Pod内主进程崩溃时,K8S能够对Pod进行重启。甚至我们还可以监测Pod中运行的程序状态,以便于对其进行管理。

  • 存活探针liveness probe
           K8S为Pod中的每个容器提供了存活探针,用于探测容器内程序的运行状况,当探测失败时,K8S会定期执行探针且重启容器。K8S中存在三种探测容器状态的机制
    • HTTP GET探针:K8S对提供的容器IP地址执行HTTP GET请求,当返回的响应正常时,容器将正常运行;否则K8S会重启该容器。
    • TCP Socket探针:K8S将尝试与对应的容器建立连接,当连接失败时,表明探测失败,容器将被重新启动。
    • Exec探针:将在对应的容器中尝试执行命令,并检查命令的退出状态码。一旦执行失败,则认为探测失败,该容器将被重启。
  • 创建探针(基于HTTP)
           在创建Pod时,可以在YAML文件中为Pod指定存活探针,如下所示。该探针告知K8S定期在Pod8080端口上执行HTTP GET检测请求——按照当前的配置,该探针会在容器运行后立刻开始。
apiVersion: v1 // 描述文件遵循V1版本的K8S API
kind: pod
metadata: 
	name: kubia-manual //pod名称
spec:
	containers:
	- image: jarvis/kubia //创建容器所需的镜像
	  name: kubia
	  livenessProbe: 
	  	httpGet:
	  		path: /
	  		port: 8080
  • 使用存活探针
           当Pod启动时,被指派的存活探针将开始工作。可以使用kubectl get pod [pod-id]来查看容器的运行状态,RESTARTS字段标识了Pod重启的次数。当容器被重启后,可以使用kubectl describe pod [pod-id]来查看为什么容器被重启。通过查看EXIT CODE字段,可以了解到容器重启的类型。例如当EXIT CODE为137 = 128 x ,表明x = 9,这是SIGKILL的信号编号,表示该进程被强行终止。当容器被强行终止时,会创建一个全新的容器,而并不是重启原有的容器

  • 配置存活探针的附加属性
           在配置存活探针时,可以为探针附加更多的属性,如delay(探测指针的延迟)、timeout(程序响应探测的超时时间)、period(探针执行的周期)、failure(探针检测失败后重试的次数)等。例如要设置初始延迟时,可以在YAML文件中配置initialDelaySeconds

apiVersion: v1 // 描述文件遵循V1版本的K8S API
kind: pod
metadata: 
	name: kubia-manual //pod名称
spec:
	containers:
	- image: jarvis/kubia //创建容器所需的镜像
	  name: kubia
	  livenessProbe: 
	  	httpGet:
	  		path: /
	  		port: 8080
	  	initialDelaySeconds: 15 //表示K8S会在Pod运行15秒后开启该指针的探测
  • 创建有效的存活探针
           对于在生产环境中运行的容器,一定要为其创建一个存活探针,否则K8S将无法获取容器内服务的运行状态——只要该进程还在运行,那么K8S就会认为容器时健康的。
    • 特定的路径
             为了更好的进行存活探测,需要为探针配置特定的URL路径如/health,并让运行在Pod中的应用从内部对内部运行的所有重要组件进行检测(一定要确保该探针不受任何外部因素的影响,当该探针包含检测外部服务时,容器的健康状态将会与外部服务的状态强相关),以确保他们的状态是健康的。同时请确保该特定的路径不需要认证,否则探针检测将一致失败,导致容器无限重启。
    • 探针保持轻量
             存活探针不应当占用太多的资源,并且运行时间不应太长。一个过重的探针将会大大影响容器的运行——因为K8S执行探针的频率通常会比较高。在后面的内容中,我们可以限制容器可用的CPU时间,探针的CPU时间同样会计入容器的CPU时间,因此过重的探针将会消耗容器内服务的可用资源。例如Java容器应使用HTTP GET探针,当使用Exec探针时,启动JVM会消耗大量的计算资源。
    • 探针无需在容器应用内重试
             探针的失败阈值是可配置的(failure),但是即使将失败阈值配置为1,K8S为了确保探测的准确,还是会尝试若干次。因此在容器内运行的应用中处理探针的失败重试是无意义的。
    • 存活探针将由Pod运行的节点上的Kubelet执行

ReplicationController

ReplicationController是一种K8S资源,确保由其托管的Pod始终保持运行状态,当任何原因导致的Pod消失,ReplicationController会注意到该Pod的下线并根据副本创建新的Pod作为替代。ReplictionController会监视Pod列表,会根据期望的Pod数目来增加或减少当前存在的目标”“类型”(实际上是根据标签来区分)的Pod容器。

  • ReplicationController的组成
           一个ReplicationController主要有三个组成部分,这三个组成部分可以随时更改——甚至是Pod模版,但是需要注意的是,只有副本数目的更新会影响现有的Pod(如数目减少会停止现有的若干Pod)。当仅有模版改变时,只有新创建的Pod会应用已经更新过的模版,现有的额Pod将不会与更新后的模版对齐。当标签选择器发生改变时,这就意味着之前托管到该RC的Pod失去了被托管的状态,RC会根据现有的模版和标签创建新的Pod对其进行托管。
    • Label Selector:标签选择器,用于确认受到该RC托管的Pod有哪些。
    • Replica Count:目标副本数目,用于标定该RC应当保持有多少个同类Pod保持健康状态提供服务
    • Pod Template:Pod模版,用来创建新的Pod副本
  • RC存在的意义
           ReplicationController存在的意义在于可以根据目标数目监控Pod的健康状态,当一个Pod或者某个节点因故崩溃,RC可以自动的、迅速的处理Pod的重建,以满足目标数目的需要。同时,还可以轻松实现Pod的水平伸缩——通过更改Replica Count就可以自动实现。
  • RC的创建
           和K8S中一切的其他资源一样,RC可以使用YAML文件的方式创建:
           需要注意的是,RC的标签选择器应当与模版中为Pod添加的标签相匹配,否则RC将会无休止的创建新的容器——因为创建的Pod并不符合RC标签选择器的要求——当然,K8S在底层处理了这样的情况,API服务会校验该YAML声明,当发现标签选择器与模版标签无法匹配时,该RC不会创建。当然,在声明RC时我们也可以不去处理它的标签选择器,这样API就会根据模版中的标签自动处理该RC的标签选择器,以避免问题的出现。使用kubectl create -f xxx.yaml创建RC,一旦RC被创建,它就会开始工作。
apiVersion: v1
kind: ReplicationController
metadata:
	name: kubia
spec:
	replicas: 3 #表示期望的副本数
	selector:
		app: kubia #表示该RC的标签选择器,该RC托管的pod是添加了app=kubia的pod
	template: #从这里开始,将会表示该RC托管的Pod模版,你可能已经注意到了,这里几乎就是一个pod的yaml声明
		metadata:
			labels:
				app: kubia
		spec:
			containers:
			- name: kubia
			  image: jarvis/kubia
			  ports:
			  - containerPort: 8080
学新通
  • RC创建新的Pod
           我们已经了解到,RC会对符合要求的Pod进行监控,一旦有Pod出现减少的情况,RC会自动创建出新的Pod保持运行。但是,RC通常不会直接响应Pod删除的操作——尽管在删除Pod时RC会立即收到该通知(API允许客户端监听资源和资源列表的改动),但是这并不是RC创建新的Pod的直接理由。由于RC维护了Replica Count,因此RC响应删除操作的方式是检查实际运行的Pod数目,与Replica Count比对之后执行响应的操作(增加Pod、删除Pod等)

  • 将Pod移入 或者移出RC的作用域
           RC根据标签选择器决定自己能够管理的Pod列表,这说明Pod并非直接绑定到RC上。因此在任何时刻,我们可以通过更改Pod或者RC的标签(标签选择器)来决定RC是否管理哪些Pod。需要注意的是,RC并不关心不在自己标签选择器列表中的标签——即你可以为Pod增加新的其他标签,而RC对这一操作不做举动。
           当对Pod的托管标签/RC的托管标签选择器进行改动时,RC会根据目标副本数重建Pod,这表明此时该Pod已经与该RC不存在托管关系了。在RC中,存在这样的情况,同一个Pod有可能存在满足多个ReplicationController的多个标签,如app=kubia , app2=kubia2,当存在两个标签选择器分别为app=kubiaapp2=kubia2的控制器时,这样的局面可以存在。在Deployment中,会根据副本hash出的值,为特定托管的Pod添加一个pod-template-hash标签,这样就能避免一个Pod满足多个控制器标签的情况发生。
           尽管Pod并没有直接绑定在RC上,但是Pod在metadata.ownerReferences中引用了它,我们可以轻松的使用kubectl get pod [pod-id] -o yaml获知Pod属于哪个RC/RS。

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2023-06-15T08:16:21Z"
  generateName: kubia2-5bf68857c5-
  labels:
    app2: kubia2
    pod-template-hash: 5bf68857c5
  name: kubia2-5bf68857c5-5xh2t
  namespace: default
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: kubia2-5bf68857c5
    uid: 2d91e61e-83a1-48c8-aad7-2b5868f792cd
  resourceVersion: "5258534"
  uid: 69c4d569-d384-491a-9d6f-8b683194618d
学新通
  • 更改RC的模版或者声明式的处理容器缩放
           可以使用kubectl exit rc [rc]来编辑ReplicationController,这将使用文本编辑器打开RC的YAML配置。上文已经描述,当修改RC的Pod模版时,并不会立刻更新现有的Pod容器;当修改Replica Count时,会立即根据需要创建/减少容器数目。

  • 删除RC
           当使用kubectl delete删除RC时,由其管理的Pod也会被删除。但是就像我们前面说过的,Pod并非直接绑定在ReplicationController,Pod也并不是RC的组成部分。因此我们可以在删除RC的时候保留被托管的Pod,只需要使用--cascade=fasle来保持Pod的运行即可。

ReplicaSet

       在最初,ReplictionController是K8S在处理复制容器或者节点异常迁移的唯一组件,但是在后续退出了新一代的RepliationController——ReplicaSet。从现在其,你应当时刻保持这样的观念,使用ReplicaSet而不是ReplicationController。他们几乎完全相同,因此在使用上你不会遇到任何麻烦——更重要的是ReplicationController最终将被弃用。
       通常来说,你并不会直接创建ReplicaSet,而是使用更高一级的Deployment资源时自动创建他们。

  • ReplicaSet拥有更好的标签表达能力
           ReplicationController与ReplicaSet的行为完全相同,但是ReplicaSet对于Pod标签选择器的表达能力更强。RS允许匹配缺少某个标签的pod,或者包含特定标签名的Pod
           在使用YAML创建RS时,可以使用更加强大的matchExpression属性来重写选择器,每个表达式都需要包含一个keyoperator,甚至基于运算符的类型不同,还可以包含一个values的列表。当我们给定了多个匹配规则时,这些匹配规则必须同时满足,才表明Pod与RS匹配,接受RS的管理。你可以看到有四种有效的运算符:
    • In:表示Label的值必须与其中一个指定的values匹配
    • NotIn:表示值与任何给定的values值都不应匹配
    • Exists:必须包含一个指定名称的标签,此时标签值不重要
    • DoesNotExist:Pod必须不包含指定名称的标签,同样的,此时标签值不重要
apiVersion: apps/v1
kind: ReplicaSet
metadata: 
	name: kubia
spec:
	replicas: 3
	selector:
		matchLabels:    	#当使用matchLabels属性时,与ReplicationController的标签选择能力相同
			app: kubia
		matchExpressions:
			- key: app2
			  operator: In
			  values:
			  	- kubia2
			  	  kubia22
			  key: app3
			  operator: Exists
	template:
		metadata:
			labels:
				app: kubia
		spec:
			containers:
			- name: kubia
			  image: jarvis/kubia
学新通

DaemonSet

       在上文中,我们已经描述过RC和RS,他们均可以实现在K8S中监控管理Pod的声明周期。但是当我们需要在集群中的每个节点上运行Pod,且每个节点上的Pod有且仅有一个时,可以使用DaemonSet。这种情况一般发生在需要在每个节点上处理日志收集和资源监视等系统服务时,比如K8S自己的kube-proxy进程就是在每个节点上都会运行一个容器实例。
       当使用YAML创建一个DS时,这与创建一个DC或者DS的操作很类似。DS确保创建足够的匹配它标签的Pod,并使这些Pod运行与每一个节点。尽管如此,DS并没有预期副本数的概念,它也并不需要这样的概念,因为它的目的是确保每个节点上都会运行一个模板定义的Pod。
       当集群中某个节点因故下线时,DS不会做额外操作,当某个新的节点加入集群时,DS保证其上能够运行自己要求的Pod容器。当然,我们可以在Pod模版中使用nodeSelector属性来选定DS管理的Pod运行在哪些特定节点上。并且在后续的介绍中,节点可以设置为不可调度的,以防止某些Pod调度到该节点——但是DaemonSet仍然会将Pod部署在这些节点上。因为节点的不可调度只会被调度器使用,而DaemonSet则会绕过调度器,将模版定义的Pod容器部署上去。这符合K8S的预期,因为DaemonSet管理的容器的目的是运行系统服务,即使某个节点被标记为不可调度,在其上仍然需要运行系统服务。

运行执行单个任务的Pod

       到目前为止,上文已经介绍了ReplicationController、ReplicaSet和DaemonSet三种控制器,尤其部署管理的Pod容器会持续运行,不会达到终止状态——因为这些容器无论因为什么原因终止,前者总会有办法重启或者重建它。当我们需要运行一个可预期完成的任务、或者需要在某些指定时刻运行的服务时,上述控制器就无法满足要求。

  • Job资源
           K8S通过Job资源提供了对Pod可终止需求的支持,Job资源与上述介绍的三种控制资源类似,但是它允许托管的Pod在内部的任务结束后不重启容器,一旦任务完成,标志着Pod处于完成状态。
           当节点发生故障时,Job资源会与RS类似,将节点上由Job管理的Pod重新安排到其他节点。当然也可以为Job添加配置,当Job管理的Pod进程运行异常退出时重启该容器。在一个Pod容器的定义中,可以使用spec.restartPolicy来配置当容器内进程结束时告知K8S做出什么样反应,默认为Always,这表明Pod内进程结束后,该Pod总是会重新启动。但是被Job管理的Pod不应当使用这样的配置,他应当明确的被设置为OnFailure或者Never
apiVersion: batch/v1
kind: Job
metadata: 
	name: batch-job
spec:
	template:
		matadata:
			labels:
				app: batch-job
		spec:
			restartPolicy: OnFailure
			containers:
				- name: batch-job
				  image: jarvis/batch-job
  • Job运行Pod
           当创建Job后,Job会根据配置立刻启动一个Pod。当Pod内进程运行结束后,该Pod的状态会被设置为Completed,使用kubectl get pods --show-all或者kubectl get pods -a来查看所有的pod列表,因为在默认情况下状态为已经完成的Pod不会显示在Pod列表中。Job资源管理的Pod在运行结束后不会立刻删除,因为允许查阅该Pod的日志,如kubectl logs [pod-id]

  • 在Job中配置运行多个Pod实例
           可以在Job中配置创建运行多个Pod实例,使用并行或者串行的方式运行它们,在Job的配置中设置completionsparallelism来实现。
           当使用串行方式运行实例时,Job将会一个接一个的创建Pod,当前面的容器运行完毕后才会创建新的容器运行。如果其中某一个Pod发生故障,那么Job会创建新的Pod代替。
           并行方式运行实例时,Job会根据设置的并行数同时运行多个实例Pod。当启动满足并行数的实例后,Job会根据Pod的运行情况决定是否启动新实例继续运行。同时,Job还支持在运行时更改parallelism属性,以便在运行时更改并行期望,达成Job控制的Pod缩放。

apiVersion: batch/v1
kind: Job
metadata: 
	name: batch-job
spec:
	completions: 50 #此Job期望的Pod成功运行数
	parallelism: 5 #表示Job期望的并行运行的Pod数目,当需要串行顺序运行Pod时,此属性可忽略或者设置为1
	template:
		matadata:
			labels:
				app: batch-job
		spec:
			restartPolicy: OnFailure
			containers:
				- name: batch-job
				  image: jarvis/batch-job
学新通
  • 限制Job托管的Pod的运行时长
           通过在Pod中设置activeDeadlineSeconds属性,可以限制pod执行的时间。如果Pod的运行超过了此时间,那么K8S将尝试终止该Pod,并且将托管其的Job标记为失败。如果Pod运行的进程卡住或者最终根本无法完成时,这是一种限制的方式。同时通过设置Job配置中的spec.backoffLimit字段,可以指定Job在被标记为失败前重试的次数,默认为6。

安排任务定期运行

       如果在Linux系统中你使用过crontab,那么这部分内容对你来说会非常容易。K8S中同样支持cron任务,通过配置CronJob来实现,运行任务的时间表也同样由cron格式来指定。在运行时,K8S将根据在CronJob中的Job模版来创建Job资源,剩下的事情你应该已经在前文总了解过了。

apiVersion: batch/v1
kind: CronJob
metadata:
	name: batch-job-per-15-mins
spec:
	schedule: "0,15,30,45 * * * *" #cron格式的运行时间表
	jobTemplate: 
		spec:
			template:
				metadata:
					labels:
						app: batch-job-per-15-mins
				spec:
					restartPolicy: OnFailure
					containers:
					- name: main
					  image: jarvis/kubia
学新通

       在计划的时间内,CronJob会创建Job资源,随后Job资源创建Pod资源。但是有可能会发生Job或者Pod创建或者运行的相对较晚的情况。当你对Job运行的时间有很高的要求,任务开始时间不能比预期时间落后太多时,可以使用CronJob的spec.startingDeadlineSeconds属性来指定截止时间,当超出该截止时间时,任务将不会运行,并且K8S将该任务标记为Failed

apiVersion: batch/v1
kind: CronJob
metadata:
	name: test-cron-job-with-limit
spec:
	schedule: "0,15,30,45 * * * *" #cron格式的运行时间表
	startingDeadlineSeconds: 20
	......

       如上面的YAML所示,我们需求整点的15分钟时会运行一次该任务,但是由于某种原因在XX:15:20时该任务仍然没有运行,那么该任务将不会运行。

       正常情况下CronJob总会为计划表中配置的每次执行创建一个Job,但是有可能会创建两个或者根本不创建Job。对于创建多个Job的情况,需要确保任务实际是幂等的,多次执行并不会得到不想要的结果。当不创建Job时,请确保当下次任务执行时,会处理掉本该本次任务完成的一切工作。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfkfggg
系列文章
更多 icon
同类精品
更多 icon
继续加载