K8S-Pod控制器

目录

  • [1 Pod 控制器类型](#1 Pod 控制器类型)
  • [2 Deployment](#2 Deployment)
    • [2.1 deployment 创建 Pod 示例](#2.1 deployment 创建 Pod 示例)
  • [3 SatefulSet](#3 SatefulSet)
    • [3.1 StatefulSet 的组成](#3.1 StatefulSet 的组成)
      • [3.1.1 为什么要有 headless](#3.1.1 为什么要有 headless)
      • [3.1.2 为什么要有 volumeClainTemplate](#3.1.2 为什么要有 volumeClainTemplate)
    • [3.2 清单定义 StatefulSet示例(静态创建)](#3.2 清单定义 StatefulSet示例(静态创建))
  • [4 服务发现](#4 服务发现)
    • [4.1 服务发现示例](#4.1 服务发现示例)
  • [5 滚动更新](#5 滚动更新)
    • [5.1 滚动更新示例](#5.1 滚动更新示例)
  • [6 重点总结](#6 重点总结)
    • [6.1 无状态与有状态](#6.1 无状态与有状态)
    • [6.2 常规 service 和无头服务区别](#6.2 常规 service 和无头服务区别)
    • [6.3 扩展伸缩](#6.3 扩展伸缩)
  • [7 DaemonSet](#7 DaemonSet)
    • [7.1 DaemonSet 示例](#7.1 DaemonSet 示例)
  • [8 Job](#8 Job)
    • [8.1 Job 示例](#8.1 Job 示例)
  • [9 CronJob](#9 CronJob)
    • [8.1 CronJob 示例](#8.1 CronJob 示例)

什么是 Pod 控制器?
Pod 控制器是 Kubernetes 中的一种控制器,用于管理和控制 Pod 的生命周期。它负责确保 Pod 的副本数量符合用户指定的期望值,并在需要时启动、重新调度或终止 Pod。Pod 通过控制器实现应用的运维,如伸缩,升级等。

1 Pod 控制器类型

  1. ReplicaSet:代替用户创建指定数量的 pod 副本,确保 pod 副本数量符合预期,并且支持滚动式自动扩容和缩容功能。

    ReplicaSet 主要三个组件/功能:

    1. 用户期望的 pod 副本数量
    2. 标签选择器,判断哪个 pod 归自己管理
    3. 当现存的 pod 数量不足,会根据 pod 资源模板进行新建

    ReplicaSet 可以帮助用户管理无状态的 pod 资源,精确反应用户定义的目标数量,但是 RelicaSet 不是直接使用的控制器,一般是直接使用 Deployment。

  2. Deployment:工作在 ReplicaSet 之上,用于管理无状态 应用,目前来说最好的控制器。支持滚动更新和回滚功能,还提供声明式配置。

    ReplicaSet 与 Deployment 这两个资源对象逐步替代了之前RC的作用。

  3. DaemonSet:用于确保集群中的每一个节点只运行特定的 pod 副本,通常用于实现系统级后台任务,比如 ELK 服务。它的特性是服务是无状态的而且服务必须是守护进程。

  4. StatefulSet:管理有状态应用

  5. Job:只要完成就立即退出,不需要重启或重建

  6. Cronjob:周期性任务控制,不需要持续后台运行

2 Deployment

deployment 用来部署无状态应用,管理 Pod 和 ReplicaSet,具有上线部署、副本设定、滚动升级、回滚等功能,提供声明式更新(例如只更新一个新的image)

应用场景:web服务

2.1 deployment 创建 Pod 示例

vim nginx-deployment.yaml

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx	
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.15.4
        ports:
        - containerPort: 80

kubectl create -f nginx-deployment.yaml

查看相关信息

kubectl get pods,deployment,rs

查看控制器配置

kubectl edit deployment/nginx-deployment

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: "2021-04-19T08:13:50Z"
  generation: 1
  labels:
    app: nginx					#Deployment资源的标签
  name: nginx-deployment
  namespace: default
  resourceVersion: "167208"
  selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/nginx-deployment
  uid: d9d3fef9-20d2-4196-95fb-0e21e65af24a
spec:
  progressDeadlineSeconds: 600
  replicas: 3					#期望的pod数量,默认是1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: nginx
  strategy:
    rollingUpdate:
      maxSurge: 25%				#升级过程中会先启动的新Pod的数量不超过期望的Pod数量的25%,也可以是一个具体的数字
      maxUnavailable: 25%		#升级过程中在新的Pod启动好后销毁的旧Pod的数量不超过期望的Pod数量的25%,也可以是一个具体的数字
    type: RollingUpdate			#滚动升级
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx				#Pod副本关联的标签
    spec:
      containers:
      - image: nginx:1.15.4				#镜像名称
        imagePullPolicy: IfNotPresent	#镜像拉取策略
        name: nginx
        ports:
        - containerPort: 80				#容器暴露的监听端口
          protocol: TCP
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always				#容器重启策略
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
......

查看历史版本

kubectl rollout history deployment/nginx-deployment

3 SatefulSet

部署有状态应用,即:

  • 稳定的持久化存储:Pod 重新调度后还是能访问到相同的持久化数据,基于 PVC 来实现
  • 稳定的网络标志:Pod 重新调度后其 PodName 和 HostName 不变,基于 Headless Service(即没有Cluster IP的Service)来实现
  • 有序部署,有序扩展:Pod 是有顺序的,在部署或者扩展的时候要依据定义的顺序依次进行,即从 0 到 N-1,在下一个 Pod 运行之前所有之前的 Pod 必须都是 Running 和 Ready 状态,基于 init containers 来实现
  • 有序收缩,有序删除:反过来,即从 N-1 到 0
    常见的应用场景:数据库

3.1 StatefulSet 的组成

从上面的应用场景可以发现,StatefulSet 由以下几个部分组成:

  • Headless Service(无头服务):用于为 Pod 资源标识符生成可解析的 DNS 记录。
  • volumeClaimTemplates(存储卷申请模板):基于静态或动态 PV 供给方式为 Pod 资源提供专有的固定存储。
  • StatefulSet:用于管控 Pod 资源。

3.1.1 为什么要有 headless

在 deployment 中,每一个 pod 是没有名称,是随机字符串,是无序的。而 statefulset 中是要求有序的,每一个 pod 的名称必须是固定的。当节点挂了,重建之后的标识符是不变的,每一个节点的节点名称是不能改变的。pod 名称是作为 pod 识别的唯一标识符,必须保证其标识符的稳定并且唯一。

为了实现标识符的稳定这个目标,就需要一个 headless service 解析直达到 pod,还需要给 pod 配置一个唯一的名称。

3.1.2 为什么要有 volumeClainTemplate

大部分有状态副本集都会用到持久存储 ,比如分布式系统来说,由于数据是不一样的,每个节点都需要自己专用的存储节点。

在 deployment 中 pod 模板中创建的存储卷是一个共享的存储卷,多个 pod 使用同一个存储卷,而 statefulset 定义中的每一个 pod 都不能使用同一个存储卷,由此基于 pod 模板创建 pod 是不适应的。

这就需要引入 volumeClainTemplate:当在使用 statefulset 创建 pod 时,会自动生成一个 PVC,从而请求绑定一个 PV,从而使每个 Pod 有自己专用的存储卷。

3.2 清单定义 StatefulSet示例(静态创建)

如上所述,一个完整的 StatefulSet 控制器由一个 Headless Service、一个 StatefulSet 和一个 volumeClaimTemplate 组成。如下资源清单中的定义:

vim stateful-demo.yaml

复制代码
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
  labels:
    app: myapp-svc
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: myapp-pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: myapp
spec:
  serviceName: myapp-svc
  replicas: 3
  selector:
    matchLabels:
      app: myapp-pod
  template:
    metadata:
      labels:
        app: myapp-pod
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: myappdata
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: myappdata
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 2Gi

解析上例:由于 StatefulSet 资源依赖于一个实现存在的 Headless 类型的 Service 资源,所以需要先定义一个名为 myapp-svc 的 Headless Service 资源,用于为关联到每个 Pod 资源创建 DNS 资源记录。接着定义了一个名为 myapp 的 StatefulSet 资源,它通过 Pod 模板创建了 3 个 Pod 资源副本,并基于 volumeClaimTemplates 向前面创建的PV进行了请求大小为 2Gi 的专用存储卷。

创建pv

//stor01节点

mkdir -p /data/volumes/v{1,2,3,4,5}

vim /etc/exports

复制代码
/data/volumes/v1 192.168.80.0/24(rw,no_root_squash)
/data/volumes/v2 192.168.80.0/24(rw,no_root_squash)
/data/volumes/v3 192.168.80.0/24(rw,no_root_squash)
/data/volumes/v4 192.168.80.0/24(rw,no_root_squash)
/data/volumes/v5 192.168.80.0/24(rw,no_root_squash)

systemctl restart rpcbind

systemctl restart nfs

exportfs -arv

showmount -e

定义PV

//master 节点

vim pv-demo.yaml

复制代码
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
  labels:
    name: pv001
spec:
  nfs:
    path: /data/volumes/v1
    server: stor01
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv002
  labels:
    name: pv002
spec:
  nfs:
    path: /data/volumes/v2
    server: stor01
  accessModes: ["ReadWriteOnce"]
  capacity:
    storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
  labels:
    name: pv003
spec:
  nfs:
    path: /data/volumes/v3
    server: stor01
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv004
  labels:
    name: pv004
spec:
  nfs:
    path: /data/volumes/v4
    server: stor01
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv005
  labels:
    name: pv005
spec:
  nfs:
    path: /data/volumes/v5
    server: stor01
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 2Gi

kubectl apply -f pv-demo.yaml

kubectl get pv

创建statefulset

kubectl apply -f stateful-demo.yaml

创建前可以另开一个shell,查看 pod 创建的顺序

kubectl get pods -w

查看创建的无头服务myapp-svc

kubectl get svc

查看statefulset

kubectl get sts

查看pvc绑定

kubectl get pvc

查看pv绑定

kubectl get pv

查看Pod信息

kubectl get pods

当删除的时候是从myapp-2开始进行删除的,关闭是逆向关闭

kubectl delete -f stateful-demo.yaml

kubectl get pods -w

此时PVC依旧存在的,再重新创建pod时,依旧会重新去绑定原来的pvc

kubectl apply -f stateful-demo.yaml

kubectl get pvc

4 服务发现

就是应用服务之间相互定位的过程。

应用场景

  • 动态性强:Pod会飘到别的 node 节点
  • 更新发布频繁
  • 支持自动伸缩:能够在需要时扩容或缩容副本

K8S里服务发现的方式------DNS:使 K8S 集群能够自动关联 Service 资源的"名称"和 "CLUSTER-IP",从而达到服务被集群自动发现的目的。

实现 K8S 中 DNS 功能的插件:

  • skyDNS:Kubernetes 1.3之前的版本
  • kubeDNS:Kubernetes 1.3至 Kubernetes 1.11
  • CoreDNS:Kubernetes 1.11开始至今

4.1 服务发现示例

安装CoreDNS

(仅二进制部署环境需要安装 CoreDNS)

准备coredns.yaml文件
方法一 :下载 yaml 文件,链接:

https://github.com/kubernetes/kubernetes/blob/master/cluster/addons/dns/coredns/coredns.yaml.base

vim transforms2sed.sed

复制代码
s/__DNS__SERVER__/10.0.0.2/g
s/__DNS__DOMAIN__/cluster.local/g
s/__DNS__MEMORY__LIMIT__/170Mi/g
s/__MACHINE_GENERATED_WARNING__/Warning: This is a file generated from the base underscore template file: coredns.yaml.base/g

sed -f transforms2sed.sed coredns.yaml.base > coredns.yaml

方法二:直接上传现成的 coredns.yaml 文件

准备好 coredns.yaml 文件后创建

kubectl create -f coredns.yaml

kubectl get pods -n kube-system

(我不是二进制安装,所以没有截图:D)

创建 Pod

vim nginx-service.yaml

复制代码
apiVersion: v1  
kind: Service  
metadata:
  name: nginx-service
  labels:
    app: nginx  
spec:
  type: NodePort  
  ports:
  - port: 80
    targetPort: 80  
  selector:
    app: nginx

kubectl create -f nginx-service.yaml

kubectl get svc

vim pod6.yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: dns-test
spec:
  containers:
  - name: busybox
    image: busybox:1.28.4
    args:
    - /bin/sh
    - -c
    - sleep 36000
  restartPolicy: Never

kubectl create -f pod6.yaml

检查 dns 解析是否正常,进入 Pod

kubectl exec -it dns-test sh

nslookup kubernetes

nslookup nginx-service

5 滚动更新

StatefulSet 控制器将在 StatefulSet 中删除并重新创建每个 Pod。它将以与 Pod 终止相同的顺序进行(从最大的序数到最小的序数),每次更新一个 Pod。在更新其前身之前,它将等待正在更新的 Pod 状态变成正在运行并就绪。

5.1 滚动更新示例

如下操作的滚动更新是按照2-0的顺序更新。

修改image版本为v2

vim stateful-demo.yaml

kubectl apply -f stateful-demo.yaml

查看滚动更新的过程

kubectl get pods -w

在创建的每一个 Pod 中,每一个 pod 自己的名称都是可以被解析的

kubectl exec -it myapp-0 /bin/sh

nslookup myapp-1.myapp-svc.default.svc.cluster.local

nslookup myapp-2.myapp-svc.default.svc.cluster.local

//从上面的解析,我们可以看到在容器当中可以通过对 Pod 的名称进行解析到 ip。其解析的域名格式如下:
(pod_name).(service_name).(namespace_name).svc.cluster.local

6 重点总结

6.1 无状态与有状态

无状态

  • deployment 认为所有的 pod 都是一样的
  • 不用考虑顺序的要求
  • 不用考虑在哪个 node 节点上运行
  • 可以随意扩容和缩容

有状态

  • 实例之间有差别,每个实例都有自己的独特性,元数据不同,例如 etcd,zookeeper
  • 实例之间不对等的关系,以及依靠外部存储的应用。

6.2 常规 service 和无头服务区别

service :一组 Pod 访问策略,提供 cluster-IP 群集之间通讯,还提供负载均衡和服务发现。
Headless service:无头服务,不需要 cluster-IP,而是直接以 DNS 记录的方式解析出被代理 Pod 的 IP 地址。

6.3 扩展伸缩

扩容副本增加到4个

kubectl scale sts myapp --replicas=4

动态查看扩容

kubectl get pods -w

查看pv绑定

kubectl get pv

打补丁方式缩容

kubectl patch sts myapp -p '{"spec":{"replicas":2}}'

动态查看缩容

kubectl get pods -w

7 DaemonSet

DaemonSet 确保全部(或者一些)Node 上都运行同一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个 Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。

DaemonSet 的典型应用场景

  • 运行集群存储 daemon,例如在每个 Node 上运行 glusterd、ceph。
  • 在每个 Node 上运行日志收集 daemon,例如fluentd、logstash。
  • 在每个 Node 上运行监控 daemon,例如 Prometheus Node Exporter、collectd、Datadog 代理、New Relic 代理,或 Ganglia gmond。

7.1 DaemonSet 示例

vim ds.yaml

复制代码
apiVersion: apps/v1
kind: DaemonSet 
metadata:
  name: nginx-daemonset
  labels:
    app: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.15.4
        ports:
        - containerPort: 80

kubectl apply -f ds.yaml

DaemonSet会在每个node节点都创建一个Pod

kubectl get pods

8 Job

Job 分为普通任务(Job)和定时任务(CronJob)

常用于运行那些仅需要执行一次的任务

应用场景:数据库迁移、批处理脚本、kube-bench扫描、离线数据处理,视频解码等业务

8.1 Job 示例

vim job.yaml

复制代码
apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

参数解释

  • .spec.template.spec.restartPolicy:主要用于描述 Pod 内容器的重启策略。在 Job 中只能将此属性设置为 OnFailure 或 Never,否则 Job 将不间断运行。
  • .spec.backoffLimit:用于设置 Job 失败后进行重试的次数,默认值为 6。默认情况下,除非 Pod 失败或容器异常退出,Job 任务将不间断的重试,此时 Job 遵循 .spec.backoffLimit 上述说明。一旦 .spec.backoffLimit 的次数达到,作业将被标记为失败。

在所有node节点下载perl镜像,因为镜像比较大,所以建议提前下载好

docker pull perl

kubectl apply -f job.yaml

kubectl get pods

结果输出到控制台

kubectl logs pi-bqtf7

清除 job 资源

kubectl delete -f job.yaml

9 CronJob

周期性任务,像Linux的 Crontab 一样。

应用场景:通知,备份

8.1 CronJob 示例

每分钟打印hello

vim cronjob.yaml

复制代码
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            imagePullPolicy: IfNotPresent
            args:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

cronjob 可用参数的介绍

复制代码
spec:
  concurrencyPolicy: Allow			#要保留的失败的完成作业数(默认为1)
  schedule: '*/1 * * * *'			#作业时间表。在此示例中,作业将每分钟运行一次
  startingDeadlineSeconds: 15		#pod必须在规定时间后的15秒内开始执行,若超过该时间未执行,则任务将不运行,且标记失败
  successfulJobsHistoryLimit: 3		#要保留的成功完成的作业数(默认为3)
  terminationGracePeriodSeconds: 30	#job存活时间 默认不设置为永久
  jobTemplate:						#作业模板。这类似于工作示例

kubectl create -f cronjob.yaml

kubectl get cronjob

kubectl get pods

kubectl logs hello-1709198160-pdmzg

如果报错:Error from server (Forbidden): Forbidden (user=system:anonymous, verb=get, resource=nodes, subresource=proxy) ( pods/log hello-1621587780-c7v54)

解决办法:绑定一个cluster-admin的权限

kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous

相关推荐
huohuopro10 分钟前
idea使用教程
java·ide·intellij-idea
NGC_661113 分钟前
ArrayList扩容机制
java·前端·算法
HalvmånEver8 小时前
7.高并发内存池大页内存申请释放以及使用定长内存池脱离new
java·spring boot·spring
凤山老林8 小时前
SpringBoot 使用 H2 文本数据库构建轻量级应用
java·数据库·spring boot·后端
小夏卷编程8 小时前
Ubuntu 20.04.4 宝塔 docker showdoc v3.2 更新到v3.7.3
运维·docker·容器
JEECG低代码平台8 小时前
JeecgBoot低代码平台 Docker 部署 OnlyOffice 文档服务完整指南
低代码·docker·容器
赶路人儿9 小时前
UTC时间和时间戳介绍
java·开发语言
dreamread9 小时前
【SpringBoot整合系列】SpringBoot3.x整合Swagger
java·spring boot·后端
6+h9 小时前
【java】基本数据类型与包装类:拆箱装箱机制
java·开发语言·python