From b67691c7e7ea74bb0babd0ab93ce150a3877df14 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Thu, 28 Oct 2021 22:45:42 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=86=95=20Add=20tiny=20operator=20example:?= =?UTF-8?q?=20nsplease?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- slides/k8s/operators-example.md | 150 ++++++++++++++++++++++++++++++++ slides/kadm-twodays.yml | 1 + slides/kube-adv.yml | 1 + slides/kube-fullday.yml | 1 + slides/kube-selfpaced.yml | 1 + slides/kube-twodays.yml | 1 + 6 files changed, 155 insertions(+) create mode 100644 slides/k8s/operators-example.md diff --git a/slides/k8s/operators-example.md b/slides/k8s/operators-example.md new file mode 100644 index 00000000..170ef555 --- /dev/null +++ b/slides/k8s/operators-example.md @@ -0,0 +1,150 @@ +# Writing an tiny operator + +- Let's look at a simple operator + +- It has: + + - control loop + + - resource management + + - deployment instructions + +- It doesn't have: + + - CRDs (and therefore, resource versioning, conversion webhooks...) + +--- + +## Use case + +*When I push code to my source control system, I want that code +to be built into a container image, and that image to be deployed +in a staging environment. I want each branch/tag/commit (depending +on my needs) to be deployed into its specific Kubernetes Namespace.* + +- The last part requires the CI/CD pipeline to manage Namespaces + +- ...And permissions in these Namespaces + +- This requires elevated privileges for the CI/CD pipeline + + (read: `cluster-admin`) + +- If the CI/CD pipeline is compromised, this can lead to cluster compromise + +- This can be a concern if the CI/CD pipeline is part of the repository + + (which is the default modus operandi with GitHub, GitLab, Bitbucket...) + +--- + +## Proposed solution + +- On-demand creation of Namespaces + +- Creation is triggered by creating a ConfigMap in a dedicated Namespace + +- Namespaces are set up with basic permissions + +- Credentials are generated for each Namespace + +- Credentials only give access to their Namespace + +- Credentials are exposed back to the dedicated configuration Namespace + +- Operator implemented as a shell script + +--- + +## An operator in shell... Really? + +- About 150 lines of code + + (including comments + white space) + +- Performance doesn't matter + + - operator work will be a tiny fraction of CI/CD pipeline work + + - uses *watch* semantics to minimize control plane load + +- Easy to understand, easy to audit, easy to tweak + +--- + +## Show me the code! + +- GitHub repository and documentation: + + https://github.com/jpetazzo/nsplease + +- Operator source code: + + https://github.com/jpetazzo/nsplease/blob/main/nsplease.sh + +--- + +## Main loop + +```bash + info "Waiting for ConfigMap events in $REQUESTS_NAMESPACE..." + kubectl --namespace $REQUESTS_NAMESPACE get configmaps \ + --watch --output-watch-events -o json \ + | jq --unbuffered --raw-output '[.type,.object.metadata.name] | @tsv' \ + | while read TYPE NAMESPACE; do + + debug "Got event: $TYPE $NAMESPACE" +``` + +- `--watch` to avoid active-polling the control plane + +- `--output-watch-events` to disregard e.g. resource deletion, edition + +- `jq` to process JSON easily + +--- + +## Resource ownership + +- Check out the `kubectl patch` commands + +- The created Namespace "owns" the corresponding ConfigMap and Secret + +- This means that deleting the Namespace will delete the ConfigMap and Secret + +- We don't need to watch for object deletion to clean up + +- Clean up will we done automatically even if operator is not running + +--- + +## Why no CRD? + +- It's easier to create a ConfigMap + + (e.g. `kubectl create configmap --from-literal=` one-liner) + +- We don't need the features of CRDs + + (schemas, printer columns, versioning...) + +- “This CRD could have been a ConfigMap!” + + (this doesn't mean *all* CRDs could be ConfigMaps, of course) + +--- + +## Discussion + +- A lot of simple, yet efficient logic, can be implemented in shell scripts + +- These can be used to prototype more complex operators + +- Not all use-cases require CRDs + + (keep in mind that correct CRDs are *a lot* of work!) + +- If the algorithms are correct, shell performance won't matter at all + + (but it will be difficult to keep a resource cache in shell) diff --git a/slides/kadm-twodays.yml b/slides/kadm-twodays.yml index 5b0dc2d3..d649c6e3 100644 --- a/slides/kadm-twodays.yml +++ b/slides/kadm-twodays.yml @@ -70,6 +70,7 @@ content: - k8s/operators.md - k8s/eck.md ###- k8s/operators-design.md + ###- k8s/operators-example.md # CONCLUSION - - k8s/lastwords.md - k8s/links.md diff --git a/slides/kube-adv.yml b/slides/kube-adv.yml index 20710080..8e923811 100644 --- a/slides/kube-adv.yml +++ b/slides/kube-adv.yml @@ -74,6 +74,7 @@ content: - k8s/hpa-v2.md - #9 - k8s/operators-design.md + - k8s/operators-example.md - k8s/kubebuilder.md - k8s/events.md - k8s/finalizers.md diff --git a/slides/kube-fullday.yml b/slides/kube-fullday.yml index bb04fdbd..1b1924a9 100644 --- a/slides/kube-fullday.yml +++ b/slides/kube-fullday.yml @@ -115,6 +115,7 @@ content: #- k8s/admission.md #- k8s/operators.md #- k8s/operators-design.md + #- k8s/operators-example.md #- k8s/staticpods.md #- k8s/finalizers.md #- k8s/owners-and-dependents.md diff --git a/slides/kube-selfpaced.yml b/slides/kube-selfpaced.yml index 1f267b2a..3e4d1079 100644 --- a/slides/kube-selfpaced.yml +++ b/slides/kube-selfpaced.yml @@ -130,6 +130,7 @@ content: - k8s/admission.md - k8s/operators.md - k8s/operators-design.md + - k8s/operators-example.md - k8s/kubebuilder.md - k8s/sealed-secrets.md #- k8s/exercise-sealed-secrets.md diff --git a/slides/kube-twodays.yml b/slides/kube-twodays.yml index 3a7c73ca..b4fbefd5 100644 --- a/slides/kube-twodays.yml +++ b/slides/kube-twodays.yml @@ -115,6 +115,7 @@ content: #- k8s/admission.md #- k8s/operators.md #- k8s/operators-design.md + #- k8s/operators-example.md #- k8s/staticpods.md #- k8s/owners-and-dependents.md #- k8s/gitworkflows.md