Ansible管理K8S&开发K8S Ansible Operator
Posted 大魏分享
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ansible管理K8S&开发K8S Ansible Operator相关的知识,希望对你有一定的参考价值。
阅读提示|本文大概5000字 阅读需要30分钟
使用Ansible在K8S中部署资源
传统上,Ansible是面向运维的运行k8s Ansible模块。实际上,现在Ansible现在也可以和K8S对接。
wget -q https://raw.githubusercontent.com/openshift-labs/learn-katacoda/master/ansibleop/ansible-k8s-modules/assets/tasksmain1.yml -O /root/tutorial/example-role/tasks/main.yml
查看playbook的内容,这是在K8S集群创建一个项目(注意下面playbook的关键词是k8s)。
---
- name: set test namespace to {{ state }}
k8s:
api_version: v1
kind: Namespace
name: test
state: "{{ state }}"
ignore_errors: true
修改vars文件example-role/defaults/main.yml,设置state: present
我们有一个crc的环境,连接这个精简OCP通过本地连接。
查看inventory文件:
运行playbook:
ansible-playbook -i myhosts playbook.yml
playbook执行完毕后,确认项目已经被创建:
接下来,我们将使用Ansible k8s模块来控制和配置Kubernetes和OpenShift资源文件。我们展示通过Ansible在OpenShift中部署nginx
将nginx的nginx-deployment.yml复制到example-role/templates中,添加.j2扩展名(我们可以观察到deployment中设置的副本数为3)
cp nginx-deployment.yml ./example-role/templates/nginx-deployment.yml.j2
$ cat ./example-role/templates/nginx-deployment.yml.j2 kind: Deployment apiVersion: v1 metadata: name: nginx-deployment spec: template: metadata: labels: name: nginx spec: containers: - name: nginx image: nginx:1.15.4 ports: - containerPort: 80 replicas: 3 selector: name: nginx
更新任务文件example-role/tasks/main.yml以使用k8s模块、在test namespaces中创建nginx deployments。(文件标黄处):
---
- name: set test namespace to {{ state }}
k8s:
api_version: v1
kind: Namespace
name: test
state: "{{ state }}"
- name: set nginx deployment to {{ state }}
k8s:
state: "{{ state }}"
definition: "{{ lookup('template', 'nginx-deployment.yml.j2') }}"
namespace: test
执行playbook
ansible-playbook -i myhosts playbook.yml
执行完毕后,确认pod已经在tets项目总被创建:
使用Ansible自定义k8s资源文件
接下来,通过向deployment模板添加nginx_replicas变量并使用Ansible动态填充变量值,使我们能够为nginx deployments自定义副本数。
修改vars文件example-role/defaults/main.yml,设置nginx_replicas:2
---
state: present
nginx_replicas: 2
修改nginx部署定义nginx-deployment.yml.j2以从nginx_replicas变量读取副本:
kind: Deployment
apiVersion: v1
metadata:
name: nginx-deployment
spec:
template:
metadata:
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.15.4
ports:
- containerPort: 80
replicas: {{ nginx_replicas }}
selector:
name: nginx
再次运行Playbook将读取变量nginx_replicas,并使用提供的值来自定义nginx部署。
ansible-playbook -i myhosts playbook.yml
我们确认pod的数量,已经由之前的三个减少到两个。
接下来,我们删除nginx的deployments:
ansible-playbook -i myhosts playbook.yml --extra-vars state=absent
Ansible Operator
Ansible Operator的思路是:将Kubernetes事件映射到Ansible Playbook或Roles。
创建Ansible Operator的步骤如下:
使用Operator SDK命令行界面(CLI)创建新的Operator项目
使用Ansible Playbooks和Roles为您的对象编写协调逻辑(reconciling logic)
使用SDK CLI生成和生成Operator部署清单(deployment manifests)
(可选)使用SDK CLI添加其他CRD,并重复步骤2和3
Watches文件role
在上文中,我们已经演示了Ansible k8s模块,我们想在自定义资源更改时触发Ansible逻辑。Ansible Operator使用YAML编写的Watches文件,其中包含自定义资源和Ansible Roles/Playbook之间的映射。watches用于监视资源的变化。
Watches文件将自定义资源映射到Ansibleroles和Playbook。Operators的watches文件默认的位置:/opt/ansible/watches.yaml
Watches文件中的每个映射都有必填字段:
group:要监控的自定义资源的组。
version::要监控的自定义资源的版本。
kind:要监控的自定义资源的种类。
role(默认):Operator应为特定的Group-Version-Kind(GVK)运行的role的路径。此字段与playbook字段互斥,使用其一即可。
playbook(可选):运营商应针对特定的Group-Version-Kind(GVK)运行的Playbook的路径。剧本可用于调用多个角色。该字段与“角色”字段互斥。
watches.yaml的范例:
--- - version: v1alpha1 group: foo.example.com kind: Foo # associates GVK with Role role: /opt/ansible/roles/Foo
默认情况下,执行operator-sdk new --type ansible创建“ watches.yaml”,配置为响应自定义资源事件执行的role。
这对于较小的项目我们使用单一role即可,但是对于更复杂的Ansible,我们可能不希望所有逻辑都在一个角色中。此外,如果情况比较复杂,我们希望变化触发playbook而不是roles。
在Operator中使用Playbook,修改watchs.yaml:
--- - version: v1alpha1 group: foo.example.com kind: Foo # associating a Custom Resource GVK with a Playbook playbook: /opt/ansible/playbook.yaml
为此,我们需要将playbook.yaml复制到容器镜像中。
通过将Operator Dockerfile修改为COPY'playbook.yaml'到容器中来完成此操作,如下所示:
# Dockerfile at <project-name>/build/Dockerfile FROM quay.io/operator-framework/ansible-operator COPY roles/ ${HOME}/roles COPY watches.yaml ${HOME}/watches.yaml # New 'COPY' build step for playbook.yaml COPY playbook.yaml ${HOME}/playbook.yaml
如果从一开始就知决定Operator使用Playbook而不是Role,则可以使用--generate-playbook标志生成项目教授叫:
operator-sdk new --type ansible --kind Foo --api-version foo.example.com/v1alpha1 foo-operator --generate-playbook --skip-git-init
Custom Resource File
使用Ansible Operator时,自定义资源(CR)状态的更改会向Operator发出信号,表明应执行某些Playbook/Roles。那么自定义资源是什么样的?
编写Ansible Opertor必须要创建CR,自定义资源的结构采用Kubernetes资源的格式。对象定义具有必填字段如下:
apiVersion: Version of the Custom Resource that will be created
kind: Kind of the Custom Resource that will be created
metadata: Kubernetes metadata that will be created
spec: Key-value list of variables which are passed to Ansible. Optional and will be empty by default.
annotations: Kubernetes annotations to be appended to the CR. See the below section for Ansible Operator specific annotations.
Custom Resource annotations可以应用于修改Ansible Operator行为:
ansible.operator-sdk / reconcile-period:用于指定CR的对reconciliation interval 。
使用标准 Golang 'Package time'. 解析此值。具体来说,使用ParseDuration,它将使用默认的's'后缀以秒为单位给出值(例如,“ 30”将变为“ 30s”,如下所示)。
如果Ansible Operator正在监控kind: "Foo"的实践,则Ansible Playbook/Role可能会触发,以响应以下所示资源的创建。
apiVersion: "foo.example.com/v1alpha1"
kind: "Foo"
metadata:
name: "example"
annotations:
ansible.operator-sdk/reconcile-period: "30s"
要将“Extra Vars”传递给Operator正在运行的Playbooks/roles,您可以将键值对嵌入自定义资源(CR)的 'spec'部分。这等效于--extra-vars如何传递到ansible-playbook命令中。
下面的CR代码段显示了通过规范传入的两个'extra vars' (message和newParamater)。 通过CR传递'extra vars'可以根据每个CR实例的内容自定义Ansible逻辑。
# Sample CR definition where some # 'extra vars' are passed via the spec apiVersion: "app.example.com/v1alpha1" kind: "Database" metadata: name: "example"spec: message: "Hello world 2" newParameter: "newParam"
现在,您已通过CR规范将“Extra Vars”传递给了Playbook,我们需要从构成Operator的Ansible逻辑中读取它们。
通过CR规范传递的变量在顶层可用,可以从Jinja模板中读取。 对于上面的CR示例,我们可以像这样从Playbook中读取vars“ message”和“ newParameter”:
- debug: msg: "message value from CR spec: {{ message }}" - debug: msg: "newParameter value from CR spec: {{ new_parameter }}"
我们在CR规范中设置的“ newParameter”变量被作为“ new_parameter”访问。 请牢记从camelCase到snake_case的自动转换,因为传递给CR规范的所有“额外变量”都会发生这种情况。
JSON结构
运行reconciliation job,关联的CR的内容在Ansible运行时环境中可用作变量。下面的JSON是传递给ansible-runner(Ansible Operator运行时)的示例。
请注意,添加到CR的“ spec”部分中的var(“ message”和“ new_parameter”)位于此结构的顶层,以便于访问。
{ "meta": { "name": "<cr-name>", "namespace": "<cr-namespace>", }, "message": "Hello world 2", "new_parameter": "newParam", "_app_example_com_database": { <Full CR> }, }
访问CRmetadata
meta字段提供与reconciliation job关联的CR'name' 和'namespace'。 这些和其他嵌套字段可以在Ansible中使用点符号进行访问。
- debug: msg: "name: {{ meta.name }}, namespace: {{ meta.namespace }}"
在下一步中,我们将使用operator-sdk生成我们的Operator项目支架。
创建Ansible Operator项目。
接下来,我们将学习如何使用operator-sdk CLI通过“ new”命令创建Ansible Operator项目。
operator-sdk new <project-name> --type ansible
此命令告诉operator-sdk用您选择的名称初始化一个新的Ansible Operator项目脚手架。
但是,在运行命令之前,我们需要通过标志添加更多必需的参数。
--api-version
Kubernetes apiVersion, has a format of $GROUP_NAME/$VERSION (e.g myapp.example.com/v1alpha1)
--kind
Kubernetes Custom Resource kind (e.g MyOperatedApp
这些标志由operator-sdk使用以生成:
Custom Resource files customized according to flag arguments
An Ansible Role whose name matches the input for '--kind'.
放在一起,我们最终得到一个如下所示的命令:
$ operator-sdk new my-project --type=ansible --api-version=myapi.example.com/v1alpha1 --kind=MyOperatedApp [...] # See if you can spot similarities between command args and generated scaffolding. $ tree my-project/ my-project/ ├── build │ └── Dockerfile ├── deploy │ ├── crds │ │ ├── myapi_v1alpha1_myoperatedapp_crd.yaml │ │ └── myapi_v1alpha1_myoperatedapp_cr.yaml │ ├── operator.yaml │ ├── role_binding.yaml │ ├── role.yaml │ └── service_account.yaml ├── roles │ └── MyOperatedApp │ ├── defaults │ │ └── main.yml │ ├── files │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── README.md │ ├── tasks │ │ └── main.yml │ ├── templates │ ├── tests │ │ ├── inventory │ │ └── test.yml │ └── vars │ └── main.yml └── watches.yaml
创建Memcached Ansible运算符。
operator-sdk new memcached-operator --type=ansible --api-version=cache.example.com/v1alpha1 --kind=Memcached
这将创建一个新的memcached-operator项目,该项目专门用于使用APIVersion'cache.example.com/v1alpha1'和Kind'Memcached'监视Memcached资源。
$ tree memcached-operator
memcached-operator
├── build
│ ├── Dockerfile
│ └── test-framework
│ ├── ansible-test.sh
│ └── Dockerfile
├── deploy
│ ├── crds
│ │ ├── cache.example.com_memcacheds_crd.yaml
│ │ └── cache.example.com_v1alpha1_memcached_cr.yaml
│ ├── operator.yaml
│ ├── role_binding.yaml
│ ├── role.yaml
│ └── service_account.yaml
├── molecule
│ ├── default
│ │ ├── asserts.yml
│ │ ├── molecule.yml
│ │ ├── playbook.yml
│ │ └── prepare.yml
│ ├── test-cluster
│ │ ├── molecule.yml
│ │ └── playbook.yml
│ └── test-local
│ ├── molecule.yml
│ ├── playbook.yml
│ └── prepare.yml
├── roles
│ └── memcached
│ ├── defaults
│ │ └── main.yml
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── README.md
│ ├── tasks
│ │ └── main.yml
│ ├── templates
│ └── vars
│ └── main.yml
└── watches.yaml
在使用operator-sdk new --type ansible创建新的Operator项目之后,项目目录包含许多生成的文件夹和文件。 下表描述了每个生成的文件/目录的基本摘要。
自定义Operator logic
到目前为止,我们已经创建了memcached-operator项目,该项目专门用于使用APIVersion'cache.example.com/v1apha1'和Kind'Memcached'监视Memcached资源。 现在是时候定义Operator逻辑了。
对于此示例,memcached Operator将为每个“ Memcached”自定义资源(CR)执行以下协调逻辑:
创建memcached Deployments(如果不存在)
确保部署大小与“ Memcached” CR指定的大小相同
为了加快Operator的开发速度,我们可以重用roles。 从Ansible Galaxy安装角色到Operator中:
dymurray.memcached_operator_role (galaxy.ansible.com)
执行如下命令安装role:
$ cd memcached-operator
$ ansible-galaxy install dymurray.memcached_operator_role -p ./roles
由于我们将重用'dymurray.memcached_operator_role'中的逻辑,因此我们可以地删除由先前运行的'operator-sdk new'命令自动生成的占位符Role。
rm -rf ./roles/memcached
查看dymurray.memcached_operator_role的目录结构:
该角色为用户提供了一个用于控制要创建的Deployment副本的数量的数值。 您可以在memcached角色defaults/main.yml文件中找到此变量的默认值:
检查memcached Role tasks/main.yml文件,该文件使用k8s(Kubernetes)Ansible模块创建memcachedDeployments。
$ cat roles/dymurray.memcached_operator_role/tasks/main.yml
---
# tasks file for Memcached
- name: start memcached
k8s:
definition:
kind: Deployment
apiVersion: apps/v1
metadata:
name: '{{ meta.name }}-memcached'
namespace: '{{ meta.namespace }}'
spec:
replicas: "{{size}}"
selector:
matchLabels:
app: memcached
template:
metadata:
labels:
app: memcached
spec:
containers:
- name: memcached
command:
- memcached
- -m=64
- -o
- modern
- -v
image: "memcached:1.4.36-alpine"
ports:
- containerPort: 11211
接下来,修改必要的文件以确Operator使用此角色而不是使用默认生成的脚手架roles。
默认情况下,memcached-operator监视watchs.yaml中显示的Memcached资源事件,并执行Ansible Role Memcached。
由于我们已经将原始role换成从Ansible Galaxy中安装的角色,因此更改Watches文件:
修改前后对比:
创建Custom Resource Definition
在运行Operator之前,Kubernetes需要了解Operator将要观察的新的自定义资源定义。
部署Memcached自定义资源定义(CRD):
$ cat deploy/crds/cache.example.com_memcacheds_crd.yaml
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: memcacheds.cache.example.com
spec:
group: cache.example.com
names:
kind: Memcached
listKind: MemcachedList
plural: memcacheds
singular: memcached
scope: Namespaced
subresources:
status: {}
validation:
openAPIV3Schema:
type: object
x-kubernetes-preserve-unknown-fields: true
versions:
- name: v1alpha1
served: true
storage: true
应用配置:
oc create -f deploy/crds/cache.example.com_memcacheds_crd.yaml
通过运行此命令,我们在集群上创建了一种新的资源类型memcached。通过创建和修改此类资源将会驱动Operator工作。
创建CRD后,有两种方法可以运行Operator:
作为Kubernetes集群中的Pod
使用Operator-SDK在群集外部作为Go程序。 这对于您的运营商的本地发展非常有用。
如果要在在本地运行我们Operator,我们将手动将Operator使用的所有角色复制到本地计算机的已配置Ansible角色路径(例如/ etc / ansible / roles)。
mkdir -p /opt/ansible/roles cp -r ~/tutorial/memcached-operator/roles/dymurray.memcached_operator_role /opt/ansible/roles/
自动设置KUBECONFIG=$HOME/.kube/config:
$ operator-sdk run --local
或者直接指定路径运行:
$ operator-sdk run --local --kubeconfig=/tmp/config
接下来,我们详细介绍通过pod的方式来运行Operator:
创建项目:
oc new-project tutorial
operator-sdk run --local --namespace tutorial
接下来,使用打开第二个终端窗口,进入对应的目录。
目前Operator正在运行中,让我们创建一个CR并部署一个memcached实例。
# deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml apiVersion: cache.example.com/v1alpha1 kind: Memcached metadata: name: example-memcached spec: size: 3
oc --namespace tutorial create -f deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml
确保memcached-operator为CR创建部署3个pods:
将deploy / crds / cache.example.com_v1alpha1_memcached_cr.yaml中的spec.size字段从3更改为4。
然后重新应用cr:
oc --namespace tutorial apply -f deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml
至此,基于Ansible的Operator开发完毕。
以上是关于Ansible管理K8S&开发K8S Ansible Operator的主要内容,如果未能解决你的问题,请参考以下文章