Operator Framework是由CoreOS开发,后被RedHat收买的一个开源工具包,它能够无效的、自动化的和可扩大的形式治理 Kubernetes原生应用程序。该框架下蕴含Operator SDK,可帮助开发人员利用本人的专业知识来疏导和构建Operator,而无需理解 Kubernetes API复杂性。明天咱们就学习它,用于创立一个基于Ansible的Operator利用(之前小白在《Loki Operator扼要教程》中也简略聊到过),它能够利用现有 Ansible playbook和模块来部署和治理Kubernetes资源作为对立应用程序的生命周期,而无需编写任何Go代码。
装置
- Homebrew装置 (MacOS)
如果你应用的是Homebrew,你能够用以下命令装置SDK CLI工具。
$ brew install operator-sdk
- 二进制装置
$ export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac)$ export OS=$(uname | awk '{print tolower($0)}')$ export OPERATOR_SDK_DL_URL=https://github.com/operator-framework/operator-sdk/releases/download/v1.10.0#下载operator-sdk$ curl -LO ${OPERATOR_SDK_DL_URL}/operator-sdk_${OS}_${ARCH}$ chmod +x operator-sdk_${OS}_${ARCH} && sudo mv operator-sdk_${OS}_${ARCH} /usr/local/bin/operator-sdk
- 编译装置
$ git clone https://github.com/operator-framework/operator-sdk$ cd operator-sdk$ git checkout master$ make install
初始化
1. 初始化我的项目
应用operator-sdk命令来疾速初始化这个我的项目的空间。
$ mkdir loki-operator$ cd loki-operator$ operator-sdk init --plugins=ansible --domain cloudxiaobai.com
这条命令生成的文件中有一个Kubebuilder的PROJECT形容文件。从外面咱们能够得悉,该工程是一个基于Ansible实现的我的项目
$ cat PROJECTdomain: loki.cloudxiaobai.comlayout:- ansible.sdk.operatorframework.io/v1plugins: manifests.sdk.operatorframework.io/v2: {} scorecard.sdk.operatorframework.io/v2: {}projectName: cloudxiaobaiversion: "3"
2. 创立API
$ operator-sdk create api \ --group=plugins --version=v1 --kind=Loki \ --generate-playbook \ --generate-role
下面这条命令能够疾速帮忙咱们生成这个我的项目的脚手架。其中蕴含如下内容:
- 生成了Loki这个CRD的定义,和一个Loki CR的样例;
- 生成了Controller,用于治理CR的的服务在Kubernetes集群上的状态
- 生成了Ansible Playbook的目录构造
- 生成了一个 watches.yaml文件,它用来将CR资源与Ansible Playbook关联起来。
Ansible Playbook
在实现我的项目的初始化后,咱们在我的项目下就失去了以下次要的目录。
├── Dockerfile├── config│ ├── samples│ │ └── plugins_v1_loki.yaml //Loki的CR样例├── playbooks //playbook的入口│ └── loki.yml├── roles //playbook文件│ └── loki│ ├── README.md│ ├── defaults│ │ └── main.yml│ ├── files│ ├── handlers│ │ └── main.yml│ ├── meta│ │ └── main.yml│ ├── tasks│ │ └── main.yml│ ├── templates│ └── vars│ └── main.yml
相熟Ansible的敌人看到这个就比拟眼生了,接下来咱们就开始写入一个Loki服务简略playbook文件来演示它的根本逻辑。
1. 批改 roles/loki/tasks/main.yaml
- name: Loki Operator | Loki | StatefulSet community.kubernetes.k8s: definition: "{{ lookup('template', 'statefulset.yaml') | from_yaml }}"
能够看到ansible是通过community.kubernetes的k8s模块来跟kubernetes交互的。下面这条task的意思是让ansible去templates目录上来寻找statefulset.yaml文件,而后将它渲染成yaml文件后提交给kubernetes。
2. 创立 roles/loki/template/statefulset.yaml
statefulset.yaml是真正须要部署的ansible模版文件,咱们须要创立的内容如下:
#jinja2:lstrip_blocks: TrueapiVersion: apps/v1kind: StatefulSetmetadata: name: '{{ansible_operator_meta.name}}' namespace: '{{ansible_operator_meta.namespace}}' labels: app.kubernetes.io/name: '{{ ansible_operator_meta.name }}-loki-system'spec: replicas: {{ replicas }} serviceName: '{{ansible_operator_meta.name}}-headless' selector: matchLabels: app.kubernetes.io/name: '{{ ansible_operator_meta.name }}-loki-system' template: metadata: labels: app.kubernetes.io/name: '{{ ansible_operator_meta.name }}-loki-system' spec: containers: - name: loki-system image: grafana/loki:2.2.1 imagePullPolicy: IfNotPresent ports: - containerPort: 3100 name: http-3100 protocol: TCP
下面的Ansible利用模版中有几点信息值得强调:
#jinja2:lstrip_blocks: True
保留yaml文件中的空格、缩进等语句{{ansible_operator_meta.name}}
定义了CR外面管制的Loki资源名称{{ansible_operator_meta.namespace}}
定义了CR作用的命名空间{{ replicas }}
自定义的CR变量
能够看到咱们申明了一个名replicas的自定义变量,咱们须要通过它来管制服务的正本数。Ansible中的变量取值由用户创立的CR来管制。
Ansible的roles文件中task实际上定义了CR的状态,在Kubernetes在创立资源时,因为容许输出任意字段,所以咱们不须要在CRD中理论定义CR字段类型的申明。尽管在Operator SDK中它不能被主动生成,不过还是倡议在理论应用时最好增加上CRD的字段阐明,以便Kubernetes用户在应用CR时能够看到它对应的形容信息。
3. 创立CR
默认状况下Operator SDK会创立一个默认的CR样例文件,它位于config/samples/目录下。在本文中,咱们的CR文件名称为plugins_v1_loki.yaml
apiVersion: plugins.cloudxiaobai.com/v1kind: Lokimetadata: name: lokispec: replicas: 1
构建与部署
当实现利用的playbook编写后,咱们就能够应用make命令进行镜像的构建和上传。咱们能够提前编辑Makefile来自定义镜像的名称,
IMAGE_TAG_BASE ?= cloudxiaobai.com/cloudxiaobaiIMG ?= $(IMAGE_TAG_BASE):$(VERSION)
这样,当咱们每次build镜像时,产生固定的镜像名称。
1. 构建Operator镜像
$ make docker-build docker-push VERSION="0.1"
构建和上传operator镜像。
2. 部署Operator服务
$ make deploy# kustomize build config/default | kubectl apply -f -
能够看到在部署时调用了kustomize将config/default目录下的文件进行构建后提交到kubernetes。这外面须要留神的是,默认状况下,kustomize会创立一个名为<project-name>-system
的新命名空间用于部署Operator。
当部署实现后,咱们就能够用kubectl进行验证服务状态。
$ kubectl get deployment -n cloudxiaobai--systemNAME READY UP-TO-DATE AVAILABLE AGEloki-controller-manager 1/1 1 1 8m
3. 提交CR
将上文的CR申明文件提交到kubernetes
$ cat config/samples/plugins_v1_loki.yamlapiVersion: plugins.cloudxiaobai.com/v1kind: Lokimetadata: name: lokispec: replicas: 1$ kubectl apply -f config/samples/plugins_v1_loki.yaml
之后咱们就能够通过以下命令进行验证服务是否达到预期
$ kubectl get deploymentNAME READY UP-TO-DATE AVAILABLE AGEcloudxiaobai-31e1d3526-a1klm 1/1 1 1 1m
如果咱们要调整Loki的正本数,咱们只需有批改CR中的replicas变量即可,也能够通过patch的形式批改。
$ kubectl patch loki cloudxiaobai -p '{"spec":{"size": 2 }}' --type=merge
4. 删除资源
间接执行下列命令就能别离删除CR和Operator关联的所有资源
$ kubectl delete -f config/samples/plugins_v1_loki.yaml$ make undeploy
小技巧
1. Ansible变量转化
自定义CR中的spec字段中所有变量的名称均被操作符转换为snake_case(下横线)命名格局。例如,咱们在spec中写入了一个变量serviceAccount,那么在ansible中会被转成service_account。小白倡议能够在watches.yaml中将snakeCaseParameters设置为false来禁用这种大小写转换。
2. 应用默认值
为了能将ansible template适配大部分场景,小白倡议在模版中应用默认值,防止在CR中没有定义变量而造成的playbook执行报错。例如,咱们在CR中定义了Loki的镜像信息如下。
spec: image: repository: grafana/loki tag: 2.1.1
那咱们在template就能够如下编写:
containers: - name: loki-system image: '{{service.cluster.loki.image | default('grafana/loki')}}:{{version | default('latest')}}'
这里,如果咱们没在CR中定义image的变量,当playbook执行到这里时,就会采纳grafana/loki:latest
镜像。
3. 巧用items
因为community.kubernetes.k8s
模块不容许提交一个allinone的yaml文件,所以当在理论编写playbook时,如果想在一个task时外面实现所有yaml提交时,咱们能够应用如下语句:
- name: Loki Operator | Loki | Deploy community.kubernetes.k8s: definition: "{{ lookup('template', item) | from_yaml }}" with_items: - statefulset.yaml - service.yaml
4. 管制模块启用或敞开
如果咱们的CR中心愿可能管制某些服务的启用或敞开时,通常状况下会间接应用enabled: true
来做明确的定义,例如上面这个CR
spec: redis: enabled: true
那么,咱们在写playbook时,能够通过在state中判断CR中的该变量来决定是否执行,如下:
- name: Loki Operator | Reids Cache | PVC community.kubernetes.k8s: state: '{{"present" if redis is defined and redis.enabled else "absent"}}' definition: "{{ lookup('template', 'redis/pvc.yaml') | from_yaml }}
5. Owner References
Owner References是Kubernetes中的垃圾删除机制,它可能在删除CR后进行后续清理。默认状况下,ownerReferences由代理在ansible执行时注入。在当CR和被治理的资源在同一个命名空间下时,ownerReferences会在资源中如下显示:
metadata: ownerReferences: - apiVersion: loki.cloudxiaobai.com/v1 kind: loki name: loki uid:fda3b711-1f25-4d14-bf84-cf70f48e7ff4
CR和被治理的资源不在一个命名空间下时,ownerReferences便是通过如下的annotation字段来定义的:
operator-sdk/primary-resource: {metadata.namespace}/{metadata.name}operator-sdk/primary-resource-type: {kind}.{group}
当然,如果你要禁用ownerReferences的话,如下批改dockerfile即可:
ENTRYPOINT ["/usr/local/bin/entrypoint", "--inject-owner-ref=false"]
6. 工作并发
默认状况下,ansible调用的runtime.NumCPU()
来设置最大并发协调值,能够看到它取决于你主机的CPU外围数。减少并发协调的数量和容许并发处理事件,能够进步ansible执行工作时的协调性能。咱们能够在operator的启动参数来手动设置
- name: manager args: - "--max-concurrent-reconciles" - "3"
总结
本文通过一个小例子介绍了如何通过Operator SDK疾速构建、治理Loki利用。并通过6个小技巧让读者在应用过程中尽量避坑。目前小白在理论工作中,将Ansible Operator次要利用在kubernetes平台初始化时各种插件、三方服务的装置治理,如prometheus、loki、grafna等等,心愿它也能在其它方面帮忙到大家。
更多内容,请关注「云原生小白」