Lab 2: Create the Lab Operator Project
Create the Lab Operator Project
In this part of the lab we will create a demo Ansible operator and deploy it to our Cluster.
-
Create the
ansible-operator-frontend
directorycd mkdir ansible-operator cd ~/ansible-operator
``
-
Create the
ansible-operator-frontend
Projectoperator-sdk new ansible-operator-frontend --type=ansible --api-version=ansiblelab.ibm.com/v1beta1 --kind=MyAnsibleLabDemo > INFO[0000] Creating new Ansible operator 'ansible-operator-frontend'. > INFO[0000] Created deploy/service_account.yaml > INFO[0000] Created deploy/role.yaml > INFO[0000] Created deploy/role_binding.yaml > INFO[0000] Created deploy/crds/lab_v1beta1_MyAnsibleLabDemo_crd.yaml ...
``
You can ignore the errors concerning git
-
Change to the
ansible-operator-frontend
directorycd ~/ansible-operator/ansible-operator-frontend
``
-
The basic file structure for the Ansible Operator has been created
ll > total 36 > drwxr-x--- 7 training training 4096 Jul 1 17:29 ./ > drwxrwxr-x 3 training training 4096 Jul 1 17:29 ../ > drwxr-x--- 3 training training 4096 Jul 1 17:29 build/ > drwxr-x--- 3 training training 4096 Jul 1 17:29 deploy/ > drwxrwxr-x 7 training training 4096 Jul 1 17:29 .git/ > drwxr-x--- 5 training training 4096 Jul 1 17:29 molecule/ > drwxr-x--- 3 training training 4096 Jul 1 17:29 roles/ > -rw-r--r-- 1 training training 140 Jul 1 17:29 .travis.yml > -rw-r--r-- 1 training training 121 Jul 1 17:29 watches.yaml
``
Create the Lab Operator API
With the above, the API has already been created (unlike for GO operators) and added to the new Custom Resource (CR), with APIVersion ansiblelab.ibm.com/v1beta1
and Kind MyAnsibleLabDemo
.
-
Add the
deployment.image
field to the Custom ResourceTraining VM
gedit ~/ansible-operator/ansible-operator-frontend/deploy/crds/ansiblelab.ibm.com_v1beta1_myansiblelabdemo_cr.yaml &
``
Cloud/Standalone
nano ~/ansible-operator/ansible-operator-frontend/deploy/crds/ansiblelab.ibm.com_v1beta1_myansiblelabdemo_cr.yaml
``
Add the last two lines from the following at the end of the file and save to make it look the same
apiVersion: ansiblelab.ibm.com/v1beta1 kind: MyAnsibleLabDemo metadata: name: example-MyAnsibleLabDemo spec: --> Add fields here size: 3 demo: image: niklaushirt/k8sdemo:1.0.0
``
-
Save and quit
**We have now finished setting up the API and CRDs **
Create the Lab Operator Controller
By default, an Ansible role executes the tasks defined at roles/tasks/main.yml
.
For defining our deployment we will use the k8s module of Ansible.
1) Define the Lab Operator Controller
-
Edit the
ansible-operator-frontend
ControllerTraining VM
gedit ~/ansible-operator/ansible-operator-frontend/roles/myansiblelabdemo/tasks/main.yml &
``
Cloud/Standalone
nano ~/ansible-operator/ansible-operator-frontend/roles/myansiblelabdemo/tasks/main.yml ```
-
Replace the content with the following:
- name: Create the k8sdemo deployment community.kubernetes.k8s: definition: apiVersion: apps/v1 kind: Deployment metadata: name: k8sdemo namespace: default labels: app: k8sdemo spec: selector: matchLabels: app: k8sdemo replicas: 1 template: metadata: labels: app: k8sdemo spec: containers: - name: k8sdemo image: "{{demo.image}}" imagePullPolicy: IfNotPresent ports: - containerPort: 3000 env: - name: PORT value : "3000" - name: APPLICATION_NAME value: k8sdemo - name: BACKEND_URL value: http://k8sdemo-backend-service.default.svc:3000/api - name: Create the k8sdemo service community.kubernetes.k8s: definition: apiVersion: v1 kind: Service metadata: name: k8sdemo-service namespace: default spec: selector: app: k8sdemo ports: - protocol: TCP port: 3000 targetPort: 3000 nodePort: 32123 type: NodePort
``
This will ensure that the Pod will be created with the Image information defined in the Custom Resource (CR) definition ("{{deployment.image}}"). This picks up the value defined in the CR.
- Save and Quit
2) Build the Lab Operator Controller
-
Now let’s build the Operator container
operator-sdk build localhost:5000/ansible-operator-frontend:ansible > INFO[0000] Building OCI image localhost:5000/ansible-operator-frontend:ansible > Sending build context to Docker daemon 49.15kB > Step 1/3 : FROM quay.io/operator-framework/ansible-operator:v0.10.0 > ---> 168416e214f1 > Step 2/3 : COPY watches.yaml ${HOME}/watches.yaml > ---> Using cache > ---> 43f81409e05d > Step 3/3 : COPY roles/ ${HOME}/roles/ > ---> 0ad354c77a7a > Successfully built 0ad354c77a7a > Successfully tagged localhost:5000/ansible-operator-frontend:ansible > INFO[0001] Operator build complete.
``
Where
localhost:5000/ansible-operator-frontend:ansible
is the name of the Docker image to be created. -
And push the Operator container to the local registry
Training VM
First execute this in a separate Terminal Window/Tab in order to be able to access the private registry:
kubectl port-forward –namespace kube-system $(kubectl get po -n kube-system | grep kube-registry-v0 | \awk ‘{print $1;}') 5000:5000
> Forwarding from 127.0.0.1:5000 -> 5000
> Forwarding from [::1]:5000 -> 5000
![](../images/cloud.png) **Cloud/Standalone**
![](../images/important.png) **Cloud/Standalone** This does probably not work if you are using a standalone or cloud environment.
You can ignore this as we will be using a version already provided on Docker hub.
5. And then push the image:
![](../images/vm.png) **Training VM**
```bash
docker push localhost:5000/ansible-operator-frontend:ansible
```
![](../images/cloud.png) **Cloud/Standalone**
![](../images/important.png) **Cloud/Standalone** This does probably not work if you are using a standalone or cloud environment.
You can ignore this as we will be using a version already provided on Docker hub.
### 3) Prepare the Deployment for the Lab Operator Controller
The deployment manifest for the Operator (that was generated automatically) looks like this:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ansible-operator-frontend
spec:
replicas: 1
selector:
matchLabels:
name: ansible-operator-frontend
template:
metadata:
labels:
name: ansible-operator-frontend
spec:
serviceAccountName: ansible-operator-frontend
containers:
- name: ansible
command:
- /usr/local/bin/ao-logs
- /tmp/ansible-operator/runner
- stdout
--> Replace this with the built image name
image: "{{ REPLACE_IMAGE }}"
imagePullPolicy: "{{ pull_policy|default('Always') }}"
volumeMounts:
- mountPath: /tmp/ansible-operator/runner
name: runner
readOnly: true
- name: operator
--> Replace this with the built image name
image: "{{ REPLACE_IMAGE }}"
imagePullPolicy: "{{ pull_policy|default('Always') }}"
volumeMounts:
- mountPath: /tmp/ansible-operator/runner
name: runner
env:
- name: WATCH_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: OPERATOR_NAME
value: "ansible-operator-frontend"
volumes:
- name: runner
emptyDir: {}
Modify the YAML to use the image that we have pushed to the registry in the Operator deployment
cp ~/ansible-operator/ansible-operator-frontend/deploy/operator.yaml ~/ansible-operator/ansible-operator-frontend/deploy/operator.yaml.bak
sed -i 's|REPLACE_IMAGE|niklaushirt/ansible-operator-frontend:ansible|g' ~/ansible-operator/ansible-operator-frontend/deploy/operator.yaml
sed -i 's|{{ pull_policy.* }}|Always|g' ~/ansible-operator/ansible-operator-frontend/deploy/operator.yaml
On Mac please use:
sed -i '' 's|REPLACE_IMAGE|niklaushirt/ansible-operator-frontend:ansible|g' ~/ansible-operator/ansible-operator-frontend/deploy/operator.yaml
sed -i '' 's|{{ pull_policy.* }}|Always|g' ~/ansible-operator/ansible-operator-frontend/deploy/operator.yaml
more ~/ansible-operator/ansible-operator-frontend/deploy/operator.yaml
To the attentive observer, we’re using the prepared image from the docker hub, due to some routing issues for Kubernetes to pull the image internally - thanks minikube. The Training VM also uses a slightly older
2) Deploy the Lab Operator
-
Deploy the
ansible-operator-frontend
Custom Resource Definitionkubectl apply -f ~/ansible-operator/ansible-operator-frontend/deploy/crds/ansiblelab.ibm.com_myansiblelabdemos_crd.yaml > customresourcedefinition.apiextensions.k8s.io/MyAnsibleLabDemos.ansiblelab.ibm.com created
``
-
Create the
ansible-operator-frontend
Service Accountkubectl apply -f ~/ansible-operator/ansible-operator-frontend/deploy/service_account.yaml kubectl apply -f ~/ansible-operator/ansible-operator-frontend/deploy/role.yaml kubectl apply -f ~/ansible-operator/ansible-operator-frontend/deploy/role_binding.yaml > serviceaccount/ansible-operator-frontend created > role.rbac.authorization.k8s.io/ansible-operator-frontend created > rolebinding.rbac.authorization.k8s.io/ansible-operator-frontend created
``
-
Create the
ansible-operator-frontend
Operatorkubectl apply -f ~/ansible-operator/ansible-operator-frontend/deploy/operator.yaml > deployment.apps/ansible-operator-frontend created
``
-
Check and wait for the Operator to be running
kubectl get pods > NAME READY STATUS RESTARTS AGE > ansible-operator-frontend-fd78bcf5-zxgws 1/1 Running 0 43m
``
-
Get the log of the Operator Pod (use the Pod name from the previous step)
kubectl logs -c operator ansible-operator-frontend-fd78bcf5-zxgws
> {"level":"info","ts":1593618304.1191652,"logger":"cmd","msg":"Go Version: go1.12.5"}
> {"level":"info","ts":1593618304.1194193,"logger":"cmd","msg":"Go OS/Arch: linux/amd64"}
> {"level":"info","ts":1593618304.1194592,"logger":"cmd","msg":"Version of operator-sdk: v0.8.0"}
> {"level":"info","ts":1593618304.1194792,"logger":"cmd","msg":"Watching namespace.","Namespace":"default"}
> {"level":"info","ts":1593618304.1632428,"logger":"leader","msg":"Trying to become the leader."}
> {"level":"info","ts":1593618338.328806,"logger":"leader","msg":"Became the leader."}
> {"level":"info","ts":1593618338.3861306,"logger":"proxy","msg":"Starting to serve","Address":"127.0.0.1:8888"}
> {"level":"info","ts":1593618338.386716,"logger":"manager","msg":"Using default value for workers 1"}
> {"level":"info","ts":1593618338.3867893,"logger":"ansible-controller","msg":"Watching resource","Options.Group":"ansiblelab.ibm.com","Options.Version":"v1beta1","Options.Kind":"MyAnsibleLabDemo"}
> {"level":"info","ts":1593618338.387424,"logger":"kubebuilder.controller","msg":"Starting EventSource","controller":"myansiblelabdemo-controller","source":"kind source: ansiblelab.ibm.com/v1beta1, Kind=MyAnsibleLabDemo"}
> {"level":"info","ts":1593618338.487868,"logger":"kubebuilder.controller","msg":"Starting Controller","controller":"myansiblelabdemo-controller"}
> {"level":"info","ts":1593618338.5881243,"logger":"kubebuilder.controller","msg":"Starting workers","controller":"myansiblelabdemo-controller","worker count":1}
This means that the Operator is working and ready.