Build your own Kubernetes Operator with Ansible

Stefvnf
3 min readNov 8, 2023

Ansible is a tool for provisioning, configuration, and management of application infrastructure on compute resources. Operator SDK allows someone familiar with Ansible to quickly scaffold an operator based on Ansible playbooks and roles.

Prereqs:

# Step 1: Create a project

$ mkdir ansible-operator && cd ansible-operator
$ operator-sdk init --plugins=ansible --domain example.com

— — domainis used for any API groups the operator creates. So yours will be all *.example.com. An API Group is simply a group of related functionality, such as your operator. An API Group you might already be familiar with is rbac.authorization.k8s.io, which is where the functionality for creating RBAC resources such as ClusterRoles and ClusterRoleBindings is usually set up on a Kubernetes cluster. operator-sdk allows you to specify a custom domain you can append to any API groups that you define to help avoid name collisions.

Generated files:

$ ls -lart                                                                                                                                 ─╯
total 64
drwxr-xr-x@ 21 user x 672 Nov 8 16:27 ..
-rw-r--r-- 1 user x 205 Nov 8 16:28 requirements.yml
-rw-r--r-- 1 user x 126 Nov 8 16:28 .gitignore
drwxr-xr-x 4 user x 128 Nov 8 16:28 molecule
-rw-r--r-- 1 user x 312 Nov 8 16:28 Dockerfile
drwxr-xr-x 3 user x 96 Nov 8 16:28 playbooks
-rw-r--r-- 1 user x 10350 Nov 8 16:28 Makefile
drwx------ 11 user x 352 Nov 8 16:28 config
drwxr-xr-x 4 user x 128 Nov 8 16:28 roles
-rw-r--r-- 1 user x 179 Nov 8 16:28 watches.yaml
-rw------- 1 user x 556 Nov 8 16:28 PROJECT
drwxr-xr-x 13 user x 416 Nov 8 16:35 .
drwxr-xr-x 3 user x 96 Nov 8 16:35 bin
  • watches.yml — file that defines the mapping between your API and your Ansible playbooks and roles
  • Dockerfile — for the controller image
  • a PROJECTfile with the domain and project layout configuration
  • a Makefileto build, deploy and undeploy the project
  • requirements.yaml — holds the Ansible dependencies
  • Playbooks and rolesdirectories for respective Ansible files
  • a moleculedirectory that containts scaffolding for use with Molecule, an Ansible test framework
  • a configdirectory which hols -> base manifest; kustomization yaml; rbac yaml for authorizing various components to interact with each other; a `Patch` file for enabling Prometheus metrics

# Step 2 : Create an API

$ operator-sdk create api --group cache --version v1alpha1 --kind Memcached --generate-role

This command creates a new API by creating a new CRD (Custom Resource Definition) in the ‘cache’ API group.

--generate-role causes the Operator SDK to also generate an Ansible role that serves as the backing for your custom resource type.

This will generate you the following:

  • a Memcached custom resource definition
  • an Ansible role to back that CRD
  • scaffolding to configure the ansible-operator server image to connect them
  • RBAC to allow the ansible-operator server to edit the needed Kubernetes resources
  • sample YAML in config/samples/ to create an example Memcached custom resource object
  • changes in watches.yaml based on the new Memcached custom resource
  • changes in PROJECT to show the new API

# Step 3: Configure the Ansible role

Update roles/memcached/tasks/main.yml to contain the following:

---
- name: start memcached
community.kubernetes.k8s:
definition:
kind: Deployment
apiVersion: apps/v1
metadata:
name: '{{ ansible_operator_meta.name }}-memcached'
namespace: '{{ ansible_operator_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: "docker.io/memcached:1.4.36-alpine"
ports:
- containerPort: 11211

This role contains a single task named ‘start memcached’. It uses the interface defined by the Ansible Kubernetes collection to create a deployment configured
with the information available from an instance of our Memcached custom resource. It is configured to set the replicas of the deployment to the size variable from our custom resource’s spec.

# Step 4: Build and deploy the operator

$ make docker-build docker-push IMG=docker.io/$USERNAME/ansible-operator:1.0.0
$ make deploy IMG=docker.io/$USERNAME/ansible-operator:1.0.0

After a bit, you should see the pods containing the controller come up:

$ kubectl get pods --n ansible-operator-system
NAMESPACE NAME READY STATUS RESTARTS AGE
ansible-operator-system ansible-operator-controller-manager-7b8555fb4b-wv8mh 0/2 ContainerCreating 0 14s

Check to see that the CRD has been created:

$ kubectl get crds
NAME CREATED AT
memcacheds.cache.example.com 2021-03-13T00:20:18Z

That’s it. We are done.

Feel free to play around with it to get a feel for the behavior of the Custom Resource.

# Step 5: Cleanup

When you are done, you can cleanup the deployed operator by running the following commands:

$ kubectl delete memcached memcached-sample
$ make undeploy

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

No responses yet

Write a response