title | linkTitle | weight |
---|---|---|
Ansible Operator Tutorial |
Tutorial |
3 |
This tutorial walks operator authors through the entire process of:
- building a simple Ansible-based operator using the
operator sdk
scaffolding - deploying and using the operator on a cluster.
If you would prefer to try out an existing operator you can skip to the Using the Operator section using a container we've built from the [operator-sdk-samples][TODO/ansible-memcached] repository.
TODO(asmacdo) remove Note to reviewer
I can remove this part for now, but if we put this in place,
prospective operator authors can understand and play with a working
operator without needing to write one.
- [docker][docker_tool] version 17.03+.
- [kubectl][kubectl_tool] version v1.11.3+.
- [Ansible Operator SDK Installation][ansible-operator-install] v1.0.0+
- Access to a Kubernetes v1.11.3+ cluster.
In this tutorial we will:
- extend the Kubernetes API with a [Custom Resource Definition][TODO] that allows users to create
Memcached
resources. - create a manager that updates the state of the cluster to the desired state defined by
Memcached
resources.
Begin by generating a new project from a new directory.
# TODO(asmacdo) I Dont think this needs to be in the gopath, even for `make run`?
$ mkdir memcached-operator && cd memcached-operator
$ operator-sdk init --plugins=ansible
Among the files generated by this command is a Kubebuilder PROJECT
file. Subsequent operator-sdk
commands (and help text) run from the
project root read this file and are aware that the project type is
Ansible.
# Since this is an Ansible-based project, this help text is Ansible specific.
$ operator-sdk create api -h
Next, we will create a Memcached
API.
$ operator-sdk create api --generate-playbook --group cache --version v1alpha1 --kind Memcached --generate-role
The scaffolded operator has the following structure:
Memcached
Custom Resource Definition, and a sampleMemcached
resource.- A "Manager" that [reconciles][TODO] the state of the cluster to the desired state
- A reconciler, which is an Ansible Role or Playbook.
- A
watches.yaml
file, which connects theMemcached
resource to thememcached
Ansible Role.
See [scaffolded files reference][TODO] and [watches reference][watches reference TODO] for more detailed information
Now we need to provide the reconcile logic, in the form of an Ansible
Role, which will run every time a Memcached
resource is created,
updated, or delete.
Update roles/memecached/tasks/main.yml
:
---
- name: start memcached
community.kubernetes.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: "docker.io/memcached:1.4.36-alpine"
ports:
- containerPort: 11211
This memcached role will:
- Ensure a memcached Deployment exists
- Set the Deployment size
It is good practice to set default values for variables used in Ansible
Roles, so edit memcached-operator/roles/memecached/defaults/main.yml
:
---
# defaults file for Memcached
size: 1
Finally, update the Memcached
sample, memcached-operator/config/samples/cache_v1alpha1_memcached.yaml
:
apiVersion: cache.example.com/v1alpha1
kind: Memcached
metadata:
name: memcached-sample
spec:
size: 3
The key-value pairs in the Custom Resource spec are passed to Ansible as extra variables.
Note: The names of all variables in the spec field are converted to
snake_case by the operator before running ansible. For example,
serviceAccount in the spec becomes service_account in ansible. You can
disable this case conversion by setting the snakeCaseParameters
option
to false
in your watches.yaml
. It is recommended that you perform some
type validation in Ansible on the variables to ensure that your
application is receiving expected input.
All that remains is building and pushing the operator container to your favorite registry.
$ IMG=quay.io/someuser/image:v1.0.0 make docker-build && make docker-push
Note To allow the cluster to pull the image, the repository needs to be set to public.
This section walks through the steps that operator users will perform to deploy the operator and managed resources.
If you've built an operator using the steps above, use your image:
$ export IMG=<yourimage>
OR: If you just want to try out an operator, you can also use our pre-built image.
export IMG=quay.io/operator-sd/ansible-memcached-operator-tutorial:v0.0.0
To apply the Memcached
Kind (CRD):
$ make install
# IMG environment variable must be set
$ make deploy
Verify that the memcached-operator is up and running:
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
memcached-operator 1 1 1 1 1m
Create the resource, the operator will do the rest.
kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
Verify that Memcached pods are created
kubectl get pods
In order to see the logs from a particular you can run:
kubectl logs deployment/kb-controller-manager -c manager
The logs contain the information about the Ansible run and will make it much easier to debug issues within your Ansible tasks. Note that the logs will contain much more detailed information about the Ansible Operator's internals and interface with Kubernetes as well.
Also, you can use the environment variable ANSIBLE_DEBUG_LOGS
set as True
to check the full Ansible result in the logs in order to be able to debug it.
Example
In the deploy/operator.yaml
:
...
- name: ANSIBLE_DEBUG_LOGS
value: "True"
...
Clean up the resources:
# TODO(asmacdo) the CR should be removed when CRD is removed $ kubectl delete -f config/samples/blahblak
$ make undeploy
For development it may be easier to [run the operator locally][TODO(asmacdo)], which does not require rebuilding the manager image every iteration.
We recommend reading through the our [Ansible development section][TODO(asmacdo)] for tips and tricks.
In this tutorial, the scaffolded watches.yaml
could be used as-is, but
has additional optional features. See [watches reference][TODO(asmacdo)]
For brevity, some of the scaffolded files were left out of this guide. See [Scaffolding Reference][TODO(asmacdo)]
This example built a namespaced scope operator, but Ansible operators can also be used with cluster-wide scope. See the operator scope documentation.
To version, install, and upgrade your operator, see out [Operator Lifecycle Management integration][TODO(asmacdo)] documentation.
This method is preferred during the development cycle to speed up deployment and testing.
Note: Ensure that Ansible Runner and Ansible Runner HTTP Plugin is installed or else you will see unexpected errors from Ansible Runner when a Custom Resource is created.
It is also important that the role
path referenced in watches.yaml
exists
on your machine. Since we are normally used to using a container where the Role
is put on disk for us, we need to manually copy our role to the configured
Ansible Roles path (e.g /etc/ansible/roles
.
Run the operator locally with the default Kubernetes config file present at
$HOME/.kube/config
:
$ operator-sdk run local
INFO[0000] Go Version: go1.10
INFO[0000] Go OS/Arch: darwin/amd64
INFO[0000] operator-sdk Version: 0.0.5+git
Run the operator locally with a provided Kubernetes config file:
$ operator-sdk run local --kubeconfig=config
INFO[0000] Go Version: go1.10
INFO[0000] Go OS/Arch: darwin/amd64
INFO[0000] operator-sdk Version: 0.0.5+git
Deploy your Operator with the Operator Lifecycle Manager (OLM)
OLM will manage creation of most if not all resources required to run your operator,
using a bit of setup from other operator-sdk
commands. Check out the OLM integration
user guide for more information.
Modify deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml
as shown and create a Memcached
custom resource:
$ cat deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml
apiVersion: "cache.example.com/v1alpha1"
kind: "Memcached"
metadata:
name: "example-memcached"
spec:
size: 3
$ kubectl apply -f deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml
Ensure that the memcached-operator creates the deployment for the CR:
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
memcached-operator 1 1 1 1 2m
example-memcached 3 3 3 3 1m
Check the pods to confirm 3 replicas were created:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
example-memcached-6fd7c98d8-7dqdr 1/1 Running 0 1m
example-memcached-6fd7c98d8-g5k7v 1/1 Running 0 1m
example-memcached-6fd7c98d8-m7vn7 1/1 Running 0 1m
memcached-operator-7cc7cfdf86-vvjqk 2/2 Running 0 2m
Occasionally while developing additional debug in the Operator logs is nice to have.
Using the memcached operator as an example, we can simply add the
"ansible.sdk.operatorframework.io/verbosity"
annotation to the Custom
Resource with the desired verbosity.
apiVersion: "cache.example.com/v1alpha1"
kind: "Memcached"
metadata:
name: "example-memcached"
annotations:
"ansible.sdk.operatorframework.io/verbosity": "4"
spec:
size: 4
Change the spec.size
field in the memcached CR from 3 to 4 and apply the
change:
$ cat deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml
apiVersion: "cache.example.com/v1alpha1"
kind: "Memcached"
metadata:
name: "example-memcached"
spec:
size: 4
$ kubectl apply -f deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml
Confirm that the operator changes the deployment size:
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
example-memcached 4 4 4 4 5m
Clean up the resources:
$ kubectl delete -f deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml
$ kubectl delete -f deploy/operator.yaml
$ kubectl delete -f deploy/role_binding.yaml
$ kubectl delete -f deploy/role.yaml
$ kubectl delete -f deploy/service_account.yaml
$ kubectl delete -f deploy/crds/cache.example.com_memcacheds_crd.yaml
NOTE Additional CR/CRD's can be added to the project by running, for example, the command :operator-sdk add api --api-version=cache.example.com/v1alpha1 --kind=AppService
For more information, refer cli doc.