k8s运维基础
一、基础组件与常用命令
1.pod
- 概念:pod是k8s最基础的调度单位,一个pod是一组紧密相关的容器,这组容器运行在同一个工作节点上,每个pod就像一个独立的逻辑机器,拥有自己的ip,进程名,主机名等。
- 常用命令
-
- 创建pod:pod使用yaml文件创造,该描述文件包括了pod使用的api服务版本,pod名称,pod中所需运行的容器信息等,如下:
apiVersion: v1 # 指定要使用的k8s api版本,通常是v1 kind: Pod # 指定资源的类型,这里是pod metadata: # 包含有关pod的元数据,例如标签和名称 name: my-pod spec: # 定义pod的规格,包括容器的配置 containers: # 这是一个列表,包含了在pod中运行的容器的配置 - name: my-container # 容器的名称 image: nginx:latest # 要是用的容器镜像 ports: # 要监听的端口 - containerPort: 80 #容器对外暴露的端口 protocol: TCP #容器对外网络协议 - containerPort: 12345 protocol: UDP - name: sidecar-container image: sidecar-app:latest
- 切换命名空间:
kubens namespace
-
创建一个pod:
kubectl create -f [podname] [pod.yaml]
- 列出pod:
kubectl get pods -o wide
- 查看pod的详细信息:
kubectl describe pod [podName]
- 查看创建pod的yaml描述文件信息:
kubectl get pod [podname] -o yaml
- 查看pod中运行的容器日志:
kubectl logs [podname]
- 设置本地端口转发远程pod端口:
kubectl port-forward [portname] [localport:remoteport]
- 删除pod:
kubectl delete pod [podname]
删除pod的过程是向pod中运行的进行发送一个SIGTERM信号并等待一定时间(默认30秒),等待时间过后若k8s发现进程没有正常关闭则通过SIGKILL信号青雉关闭,为了优雅退出,程序需要添加针对SIGTERM信号的处理逻辑
- 创建pod:pod使用yaml文件创造,该描述文件包括了pod使用的api服务版本,pod名称,pod中所需运行的容器信息等,如下:
2.label
- 概念:标签是可以放假到任意资源(pod/service/rc/rs/depoly等)的键值对,由于标识某一类资源,通过标签可以方便地对一组资源进行批量处理;
- 命令
-
- 给资源添加标签:一般是在资源描述配置文件中指定标签值,如下所示:
apiVersion: v1 #必选,api版本号 kind: Pod #必选,资源对象名称 metadata: #b必选,元数据 map类型 name: <your-pod-name> #必选,pod名称 namespace: <your-pod-namespace> #默认default,pod所属的命名空间 labels: name: <your-labes-name> #自定义的pod标签
- 查看资源的标签,以pod为例:
kebuctl get pods [portname] --show-labels
- 修改资源标签,以pod为例:
kubectl label pods [portname] [labelKey=newLabelValue] --overwrite
- 获取统一标签的资源,以pod为例:
kubectl get pods -l [labelkey=labelvalue]
- 通过标签将pod调度到指定标签节点,如下所示:
# 给节点资源添加标签:
kubectl label node [nodeName] gpu=true# 在pod描述文件中添加节点选择条件:
apiVersion: v1 #必选,api版本号 kind: Pod #必选,资源对象名称 metadata: #b必选,元数据 map类型 name: <your-pod-name> #必选,pod名称 spec: nodeSelector: gpu:"true" #通过标签指定部署的节点类型
- 给资源添加标签:一般是在资源描述配置文件中指定标签值,如下所示:
- 通过kubectl来添加标签:
kubectl label <资源类型> <资源名称> <标签键>=<标签值>
3.namespace
- 概念:命名空间与label类似,也是一个分组概念,但是label是兼容的,一个k8s资源对象可以有多个标签,但是一个资源只能有一个命名空间。命令空间通过这种分组互斥性简单地为k8s对象提供了一个作用域。在实际应用中,一般使用命令空间来标识k8s对象属于生产环境还是测试环境。
- 命令:
- 首先创建命令空间的描述文件ns.yaml,如下:
apiVersion: v1 #必选,api版本号 kind: Namespace #必选,资源对象名称 metadata: #b必选,元数据 map类型 name: <your-pod-name> #必选,pod名称
- 命令创建命名空间:
kubectl create ns [nsname]
-
基于描述文件创建资源:
kubectl create -f ns.yaml
- 为k8s资源对象指定命名空间:
kubectl create -f [object].yaml -n [namespace]
- 设置某一命名空间为默认命名空间:
kubectl config set-context [namespace] --namespace
- 根据命名空间批量操作对象,如批量查看某一命名空间下的所有pod:
kubectl get pods -n [namespace]
4.存活探针
- 概念:存活探针不是一种k8s资源,而是k8s的一种容灾机制,通过定时向容器中运行的应用发送网络请求来判断应用是否正常运行,若判断应用没有正常运行则重启容器。k8s提供了三种探针:
- livenessProbe:存活探针用于检测容器内应用程序的健康状态。如果存活探针失败(即应用程序不健康),Kubernetes 将会自动重启容器,以尝试恢复应用程序的健康状态。如果重启容器仍然无法解决问题,Kubernetes 可能会根据配置的重启策略进一步采取行动。重启策略包括:
- always:始终重启容器,无限次数地尝试恢复应用程序的健康状态。
- OnFailure:仅在容器失败(退出状态码非零)时重启容器,尝试恢复应用程序的健康状态。
- 仅在容器失败(退出状态码非零)时重启容器,尝试恢复应用程序的健康状态
- readinessProbe:用于检测容器是否已经准备好接收流量。如果就绪探针失败(即容器未准备好),Kubernetes 将会从服务负载均衡的池中剔除该容器,不会将流量路由到该容器,直到探测成功。
- StartupProbe:启动探针用于检测容器内应用程序是否已经启动成功。与存活探针和就绪探针不同,启动探针仅在容器启动时执行,并且只需检测一次。启动探针的结果不会影响容器的重启或负载均衡。它主要用于检测应用程序是否成功启动,并在启动过程中提供一定的等待时间。如果启动探针失败,Kubernetes 不会采取任何特殊行动。这是因为启动探针失败只意味着应用程序尚未成功启动,并且不会触发容器的重启或负载均衡操作。
- livenessProbe:存活探针用于检测容器内应用程序的健康状态。如果存活探针失败(即应用程序不健康),Kubernetes 将会自动重启容器,以尝试恢复应用程序的健康状态。如果重启容器仍然无法解决问题,Kubernetes 可能会根据配置的重启策略进一步采取行动。重启策略包括:
- HTTP探测:使用HTTP GET请求检查容器的健康状态。如果容器的HTTP端点返回200 ok响应,则认为容器时存活的。这对于Web服务器等应用程序非常有用。
livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 15 periodSeconds: 10
- TCP探测:使用TCP套接字检查容器的健康状态。如果可以建立TCP连接,则认为容器时存活的。这对于没有HTTP服务的应用程序非常有用。
livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 15 periodSeconds: 10
- 命令探测: 执行一个自定义命令,并根据其退出代码来判断容器的健康状态。如果命令成功执行(退出代码为0),则认为容器是存活的。
livenessProbe: exec: command: - /bin/sh - -c - ps aux | grep myprocess initialDelaySeconds: 15 periodSeconds: 10
- pod中完整添加探针:
apiVersion: v1 kind: Pod metadata: name: my-app-pod spec: containers: - name: my-app-container image: my-app-image:latest ports: - containerPort: 8080 livenessProbe: # 在这里定义存活探针 httpGet: path: /healthz # 指定探测的路径 port: 8080 # 指定容器内部监听的端口 initialDelaySeconds: 15 # 容器启动后等待多少秒开始探测 periodSeconds: 10 # 探测的时间间隔
- 存活探针的配置包括:
-
- initialDelaySeconds: 容器启动后多少秒开始进行第一次探测
- periodSeconds:探测的间隔时间
- timeoutSeconds:探测的超时时间
- successThreshold: 连续成功探测的次数,用于将容器标记为存活
- failureThreshold:连续失败探测的次数,用于将容器标记为失败。
5.ReplicationController
- 概念:rc是一种管理pod数量的k8s资源,在创建rc是可以指定期望pod数量,当运行中pod数量不等于预先设置好的数量时,rc会通过拉起或删除pod的方式保证pod数量等于预先设置的期望值。创建一个rc时,rc会根据配置文件中设定pod模板和期望数量自动拉起对应数量pod,无需手动创建pod;
- 副本数量管理:replicationcontroller的主要责任是管理指定副本数量的pod。你可以在replicationcontroller的配置中指定所需的副本数量,然后它会不断监控并确保这个数量保持稳定。
- 自动恢复:如果某个pod副本因故障或其他原因而终止,replicationcontroller将自动创建新的pod副本,以维持所需的副本数量。这有助于确保应用程序的高可用性。
- 标签选择器:replicationcontroller使用标签选择器来确定需要管理的pod。可以通过标签选择器选择特定的pod,以便replicationcontroller只管理满足特性标签要求的pod。
- 更新策略:replicationcontroller还可以用于试试滚动更新策略。可以将新的pod镜像版本部署到集群中,并逐步替换旧版本的pod,以确保应用程序的平滑升级。
- rc的配置文件由标签选择器(通过标签判断pod数量)、副本数量和pod模板(用于创建pod)组成,其中标签选择器的标签必须保证与pod模板中的标签值相同,如下所示:
apiVersion: v1 kind: ReplicationController metadata: name: [rcName] spec: #指定期望副本数和操作的pod标签 replicas: [podNum] selector: [labelKey]: [labelValue] template: #pod模板信息 metadata: name: [podName] labels: [labelKey]: [labelValue] spec: containers:
apiVersion: v1 kind: ReplicationController metadata: name: my-app-rc spec: replicas: 3 # 指定副本数量 selector: app: my-app # 标签选择器,用于选择要管理的pod template: metadata: labels: app: my-app # pod模板的标签 spec: containers: - name: my-app-container image: my-app-image:latest # pod使用的容器镜像 ports: - containerPort: 80 # 容器监听的端口
创建rc:
kubectl create -f [rcName].yaml
- 扩容或缩容pod副本数量:通过重新编辑rc配置文件实现:
kubectl edit rc [rcName]
- 删除rc
- 删除rc及其管理的pod:
kubectl delete rc [rcName]
-
删除rc但保留pod:
kubectl delete rc [rcName] --cascade=false
6.ReplicationSet
- 概念:rs可以视为一个具有标签选择器的rc,标签选择器以表达式来指定标签,更加灵活。下面是ReplicaSet的重要特性
- Pod副本数量控制:通过ReplicaSet,用户可以指定想要的Pod副本数,ReplicaSet会自动创建或删除Pod副本数来达到改数量。
- 根据标签选择器筛选Pod:ReplicaSet会基于一组标签选择器来选择匹配的Pod,以便创建或删除相应的Pod副本。标签选择器可以指定某个应用所有的Pod,也可以根据不同的部署环境来选择特定的Pod
- 确保Pod的健康状态:ReplicaSet会监控所有的Pod副本的运行状态,并确保在有Pod发生故障时进行恢复。如果某个Pod副本意外退出,ReplicaSet会自动创建一个新的Pod副本来代替它,以维持指定的副本数。
- 滚动更新和回滚:ReplicaSet还支持滚动更新和回滚操作,用户可以通过指定更新的策略和版本号,对应用程序进行更新和回滚操作。
- 与其他控制器的协作:ReplicaSet可以与k8s其他控制器对象(比如Deployment)协同工作,来完成应用程序的部署和管理任务。
- 控制器:在k8s中,ReplicaSet是一种控制器,实现了k8s API对象的控制循环。ReplicaSet 控制器的控制循环过程如下:
- ReplicaSet控制监视Pod的状态,确保其与当前 ReplicaSet 配置文件中定义的副本数一致。
- 数量小于情况:如果当前 Pod 的数量小于 ReplicaSet 配置文件中定义的数量,则 ReplicaSet 控制器会启动新的 Pod 副本来替换当前缺少的 Pod。
- 数量大于情况:如果当前 Pod 的数量大于 ReplicaSet 配置文件中定义的数量,则ReplicaSet 控制器会停止一些 Pod 副本,以保持与定义的数量一致。
- 自动伸缩:
ReplicaSet 控制器还可以结合 HorizontalPodAutoscaler(HPA)组件实现自动伸缩功能。HPA 可以根据 Pod 的 CPU 使用率等指标来自动调整 ReplicaSet 中的 Pod 副本数,以满足应用程序的需求。
当应用程序的负载增加时,HPA 可以自动增加 Pod 副本数,从而提高应用程序的吞吐量;
当负载下降时,HPA 可以自动减少 Pod 副本数,从而节省资源。示例:
apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler #资源类型 metadata: name: my-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: ReplicaSet name: my-replicaset minReplicas: 1 maxReplicas: 10 targetCPUUtilizationPercentage: 50
在上面的示例中,HPA 将根据
targetCPUUtilizationPercentage: 50
指定的 CPU 使用率来自动调整my-replicaset
ReplicaSet 中的 Pod 副本数,确保其数在1
到10
之间。 - rs的配置文件格式如下,通过标签表达式来指定管理的标签:
apiVersion: app/v1beta2 #注:v1版本的api服务器无法创建rs kind: ReplicaSet metadata: name: [rcName] spec: #指定期望副本数和操作的pod标签 replicas: [podNum] selector: matchExpressions: - key: [labeKey] #指定标签的key operator: In #运算符 values: #指定标签的value - [labelValue1] - [labelValue2] spec: containers: - name: my-container image: my-image ports: - containerPort: 80
注:表达式的运算符有In、Notln、Exists、DoesNotExist四种;
# 创建rs kubectl create -f [rsName].yaml
7.DaemonSet
- 概念:ds是类似rs和rc的一种管理pod的k8s资源,但rs和rc的pod部署在集群上是随机的,而ds是可以控制pod部署到特定节点的。一般情况下,若不特别指定,ds会在集群上所有实例节点部署pod,也可以通过标签向特定节点部署pod。一般情况下,ds用于创建基础服务如日志服务或监控服务。
- 通过nodeSelector向特定节点部署pod,这需要提前给节点实例添加标签值,如下:
kubectl label node [nodeName] [labelkey]=[labelvalue]
然后通过nodeSelector指定部署到特定标签节点,如下所示:
apiVersion: app/v1beta2 #注:v1版本的api服务器无法创建rs kind: DaemonSet metadata: name: [dsName] spec: selector: nodeSelector: #指定要部署的节点,通过标签实现 [labelKey]:[labelValue] ......
创建ds:
kubectl create -f [dsName].yaml
8.job
- 概念:job同样是一种管理pod资源,但是job可以控制任务执行的次数,上文所述的rc或rs通过存活指针保证一直会有pod被拉起执行任务,而job可以让pod内部进行执行结束后不重启容器,适合管理临时任务。以下是job控制器的一些关键特性和用法:
- 一次性任务:job控制器用于管理一次性任务,这些任务在成功完成后通常不会保持运行状态。一旦任务完成,job控制器将终止与任务相关的pod。
- 任务成功和失败的处理:job控制器可以选择定义任务成功和失败的条件。如果任务成功,则相关pod会被终止。如果任务失败,可以选择进行重试或保留失败的pod以进行排查。
- 并行任务:job控制器可以并行多个任务,每个任务都有其自己的pod副本。你可以指定要运行的任务数量。
- 任务的顺序:如果需要确保任务按顺序执行,你可以使用cronjob控制器,它是job的一种特殊类型,可用于调度和管理定时任务。
- RestartPolicy:
- Never:job会在pod出现故障时创建新的pod,且故障不会消失。status.failed加1
- OnFailure:则job会在pod出现故障时其内部重启容器,而不是创建pod。status.failed不变
- job的定义配置文件如下所示,需要特别指定重启策略为失败重启,其他情况不
apiVersion: batch/v1 kind: Job metadata: creationTimestamp: null name: job1 spec: template: metadata: creationTimestamp: null spec: containers: - command: - sh - -c - date ; sleep 10 image: busybox #node节点上得有这个镜像啊 imagePullPolicy: IfNotPresent name: job1 resources: {} #RestartPolicy仅支持Never和OnFailure两种,不支持Always restartPolicy: Never status: {}
创建job:
# 创建 [root@master job]# kubectl apply -f job1.yaml job.batch/job1 created [root@master job]# # 羡慕CompLETIONS是0/1,是因为job还没创建, #需要等待seelp 10 以后,就是10 秒以后才会创建 [root@master job]# kubectl get job NAME COMPLETIONS DURATION AGE job1 0/1 5s 5s [root@master job]# [root@master job]# kubectl get job NAME COMPLETIONS DURATION AGE job1 0/1 11s 11s [root@master job]# # 10秒以后创建了,状态也成0/0了 [root@master job]# kubectl get job NAME COMPLETIONS DURATION AGE job1 1/1 13s 22s # 创建成功以后pod状态也就成 completed了【10秒以前状态是Running】,不会再创建了 # 也就是说该pod也就是失效了 可以删除了 [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job1-rll96 0/1 Completed 0 28s [root@master job]# [root@master job]# kubectl delete pod job1-rll96 pod "job1-rll96" deleted [root@master job]#
- 增加job任务次数,spec[下面参数放在spec下面]:
- backoffLimit:4 如果job失败,则重试几次
- completion:6 job结束需要成功运行的pod个数,及状态为completed的pod数量
- parallelism:2 一次性运行n个pod,这个值不会吵过completions的值
apiVersion: batch/v1 kind: Job metadata: creationTimestamp: null name: job2 spec: backoffLimit: 4 completions: 6 parallelism: 2 template: metadata: creationTimestamp: null spec: containers: - command: - sh - -c - date ; sleep 10 image: busybox imagePullPolicy: IfNotPresent name: job2 resources: {} restartPolicy: Never status: {}
# 创建job2,可以看到job2一共有6个任务 [root@master job]# kubectl apply -f job2.yaml job.batch/job2 created [root@master job]# [root@master job]# kubectl get job NAME COMPLETIONS DURATION AGE job1 1/1 13s 15m job2 0/6 5s 5s [root@master job]# # job一次创建2个,可以看到pod确实有2个生成 [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job2-7rp99 1/1 Running 0 11s job2-xkjd4 1/1 Running 0 11s [root@master job]# # 因为一次执行2个,所以2个执行完呢状态就会为completed了,又会重新生成2个新pod执行 [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job2-7rp99 0/1 Completed 0 22s job2-fmbdp 1/1 Running 0 8s job2-kxtqg 1/1 Running 0 8s job2-xkjd4 0/1 Completed 0 22s [root@master job]# [root@master job]# kubectl get job NAME COMPLETIONS DURATION AGE job1 1/1 13s 15m job2 4/6 27s 27s [root@master job]# [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job2-7rp99 0/1 Completed 0 29s job2-fmbdp 0/1 Completed 0 15s job2-kxtqg 0/1 Completed 0 15s job2-nqf48 1/1 Running 0 3s job2-ttmxb 1/1 Running 0 3s job2-xkjd4 0/1 Completed 0 29s [root@master job]# [root@master job]# kubectl get job NAME COMPLETIONS DURATION AGE job1 1/1 13s 15m job2 4/6 34s 34s # 直到6个任务分3次执行完且状态全部为completed为止哦。 [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job2-7rp99 0/1 Completed 0 35s job2-fmbdp 0/1 Completed 0 21s job2-kxtqg 0/1 Completed 0 21s job2-nqf48 1/1 Running 0 9s job2-ttmxb 1/1 Running 0 9s job2-xkjd4 0/1 Completed 0 35s [root@master job]# kubectl get job NAME COMPLETIONS DURATION AGE job1 1/1 13s 15m job2 6/6 38s 39s [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job2-7rp99 0/1 Completed 0 41s job2-fmbdp 0/1 Completed 0 27s job2-kxtqg 0/1 Completed 0 27s job2-nqf48 0/1 Completed 0 15s job2-ttmxb 0/1 Completed 0 15s job2-xkjd4 0/1 Completed 0 41s [root@master job]#
- RestartPolicy测试。将pod里面定义的command命令错误:
[root@master job]# cat job2.yaml apiVersion: batch/v1 kind: Job metadata: creationTimestamp: null name: job2 spec: backoffLimit: 4 completions: 6 parallelism: 2 template: metadata: creationTimestamp: null spec: containers: - command: - sh - -c # 我在下面seelp后面加了个x,没有这个命令的 - date ; sleepx 10 image: busybox imagePullPolicy: IfNotPresent name: job2 resources: {} restartPolicy: Never status: {} [root@master job]#
开始测试:
[root@master job]# kubectl apply -f job2.yaml job.batch/job2 created [root@master job]# # 创建成功以后 job状态一直是 0/6 因为不会执行成功的 [root@master job]# kubectl get job NAME COMPLETIONS DURATION AGE job2 0/6 5s 5s [root@master job]# # pod数量这个就是 backoffLimit: 4 定义的,需要重复4次,一次2个,但状态都会为Error,全是失败的 [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job2-76z75 0/1 Error 0 9s job2-n52l6 0/1 Error 0 9s job2-tr59f 0/1 Error 0 6s job2-trtwd 0/1 Error 0 6s [root@master job]# [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job2-76z75 0/1 Error 0 12s job2-n52l6 0/1 Error 0 12s job2-tr59f 0/1 Error 0 9s job2-trtwd 0/1 Error 0 9s [root@master job]# kubectl get job NAME COMPLETIONS DURATION AGE job2 0/6 15s 15s [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job2-76z75 0/1 Error 0 18s job2-jn89q 0/1 Error 0 5s job2-mv6z7 0/1 Error 0 5s job2-n52l6 0/1 Error 0 18s job2-tr59f 0/1 Error 0 15s job2-trtwd 0/1 Error 0 15s [root@master job]# kubectl get job NAME COMPLETIONS DURATION AGE job2 0/6 24s 24s [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job2-76z75 0/1 Error 0 26s job2-jn89q 0/1 Error 0 13s job2-mv6z7 0/1 Error 0 13s job2-n52l6 0/1 Error 0 26s job2-tr59f 0/1 Error 0 23s job2-trtwd 0/1 Error 0 23s # 理论上,一次2个,重复4次,一共有8次才对,但最终只有6次 # 所以 backoffLimit: 4定义的次数是不准的,这是正常的哈,我们不要去数,不要去较这个真 [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job2-76z75 0/1 Error 0 29s job2-jn89q 0/1 Error 0 16s job2-mv6z7 0/1 Error 0 16s job2-n52l6 0/1 Error 0 29s job2-tr59f 0/1 Error 0 26s job2-trtwd 0/1 Error 0 26s # 可以用这个命令看到详细过程的哈 [root@master job]# kubectl describe job job2 Name: job2 Namespace: job Selector: controller-uid=de313ff4-ec7a-49d8-a719-46e83ad25e4e Labels: controller-uid=de313ff4-ec7a-49d8-a719-46e83ad25e4e job-name=job2 Annotations: <none> Parallelism: 2 Completions: 6 Start Time: Wed, 08 Sep 2021 12:23:59 +0800 Pods Statuses: 0 Running / 0 Succeeded / 6 Failed Pod Template: Labels: controller-uid=de313ff4-ec7a-49d8-a719-46e83ad25e4e job-name=job2 Containers: job2: Image: busybox Port: <none> Host Port: <none> Command: sh -c date ; sleepx 10 Environment: <none> Mounts: <none> Volumes: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 4m10s job-controller Created pod: job2-76z75 Normal SuccessfulCreate 4m10s job-controller Created pod: job2-n52l6 Normal SuccessfulCreate 4m7s job-controller Created pod: job2-tr59f Normal SuccessfulCreate 4m7s job-controller Created pod: job2-trtwd Normal SuccessfulCreate 3m57s job-controller Created pod: job2-jn89q Normal SuccessfulCreate 3m57s job-controller Created pod: job2-mv6z7 Warning BackoffLimitExceeded 2m37s job-controller Job has reached the specified backoff limit [root@master job]#
- 测试计算圆周率2000位
[root@master job]# cat job3.yaml apiVersion: batch/v1 kind: Job metadata: creationTimestamp: null name: job3 spec: template: metadata: creationTimestamp: null spec: containers: - command: - sh - -c - perl -Mbignum=bpi -wle 'print bpi(2000)' image: perl imagePullPolicy: IfNotPresent name: job3 resources: {} restartPolicy: Never status: {} [root@master job]# [root@master job]# kubectl apply -f job3.yaml job.batch/job3 created [root@master job]# # 因为计算任务没完成,所以job是0/1,pod是running [root@master job]# kubectl get job NAME COMPLETIONS DURATION AGE job3 0/1 5s 5s [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job3-4dn4c 1/1 Running 0 12s # 计算完成以后,job1/1,pod成了completed [root@master job]# kubectl get job NAME COMPLETIONS DURATION AGE job3 1/1 12s 16s [root@master job]# [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE job3-4dn4c 0/1 Completed 0 80s [root@master job]# # 我们可以通过日志的方式看输出哦 [root@master job]# kubectl logs job3-4dn4c 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901 [root@master job]#
9.Cronjob
- 概念:cronjob与job类似,也是用于管理临时任务的k8s资源,但cronjob的临时任务可以定时执行,也就是说,cronjob管理的pod任务结束后,在一定时间间隔内会重新创建pod来执行临时任务。
- 一个cronjob对象其实就是对应crontab文件中的一行,他根据配置的时间格式周期性地运行一个job,格式和crontab也是一样的。
- crontab的格式如下:
分 小时 日 月 周 要运行的命令 #第1列分钟(0~59) #第2列小时(0~23) #第3列日(1~31) #第4列月(1~12) #第5列星期(0~7)(0和7表示星期天) #第6列要运行的命令 # 不考虑具体时间的话,可以用* 【和linux的crontab一样】
- cronjob的定时任务管理是通过cron时间表达式实现的,如下所示:
apiVersion: batch/v1 kind: CronJob metadata: creationTimestamp: null name: mycj spec: jobTemplate: metadata: creationTimestamp: null name: mycj spec: template: metadata: creationTimestamp: null spec: containers: - command: - sh - -c - date ; sleep 10 image: busybox name: mycj resources: {} restartPolicy: OnFailure # */1 其实就是每分钟哈 schedule: '*/1 * * * *'
[root@master job]# kubectl get cj NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE mycj */1 * * * * False 0 <none> 6s [root@master job]# [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE mycj-27184800-2tq92 1/1 Running 0 5s [root@master job]# kubectl get cj NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE mycj */1 * * * * False 1 10s 54s [root@master job]# kubectl get pods NAME READY STATUS RESTARTS AGE mycj-27184800-2tq92 1/1 Running 0 12s [root@master job]#
[root@master job]# kubectl describe cj mycj Name: mycj Namespace: job Labels: <none> Annotations: <none> Schedule: */1 * * * * Concurrency Policy: Allow Suspend: False Successful Job History Limit: 3 Failed Job History Limit: 1 Starting Deadline Seconds: <unset> Selector: <unset> Parallelism: <unset> Completions: <unset> Pod Template: Labels: <none> Containers: mycj: Image: busybox Port: <none> Host Port: <none> Command: sh -c date ; sleep 10 Environment: <none> Mounts: <none> Volumes: <none> Last Schedule Time: Wed, 08 Sep 2021 16:08:00 +0800 Active Jobs: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 8m34s cronjob-controller Created job mycj-27184800 Normal SawCompletedJob 8m22s cronjob-controller Saw completed job: mycj-27184800, status: Complete Normal SuccessfulCreate 7m34s cronjob-controller Created job mycj-27184801 Normal SawCompletedJob 7m22s cronjob-controller Saw completed job: mycj-27184801, status: Complete Normal SuccessfulCreate 6m34s cronjob-controller Created job mycj-27184802 Normal SawCompletedJob 6m22s cronjob-controller Saw completed job: mycj-27184802, status: Complete Normal SuccessfulCreate 5m34s cronjob-controller Created job mycj-27184803 Normal SawCompletedJob 5m23s cronjob-controller Saw completed job: mycj-27184803, status: Complete Normal SuccessfulDelete 5m23s cronjob-controller Deleted job mycj-27184800 Normal SuccessfulCreate 4m34s cronjob-controller Created job mycj-27184804 Normal SawCompletedJob 4m22s cronjob-controller Saw completed job: mycj-27184804, status: Complete Normal SuccessfulDelete 4m22s cronjob-controller Deleted job mycj-27184801 Normal SuccessfulCreate 3m34s cronjob-controller Created job mycj-27184805 Normal SawCompletedJob 3m22s cronjob-controller Saw completed job: mycj-27184805, status: Complete Normal SuccessfulDelete 3m22s cronjob-controller Deleted job mycj-27184802 Normal SuccessfulCreate 2m34s cronjob-controller Created job mycj-27184806 Normal SawCompletedJob 2m22s cronjob-controller Saw completed job: mycj-27184806, status: Complete Normal SuccessfulDelete 2m22s cronjob-controller Deleted job mycj-27184803 Normal SuccessfulCreate 94s cronjob-controller Created job mycj-27184807 Normal SawCompletedJob 82s cronjob-controller Saw completed job: mycj-27184807, status: Complete Normal SuccessfulDelete 82s cronjob-controller Deleted job mycj-27184804 Normal SuccessfulCreate 34s cronjob-controller Created job mycj-27184808 Normal SawCompletedJob 22s cronjob-controller Saw completed job: mycj-27184808, status: Complete Normal SuccessfulDelete 22s cronjob-controller Deleted job mycj-27184805 [root@master job]#
10.Deployment
- 概念:Deployment是一种用于管理ReplicaSet的资源,其核心功能是保证应用的正常更新。在rs中如果要更新pod中运行的应用,那么需要执行一下步骤:
- 针对更新后的应用创建一个新镜像
- 基于rolling-update命令实现老rs的pod下线和新rs的pod上线
kubectl rolling-update [rsOld] [rsNew] --image=[NewImage]
-
rolling-update 命令在这个过程会修改老rs的pod标签名称、基于新镜像创建新rs、然后通过一个第三方rs来逐步下线老rs的pod和上线新rs的pod,从而实现滚动升级。这个过程是通过kubectl客户端而不是通过kubectl主节点来实现的,所以当客户端网络断开时会带来更新失败的风险。
-
rolling-update的更新过程繁琐且有一定风险,k8s使用Deployment来简化这个过程。Deployment是一种更顶层的k8s资源,用于管理rs,可实现自动滚动更新。
- 以下是Deployment的一些相关特性和用法
- 声明性定义:使用Deployment,你可以声明性地定义应用程序的期望状态,而不是手动执行操作。Deployment将负责集群中的实际状态与声明状态保持一致。
- 副本控制:Deployment确保指定数量的Pod副本在集群中运行。如果有太多或太少的副本,Deployment将自动进行调整。
- 滚动更新:当你需要升级应用程序版本时,可以简单地更新Deployment的镜像版本字段。Deployment会自动执行滚动更新,逐步替换旧版本的Pod,以确保应用程序的平滑升级。
- 回滚策略:如果更新后的应用程序出现问题,Deployment允许你轻松的回滚到之前的版本,避免中断。
- 自动修复:如果某个Pod失败或节点崩溃,Deploment会自动替换失败的Pod,以确保应用程序的高可用性。
- Deployment相对于Rc的最大优势在于随时可以知道Pod的部署进度。处于Pod的创建、调度、绑定节点以及在目标节点启动对应容器的拿一个过程。
- 创建dp:dp的定义配置文件如下所示:
apiVersion: apps/v1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revision: "1" creationTimestamp: "2023-09-07T07:49:17Z" generation: 1 labels: #deploy自身的标签 app: nginx name: nginx namespace: test-wang spec: progressDeadlineSeconds: 600 replicas: 1 #副本数 revisionHistoryLimit: 10 #保留历史记录的次数,设置为0的话,不保留历史数据 # minReadySeconds: 0 #可选参数,指定新创建的Pod在没有任何容器崩溃的情况下视为Ready最小的秒数,默认为0,即一旦被创建就视为可用。 selector: #匹配RS,一旦创建就不建议修改,否则RS会脱离deploy的掌控 matchLabels: app: nginx strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate #更新deployment的方式 1.RollingUpdate:滚动更新(默认),可以指定maxSurge(超过期望值的最大Pod数,默认25%)和maxUnavailable(最大不可用数量,默认25%) 2.Recreate 重建 先删除旧的Pod,在创建新的Pod template: metadata: #匹配Pod,要和匹配RS的一致 creationTimestamp: null labels: app: nginx spec: #和Pod的一致。 containers: - image: nginx:1.15.2 imagePullPolicy: IfNotPresent name: nginx resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30
apiVersion: apps/v1 kind: Deployment metadata: name: [dpName] labels: [labelKey]: [labelVal] spec: replicas: 3 #期望的pod副本数量 selector: matchLabels: [labelKey]: [labelVal] template: metadata: labels: [labelKey]: [labelVal] spec: containers: - name: [containerName] image: [containerImage] port:
- containerPort: 80创建命令:
kubectl create -f [dpName].yaml --record
上面的record选项会记录历史版本号,可用于回滚版本等。创建dp后,dp并不直接创建和管理pod,而是创建rs,并用rs来管理pod
- 基于dp来更新镜像,命令如下:
kubectl set image deployment [dpName] [containerName]=[newImageName] kubectl set image deploy nginx nginx=nginx:1.15.3
改名了会触发pod应用运行镜像的更新,更新策略和更新间隔等可以通过dp配置文件中的“spec”下面的子字段指定,如下所示:
spec: minReadySeconds: 10 #创建的pod至少成功运行多久后才视为可用 strategy: rollingUpdate: maxSurge: 1 #在滚动更新过程中,除了期望pod副本数外,最多允许超出的pod实例的数量; maxUnvalilable: 1 #在滚动更新过程中,相对于期望pod副本数,最多允许的处于不可用的pod实例数量; type: RollingUpdate #指定更新策略为滚动更新
- 镜像回滚相关命令:
- 查看当前保存的所有版本号:
[root@master deploy]# kubectl rollout history deploy nginx deployment.apps/nginx REVISION CHANGE-CAUSE 3 kubectl set image deploy nginx nginx=nginx:1.15.2 --record=true 4 <none>
kubectl rollout history deployment [dpName]
- 回滚到指定版本:
kubectl rollout undo deploy nginx --to-revision=3
kubectl rollout undo deployment [dpName] --to-revision=[version]
- 暂停滚动升级:
kubectl rollout pause deployment [dpName]
- 恢复滚动升级:
kubectl rollout resume deployment [dpName]
- 取消滚动升级:
kubectl rollout undo deployment [dpName]
- 查看当前保存的所有版本号:
11.StatefulSet
- 概念:statefulset可以视为一个有状态的ReplicaSet,用于部署有状态的应用程序,例如数据库或消息队列。与Deployment不同,StatefulSet旨在确保在应用程序实例之间维护稳定的标识,有助于保持应用程序的数据一致性和可用性。比如可以部署ElasticSearch集群、MongoDB集群或者需要持久化的RabbitMQ集群、Redis集群、kafka集群和Zookeeper集群等。以下是StatefulSet的一些关键特性和用法。
- 有状态的Pod:StatefulSet为每个Pod实例分配一个唯一的标识符(通常是索引),这个标识符在pod整个生命周期中保持不变。对于需要稳定标识的应用程序非常重要,例如数据库。
- 稳定网络标识:每个StatefulSet创建的Pod都具有稳定的网络标识,例如DNS主机名,它们以一致的方式命名,便于集群内部通信。
- 有序部署和扩展:StatefulSet可以确保Pod实例按照指定的顺序创建和删除。这个对于有状态应用程序非常重要,因为他们可能有特别的启动和关闭顺序。
- 持久性存储:StatefulSet可以与持久性存储卷(如PersistentVolume和PersistentVolumeClaims)集成,以确保数据的持久性和可用性。
- 数据迁移:当扩展StatefulSet或在节点发生故障时,StatefulSet可以自动处理Pod的数据迁移,确保数据的持久性。
- 保证ss存储一致:ss本身是无法保证每个相同名称的pod写入的存储一致的,这个功能是通过本文第三节介绍的持久性存储实现的,基本原理就是为ss管理的每一个pod创建一个对应的持久卷,ss保证基于相同诸暨名写入相同持久卷,从而保证了存储状态一致。
- 创建ss:ss的定义配置文件如下:
apiVersion: apps/v1 kind: StatefulSet metadata: name: redis-sts spec: serviceName: redis-svc replicas: 2 selector: matchLabels: app: redis-sts template: metadata: labels: app: redis-sts spec: containers: - image: redis name: redis ports: - containerPort: 6379
apiVersion: apps/v1 kind: StatefulSet metadata: name: [dpName] labels: [labelKey]: [labelVal] spec: replicas: [num] #期望的pod副本数量 selector: matchLabels: [labelKey]: [labelVal] template: metadata: labels: [labelKey]: [labelVal] spec: containers: - name: [containerName] image: [containerImage] #...... volumeClaimTemplates: #这里一般是个持久卷列表,列表数量与pod副本数量一致
创建命令:
[root@master statefulset]# kubectl get sts NAME READY AGE redis-sts 2/2 36s
# 可以发现pod名有了序号 [root@master statefulset]# kubectl get pod NAME READY STATUS RESTARTS AGE redis-sts-0 1/1 Running 0 45s redis-sts-1 1/1 Running 0 38s [root@master statefulset]#kubectl create -f [ssName].yaml
- 保证有状态节点的唯一性:
k8s的节点分为主节点和工作节点,pod运行在工作节点上,当工作节点由于某些原因与主节点断开连接时,ss是如何保证相同状态节点的唯一性的呢?这个问题是通过网络探针实现的,主节点会与工作节点的pod保持通信,当通信断开并持续一段时间后,主节点会将该pod标记为删除状态,服务流量不会流向该pod,而工作节点发现无法与主节点通信后也会停止运行pod,这个时候就需要程序员手动介入删除pod了。
二、k8s通信
1.Service
- 概念:k8s服务是一种为一组功能相同的pod提供统一接入点的资源,服务有固定的的ip和端口,客户端通过服务来访问pod,从功能而言有点类似反向代理。Service通常与以下几个主要方面
- 服务发现:Service允许你创建一个虚拟的网络端点,它会自动将流量负载均衡到一组后端Pod上,而无需直接引用每个Pod的IP地址。这样,你可以通过Service名称来访问应用程序,而不必担心后端pod的具体位置。
- 负载均衡:Service可以用于在多个副本的pod之间均衡流量,确保应用程序的高可用性和可伸缩性。流量会分发到具有相同标签选择器的pod上。
- Session Affinity(会话亲和性):Service允许你选择会话亲和性策略,以确保客户端的连接在多次请求之间路由到相同的后端Pod,适用于需要在统一会话中保持状态的应用程序。
- 外部暴露:通过Service,你可以将应用程序暴露到集群外部。这可以通过不同类型的Service来实现,如NodePort、LoadBalance和Ingress。
- k8s支持不同类型的Service,每种类型适用于不同的用例:
- ClusterIP:这是默认的Service类型,将创造一个虚拟IP地址,用于集群内部的交流量负载均衡。通常用于内部通信,不暴露到集群外部。
- NodePort:NodePort Service类型允许将应用程序暴露到每个节点的IP地址上,以便从集群外部访问Service。
- LoadBalancer:LoadBalancer Service类型使用云提供商的负载均衡服务来公开应用程序,适用于云上部署。
- ExternalName:ExternalName Service类型用于将Service映射到DNS名称而不是IP地址,通常用于连接到外部服务。
- Headless Service:Headless Service是一种特殊类型的Service,不分配ClusterIP,通常与StatefulSet配合使用。
- 创建服务:首先需要创建服务的定义配置文件,如下所示:
apiVersion: v1 kind: Service metadata: name: [svcName] spec: selector: [labelKey]: [labelVal] ports: - protocol: TCP #网络协议 port: 80 #该服务对外暴露的端口 targetPort: 9376 #pod实际可用端口,服务将请求转发到该端口
创建服务:
kubectl create -f [svcName].yaml
查看服务的ip:
kubectl get svc [svcname]
集群内部的节点可以通过服务的ip和端口访问对应的pod
- 设置哈希转发:将同一客户端ip的请求转发到一个相同的pod,可以通过讲服务配置文件下的spec字段下面的sessionAffinity字段设为ClientIP实现。
- endpoint:k8s的服务不是直接存储pod的ip和端口信息的,而是先创建一个endpoint资源,endpoint资源根据标签选择器去获取pod的网络地址列表并存储起来,通过以下命令可以查看服务的endpoint信息:
kubectl describe svc [svcName]
- 对外部客户端暴露服务:
-
- 仅限集群内部节点客户端访问:将服务节点类型设置为NodePort,然后集群内部其他节点就可以通过svc的clusterIP来访问pod,节点类型定义如下:
apiVersion: v1 kind: Service metadata: name: [svcName] spec: type: NodePort #设置服务类型 selector: [labelKey]: [labelVal] ports: - protocol: TCP #网络协议 port: 80 #该服务对外暴露的端口 targetPort: 9376 #pod实际可用端口,服务将请求转发到该端口 nodePort: 1113 # 集群其他节点通过该端口可以访问该服务
-
允许集群外部客户端访问:将服务节点设置为LoadBalance,然后集群外部可以通过svc的externalIP(公有ip地址)来访问对应的pod,如下所示:
apiVersion: v1 kind: Service metadata: name: [svcName] spec: type: LoadBalancer #设置服务类型 selector: [labelKey]: [labelVal] ports: - protocol: TCP #网络协议 port: 80 #该服务对外暴露的端口 targetPort: 9376 #pod实际可用端口,服务将请求转发到该端口 nodePort: 1113 # 集群其他节点通过该端口可以访问该服务
上述没有指定端口的情况下由k8s分配端口
- 仅限集群内部节点客户端访问:将服务节点类型设置为NodePort,然后集群内部其他节点就可以通过svc的clusterIP来访问pod,节点类型定义如下:
2.ingress
-
ingress是k8s基于应用层协议创建的一种资源,与service只能为一个服务提供转发不同,ingress可以为多个服务提供转发,其原理视为多个请求路径设置对应的服务地址。
-
创建ingress:首先需要创建ingress的定义配置文件,如下所示:
piVersion: networking.k8s.io/v1 kind: Ingress metadata: name: [ingName] spec: rules: - http: #指定网络协议 paths: - path: /path1 #指定请求路径 backend: #指定请求服务对应的后端服务 service: name: [podLabel] #pod的标签值 port: number: [Port] - path: /path2 backend: #...
ingrss对于每一个服务都创建一个endpoint资源,endpoint根据标签值去获取对应的pod地址列表,所以外部客户端访问ingress时实际上的访问路径是:外部客户端->主节点ingress->主节点endpoint->工作节点ip:port
三、存储
1.volume
一些需要持久化数据的程序才会用到volume,或者一些共享数据的容器需要用到volume。
中有个Volume概念,Volumn是Pod中能够被多个容器访问的共享目录,k8s的Volume定义在pod上,然后被一个pod里的多个容器挂载到具体的文件目录下,k8s通过Volume实现同一个pod中不同容器之间的数据共享以及数据的持久化存储,Volume的生命周期不与pod中单个容器的生命周期相关,当容器终止或重启的时候,Volume中的数据也不会被丢失。
volume支持常见的类型如下:
2.基本存储
- emptydir:最基础的volume类型,一个emptyDir就是host上的一个空目录。
- 概念:它是在pod被分配到node节点上时才会被创建,初始内容为空,并且无需指定宿主机上对应的目录文件,它会自动在宿主机上分配一个目录。
- 值得关注:pod销毁时,emptydir中的数据也会被永久删除。
- 用处:
- 临时空间,比如web服务器写日志或者tmp文件需要的临时目录。
- 用作多容器之间的共享目录(一个容器需要从另一个容器中获取数据的目录)
- 实战:
apiVersion: v1 kind: Pod metadata: name: nginx namespace: cbuc-test labels: app: nginx-pod spec: containers: - name: nginx image: nginx:1.14-alpine ports: - containerPort: 80 volumeMounts: # 将 nginx-Log 挂载到nginx容器中,容器内目录为/var/log/nginx - name: nginx-log mountPath: /var/log/nginx volumes: #在此声明volume - name: nginx-log emptyDir: {}
- 然后我们创建后可以看看emptyDir存储卷在宿主机的位置。默认情况下宿主机中声明volume的目录位置是在
/var/lib/kubelet/pods/<Pod 的 ID>/volumes/kubernetes.io~<Volume 类型 >/<Volume 名字 >
中。
- Hostpath
- 概念:hostpath就是将node节点上一个实际目录挂载到pod中,供容器使用,这种好处就是在pod销毁后,该目录下的数据依旧存在。
- 实战:
apiVersion: v1 kind: Pod metadata: name: nginx namespace: cbuc-test labels: app: nginx-pod spec: containers: - name: nginx image: nginx:1.14-alpine ports: - containerPort: 80 volumeMounts: - name: nginx-log mountPath: /var/log/nginx volumes: - name: nginx-log hostPath: # 指定宿主机目录为 /data/nginx/log path: /data/nginx/log type: DirectoryOrCreate # 创建类型
-
spec.volumes.hostPath.type
(创建类型):- DirectorOrCreate:目录存在就使用,不存在就先创建再使用。
- Directory:目录必须存在
- FileOrCreate:文件存在就使用,不存在就先创建再使用。
- File:文件必须存在
- Socker:unix套接字必须存在
- CharDevice:字符设备必须存在
- BlockDevice:块设备必须存在
- NFS
- HostPath 是我们日常中比较经常使用到的存储方式了,已经可以满足基本的使用场景。目前为止我们小小的总结一下:EmptyDir 是针对
pod
,如果 pod 被销毁了,那么改数据就会丢失。针对该问题,HostPath 进行了改进,存储变成是针对 Node ,但是如果 Node 宕机了,那么数据还是会丢失。这个时候就需要准备单独的网络存储系统了,而比较常用的便是 NFS、CIFS。 - 概念:NFS是一个网络存储系统,可以搭建一台NFS服务器然后将pod中的存储直接连接到NFS系统上,这样无论pod在节点上如何转移,只要node节点和nfs服务器对接没问题,数据就不会出现问题。
- 实战:选取 master 节点来安装NFS 服务器
# 安装 nfs 服务器 yum install -y nfs-utils # 准备共享目录 mkdir -p /data/nfs/nginx # 将共享目录以读写权限暴露给 192.168.108.0/24 网段的所有主机 vim /etc/exports # 添加以下内容 /data/nfs/nginx 192.168.108.0/24(rw,no_root_squash) # 启动 nfs 服务器 systemctl start nfs
然后我们在各个节点上同样安装 NFS,以供驱动 NFS 设备:
yum install -y nfs-utils
apiVersion: v1 kind: Pod metadata: name: nginx namespace: cbuc-test labels: app: nginx spec: containers: - name: nginx-pod image: nginx:1.14-alpine ports: - containerPort: 80 volumeMounts: - name: nginx-log mountPath: /var/log/nginx volumes: - name: nginx-log nfs: server: 192.168.108.100 # NFS服务器地址,也就是master地址 path: /data/nfs/nginx # 共享文件路径
- HostPath 是我们日常中比较经常使用到的存储方式了,已经可以满足基本的使用场景。目前为止我们小小的总结一下:EmptyDir 是针对
3.高级存储
- 管理存储是管理计算的一个明显问题。该部分需要抽象出如何根据消费方式来提供存储的详细信息。而k8s也很好的支持了,引入了两个新的API资源:PersistentVolume和PersistentVolumeClaim
- PersistentVolume(pv)是持久化卷的意思,是对底层共享存储的一种抽象,一般情况下pv由k8s管理员进行创建和配置,它与底层具体的共享存储技术有关,并通过插件完成与共享存储的对象。
- PersistentVolumeClaim(pvc)是持久卷生命的意思,是用户对存储需求的一种声明,换句话说pvc其实就是用户向k8s发出的一种资源需求申请。
- pv
- pv是集群中有管理员配置的一段网络存储,它也是集群中的一种资源,资源清单模板如下:
apiVersion: v1 kind: PersistentVolume meatadata: name: pv spec: nfs: # 存储类型,可以是 CIFS、GlusterFS capacity: # 存储空间的设置 storage: 2Gi accessModes: # 访问模式 storageClassName: # 存储类别 persistentVolumeReclaimPolicy: # 回收策略
- 存储类型:底层实际存储的类型,k8s支持多种存储类型,每种类型的配置都有差异。
- 存储能力(capacity):目前只支持存储空间的设置,未来可能会加入IOPS、吞吐量等指标的设置。
- 访问模式(accessModes):用于描述用户对应存储资源的访问权限
- ReadWirteOnce(RWO):读写权限,但是能被单个节点挂载。
- ReadOnlyMany(ROM):只读权限,可以被多个节点挂载。
- ReadWriteMany(RWM):读写权限,可以被多个节点挂载。
- 存储类别:PV 可以通过storageClassName参数指定一个存储类别
- 具有特定类别的PV只能与请求了该类别的PVC进行绑定
- 未设定类别的PV则只能与不请求任何类别的PVC进行绑定
- 回收策略(PersistentVolumeReclaimPolicy),当PV没有再被使用的时候,需要对其处理的方式(不同的存储类型支持的策略也会不同),有以下几种回收策略:
- Retain(保留):保留数据。需要管理员手动清理数据
- Recycle(回收):清除PV中的数据,效果相当于
rm -rf
- Delete(删除):与 PV 相连的后端存储完成 volume 的删除操作,常见于云服务商的存储服务
- 生命周期:一个pv的生命周期可能会处于4种不同阶段:
- Available(可用):表示可用状态,还未被任何pvc绑定
- Bound(已绑定):表示PV已经被PVC绑定
- Released(已释放):表示pvc已经被删除,但是资源还未被集群重新声明
- Failed(失败):表示该pv的自动回收失败
- 实战:这里也依然使用 NFS 服务器做底层存储。首先我们需要创建1个PV,也对应着NFS中1个需要暴露的路径。
# 创建目录 mkdir /data/pv1 -pv # 向NFS暴露路径 vim /etc/exports /data/pv1 192.168.108.0/24(rw,no_root_squash)
完成后创建1个pv:
apiVersion: v1 kind: PersistentVolume metadata: name: pv01 namespace: cbuc-test labels: app: pv spec: capacity: storage: 1Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain nfs: path: /data/pv1 server: 192.168.108.100
- pvc
- pvc是资源的申请,用来声明对存储空间,访问模式,存储类别的需求信息,资源清单模板:
apiVersion: v1 kind: persistentVolumeClaim metadata: name: pvc namespace: cbuc-test labels: app: pvc spec: accessModes: # 访问模式 selector: # 采用标签对PV选择 storageClassName: # 存储类别 resources: # 请求空间 request: storage: 1Gi
- 访问模式(accessModes):用于描述用户对应存储资源的访问权限
- 选择条件(selector):通过labels selector的设置,对于系统中已经存在的pv进行筛选管理。
- 资源类别(storageClassName):pvc在定义是可以设定需要的后端存储类别,只有设置了该class的pv才能被系统选出
- 资源请求(resources):描述对存储资源的请求
- 实战:
- 使用默认的 StorageClass:当没有在 PVC 的定义中明确指定
storageClassName
时,Kubernetes 会使用默认的 StorageClass,该 StorageClass 通常在集群级别配置。默认的 StorageClass 是通过kubectl get storageclass
命令来查看的,并且在 PVC 中没有明确指定 StorageClass 的情况下,Kubernetes 会尝试匹配 PV 和 PVC 的存储要求。 - 匹配存储要求:Kubernetes 会查找已经存在的 PV,然后匹配这些 PV 的存储资源(容量、访问模式等)与 PVC 的要求是否相符。当找到一个匹配的 PV 且它的存储资源满足 PVC 的需求时,Kubernetes 将 PV 绑定到 PVC。
- 使用默认的 StorageClass:当没有在 PVC 的定义中明确指定
- 清单:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc01 namespace: cbuc-test spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi
- pvc是资源的申请,用来声明对存储空间,访问模式,存储类别的需求信息,资源清单模板:
- 实际使用
- pod清单:
apiVersion: v1 kind: Pod metadata: name: pod-pvc namespace: cbuc-test spec: containers: - name: nginx01 image: nginx:1.14-alpine volumeMounts: - name: test-pv mountPath: /var/log/nginx volumes: - name: test-pv persistentVolumeClaim: claimName: pvc01 readOnly: true
- pod清单:
- 生命周期
- 资源供应:管理员手动创建底层存储和pv
- 绑定资源:用户创建pvc,k8s负责根据pvc的声明去寻找pv,并绑定
- 如果找到,则会成功进行绑定,用户的应用就可以使用这个PVC了
- 如果找不到,PVC则会无限处于Pending的状态,直到等到系统管理员创建了一个符合其要求的PV
- 资源使用:用户可在Pod中像Volume一样使用pvc
- 资源释放:用户通过删除pvc来释放pv,当存储资源使用完毕后,用户可以删除pvc,与该pvc绑定的pv将会标记为已释放,但还不能立刻与其他pvc进行绑定,通过之前pvc写入的数据可能还留在存储设备上,只有在清除之后该pv才能再次使用。
- 资源回收:k8s会根据pv设置的回收策略进行回收。
- pv是集群中有管理员配置的一段网络存储,它也是集群中的一种资源,资源清单模板如下:
4.配置存储
-
配置存储,用来存储配置,其中包括了两种配置存储,分别是ConfigMap和Secret
-
ConfigMap:ConfigMap是一种比较特殊的存储卷,它的主要作用是用来存储配置信息的。资源清单如下:
apiVersion: v1 kind: ConfigMap metadata: name: cmp namespace: cbuc-test data: info: username:cbuc sex:male
使用方式很简单,少了spec,多了data.info,只需要info下级以key:value的方式存储自己想要配置的配置文件即可。
-
通过kubectl create -f configmap.yaml命令可以创建出一个ConfigMap:
具体使用如下,需要创建一个pod:
apiVersion: v1 kind: Pod metadata: name: test-pod namespace: cbuc-test spec: containers: - name: nginx image: nginx:1.15.2 volumeMounts: # 将 configMap 挂载到目录中 - name: config mountPath: /var/configMap/config volumes: - name: config configMap: name: cmp # 上面我们创建 configMap 的名称
-
-
secret
-
在 k8s 中,还存在一种和 ConfigMap 非常类似的对象,称之为 Secret 对象。它主要用于存储敏感信息,例如密码、秘钥、证书等信息。我们首先对想要配置的数据进行 base64 加密:
# 加密用户名 [root@master test]# echo -n 'cbuc' | base64 Y2J1Yw== # 加密密码 [root@master test]# echo -n '123456' | base64 MTIzNDU2
然后准备 Secret 资源清单文件
apiVersion: v1 kind: Secret metadata: name: secret namespace: cbuc-test type: Opaque # 表示base64编码格式的Secret data: username: Y2J1Yw== password: MTIzNDU2
通过命令
kubectl create -f secret.yaml
创建 Secret,然后我们再准备一份Pod资源清单:apiVersion: v1 kind: Pod metadata: name: pod-secret namespace: cbuc-test spec: containers: - name: nginx image: nginx:1.14-apline volumeMounts: - name: config mountPath: /var/secret/config volumes: - name: config secret: secretName: secret
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通