zoukankan      html  css  js  c++  java
  • kuberenetes控制器(管理Pod)

    kuberenetes控制器(管理Pod)

    K8S中去管理pod的任务是由控制器(controllers)去做的,控制器又称为工作负载(workload),有了控制器才能更好的对服务进行编排,有五个比较重要的控制器,如下。

    • Deployment
    • StatefulSet
    • DaemonSet
    • Job
    • CronJob

    下面会分别介绍,先看看Pod与控制器的关系。

    Pod 与控制器的关系

    首先控制器是在集群上管理和运行容器的对象,也就是管理Pod的,第二控制与pod关联是通过标签(label-selector)进行关联,通过控制器去管理Pod会实现更多流啤的功能,像是什么弹性伸缩升级滚动更新之类的,都是在控制器层面实现的。

    Deployment部署无状态应用

    使用Deployment,这个控制器创建了nginx,这种算是无状态的应用,像是nginx根本不用去考虑分配到那个节点或容器IP是多少,所以Deployment适用于部署无状态的应用,他能管理Pod和ReplicaSet

    [root@k8s01 yml]# kubectl get replicasets.apps 
    NAME              DESIRED   CURRENT   READY   AGE
    nginx-dd6b5d745   3         3         3       3d5h
    [root@k8s01 yml]# 
    

    ReplicaSet这对于用于来说,这是一个隐藏的控制器,用作管理Pod副本数的,我预期的状态是创建三个副本,可以看一下上文的配置文件,如果有一个pod挂掉了他就会再启动一个pod,会确保有三个在运行,deployment是管理replicasets&pod的,replicasets也做版本的管理,之前我们使用kubectl rollout回滚到上一个版本就是依靠的replicasets

    所以总结一下就是deployment能管理PodReplicaSet、具有上线部署、副本设定、滚动更新、回滚等功能,下面编辑一下nginx-deployment的配置文件

    [root@k8s01 yml]# kubectl edit deployments.apps nginx 
    spec:
      progressDeadlineSeconds: 600
      replicas: 3					#设置副本数
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          run: nginx				#标签选择器,pod与控制器关联
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate			# 滚动更新策略,默认滚动更新
    

    查看回滚版本,也是replicasets来做的。

    [root@k8s01 yml]# kubectl rollout history deployment nginx 
    deployment.apps/nginx 
    REVISION  CHANGE-CAUSE
    1         <none>
    
    [root@k8s01 yml]# 
    

    支持声明式更新,例如想更新某一个字段,他就会更新某一个字段,例如更新image字段,deployments比较适合Web服务,之前部署用的就是deployments

    有状态和无状态服务区别

    刚刚上面提到了deployment部署的是无状态服务,还有一种服务是有状态服务,这俩服务有啥区别,下面分别看一下。

    无状态服务概述

    deployment认为所有的Pod都是一样的,也就是这些。

    [root@k8s01 yml]# kubectl get pods 
    NAME                    READY   STATUS    RESTARTS   AGE
    nginx-dd6b5d745-6z8lx   1/1     Running   5          3d5h
    nginx-dd6b5d745-cv4t8   1/1     Running   4          3d5h
    nginx-dd6b5d745-tgh5c   1/1     Running   5          3d5h
    [root@k8s01 yml]# 
    

    这三个副本都是一模一样的,都是使用同一个镜像去启动的,里面的数据也是完全一样的,属于是对等关系,而且他们的启动顺序也是没有任何规律,先启动哪个都无所谓,对我应用部署没有任何影响,也不用考虑pod在哪个node运行,更不用也不用考虑Pod:IP是什么,所以你可以随意扩容和缩容。

    有状态服务概述

    举一个最简单的例子,例如我现在需要使用三个zookeeper做一个集群,集群最低要求要有三个zookeeper实例,每个容器都设置的一个名为ZOO_MY_ID 的全局变量,而且这个值各个容器之间都不一样,有三个容器,我设置的分别是{1..3},各个节点地址都是用的zoo{1..3},这算是唯一的网络标识符,容器挂了重启这个标识符是不变的,但是我那个zookeeper没有挂载数据卷,其实还要有持久存储。

    像是这种服务你就不能随意的扩容和缩减了,需要有序进行了,包括扩展删除终止滚动更新服务,像是这种就算有状态服务了,每个实例之间属于不对等关系,各个容器之间有些参数不一致,或是挂载的数据卷源/位置不一致,你不可以随意的扩容或缩减这些服务,否则就会有问题,在K8S中,要实现这种服务就要使用StatefulSet了。

    headless service

    想知道StatefulSet具体是怎么实现的,要从一个服务谈起,也就是headless service,称为无头服务,回忆一下之前的Service,它是一组pod的访问策略,提供负载均衡和服务发现,访问这个Service他会帮你把请求转发到某个Pod,也就是这个东西,这是之前创建的。

    [root@k8s01 yml]# kubectl get services 
    NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
    kubernetes      ClusterIP   10.0.0.1     <none>        443/TCP        10d
    nginx-service   NodePort    10.0.0.180   <none>        80:30010/TCP   3d21h
    [root@k8s01 yml]# 
    

    类型NodePort,无头服务也是使用了Service,不过在定义的时候不需要CLUSTER-IP了,直接会绑定具体Pod的IP,上面就是一个常规的Service,他关联了三个标签为nginxPod,且提供了一个统一的入口,IP10.0.0.180,你访问这个IP:port他会帮你把请求转发到后端Pod,也就是这里。

    [root@k8s01 yml]# kubectl get endpoints nginx-service 
    NAME            ENDPOINTS                                        AGE
    nginx-service   10.244.0.38:80,10.244.1.100:80,10.244.1.101:80   3d22h
    [root@k8s01 yml]# 
    

    再来看headless service,和常规的稍微有点区别,他会将CLUSTER-IP置位none

    [root@k8s01 yml]# cat headless-service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      ports:
      - port: 80
        name: web
      clusterIP: None
      selector:
        app: nginx
    

    和正常创建Service的区别就是clusteripnone,默认clusterIP是启用的,现在制定为none了就是不为这个Service分配一个clusterip了,创建一下看效果。

    [root@k8s01 yml]# kubectl create -f headless-service.yaml 
    service/nginx created
    [root@k8s01 yml]# kubectl get services nginx
    NAME    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    nginx   ClusterIP   None         <none>        80/TCP    6s
    [root@k8s01 yml]# 
    

    可以看到CLUSTER-IPNone了,他没有具体的IP,这种情况下主要用的就是DNS访问了,他保证了唯一的网络标识符,使用IP无法保证你这个pod挂掉重启后永远都是使用这个IP,所以这就是利用了DNS保证了网络唯一标识符的,我们之前部署过了coredns,下面开始部署有状态服务。

    部署有状态应用

    SatefulSet是部署有状态应用,解决Pod独立生命周期,保持Pod顺序和唯一性。稳定,唯一的网络标识符,持久存储。有序,优雅的部署和扩展,删除和终止。有序,滚动升级

    [root@k8s01 yml]# kubectl delete -f headless-service.yaml 
    service "nginx" deleted
    [root@k8s01 yml]# kubectl delete -f deployment.yaml 
    deployment.apps "nginx-deployment" deleted
    [root@k8s01 yml]# kubectl delete -f services.yaml 
    service "nginx-service" deleted
    
    [root@k8s01 yml]# cat nginx-headless.yaml 
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      ports:
      - port: 80
        name: web
      clusterIP: None
      selector:
        app: nginx
    
    ---
    
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: nginx
    spec:
      selector:
        matchLabels:
          app: nginx
      serviceName: "nginx"
      replicas: 3
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:latest
            ports:
            - containerPort: 80
              name: nginx
    

    我把ServiceStatefulSet写到了一起,StatefulSetdeployment有差别的地方就是StatefulSet有个serviceName,他是用来关联上面无头service的,上面无头Service的名称就是nginx,直接用这个文件进行部署,部署完之后看一下所创建的StatefulSetService

    [root@k8s01 yml]# kubectl create -f nginx-headless.yaml 
    service/nginx created
    statefulset.apps/nginx created
    [root@k8s01 yml]# kubectl get services nginx
    NAME    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    nginx   ClusterIP   None         <none>        80/TCP    14s
    [root@k8s01 yml]# kubectl get pods
    NAME      READY   STATUS    RESTARTS   AGE
    nginx-0   1/1     Running   0          53s
    nginx-1   1/1     Running   0          36s
    nginx-2   1/1     Running   0          20s
    [root@k8s01 yml]# 
    

    创建好了,现在了解一下唯一的网络标识是怎么来的,就是上图NAME那一行的名称,这就是一个固定的DNS名称了,而且会有有序编号,现在随便启动一个镜像去测试一下。

    [root@k8s01 yml]# kubectl run -it --image=busybox:1.28.4 --rm --restart=Never sh
    If you don't see a command prompt, try pressing enter.
    / # 
    / # for i in 0 1 2;do nslookup nginx-$i.nginx;done
    Server:    10.0.0.2
    Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local
    
    Name:      nginx-0.nginx
    Address 1: 10.244.1.102 nginx-0.nginx.default.svc.cluster.local
    Server:    10.0.0.2
    Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local
    
    Name:      nginx-1.nginx
    Address 1: 10.244.0.39 nginx-1.nginx.default.svc.cluster.local
    Server:    10.0.0.2
    Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local
    
    Name:      nginx-2.nginx
    Address 1: 10.244.1.103 nginx-2.nginx.default.svc.cluster.local
    / # pod "sh" deleted
    [root@k8s01 yml]# kubectl get pods -o wide
    NAME      READY   STATUS    RESTARTS   AGE     IP             NODE    NOMINATED NODE   READINESS GATES
    nginx-0   1/1     Running   0          9m19s   10.244.1.102   k8s03   <none>           <none>
    nginx-1   1/1     Running   0          9m2s    10.244.0.39    k8s02   <none>           <none>
    nginx-2   1/1     Running   0          8m46s   10.244.1.103   k8s03   <none>           <none>
    [root@k8s01 yml]# 
    

    没什么问题, pod名称后需要加上Service的名称才能解析到,这就是一个Pod有一个唯一的域名,这是个固定的,并且解析到自身的IP,所以,总结一下。

    StatefulSetdeployment的主要区别就是StatefulSet是有身份的,这个身份有三要素,分别是有自己的域名、主机名、存储(PVC),每一个Pod都有一个唯一的主机名,看一下是什么就知道了。

    [root@k8s01 yml]# for i in {0,1,2};do kubectl exec nginx-$i hostname;done
    nginx-0
    nginx-1
    nginx-2
    [root@k8s01 yml]# 
    

    DaemonSet

    这个比较好理解,他会在你每一个Node上运行一个Pod,新加入的Node也会自动运行一个Pod,比较适合运行采集器之类的东西

    [root@k8s01 yml]# cat daemonset.yaml
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: filebeat
    spec:
      selector:
        matchLabels:
          app: filebeat
      template:
        metadata:
          labels:
            app: filebeat
        spec:
          containers:
          - name: filebeat
            image: nginx:latest
            volumeMounts: 
            - mountPath: /log
              name: varlog
          volumes:
          - name: varlog
            hostPath: 
              path: /var/log
              type: Directory
    [root@k8s01 yml]# 
    

    使用了nginx的镜像,你就把他当成filebeat,这东西是干嘛的应该都了解过,上面把宿主机的/var/log目录挂在到了容器的/log,上面提到了这个类型会在所有的Node节点都启动一个的pod,所以你可以理解为该Pod可以收集宿主机日志,通过filebeat读取挂载目录的日志推到logstash||elasticsearch

    [root@k8s01 yml]# kubectl create -f daemonset.yaml
    daemonset.apps/filebeat created
    [root@k8s01 yml]# kubectl get pods -o wide
    NAME             READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
    filebeat-5sfvj   1/1     Running   0          26s   10.244.0.46    k8s02   <none>           <none>
    filebeat-q5f7c   1/1     Running   0          26s   10.244.2.60    k8s05   <none>           <none>
    filebeat-zcl56   1/1     Running   0          26s   10.244.1.104   k8s03   <none>           <none>
    

    可以看到每个节点都有一个在运行,下面去Pod里看看宿主机的东西是否被挂载到Pod,挂载到了就没问题

    [root@k8s01 yml]# kubectl exec -it filebeat-5sfvj /bin/bash
    root@filebeat-5sfvj:/# ls -l /log/
    total 5468
    drwxr-xr-x. 2 root root      204 May  1 05:24 anaconda
    drwx------. 2 root root       23 May  1 05:24 audit
    -rw-------. 1 root root        0 Jun  5 03:19 boot.log
    -rw-------  1 root root    78724 Jun  2 02:50 boot.log-20200602
    -rw-------  1 root root     9076 Jun  3 08:06 boot.log-20200603
    -rw-------  1 root root    37533 Jun  5 03:19 boot.log-20200605
    -rw-------. 1 root voice       0 May  1 05:22 btmp
    drwxr-xr-x  2 root root     4096 Jun  5 08:44 containers
    -rw-------. 1 root root   294625 Jun  5 08:46 cron
    -rw-r--r--  1 root root   122195 Jun  5 02:58 dmesg
    -rw-r--r--  1 root root   122185 Jun  5 02:42 dmesg.old
    -rw-r--r--. 1 root root     1842 May  1 05:27 firewalld
    -rw-r--r--. 1 root root      193 May  1 05:21 grubby_prune_debug
    -rw-r--r--. 1 root root   292000 Jun  5 06:13 lastlog
    -rw-------. 1 root root   153548 Jun  5 08:46 maillog
    -rw-------. 1 root root  4517207 Jun  5 08:46 messages
    drwxr-xr-x  7 root root     4096 Jun  5 08:43 pods
    drwxr-xr-x. 2 root root        6 May  1 05:24 rhsm
    drwxr-xr-x. 2 root root       91 Jun  5 02:42 sa
    -rw-------. 1 root root    51606 Jun  5 08:24 secure
    -rw-------. 1 root root        0 May  1 05:22 spooler
    -rw-------. 1 root root        0 May  1 05:21 tallylog
    drwxr-xr-x. 2 root root       23 May  1 05:24 tuned
    -rw-r--r--. 1 root root    21390 Jun  5 02:58 vmware-vgauthsvc.log.0
    -rw-r--r--. 1 root root    27822 Jun  5 06:05 vmware-vmsvc.log
    -rw-rw-r--. 1 root voice   41472 Jun  5 08:24 wtmp
    -rw-------. 1 root root     4262 Jun  1 09:35 yum.log
    root@filebeat-5sfvj:/# 
    
    

    没问题,使用场景就是这样,将来使用filebeat就可以直接采集这个目录下的日志文件了

    Job与CronJob

    Job分为普通任务(Job)和定时任务(CronJob),普通任务是一次性执行的,定时任务就是有计划的去执行,下面分别去了解一下。

    Job

    也就是普通任务,下面是一个例子,在官网扒过来的。

    [root@k8s01 yml]# cat 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
    

    使用perl镜像启动一个容器,运行一条命令去计算,这个不用深入了解,重启策略为Never,表示容器退出码为0的情况下从不重启,backoffLimit设置重试的次数,如果这个任务执行失败了怎么办,现在定义了4,如果失败了他会帮你重试4次,为毛要有这个?上面提到了Never表示容器退出码为0的情况下从不重启,如果退出状态码非0还是会重启,如果四次退出码都是0,也就是到达了backoffLimit的限制,他就不会再重启了,默认是6,下面创建一下。

    [root@k8s01 yml]# kubectl create -f job.yml 
    job.batch/pi created
    [root@k8s01 yml]# kubectl get jobs.batch 
    NAME   COMPLETIONS   DURATION   AGE
    pi     1/1           3m17s      3m22s
    [root@k8s01 yml]# kubectl get pod pi-k2zvd 
    NAME       READY   STATUS      RESTARTS   AGE
    pi-k2zvd   0/1     Completed   0          3m25s
    [root@k8s01 yml]# 
    

    可以看到pod的状态为Completed了,说明他执行完命令后正常关闭了,关闭后他不会被删除,自行删除吧,所以这个job比较适合临时跑一个任务,跑完之后就退出了,不再执行了。

    CronJob

    定时任务,像crontab一样,基于时间去调度,用来做备份还是蛮不错的,下面一个例子,也是在官方扒过来的,顺便改了改。

    [root@k8s01 yml]# cat cronjob.yaml
    apiVersion: batch/v1beta1
    kind: CronJob
    metadata:
      name: opesn
    spec:
      schedule: "*/1 * * * *"
      jobTemplate:
        spec:
          template:
            spec:
              containers:
              - name: opesn
                image: centos:latest
                command: ["bash","-c","date; echo opesn"]
              restartPolicy: OnFailure
    [root@k8s01 yml]# 
    

    schedule为时间表达式,和crontab的表达式写法是一样的,所以这个就是一分钟一次,重启策略为OnFailure,如果容器异常退出就会重启.

    [root@k8s01 yml]# kubectl create -f cronjob.yaml 
    cronjob.batch/opesn created
    [root@k8s01 yml]# kubectl get cronjobs.batch opesn 
    NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
    opesn   */1 * * * *   False     1        17s             59s
    
    
    [root@k8s01 yml]# kubectl get pod
    NAME                     READY   STATUS              RESTARTS   AGE
    opesn-1591347900-492v4   0/1     ContainerCreating   0          17s
    [root@k8s01 yml]# kubectl logs opesn-1591347900-492v4 
    Fri Jun  5 09:05:22 UTC 2020
    opesn
    [root@k8s01 yml]# 
    
    
    [root@k8s01 yml]# kubectl get pod
    NAME                     READY   STATUS      RESTARTS   AGE
    opesn-1591347900-492v4   0/1     Completed   0          107s
    opesn-1591347960-4fn49   0/1     Completed   0          47s
    [root@k8s01 yml]# kubectl logs opesn-1591347960-4fn49 
    Fri Jun  5 09:06:21 UTC 2020
    opesn
    [root@k8s01 yml]# 
    
    
    [root@k8s01 yml]# kubectl get pod
    NAME                     READY   STATUS      RESTARTS   AGE
    opesn-1591347900-492v4   0/1     Completed   0          2m36s
    opesn-1591347960-4fn49   0/1     Completed   0          96s
    opesn-1591348020-4fs92   0/1     Completed   0          36s
    [root@k8s01 yml]# kubectl logs opesn-1591348020-4fs92 
    Fri Jun  5 09:07:21 UTC 2020
    opesn
    [root@k8s01 yml]# 
    

    就是这种效果,创建成功后每分钟执行一次,历史默认保留三次

  • 相关阅读:
    用Total Commander for Android管理应用程序
    我的zsh简单设置
    C# Newtonsoft.Json 使用
    Wireshark 抓包 test
    C# 调用API test
    C# 委托 的语法 之一
    C# 对象初始化器 和数组初始化语法
    C 语言 数据类型长度
    vue 使用 test
    test
  • 原文地址:https://www.cnblogs.com/opesn/p/13156207.html
Copyright © 2011-2022 走看看