feat: add controllers (#33)

pull/34/head
Rémy-Christophe Schermesser 5 years ago committed by GitHub
parent 348d5f2bd6
commit 5e086e11ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,7 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: configuration
annotations:
k8spatterns.io/podDeleteSelector: "app=nginx"

@ -0,0 +1,17 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx

@ -0,0 +1,43 @@
---
# Service account required for watching to resources
apiVersion: v1
kind: ServiceAccount
metadata:
name: expose-controller
---
# Bind to an appropriate permission
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: expose-controller
subjects:
- kind: ServiceAccount
name: expose-controller
roleRef:
name: edit
kind: ClusterRole
apiGroup: rbac.authorization.k8s.io
---
# Example Deployment using a config map as input for a template
# which is processed from an init-container
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller
spec:
replicas: 1
selector:
matchLabels:
app: controller
template:
metadata:
labels:
app: controller
spec:
serviceAccountName: expose-controller
containers:
- name: expose-controller
image: elpicador/kubernetes-controller
command: ["sh", "+x", "/root/config-watcher-controller.sh"]
- name: kubeapi-proxy
image: k8spatterns/kubeapi-proxy

@ -2,14 +2,126 @@
## Introduction
## Exercices
A controller is an application that watches and maintains a set of resources in a desired state.
Most of the previous resources we saw are in fact controllers, like the deployments.
Nothing to see here.
To sum it up it is an application that looks like that:
```go
for {
desired := getDesiredState()
current := getCurrentState()
makeChanges(desired, current)
}
```
We won't go into all the details of a controller. There are already a good resources online if you are interested.
## The basics of controllers
For this, we will use the example from the [Kubernetes patterns book](https://learning.oreilly.com/library/view/kubernetes-patterns/9781492050278/). The source code of the example we will use is available [here](https://github.com/k8spatterns/examples/tree/master/advanced/Controller).
We will write a controller that deletes pods based on a annotation in a `ConfigMap`
First let's create a [ConfigMap](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/). A `ConfigMap` is a list of key/values that can be shared between pods.
```yml
apiVersion: v1
kind: ConfigMap
metadata:
name: configuration
annotations:
k8spatterns.io/podDeleteSelector: "app=nginx"
```
We will only use the `annotations` field in this config map. We created a custom annotation named "k8spatterns.io/podDeleteSelector". Our controller will act only on this annotation. Here we will delete pods with the label `app=nginx`.
Review and apply the manifest [01-configmap.yml](01-configmap.yml).
Next, let's create a deployment that will create pods for us, with the label `app=nginx`:
```yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
```
Review and apply the manifest [02-deployment.yml](02-deployment.yml).
Now we need a controller to act on this `ConfigMap`. To simplify, an image containing the controller code is available on [docker hub](https://cloud.docker.com/u/elpicador/repository/docker/elpicador/kubernetes-controller). The controller [config-watcher-controller.sh](https://github.com/k8spatterns/examples/blob/master/advanced/Controller/config-watcher-controller.sh) is taken from the Kubernetes patterns github repository. For now don't look at it.
Review and apply the manifest [03-controller.yml](03-controller.yml). For now ignore the manifests `ServiceAccount` and `RoleBinding`.
Display the log of the container `expose-controller`, and the pods running. What can you see? Did you expect it?
In fact, the controller only reacts when a config map is modified. So modify the config map. See what happens.
## Deep dive in the controller code
Remember a controller is a loop doing:
```go
for {
desired := getDesiredState()
current := getCurrentState()
makeChanges(desired, current)
}
```
You can look at the source code [here](https://raw.githubusercontent.com/ElPicador/kubernetes-controller/master/config-watcher-controller.sh).
In our case the `desired` is which pods should be deleted, so the content of the annotation `k8spatterns.io/podDeleteSelector`.
We get this by calling the Kubernetes API with the call:
```sh
curl -N -s "$base/api/v1/$ns/configmaps?watch=true" | while read -r event
```
The `current` is the pods actually running. Same, to get this we call the Kubernetes API:
```sh
local pods=$(curl -s ${base}/api/v1/${ns}/pods?labelSelector=${selector} | \
jq -r .items[].metadata.name)
```
Fortunatelly, the API supports `labelSelector` so we can filter the pods easily.
Finally, the `makeChanges` is to delete all the pods matching the annotations:
```sh
exit_code=$(curl -s -X DELETE -o /dev/null -w "%{http_code}" ${base}/api/v1/${ns}/pods/${pod})
```
Again, we use the Kubernetes API for this
All the rest of the code is purely bash wrapping and `jq` magic to get the information we want.
## Around the controller
You've probably see that the manifests for our controller doesn't only contain a container with our code the `expose-controller`. It has a sidecar container `kubeapi-proxy`. This container is a proxy to the Kubernetes API, with all the security baked in.
The `ServiceAccount` and `RoleBinding` are here to declare which rights our pods needs when interracting with the Kubernetes API. We will see more details in the [RBAC chapter](../21-rbac).
For now think of the `ServiceAccount` as a user. And the `RoleBinding` as assigning rights to a specific user. Then in pod we specify a service account for it to use with the `serviceAccountName: expose-controller`.
## Clean up
```sh
kubectl delete service,deployment,pod --all
kubectl delete deployment,configmap,serviceaccount,rolebinding --all
```
## Links
* https://engineering.bitnami.com/articles/a-deep-dive-into-kubernetes-controllers.html

Loading…
Cancel
Save