Thanks to @keeyzar for refreshing the guide to Quarkus 1.9
creation of the certificate request is done with cfssl & cfssljson;
- install go https://golang.org/doc/install
- install plugins cfssl and cfssljson for go https://github.com/cloudflare/cfssl
minikube is utilized; don't push images into a registry, tell docker to utilize minikube docker daemon https://stackoverflow.com/a/42564211
- start minikube
- set docker environment to minikube docker
minikube start
eval $(minikube docker-env)
a quarkus application has been created with the following extensions
mvn io.quarkus:quarkus-maven-plugin:1.9.0.CR1:create \
-DprojectGroupId=eu.sevel.quarkus.admission \
-DprojectArtifactId=quarkus-admission-controller \
-DclassName="eu.sevel.quarkus.admission.ValidatingAdmissionController" \
-Dpath="/validate" \
-Dextensions="resteasy-jsonb,kubernetes-client"
build the application
mvn package
docker build -f src/main/docker/Dockerfile.jvm -t quarkus/quarkus-admission-controller-jvm .
create admission namespace
kubectl create ns admission
kubectl config set-context $(kubectl config current-context) --namespace=admission
deploy a certificate for host quarkus-admission-controller.admission.svc
chmod +x ./create-cert.sh
./create-cert.sh
deploy controller
kubectl apply -f quarkus-admission-controller.yaml
kubectl wait --for=condition=available --timeout=100s deployment/quarkus-admission-controller
controller=$(kubectl get pods --selector=app=quarkus-admission-controller -o jsonpath='{.items[*].metadata.name}')
kubectl logs $controller -f
create test namespace and deploy test application
kubectl create ns test-admission
kubectl label ns test-admission admission=enabled
kubectl apply -f httpbin.yaml
kubectl wait --for=condition=available --timeout=100s deployment/httpbin
verify the controller service is working properly
httpbin=$(kubectl get pods -n test-admission --selector=app=httpbin -o jsonpath='{.items[*].metadata.name}')
kubectl exec $httpbin -n test-admission -- curl \
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
--request POST \
-H "Content-Type: application/json" \
--data '{"additionalProperties":{},"apiVersion":"admission.k8s.io/v1","kind":"AdmissionReview","request":{"additionalProperties":{},"kind":{"additionalProperties":{},"group":"extensions","kind":"Deployment","version":"v1"},"name":"httpbin","namespace":"test-admission","operation":"UPDATE","resource":{"additionalProperties":{},"group":"extensions","resource":"deployments","version":"v1"},"uid":"75a55056-bc03-11e9-82d4-025000000001","userInfo":{"additionalProperties":{},"groups":["system:masters","system:authenticated"],"username":"docker-for-desktop"}}}' \
https://quarkus-admission-controller.admission.svc/validate
you should get
{"additionalProperties":{},"apiVersion":"admission.k8s.io/v1beta1","kind":"AdmissionReview","response":{"additionalProperties":{},"allowed":true,"auditAnnotations":{},"uid":"75a55056-bc03-11e9-82d4-025000000001"}}
get the base64 encoded ca bundle
cert=$(kubectl exec $controller -- cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt | base64 | tr -d '\n')
replace the value in field caBundle of file validating-webhook.yaml
sed -i.bak -E "s/caBundle:.*?/caBundle: $cert/" validating-webhook.yaml
sed -i.bak -E "s/caBundle:.*?/caBundle: $cert/" mutating-webhook.yaml
deploy validating webhook
kubectl apply -f validating-webhook.yaml
delete the test application
kubectl delete -f httpbin.yaml
you should see a DELETE event in the controller logs
DELETE event
{
{
"additionalProperties": {
},
"apiVersion": "admission.k8s.io/v1beta1",
"kind": "AdmissionReview",
"request": {
"additionalProperties": {
},
"dryRun": false,
"kind": {
"additionalProperties": {
},
"group": "apps",
"kind": "Deployment",
"version": "v1"
},
"name": "httpbin",
"namespace": "test-admission",
"oldObject": {
"additionalProperties": {
},
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"additionalProperties": {
},
"annotations": {
"deployment.kubernetes.io/revision": "1",
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{},\"labels\":{\"app\":\"httpbin\"},\"name\":\"httpbin\",\"namespace\":\"test-admission\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"httpbin\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"httpbin\"}},\"spec\":{\"containers\":[{\"command\":[\"sleep\",\"3600\"],\"image\":\"scrapinghub/httpbin:latest\",\"name\":\"httpbin\",\"resources\":{\"requests\":{\"cpu\":0.1,\"memory\":200}}}]}}}}\n"
},
"creationTimestamp": "2020-10-18T16:26:44Z",
"finalizers": [
],
"generation": 1,
"labels": {
"app": "httpbin"
},
"managedFields": [
{
"additionalProperties": {
},
"apiVersion": "apps/v1",
"fieldsType": "FieldsV1",
"fieldsV1": {
"additionalProperties": {
"f:metadata": {
"f:annotations": {
".": {
},
"f:kubectl.kubernetes.io/last-applied-configuration": {
}
},
"f:labels": {
".": {
},
"f:app": {
}
}
},
"f:spec": {
"f:progressDeadlineSeconds": {
},
"f:replicas": {
},
"f:revisionHistoryLimit": {
},
"f:selector": {
"f:matchLabels": {
".": {
},
"f:app": {
}
}
},
"f:strategy": {
"f:rollingUpdate": {
".": {
},
"f:maxSurge": {
},
"f:maxUnavailable": {
}
},
"f:type": {
}
},
"f:template": {
"f:metadata": {
"f:labels": {
".": {
},
"f:app": {
}
}
},
"f:spec": {
"f:containers": {
"k:{\"name\":\"httpbin\"}": {
".": {
},
"f:command": {
},
"f:image": {
},
"f:imagePullPolicy": {
},
"f:name": {
},
"f:resources": {
".": {
},
"f:requests": {
".": {
},
"f:cpu": {
},
"f:memory": {
}
}
},
"f:terminationMessagePath": {
},
"f:terminationMessagePolicy": {
}
}
},
"f:dnsPolicy": {
},
"f:restartPolicy": {
},
"f:schedulerName": {
},
"f:securityContext": {
},
"f:terminationGracePeriodSeconds": {
}
}
}
}
}
},
"manager": "kubectl-client-side-apply",
"operation": "Update",
"time": "2020-10-18T16:26:44Z"
},
{
"additionalProperties": {
},
"apiVersion": "apps/v1",
"fieldsType": "FieldsV1",
"fieldsV1": {
"additionalProperties": {
"f:metadata": {
"f:annotations": {
"f:deployment.kubernetes.io/revision": {
}
}
},
"f:status": {
"f:availableReplicas": {
},
"f:conditions": {
".": {
},
"k:{\"type\":\"Available\"}": {
".": {
},
"f:lastTransitionTime": {
},
"f:lastUpdateTime": {
},
"f:message": {
},
"f:reason": {
},
"f:status": {
},
"f:type": {
}
},
"k:{\"type\":\"Progressing\"}": {
".": {
},
"f:lastTransitionTime": {
},
"f:lastUpdateTime": {
},
"f:message": {
},
"f:reason": {
},
"f:status": {
},
"f:type": {
}
}
},
"f:observedGeneration": {
},
"f:readyReplicas": {
},
"f:replicas": {
},
"f:updatedReplicas": {
}
}
}
},
"manager": "kube-controller-manager",
"operation": "Update",
"time": "2020-10-18T16:26:48Z"
}
],
"name": "httpbin",
"namespace": "test-admission",
"ownerReferences": [
],
"resourceVersion": "6556",
"uid": "66a165ff-98a3-4289-b29b-cb1f49013c23"
},
"spec": {
"additionalProperties": {
},
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"additionalProperties": {
},
"matchExpressions": [
],
"matchLabels": {
"app": "httpbin"
}
},
"strategy": {
"additionalProperties": {
},
"rollingUpdate": {
"additionalProperties": {
},
"maxSurge": {
"additionalProperties": {
},
"kind": 1,
"strVal": "25%"
},
"maxUnavailable": {
"additionalProperties": {
},
"kind": 1,
"strVal": "25%"
}
},
"type": "RollingUpdate"
},
"template": {
"additionalProperties": {
},
"metadata": {
"additionalProperties": {
},
"finalizers": [
],
"labels": {
"app": "httpbin"
},
"managedFields": [
],
"ownerReferences": [
]
},
"spec": {
"additionalProperties": {
},
"containers": [
{
"additionalProperties": {
},
"args": [
],
"command": [
"sleep",
"3600"
],
"env": [
],
"envFrom": [
],
"image": "scrapinghub/httpbin:latest",
"imagePullPolicy": "Always",
"name": "httpbin",
"ports": [
],
"resources": {
"additionalProperties": {
},
"requests": {
"cpu": {
"additionalProperties": {
},
"amount": "100",
"format": "m"
},
"memory": {
"additionalProperties": {
},
"amount": "200",
"format": ""
}
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeDevices": [
],
"volumeMounts": [
]
}
],
"dnsPolicy": "ClusterFirst",
"ephemeralContainers": [
],
"hostAliases": [
],
"imagePullSecrets": [
],
"initContainers": [
],
"readinessGates": [
],
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"additionalProperties": {
},
"supplementalGroups": [
],
"sysctls": [
]
},
"terminationGracePeriodSeconds": 30,
"tolerations": [
],
"topologySpreadConstraints": [
],
"volumes": [
]
}
}
},
"status": {
"additionalProperties": {
},
"availableReplicas": 1,
"conditions": [
{
"additionalProperties": {
},
"lastTransitionTime": "2020-10-18T16:26:48Z",
"lastUpdateTime": "2020-10-18T16:26:48Z",
"message": "Deployment has minimum availability.",
"reason": "MinimumReplicasAvailable",
"status": "True",
"type": "Available"
},
{
"additionalProperties": {
},
"lastTransitionTime": "2020-10-18T16:26:44Z",
"lastUpdateTime": "2020-10-18T16:26:48Z",
"message": "ReplicaSet \"httpbin-5644b4777\" has successfully progressed.",
"reason": "NewReplicaSetAvailable",
"status": "True",
"type": "Progressing"
}
],
"observedGeneration": 1,
"readyReplicas": 1,
"replicas": 1,
"updatedReplicas": 1
}
},
"operation": "DELETE",
"options": {
"additionalProperties": {
},
"apiVersion": "meta.k8s.io/v1",
"dryRun": [
],
"kind": "DeleteOptions",
"propagationPolicy": "Background"
},
"requestKind": {
"additionalProperties": {
},
"group": "apps",
"kind": "Deployment",
"version": "v1"
},
"requestResource": {
"additionalProperties": {
},
"group": "apps",
"resource": "deployments",
"version": "v1"
},
"resource": {
"additionalProperties": {
},
"group": "apps",
"resource": "deployments",
"version": "v1"
},
"uid": "bbd83bf5-673d-4d2b-8be9-1beb2e817457",
"userInfo": {
"additionalProperties": {
},
"groups": [
"system:masters",
"system:authenticated"
],
"username": "minikube-user"
}
}
}
recreate the application
kubectl apply -f httpbin.yaml
you should now see a CREATE event with object
CREATE event
{
"additionalProperties": {
},
"apiVersion": "admission.k8s.io/v1beta1",
"kind": "AdmissionReview",
"request": {
"additionalProperties": {
},
"dryRun": false,
"kind": {
"additionalProperties": {
},
"group": "apps",
"kind": "Deployment",
"version": "v1beta1"
},
"namespace": "test-admission",
"object": {
"additionalProperties": {
},
"apiVersion": "apps/v1beta1",
"kind": "Deployment",
"metadata": {
"additionalProperties": {
},
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1beta1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{},\"name\":\"httpbin\",\"namespace\":\"test-admission\"},\"spec\":{\"replicas\":1,\"template\":{\"metadata\":{\"labels\":{\"name\":\"httpbin\"}},\"spec\":{\"containers\":[{\"command\":[\"sleep\",\"3600\"],\"image\":\"scrapinghub/httpbin:latest\",\"name\":\"httpbin\",\"resources\":{\"requests\":{\"cpu\":0.1,\"memory\":200}}}]}}}}\n"
},
"creationTimestamp": "2019-08-11T09:27:13Z",
"finalizers": [
],
"generation": 1,
"labels": {
"name": "httpbin"
},
"name": "httpbin",
"namespace": "test-admission",
"ownerReferences": [
],
"uid": "33b61451-bc1a-11e9-b52a-025000000001"
},
"spec": {
"additionalProperties": {
},
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 2,
"selector": {
"additionalProperties": {
},
"matchExpressions": [
],
"matchLabels": {
"name": "httpbin"
}
},
"strategy": {
"additionalProperties": {
},
"rollingUpdate": {
"additionalProperties": {
},
"maxSurge": {
"additionalProperties": {
},
"strVal": "25%"
},
"maxUnavailable": {
"additionalProperties": {
},
"strVal": "25%"
}
},
"type": "RollingUpdate"
},
"template": {
"additionalProperties": {
},
"metadata": {
"additionalProperties": {
},
"finalizers": [
],
"labels": {
"name": "httpbin"
},
"ownerReferences": [
]
},
"spec": {
"additionalProperties": {
},
"containers": [
{
"additionalProperties": {
},
"args": [
],
"command": [
"sleep",
"3600"
],
"env": [
],
"envFrom": [
],
"image": "scrapinghub/httpbin:latest",
"imagePullPolicy": "Always",
"name": "httpbin",
"ports": [
],
"resources": {
"additionalProperties": {
},
"requests": {
"cpu": {
"additionalProperties": {
},
"amount": "100m"
},
"memory": {
"additionalProperties": {
},
"amount": "200"
}
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeDevices": [
],
"volumeMounts": [
]
}
],
"dnsPolicy": "ClusterFirst",
"hostAliases": [
],
"imagePullSecrets": [
],
"initContainers": [
],
"readinessGates": [
],
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"additionalProperties": {
},
"supplementalGroups": [
],
"sysctls": [
]
},
"terminationGracePeriodSeconds": 30,
"tolerations": [
],
"volumes": [
]
}
}
},
"status": {
"additionalProperties": {
},
"conditions": [
]
}
},
"operation": "CREATE",
"resource": {
"additionalProperties": {
},
"group": "apps",
"resource": "deployments",
"version": "v1beta1"
},
"uid": "33b62ca7-bc1a-11e9-b52a-025000000001",
"userInfo": {
"additionalProperties": {
},
"groups": [
"system:masters",
"system:authenticated"
],
"username": "docker-for-desktop"
}
}
}
make a modification
kubectl label deployment httpbin -n test-admission foo=bar
you should see an UPDATE event with object and oldObject
UPDATE event
{
"additionalProperties": {
},
"apiVersion": "admission.k8s.io/v1beta1",
"kind": "AdmissionReview",
"request": {
"additionalProperties": {
},
"dryRun": false,
"kind": {
"additionalProperties": {
},
"group": "apps",
"kind": "Deployment",
"version": "v1"
},
"name": "httpbin",
"namespace": "test-admission",
"object": {
"additionalProperties": {
},
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"additionalProperties": {
},
"annotations": {
"deployment.kubernetes.io/revision": "1",
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{},\"labels\":{\"app\":\"httpbin\"},\"name\":\"httpbin\",\"namespace\":\"test-admission\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"httpbin\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"httpbin\"}},\"spec\":{\"containers\":[{\"command\":[\"sleep\",\"3600\"],\"image\":\"scrapinghub/httpbin:latest\",\"name\":\"httpbin\",\"resources\":{\"requests\":{\"cpu\":0.1,\"memory\":200}}}]}}}}\n"
},
"creationTimestamp": "2020-10-18T16:28:43Z",
"finalizers": [
],
"generation": 1,
"labels": {
"app": "httpbin",
"foo": "bar"
},
"managedFields": [
{
"additionalProperties": {
},
"apiVersion": "apps/v1",
"fieldsType": "FieldsV1",
"fieldsV1": {
"additionalProperties": {
"f:metadata": {
"f:annotations": {
".": {
},
"f:kubectl.kubernetes.io/last-applied-configuration": {
}
},
"f:labels": {
".": {
},
"f:app": {
}
}
},
"f:spec": {
"f:progressDeadlineSeconds": {
},
"f:replicas": {
},
"f:revisionHistoryLimit": {
},
"f:selector": {
"f:matchLabels": {
".": {
},
"f:app": {
}
}
},
"f:strategy": {
"f:rollingUpdate": {
".": {
},
"f:maxSurge": {
},
"f:maxUnavailable": {
}
},
"f:type": {
}
},
"f:template": {
"f:metadata": {
"f:labels": {
".": {
},
"f:app": {
}
}
},
"f:spec": {
"f:containers": {
"k:{\"name\":\"httpbin\"}": {
".": {
},
"f:command": {
},
"f:image": {
},
"f:imagePullPolicy": {
},
"f:name": {
},
"f:resources": {
".": {
},
"f:requests": {
".": {
},
"f:cpu": {
},
"f:memory": {
}
}
},
"f:terminationMessagePath": {
},
"f:terminationMessagePolicy": {
}
}
},
"f:dnsPolicy": {
},
"f:restartPolicy": {
},
"f:schedulerName": {
},
"f:securityContext": {
},
"f:terminationGracePeriodSeconds": {
}
}
}
}
}
},
"manager": "kubectl-client-side-apply",
"operation": "Update",
"time": "2020-10-18T16:28:43Z"
},
{
"additionalProperties": {
},
"apiVersion": "apps/v1",
"fieldsType": "FieldsV1",
"fieldsV1": {
"additionalProperties": {
"f:metadata": {
"f:annotations": {
"f:deployment.kubernetes.io/revision": {
}
}
},
"f:status": {
"f:availableReplicas": {
},
"f:conditions": {
".": {
},
"k:{\"type\":\"Available\"}": {
".": {
},
"f:lastTransitionTime": {
},
"f:lastUpdateTime": {
},
"f:message": {
},
"f:reason": {
},
"f:status": {
},
"f:type": {
}
},
"k:{\"type\":\"Progressing\"}": {
".": {
},
"f:lastTransitionTime": {
},
"f:lastUpdateTime": {
},
"f:message": {
},
"f:reason": {
},
"f:status": {
},
"f:type": {
}
}
},
"f:observedGeneration": {
},
"f:readyReplicas": {
},
"f:replicas": {
},
"f:updatedReplicas": {
}
}
}
},
"manager": "kube-controller-manager",
"operation": "Update",
"time": "2020-10-18T16:28:46Z"
},
{
"additionalProperties": {
},
"apiVersion": "apps/v1",
"fieldsType": "FieldsV1",
"fieldsV1": {
"additionalProperties": {
"f:metadata": {
"f:labels": {
"f:foo": {
}
}
}
}
},
"manager": "kubectl-label",
"operation": "Update",
"time": "2020-10-18T16:28:54Z"
}
],
"name": "httpbin",
"namespace": "test-admission",
"ownerReferences": [
],
"resourceVersion": "6671",
"uid": "21c2d418-01c5-431d-bef1-19db4c8d6b7f"
},
"spec": {
"additionalProperties": {
},
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"additionalProperties": {
},
"matchExpressions": [
],
"matchLabels": {
"app": "httpbin"
}
},
"strategy": {
"additionalProperties": {
},
"rollingUpdate": {
"additionalProperties": {
},
"maxSurge": {
"additionalProperties": {
},
"kind": 1,
"strVal": "25%"
},
"maxUnavailable": {
"additionalProperties": {
},
"kind": 1,
"strVal": "25%"
}
},
"type": "RollingUpdate"
},
"template": {
"additionalProperties": {
},
"metadata": {
"additionalProperties": {
},
"finalizers": [
],
"labels": {
"app": "httpbin"
},
"managedFields": [
],
"ownerReferences": [
]
},
"spec": {
"additionalProperties": {
},
"containers": [
{
"additionalProperties": {
},
"args": [
],
"command": [
"sleep",
"3600"
],
"env": [
],
"envFrom": [
],
"image": "scrapinghub/httpbin:latest",
"imagePullPolicy": "Always",
"name": "httpbin",
"ports": [
],
"resources": {
"additionalProperties": {
},
"requests": {
"cpu": {
"additionalProperties": {
},
"amount": "100",
"format": "m"
},
"memory": {
"additionalProperties": {
},
"amount": "200",
"format": ""
}
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeDevices": [
],
"volumeMounts": [
]
}
],
"dnsPolicy": "ClusterFirst",
"ephemeralContainers": [
],
"hostAliases": [
],
"imagePullSecrets": [
],
"initContainers": [
],
"readinessGates": [
],
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"additionalProperties": {
},
"supplementalGroups": [
],
"sysctls": [
]
},
"terminationGracePeriodSeconds": 30,
"tolerations": [
],
"topologySpreadConstraints": [
],
"volumes": [
]
}
}
},
"status": {
"additionalProperties": {
},
"availableReplicas": 1,
"conditions": [
{
"additionalProperties": {
},
"lastTransitionTime": "2020-10-18T16:28:46Z",
"lastUpdateTime": "2020-10-18T16:28:46Z",
"message": "Deployment has minimum availability.",
"reason": "MinimumReplicasAvailable",
"status": "True",
"type": "Available"
},
{
"additionalProperties": {
},
"lastTransitionTime": "2020-10-18T16:28:43Z",
"lastUpdateTime": "2020-10-18T16:28:46Z",
"message": "ReplicaSet \"httpbin-5644b4777\" has successfully progressed.",
"reason": "NewReplicaSetAvailable",
"status": "True",
"type": "Progressing"
}
],
"observedGeneration": 1,
"readyReplicas": 1,
"replicas": 1,
"updatedReplicas": 1
}
},
"oldObject": {
"additionalProperties": {
},
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"additionalProperties": {
},
"annotations": {
"deployment.kubernetes.io/revision": "1",
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{},\"labels\":{\"app\":\"httpbin\"},\"name\":\"httpbin\",\"namespace\":\"test-admission\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"httpbin\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"httpbin\"}},\"spec\":{\"containers\":[{\"command\":[\"sleep\",\"3600\"],\"image\":\"scrapinghub/httpbin:latest\",\"name\":\"httpbin\",\"resources\":{\"requests\":{\"cpu\":0.1,\"memory\":200}}}]}}}}\n"
},
"creationTimestamp": "2020-10-18T16:28:43Z",
"finalizers": [
],
"generation": 1,
"labels": {
"app": "httpbin"
},
"managedFields": [
],
"name": "httpbin",
"namespace": "test-admission",
"ownerReferences": [
],
"resourceVersion": "6671",
"uid": "21c2d418-01c5-431d-bef1-19db4c8d6b7f"
},
"spec": {
"additionalProperties": {
},
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"additionalProperties": {
},
"matchExpressions": [
],
"matchLabels": {
"app": "httpbin"
}
},
"strategy": {
"additionalProperties": {
},
"rollingUpdate": {
"additionalProperties": {
},
"maxSurge": {
"additionalProperties": {
},
"kind": 1,
"strVal": "25%"
},
"maxUnavailable": {
"additionalProperties": {
},
"kind": 1,
"strVal": "25%"
}
},
"type": "RollingUpdate"
},
"template": {
"additionalProperties": {
},
"metadata": {
"additionalProperties": {
},
"finalizers": [
],
"labels": {
"app": "httpbin"
},
"managedFields": [
],
"ownerReferences": [
]
},
"spec": {
"additionalProperties": {
},
"containers": [
{
"additionalProperties": {
},
"args": [
],
"command": [
"sleep",
"3600"
],
"env": [
],
"envFrom": [
],
"image": "scrapinghub/httpbin:latest",
"imagePullPolicy": "Always",
"name": "httpbin",
"ports": [
],
"resources": {
"additionalProperties": {
},
"requests": {
"cpu": {
"additionalProperties": {
},
"amount": "100",
"format": "m"
},
"memory": {
"additionalProperties": {
},
"amount": "200",
"format": ""
}
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeDevices": [
],
"volumeMounts": [
]
}
],
"dnsPolicy": "ClusterFirst",
"ephemeralContainers": [
],
"hostAliases": [
],
"imagePullSecrets": [
],
"initContainers": [
],
"readinessGates": [
],
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"additionalProperties": {
},
"supplementalGroups": [
],
"sysctls": [
]
},
"terminationGracePeriodSeconds": 30,
"tolerations": [
],
"topologySpreadConstraints": [
],
"volumes": [
]
}
}
},
"status": {
"additionalProperties": {
},
"availableReplicas": 1,
"conditions": [
{
"additionalProperties": {
},
"lastTransitionTime": "2020-10-18T16:28:46Z",
"lastUpdateTime": "2020-10-18T16:28:46Z",
"message": "Deployment has minimum availability.",
"reason": "MinimumReplicasAvailable",
"status": "True",
"type": "Available"
},
{
"additionalProperties": {
},
"lastTransitionTime": "2020-10-18T16:28:43Z",
"lastUpdateTime": "2020-10-18T16:28:46Z",
"message": "ReplicaSet \"httpbin-5644b4777\" has successfully progressed.",
"reason": "NewReplicaSetAvailable",
"status": "True",
"type": "Progressing"
}
],
"observedGeneration": 1,
"readyReplicas": 1,
"replicas": 1,
"updatedReplicas": 1
}
},
"operation": "UPDATE",
"options": {
"additionalProperties": {
},
"apiVersion": "meta.k8s.io/v1",
"dryRun": [
],
"fieldManager": "kubectl-label",
"kind": "UpdateOptions"
},
"requestKind": {
"additionalProperties": {
},
"group": "apps",
"kind": "Deployment",
"version": "v1"
},
"requestResource": {
"additionalProperties": {
},
"group": "apps",
"resource": "deployments",
"version": "v1"
},
"resource": {
"additionalProperties": {
},
"group": "apps",
"resource": "deployments",
"version": "v1"
},
"uid": "fffffd16-ed50-4f7e-bce0-301d8fb93938",
"userInfo": {
"additionalProperties": {
},
"groups": [
"system:masters",
"system:authenticated"
],
"username": "minikube-user"
}
}
}
deploy the mutating webhook
kubectl apply -f mutating-webhook.yaml
redeploy the application
kubectl delete -f httpbin.yaml
kubectl apply -f httpbin.yaml
you should see
patching with [{"op":"add","path":"/metadata/labels/foo","value":"bar"}]
check that label has been applied to the deployment
kubectl get deploy -n test-admission httpbin -o yaml
you should see
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
...
labels:
foo: bar
name: httpbin
name: httpbin
namespace: test-admission
cleanup
kubectl delete ns admission
kubectl delete ns test-admission
kubectl delete csr quarkus-admission-controller
kubectl delete ValidatingWebhookConfiguration validating-quarkus-admission-controller
kubectl delete MutatingWebhookConfiguration mutating-quarkus-admission-controller