Skip to content

Commit b5dbae5

Browse files
dymurrayShawn Hurley
authored andcommitted
docs: Add a user guide for using an Ansible Operator (#559)
- Sdk-cli-reference updates - Ansible Operator User Guide - Ansible Operator Project Layout
1 parent 5a02841 commit b5dbae5

File tree

4 files changed

+379
-0
lines changed

4 files changed

+379
-0
lines changed

doc/ansible/project_layout.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Project Scaffolding Layout
2+
3+
After creating a new operator project using
4+
`operator-sdk new --type ansible`, the project directory has numerous generated folders and files. The following table describes a basic rundown of each generated file/directory.
5+
6+
7+
| File/Folders | Purpose |
8+
| :--- | :--- |
9+
| deploy | Contains a generic set of kubernetes manifests for deploying this operator on a kubernetes cluster. |
10+
| roles/<kind> | Contains an Ansible Role initialized using [Ansible Galaxy](https://docs.ansible.com/ansible/latest/reference_appendices/galaxy.html) |
11+
| tmp | Contains scripts that the operator-sdk uses for build and initialization. |
12+
| watches.yaml | Contains Group, Version, Kind, and Ansible invocation method. |

doc/ansible/user-guide.md

Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
# User Guide
2+
3+
This guide walks through an example of building a simple memcached-operator
4+
powered by Ansible using tools and libraries provided by the Operator SDK.
5+
6+
## Prerequisites
7+
8+
- [git][git_tool]
9+
- [docker][docker_tool] version 17.03+.
10+
- [kubectl][kubectl_tool] version v1.9.0+.
11+
- [ansible][ansible_tool] version v2.6.0+
12+
- [ansible-runner][ansible_runner_tool] version v1.1.0+
13+
- [ansible-runner-http][ansible_runner_http_plugin] version v1.0.0+
14+
- [dep][dep_tool] version v0.5.0+. (Optional if you aren't installing from source)
15+
- [go][go_tool] version v1.10+. (Optional if you aren't installing from source)
16+
- Access to a kubernetes v.1.9.0+ cluster.
17+
18+
**Note**: This guide uses [minikube][minikube_tool] version v0.25.0+ as the
19+
local kubernetes cluster and quay.io for the public registry.
20+
21+
## Install the Operator SDK CLI
22+
23+
The Operator SDK has a CLI tool that helps the developer to create, build, and
24+
deploy a new operator project.
25+
26+
Checkout the desired release tag and install the SDK CLI tool:
27+
28+
```sh
29+
$ mkdir -p $GOPATH/src/github.com/operator-framework
30+
$ cd $GOPATH/src/github.com/operator-framework
31+
$ git clone https://github.com/operator-framework/operator-sdk
32+
$ cd operator-sdk
33+
$ git checkout master
34+
$ make dep
35+
$ make install
36+
```
37+
38+
This installs the CLI binary `operator-sdk` at `$GOPATH/bin`.
39+
40+
## Create a new project
41+
42+
Use the CLI to create a new Ansible-based memcached-operator project:
43+
44+
```sh
45+
$ mkdir -p $GOPATH/src/github.com/example-inc/
46+
$ cd $GOPATH/src/github.com/example-inc/
47+
$ operator-sdk new memcached-operator --api-version=cache.example.com/v1alpha1 --kind=Memcached --type=ansible
48+
$ cd memcached-operator
49+
```
50+
51+
This creates the memcached-operator project specifically for watching the
52+
Memcached resource with APIVersion `cache.example.com/v1apha1` and Kind
53+
`Memcached`.
54+
55+
To learn more about the project directory structure, see [project
56+
layout][layout_doc] doc.
57+
58+
## Customize the operator logic
59+
60+
For this example the memcached-operator will execute the following
61+
reconciliation logic for each `Memcached` Custom Resource (CR):
62+
- Create a memcached Deployment if it doesn't exist
63+
- Ensure that the Deployment size is the same as specified by the `Memcached`
64+
CR
65+
66+
### Watch the Memcached CR
67+
68+
By default, the memcached-operator watches `Memcached` resource events as shown
69+
in `watches.yaml` and executes Ansible Role `Memached`:
70+
71+
```yaml
72+
---
73+
- version: v1alpha1
74+
group: cache.example.com
75+
kind: Memcached
76+
```
77+
78+
#### Options
79+
**Role**
80+
Specifying a `role` option in `watches.yaml` will configure the operator to use
81+
this specified path when launching `ansible-runner` with an Ansible Role. By
82+
default, the `new` command will fill in an absolute path to where your role
83+
should go.
84+
```yaml
85+
---
86+
- version: v1alpha1
87+
group: cache.example.com
88+
kind: Memcached
89+
role: /opt/ansible/roles/Memcached
90+
```
91+
92+
**Playbook**
93+
Specifying a `playbook` option in `watches.yaml` will configure the operator to
94+
use this specified path when launching `ansible-runner` with an Ansible
95+
Playbook
96+
```yaml
97+
---
98+
- version: v1alpha1
99+
group: cache.example.com
100+
kind: Memcached
101+
playbook: /opt/ansible/playbook.yaml
102+
```
103+
104+
## Building the Memcached Ansible Role
105+
106+
The first thing to do is to modify the generated Ansible role under
107+
`roles/Memcached`. This Ansible Role controls the logic that is executed when a
108+
resource is modified.
109+
110+
### Define the Memcached spec
111+
112+
Defining the spec for an Ansible Operator can be done entirely in Ansible. The
113+
Ansible Operator will simply pass all key value pairs listed in the Custom
114+
Resource spec field along to Ansible as
115+
[variables](https://docs.ansible.com/ansible/2.5/user_guide/playbooks_variables.html#passing-variables-on-the-command-line).
116+
It is recommended that you perform some type validation in Ansible on the
117+
variables to ensure that your application is receiving expected input.
118+
119+
First, set a default in case the user doesn't set the `spec` field by modifying
120+
`roles/Memcached/defaults/main.yml`:
121+
```yaml
122+
size: 1
123+
```
124+
125+
### Defining the Memcached deployment
126+
127+
Now that we have the spec defined, we can define what Ansible is actually
128+
executed on resource changes. Since this is an Ansible Role, the default
129+
behavior will be to execute the tasks in `roles/Memcached/tasks/main.yml`. We
130+
want Ansible to create a deployment if it does not exist which runs the
131+
`memcached:1.4.36-alpine` image. Ansible 2.5+ supports the [k8s Ansible
132+
Module](https://docs.ansible.com/ansible/2.6/modules/k8s_module.html) which we
133+
will leverage to control the deployment definition.
134+
135+
Modify `roles/Memcached/tasks/main.yml` to look like the following:
136+
```yaml
137+
---
138+
- name: start memcached
139+
k8s:
140+
definition:
141+
kind: Deployment
142+
apiVersion: apps/v1
143+
metadata:
144+
name: '{{ meta.name }}-memcached'
145+
namespace: '{{ meta.namespace }}'
146+
spec:
147+
replicas: "{{size}}"
148+
selector:
149+
matchLabels:
150+
app: memcached
151+
template:
152+
metadata:
153+
labels:
154+
app: memcached
155+
spec:
156+
containers:
157+
- name: memcached
158+
command:
159+
- memcached
160+
- -m=64
161+
- -o
162+
- modern
163+
- -v
164+
image: "docker.io/memcached:1.4.36-alpine"
165+
ports:
166+
- containerPort: 11211
167+
168+
```
169+
170+
It is important to note that we used the `size` variable to control how many
171+
replicas of the Memcached deployment we want. We set the default to `1`, but
172+
any user can create a Custom Resource that overwrites the default.
173+
174+
### Build and run the operator
175+
176+
Before running the operator, Kubernetes needs to know about the new custom
177+
resource definition the operator will be watching.
178+
179+
Deploy the CRD:
180+
181+
```sh
182+
$ kubectl create -f deploy/crd.yaml
183+
```
184+
185+
Once this is done, there are two ways to run the operator:
186+
187+
- As a pod inside a Kubernetes cluster
188+
- As a go program outside the cluster using `operator-sdk`
189+
190+
#### 1. Run as a pod inside a Kubernetes cluster
191+
192+
Running as a pod inside a Kubernetes cluster is preferred for production use.
193+
194+
Build the memcached-operator image and push it to a registry:
195+
```
196+
$ operator-sdk build quay.io/example/memcached-operator:v0.0.1
197+
$ docker push quay.io/example/memcached-operator:v0.0.1
198+
```
199+
200+
Kubernetes deployment manifests are generated in `deploy/operator.yaml`. The
201+
deployment image in this file needs to be modified from the placeholder
202+
`REPLACE_IMAGE` to the previous built image. To do this run:
203+
```
204+
$ sed -i 's|REPLACE_IMAGE|quay.io/example/memcached-operator:v0.0.1|g' deploy/operator.yaml
205+
```
206+
207+
Deploy the memcached-operator:
208+
209+
```sh
210+
$ kubectl create -f deploy/rbac.yaml
211+
$ kubectl create -f deploy/operator.yaml
212+
```
213+
214+
**NOTE**: `deploy/rbac.yaml` creates a `ClusterRoleBinding` and assumes we are
215+
working in namespace `default`. If you are working in a different namespace you
216+
must modify this file before creating it.
217+
218+
Verify that the memcached-operator is up and running:
219+
220+
```sh
221+
$ kubectl get deployment
222+
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
223+
memcached-operator 1 1 1 1 1m
224+
```
225+
226+
#### 2. Run outside the cluster
227+
228+
This method is preferred during the development cycle to speed up deployment and testing.
229+
230+
**Note**: Ensure that [Ansible Runner][ansible_runner_tool] and [Ansible Runner
231+
HTTP Plugin][ansible_runner_http_plugin] is installed or else you will see
232+
unexpected errors from Ansible Runner when a Custom Resource is created.
233+
234+
It is also important that the `role` path referenced in `watches.yaml` exists
235+
on your machine. Since we are normally used to using a container where the Role
236+
is put on disk for us, we need to manually copy our role to the configured
237+
Ansible Roles path (e.g `/etc/ansible/roles`.
238+
239+
Run the operator locally with the default kubernetes config file present at
240+
`$HOME/.kube/config`:
241+
242+
```sh
243+
$ operator-sdk up local
244+
INFO[0000] Go Version: go1.10
245+
INFO[0000] Go OS/Arch: darwin/amd64
246+
INFO[0000] operator-sdk Version: 0.0.5+git
247+
```
248+
249+
Run the operator locally with a provided kubernetes config file:
250+
251+
```sh
252+
$ operator-sdk up local --kubeconfig=config
253+
INFO[0000] Go Version: go1.10
254+
INFO[0000] Go OS/Arch: darwin/amd64
255+
INFO[0000] operator-sdk Version: 0.0.5+git
256+
```
257+
258+
### Create a Memcached CR
259+
260+
Modify `deploy/cr.yaml` as shown and create a `Memcached` custom resource:
261+
262+
```sh
263+
$ cat deploy/cr.yaml
264+
apiVersion: "cache.example.com/v1alpha1"
265+
kind: "Memcached"
266+
metadata:
267+
name: "example-memcached"
268+
spec:
269+
size: 3
270+
271+
$ kubectl apply -f deploy/cr.yaml
272+
```
273+
274+
Ensure that the memcached-operator creates the deployment for the CR:
275+
276+
```sh
277+
$ kubectl get deployment
278+
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
279+
memcached-operator 1 1 1 1 2m
280+
example-memcached 3 3 3 3 1m
281+
```
282+
283+
Check the pods to confirm 3 replicas were created:
284+
285+
```sh
286+
$ kubectl get pods
287+
NAME READY STATUS RESTARTS AGE
288+
example-memcached-6fd7c98d8-7dqdr 1/1 Running 0 1m
289+
example-memcached-6fd7c98d8-g5k7v 1/1 Running 0 1m
290+
example-memcached-6fd7c98d8-m7vn7 1/1 Running 0 1m
291+
memcached-operator-7cc7cfdf86-vvjqk 1/1 Running 0 2m
292+
```
293+
294+
### Update the size
295+
296+
Change the `spec.size` field in the memcached CR from 3 to 4 and apply the
297+
change:
298+
299+
```sh
300+
$ cat deploy/cr.yaml
301+
apiVersion: "cache.example.com/v1alpha1"
302+
kind: "Memcached"
303+
metadata:
304+
name: "example-memcached"
305+
spec:
306+
size: 4
307+
308+
$ kubectl apply -f deploy/cr.yaml
309+
```
310+
311+
Confirm that the operator changes the deployment size:
312+
313+
```sh
314+
$ kubectl get deployment
315+
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
316+
example-memcached 4 4 4 4 5m
317+
```
318+
319+
### Cleanup
320+
321+
Clean up the resources:
322+
323+
```sh
324+
$ kubectl delete -f deploy/cr.yaml
325+
$ kubectl delete -f deploy/operator.yaml
326+
```
327+
328+
[layout_doc]:./project_layout.md
329+
[dep_tool]:https://golang.github.io/dep/docs/installation.html
330+
[git_tool]:https://git-scm.com/downloads
331+
[go_tool]:https://golang.org/dl/
332+
[docker_tool]:https://docs.docker.com/install/
333+
[kubectl_tool]:https://kubernetes.io/docs/tasks/tools/install-kubectl/
334+
[minikube_tool]:https://github.com/kubernetes/minikube#installation
335+
[ansible_tool]:https://docs.ansible.com/ansible/latest/index.html
336+
[ansible_runner_tool]:https://ansible-runner.readthedocs.io/en/latest/install.html
337+
[ansible_runner_http_plugin]:https://github.com/ansible/ansible-runner-http

doc/sdk-cli-reference.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,29 @@ Run code-generation for custom resources
113113
Generating deepcopy funcs
114114
```
115115

116+
#### crd - Generates a custom resource definition (CRD) and the custom resource (CR) files
117+
118+
##### Use
119+
120+
crd generator generates custom resource definition and custom resource
121+
files for the specified api-version and kind.
122+
123+
##### Flags
124+
125+
* `--api-version` **(required)** string - Kubernetes apiVersion and has a format of $GROUP_NAME/$VERSION (e.g app.example.com/v1alpha1)
126+
* `-h, --help` - help for k8s
127+
* `--kind` **(required)** string - Kubernetes CustomResourceDefinition kind. (e.g AppService)
128+
129+
##### Example
130+
131+
```bash
132+
operator-sdk generate crd --api-version app.example.com/v1alpha1 --kind AppService
133+
134+
# Output:
135+
Generating custom resource definition (CRD) file
136+
Create <path_to_project>/deploy/appservice_cr.yaml
137+
Create <path_to_project>/deploy/appservice_crd.yaml
138+
```
116139
#### olm-catalog - Generates OLM Catalog manifests
117140

118141
##### Flags
@@ -147,6 +170,8 @@ generates a default directory layout based on the input `project-name`.
147170

148171
* `--api-version` **(required)** string - Kubernetes apiVersion and has a format of `$GROUP_NAME/$VERSION` (e.g app.example.com/v1alpha1)
149172
* `--kind` **(required)** string - Kubernetes CustomResourceDefintion kind. (e.g AppService)
173+
* `--skip-git-init` Do not init the directory as a git repository
174+
* `--type` Type of operator to initialize (e.g "ansible") (default "go")
150175
* `-h, --help` - help for new
151176

152177
### Example

0 commit comments

Comments
 (0)