云原生之Kubernetes:16、详解Operator控制器

  • A+
所属分类:kubernetes 云原生 docker

1、为什么需要Operator?

我们前面讲了很多很多基础的资源对象和控制器,如pod、deployment、service、deployment等等,仿佛已经满足了我们大多数情况的场景和需求了,那我们为什么还需要operator呢?

我们之前所讲到无状态应用(如nginx)的扩容是最方便的,我们只要使用deployment控制器中的ReplicaSet字段申明,我们需要几个数量的nginx节点即可。

那有状态的应用又该怎么办呢?

此时你应该会想到这之前所说的,StatefulSet控制器,没错!他的确能够帮助我们解决有状态应用基础的扩缩容动作和行为逻辑,但是还有大多数场景,他是完成不了的。

比如mysql主从集群、多主集群的扩缩容、备份、数据迁移等包含一系列传统架构中,都需要运维人员介入,并通过脚本处理一些复杂的操作。

另外,在Kubernetes上运维人员通常喜欢使用自动化来处理重复的任务。

Operator控制器就是将运维人员的知识、操作和预期翻译成代码片段,如果你了解jenkins,就好比jenkins file、DSL和groovy。
这是我一直坚信和推崇的一个理念:
“基础设施即代码”(Infrastructure as Code)

正是如此,他们每个节点具有不同的角色配置文件、启动顺序、依赖性和自动化操作。

此时,StatefulSet控制器已经胜任不了了,Operator就此诞生!

2、什么是Operator?

Operator由CoreOS开发的,通过软件的方式进行扩展kubernetes。
Operator通过使用CRD(自定义资源)来管理他们各有应用和基础组件。

CRD(CustomResourceDefinition):通过扩展kubernetesAPI,从而满足用户的定制化需求。
我们后面会具体讲解

同时,Operator也遵循了kubernetes的原理、尤其是控制循环。

注意:Operator的开发和维护工作,并不属于kubernetes本身,而是在于各产品线(mysql、jenkins、prometheus等等)。
他们才是致力于维护各自Operator的主角,并帮助用户快速在kubernetes集群上搭建、维护和高效使用自己的产品。

3、Operator原理

云原生之Kubernetes:16、详解Operator控制器

Operator通过扩展Kubernetes定义Custom Controller,观察应用并根据实际状态执行自定义任务。

应用被定义为Kubernetes对象:Custom Resource (CR),它包含yaml spec和被API服务接受的对象类型。

如图所示,Operator控制器的调度逻辑和以往原生控制器调度的逻辑有以下的不同点:

1、Operator通过Custom Controller协调应用的spec属性,原生控制器则通过kubelet;
2、Operator可以独立运行在集群内部或外部,原生控制器则必须运行于集群内部。

Operator控制器真正价值来自于你对应用失败状态处理的最佳实践,以及Operator如何协同人工干预的期望逻辑。

4、Operator应用场景

如果有以下涉及的工作内容刚需,你可以选择operator来帮助你:

1、按需部署应用程序
2、获取并恢复应用程序状态的备份数据
3、处理应用程序升级相关的变更需求,如数据库库表,或者是额外事项的配置
4、发布一个服务,使得原本kubernetes API原生不支持的应用可以发现它
5、模拟整个或部分集群中的故障以测试其弹性
6、在没有内部成员选举程序的情况下,为分布式应用程序选择一位领导者

5、如何部署Operator

我们部署Operator最常见也是最通用的方法就是,在我们的kubernetes集群中,新增相应的CRD资源,以及和他相关联的控制器。

这个控制器通常运行于控制平面(https://kubernetes.io/docs/reference/glossary/?all=true#term-control-plane)之外。

这里我还整理了两个市面上主流的Operator资源社区,供你实践时参考使用:
operatorhub.io(https://operatorhub.io/)
awesome-operators(https://github.com/operator-framework/awesome-operators)

6、如何使用Operator

通过上面我提供的2个地址,你可以找到自己所需的Operator资源。
你可以通过一系列的帮助和文档,可能会经历一些坎坷,完成你的第一个Operator的部署工作。

一旦你部署完成,你就可以像使用原生kubernetes控制器的方法来操作他了,如:get、delete等方法。

不同的是,每个Operator都有各自特有的类型(kind),如下所示:

#mysql operator的常用操作
kuberctl get mysql
kuberctl edit mysql/mysql-1

7、实战:部署一个Jenkins Operator(v0.3.x)

操作之前,你需要make sure确保以下两点:

1、access to a Kubernetes cluster version 1.11+
2、kubectl version 1.11+

1、什么是Jenkins Operator?

jenkins operator是kubernetes平台上原生的,可以全面管理jenkins的控制器,以代码既配置的思想为基础,目前提供了以下几点功能:

1、与kubernetes集成
2、pipelines as code
3、通过groovy脚本配置进行扩展
4、安全和配置增强

2、功能现状

但operator也有不少问题待解决,一些是本身的缺陷,还有一些则是传统架构下jenkins遗留的不足之处:

1、安装具有不兼容版本或安全漏洞的插件
2、更好的配置作为代码思想
3、安全和开箱即用的特性
4、使错误对终端用户更明显
5、备份和还原作业历史记录
6、优雅关闭的处理
7、生命周期内端到端的测试

3、环境安装

1、首先,我们来部署专有的CRD资源

kubectl apply -f https://raw.githubusercontent.com/jenkinsci/kubernetes-operator/master/deploy/crds/jenkins_v1alpha2_jenkins_crd.yaml

你可以不难发现,Jenkins Operator有特有的kind名称:jenkins.jenkins.io,并且是名称空间级别的资源。

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: jenkins.jenkins.io
spec:
  group: jenkins.io
  names:
    kind: Jenkins
    listKind: JenkinsList
    plural: jenkins
    singular: jenkins
  scope: Namespaced
  versions:
    - name : v1alpha2
      served: true
      storage: true
    - name : v1alpha1
      served: true
      storage: false

2、接下来,我们要创建名为jenkins-operator的ServiceAccount、role名为jenkins-operator的RBAC策略、镜像为virtuslab/jenkins-operator:v0.3.1、并且运行在default名称空间中。

kubectl apply -f https://raw.githubusercontent.com/jenkinsci/kubernetes-operator/master/deploy/all-in-one-v1alpha2.yaml

如果碰到镜像拉取失败的情况,你可以在Jenkins_docker_hub(https://hub.docker.com/r/virtuslab/jenkins-operator)获取相关镜像。

3、此时,你可以通过命令kubectl get pods -w观察pod资源的生成情况了。

jenkins-operator-7768f7c484-rhnhz   0/1   Pending   0     0s
jenkins-operator-7768f7c484-rhnhz   0/1   Pending   0     0s
jenkins-operator-7768f7c484-rhnhz   0/1   ContainerCreating   0     0s
jenkins-operator-7768f7c484-rhnhz   1/1   Running   2     76s

4、部署Jenkins

1、Jenkins Operator我们已经部署并运行起来了,接下来我们要运行一个实际的本地jenkins实例。

apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
  name: example
spec:
  master:
    containers:
    - name: jenkins-master
      image: jenkins/jenkins:lts
      imagePullPolicy: Always
      livenessProbe:
        failureThreshold: 12
        httpGet:
          path: /login
          port: http
          scheme: HTTP
        initialDelaySeconds: 80
        periodSeconds: 10
        successThreshold: 1
        timeoutSeconds: 5
      readinessProbe:
        failureThreshold: 3
        httpGet:
          path: /login
          port: http
          scheme: HTTP
        initialDelaySeconds: 30
        periodSeconds: 10
        successThreshold: 1
        timeoutSeconds: 1
      resources:
        limits:
          cpu: 1500m
          memory: 3Gi
        requests:
          cpu: "1"
          memory: 500Mi
  seedJobs:
  - id: jenkins-operator
    targets: "cicd/jobs/*.jenkins"
    description: "Jenkins Operator repository"
    repositoryBranch: master
    repositoryUrl: https://github.com/jenkinsci/kubernetes-operator.git

这里有个坑:pod初始化的时候会去下载很多插件,探针的初始检查时间为80秒;你要视本身网络情况调整initialDelaySeconds字段的值;或者通过squid等代理的方式进行规避。

2、你可以通过以下命令申明,并观察相关资源的生成。

#声明我们的配置文件

kubectl apply -f jenkins_instance.yaml

#观察pod情况

kubectl get pods -w 

3、你可以通过以下命令获取登录所需的用户名和密码信息。

kubectl get secret jenkins-operator-credentials-example -o 'jsonpath={.data.user}' | base64 -d
kubectl get secret jenkins-operator-credentials-example -o 'jsonpath={.data.password}' | base64 -d

4、接下来我们连上jenkins就可以了,此时你就可以在本地的localhost:8080访问jenkins的登录页面了。

minikube:

minikube service jenkins-operator-http-<cr_name> --url

kubelet:

kubectl port-forward jenkins-<cr_name> 8080:8080

云原生之Kubernetes:16、详解Operator控制器

其他具体的配置功能,你可以参考configuration

w3cjava