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文件:


Ansible管理K8S&开发K8S Ansible Operator

运行playbook:

ansible-playbook -i myhosts playbook.yml

Ansible管理K8S&开发K8S Ansible Operator

playbook执行完毕后,确认项目已经被创建:

Ansible管理K8S&开发K8S Ansible Operator

接下来,我们将使用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

Ansible管理K8S&开发K8S Ansible Operator

执行完毕后,确认pod已经在tets项目总被创建:

Ansible管理K8S&开发K8S Ansible Operator





使用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

Ansible管理K8S&开发K8S Ansible Operator

我们确认pod的数量,已经由之前的三个减少到两个。

Ansible管理K8S&开发K8S Ansible Operator

接下来,我们删除nginx的deployments:

ansible-playbook -i myhosts playbook.yml --extra-vars state=absent

Ansible管理K8S&开发K8S Ansible Operator

Ansible管理K8S&开发K8S Ansible Operator




Ansible Operator

Ansible Operator的思路是:将Kubernetes事件映射到Ansible Playbook或Roles。

Ansible管理K8S&开发K8S Ansible Operator

创建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项目之后,项目目录包含许多生成的文件夹和文件。 下表描述了每个生成的文件/目录的基本摘要。

Ansible管理K8S&开发K8S 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

Ansible管理K8S&开发K8S Ansible Operator

Ansible管理K8S&开发K8S Ansible Operator

由于我们将重用'dymurray.memcached_operator_role'中的逻辑,因此我们可以地删除由先前运行的'operator-sdk new'命令自动生成的占位符Role。

rm -rf ./roles/memcached


查看dymurray.memcached_operator_role的目录结构:

Ansible管理K8S&开发K8S Ansible Operator

该角色为用户提供了一个用于控制要创建的Deployment副本的数量的数值。 您可以在memcached角色defaults/main.yml文件中找到此变量的默认值:

Ansible管理K8S&开发K8S Ansible Operator

检查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文件:


修改前后对比:

Ansible管理K8S&开发K8S Ansible Operator


创建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

Ansible管理K8S&开发K8S Ansible Operator

Ansible管理K8S&开发K8S Ansible Operator

接下来,使用打开第二个终端窗口,进入对应的目录。

目前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的主要内容,如果未能解决你的问题,请参考以下文章

CI/CD持续集成与持续交付(下)-------- jenkins的节点管理,用户管理,结合ansible和k8s

Ansible搭建K8S说明

Ansible自动化部署K8S集群

Ansible自动化部署k8s-1.16.0版集群

使用ansible一键安装 k8s

ansible搭建k8s