共计 6789 个字符,预计需要花费 17 分钟才能阅读完成。
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 PROJECT
domain: loki.cloudxiaobai.com
layout:
- ansible.sdk.operatorframework.io/v1
plugins:
manifests.sdk.operatorframework.io/v2: {}
scorecard.sdk.operatorframework.io/v2: {}
projectName: cloudxiaobai
version: "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: True
apiVersion: apps/v1
kind: StatefulSet
metadata:
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/v1
kind: Loki
metadata:
name: loki
spec:
replicas: 1
构建与部署
当实现利用的 playbook 编写后,咱们就能够应用 make 命令进行镜像的构建和上传。咱们能够提前编辑 Makefile 来自定义镜像的名称,
IMAGE_TAG_BASE ?= cloudxiaobai.com/cloudxiaobai
IMG ?= $(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--system
NAME READY UP-TO-DATE AVAILABLE AGE
loki-controller-manager 1/1 1 1 8m
3. 提交 CR
将上文的 CR 申明文件提交到 kubernetes
$ cat config/samples/plugins_v1_loki.yaml
apiVersion: plugins.cloudxiaobai.com/v1
kind: Loki
metadata:
name: loki
spec:
replicas: 1
$ kubectl apply -f config/samples/plugins_v1_loki.yaml
之后咱们就能够通过以下命令进行验证服务是否达到预期
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
cloudxiaobai-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 等等,心愿它也能在其它方面帮忙到大家。
更多内容,请关注「云原生小白」