Skip to content

Commit eb0bc40

Browse files
committed
feature: mutating webhook post ready
Signed-off-by: Batuhan Apaydın <[email protected]>
1 parent 42dd2d5 commit eb0bc40

2 files changed

+302
-0
lines changed

_posts/2020-10-27-kubernetes-webhooks-made-easy-with-openfaas.md

+6
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ $ cd deployment
146146
$ kubectl apply -f rbac.yaml,service.yaml,deployment.yaml
147147
```
148148

149+
* Label the default namespace to enable the webhook
150+
151+
```sh
152+
$ kubectl label namespaces default admission-webhook-example=enabled
153+
```
154+
149155
### 5. Build and Deploy OpenFaaS Function (Optional)
150156

151157
* Pull the [golang-middleware](https://github.com/openfaas-incubator/golang-http-template) template from [OpenFaaS Official Template Store](https://github.com/openfaas/store)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
---
2+
title: "Writing Kubernetes Admission Controllers with OpenFaaS"
3+
description: "Learn how to write your Kubernetes Admission Controllers with OpenFaaS functions"
4+
date: 2020-11-25
5+
image: /images/2020-10-27-k8s-validatingwebhook-openfaas/puzzle.jpg
6+
categories:
7+
- arkade
8+
- kubectl
9+
- faas-cli
10+
- admissionwebhooks
11+
- mutatingadmissionwebhooks
12+
- k8s extensibility
13+
author_staff_member: developer-guy
14+
dark_background: true
15+
---
16+
17+
Learn how to write your Kubernetes Admission Controllers with OpenFaaS functions
18+
19+
<p align="center">
20+
<img height="128" src="/images/openfaas/kubernetes.png">
21+
</p>
22+
23+
## Introduction to Kubernetes Admission Controllers
24+
In my last [post](https://www.openfaas.com/blog/kubernetes-webhooks-made-easy-with-openfaas/), we talked about what Kubernetes Admission Webhooks are and how can we use Validating Admission Webhook.
25+
26+
Today we will explore how to build a Kubernetes Admission Controller with a function.
27+
28+
The main difference between the two types of admission webhook is validating webhooks can reject a request, but they cannot modify the object they are receiving in the admission request, while mutating webhooks can modify objects by creating a patch that will be sent back in the admission response and can reject a request too. If a webhook rejects a request, an error is returned to the end-user.
29+
30+
Also, the other difference between the two types are validating webhooks are called in parallel and mutating webhooks are called in-sequence by the api-server.
31+
32+
## Use-cases
33+
Multi-tenant Kubernetes creates some special challenges when it comes to resource sharing and security.Multi-tenant Kubernetes is a Kubernetes deployment where multiple applications or workloads run side-by-side.When it comes to resource sharing, you must ensure that each tenant has access to the resources they need.Requests and limits are the mechanisms Kubernetes uses to control resources such as CPU and memory.So, if you forget to set a limits&requests for your application, you may affect the cluster state bad and this causes to disturb the other tenants in the platform.Because when you forget to set limits&request for the application, application is going to try to consume all the resources available on the node.To avoid that, we are going to create a Mutating Admission Webhook, this webhook will check your deployment for the resources available, If you forgot to set resources it will inject the default resources for you automatically.
34+
35+
## The Scenario
36+
We have a deployment with no resources defined.We are going to try to create this deployment and we want to make sure that this webhook will not let us to do that.
37+
38+
There is one important thing we need to say about Mutating Admission webhook is that:
39+
40+
> Mutating Admission webhooks, mutations are performed via JSON patches. While the JSON patch standard includes a lot of intricacies that go well beyond the scope of this discussion, the Go data structure in our example as well as its usage should give the user a good initial overview of how JSON patches work:
41+
42+
```golang
43+
type patchOperation struct {
44+
Op string `json:"op"`
45+
Path string `json:"path"`
46+
Value interface{} `json:"value,omitempty"`
47+
}
48+
```
49+
50+
For setting the field .spec.securityContext.runAsNonRoot of a pod to true, we construct the following patchOperation object:
51+
52+
```golang
53+
patches = append(patches, patchOperation{
54+
Op: "add",
55+
Path: "/spec/securityContext/runAsNonRoot",
56+
Value: true,
57+
})
58+
```
59+
60+
Reminder, we will use the same workflow defined in previous post like below:
61+
62+
* Kubernetes API -> Webhook (w/TLS) -> OpenFaaS Gateway (w/HTTP) -> OpenFaaS Function
63+
64+
![Workflow](/images/2020-10-27-k8s-validatingwebhook-openfaas/admission-controller-phases.png)
65+
> Credit: [https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/](https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/)
66+
67+
### Prerequisites
68+
69+
##### Arkade
70+
71+
* [arkade](https://get-arkade.dev) is The OpenFaaS community built tool for Kubernetes developers, with arkade you can easily install all necessary cli tools to your host and deploy apps to the cluster.
72+
73+
```sh
74+
$ curl -sLS https://dl.get-arkade.dev | sudo sh
75+
```
76+
77+
##### KinD (Kubernetes in Docker)
78+
79+
* Kubernetes is our recommendation for teams running at scale, but in this demo we will be using [KinD](https://kind.sigs.k8s.io/docs/user/quick-start/) for the sake of simplicity.
80+
81+
```sh
82+
$ arkade get kind
83+
```
84+
85+
##### kubectl
86+
87+
* You can control your cluster using [kubectl](https://github.com/kubernetes/kubectl) CLI.
88+
89+
```sh
90+
$ arkade get kubectl
91+
```
92+
93+
##### faas-cli
94+
95+
* [faas-cli](https://github.com/openfaas/faas-cli) is an official CLI for OpenFaaS , with "faas-cli" you can build and deploy functions easily.
96+
97+
```sh
98+
$ arkade get faas-cli
99+
```
100+
101+
### Setup
102+
103+
### 1. Setup a Kubernetes Cluster with KinD
104+
105+
You can start a Kubernetes cluster with KinD if you don't have one already
106+
107+
```bash
108+
$ arkade get kind
109+
$ kind create cluster
110+
```
111+
112+
### 2. Deploy OpenFaaS to our local Kubernetes Cluster with arkade:
113+
114+
* Install a OpenFaaS
115+
116+
```sh
117+
$ arkade install openfaas
118+
```
119+
120+
Read the output from the installation and run the commands given to you.
121+
122+
```sh
123+
# Forward the gateway to your machine
124+
kubectl rollout status -n openfaas deploy/gateway
125+
kubectl port-forward -n openfaas svc/gateway 8080:8080 &
126+
127+
# If basic auth is enabled, you can now log into your gateway:
128+
PASSWORD=$(kubectl get secret -n openfaas basic-auth -o jsonpath="{.data.basic-auth-password}" | base64 --decode; echo)
129+
echo -n $PASSWORD | faas-cli login --username admin --password-stdin
130+
```
131+
132+
You can access them again at any time with `arkade info openfaas`
133+
134+
### 3. Clone the project
135+
136+
* Clone the sample from GitHub
137+
138+
```sh
139+
$ git clone https://github.com/developer-guy/admission-webhook-example-with-openfaas
140+
$ cd admission-webhook-example-with-openfaas
141+
$ git checkout feature/mutating
142+
```
143+
144+
* Let's explore the structure of the project.
145+
146+
```
147+
deployment/ --> includes necessary manifests and scripts for the deployment of the project
148+
functions/ --> includes templates and the requiredlabel function itself
149+
Dockerfile --> includes instructions to build an image of the project
150+
build --> automated way to build and push an image of the project
151+
```
152+
153+
### 4. Deploy MutatingAdmissionWebhook
154+
155+
* We will generate the TLS certificates required for the ValidatingAdmissionWebhook using the following: [Kubernetes TLS Certificates Management](https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/)
156+
157+
```sh
158+
$ cd deployment
159+
$ sh webhook-create-signed-cert.sh
160+
```
161+
162+
* Get the Certificate Authority (CA) from the local cluster
163+
164+
```sh
165+
$ export CA_BUNDLE=$(kubectl config view --minify --flatten -o json | jq -r '.clusters[] | select(.name == "'$(kubectl config current-context)'") | .cluster."certificate-authority-data"')
166+
$ sed -e "s|\${CA_BUNDLE}|${CA_BUNDLE}|g" mutatingwebhook.yaml | kubectl apply -f -
167+
$ cd ..
168+
```
169+
170+
* Build the project
171+
172+
```sh
173+
$ export DOCKER_USER="docker-hub-username"
174+
$ ./build
175+
```
176+
177+
Now edit `deployment.yaml` and set 'DOCKER_USER' to the above.
178+
179+
* Deploy it project
180+
181+
```sh
182+
$ cd deployment
183+
$ kubectl apply -f rbac.yaml,service.yaml,deployment.yaml
184+
# Label the default namespace to enable the webhook
185+
$ kubectl label namespaces default admission-webhook-example=enabled
186+
```
187+
188+
* This time we are using "fileinjector" as a FUNCTION_NAME environment variable in the deployment.yaml file
189+
190+
```yaml
191+
env:
192+
- name: FUNCTION_NAME
193+
value: fileinjector
194+
```
195+
196+
### 5. Build and Deploy OpenFaaS Function (Optional)
197+
198+
* Pull the [golang-middleware](https://github.com/openfaas-incubator/golang-http-template) template from [OpenFaaS Official Template Store](https://github.com/openfaas/store)
199+
200+
```sh
201+
$ faas-cli template store list # check available templates in store
202+
$ faas-cli template store describe golang-middleware # describe the specific template
203+
$ faas-cli template store pull golang-middleware
204+
```
205+
206+
* Create the function
207+
208+
```sh
209+
$ export OPENFAAS_PREFIX=$DOCKER_USER
210+
$ faas-cli new fileinjector --lang go-middleware
211+
$ cd fileinjector
212+
$ go mod init fileinjector
213+
$ # fill the handler.go with the corresponding code: [functions/fileinjector/handler.go](https://github.com/developer-guy/admission-webhook-example-with-openfaas/blob/feature/mutating/functions/fileinjector/handler.go)
214+
$ go get
215+
```
216+
217+
* Deploy the function
218+
219+
```sh
220+
$ cd functions
221+
$ faas-cli up -f fileinjector.yml --build-arg GO111MODULE=on # (build-push-deploy) make sure you are using your docker hub username. i.e: devopps
222+
```
223+
224+
* Verify the functions that are working in `openfaas-fn` namespace
225+
226+
```sh
227+
$ kubectl get pods --namespace openfaas-fn
228+
```
229+
230+
### 6. Testing the whole workflow
231+
232+
* First, check the [deployment](https://github.com/developer-guy/admission-webhook-example-with-openfaas/blob/feature/mutating/deployment/busybox.yaml) manifest and see there is no resources defined for the container.
233+
234+
```sh
235+
apiersion: apps/v1
236+
kind: Deployment
237+
metadata:
238+
name: busybox
239+
namespace: default
240+
labels:
241+
app: busybox
242+
spec:
243+
selector:
244+
matchLabels:
245+
app: busybox
246+
replicas: 1
247+
template:
248+
metadata:
249+
labels:
250+
app: busybox
251+
spec:
252+
containers:
253+
- name: busybox
254+
image: busybox
255+
command: [ "/bin/sh" ]
256+
args: [ "-c", "while true; do cat /etc/config/hello-openfaas.txt; sleep 2; done" ]
257+
```
258+
259+
* Then, you can create the deployment by applying this manifest file. After doing this, you will notice that container resources are injected automatically by the mutating webhook with the default values defined by the mutating webhook.
260+
261+
```sh
262+
$ kubectl apply -f busybox.yaml
263+
```
264+
265+
* Check the YAML of the Deployment, you will see the default resources.
266+
267+
```sh
268+
$ kubectl get deployments busybox -ojsonpath='{.spec.template.spec.containers[?(@.name=="busybox")].resources}'
269+
{"limits":{"cpu":"125Mi","memory":"75Mi"},"requests":{"cpu":"100Mi","memory":"50Mi"}}
270+
```
271+
272+
273+
## 7. What can you do with it ?
274+
275+
As it stands, the demo is not ready for production environment but it gives you an overview about how you can create a mutating webhook , how you can enforce some kind of best practices(inject default resources in this case) for your cluster with the few lines of code.You can extend this demo for your organizational needs as you wish.
276+
277+
### Join the community
278+
279+
Have you got questions, comments, or suggestions? Join the community on [Slack](https://slack.openfaas.io).
280+
281+
Would you like help to set up your OpenFaaS installation, or someone to call when things don't quite go to plan? [Our Premium Subscription plan](https://www.openfaas.com/support/) gives you a say in the project roadmap, a support contact, and access to Enterprise-grade authentication with OIDC.
282+
283+
### Acknowledgements
284+
285+
* Special Thanks to [Alex Ellis](https://twitter.com/alexellisuk) for all guidance and for merging changes into OpenFaaS to better support this workflow.
286+
287+
* Special Thanks to [Furkan Türkal](https://twitter.com/furkanturkaI) for all the support.
288+
289+
### References
290+
* [https://banzaicloud.com/blog/k8s-admission-webhooks](https://banzaicloud.com/blog/k8s-admission-webhooks)
291+
* [https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/](https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/)
292+
* [https://medium.com/ibm-cloud/diving-into-kubernetes-mutatingadmissionwebhook-6ef3c5695f74](https://medium.com/ibm-cloud/diving-into-kubernetes-mutatingadmissionwebhook-6ef3c5695f74)
293+
* [https://blog.alexellis.io/get-started-with-openfaas-and-kind/](https://blog.alexellis.io/get-started-with-openfaas-and-kind/)
294+
* [https://github.com/morvencao/kube-mutating-webhook-tutorial](https://github.com/morvencao/kube-mutating-webhook-tutorial)
295+
* [https://github.com/developer-guy/admission-webhook-example-with-openfaas](https://github.com/developer-guy/admission-webhook-example-with-openfaas)
296+
* [https://platform9.com/blog/kubernetes-multi-tenancy-best-practices/](https://platform9.com/blog/kubernetes-multi-tenancy-best-practices/)

0 commit comments

Comments
 (0)