This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

KubeOps Compliance 2.0

Start with Kubeops Compliance 2.0

Follow the quickstart guides to learn how to create cluster in a secure, fast way with kubeopsctl.

1 - Release Notes

Check out the latest release notes, providing a thorough insight into the exhilarating updates and enhancements within our newest kubeopsctl version.

1.1 - KubeOps Versions

Here is the KubeOps and it’s supported tools versions list. Make sure to install or upgrade according to supported versions only.

KubeOps Supported KOSI Version Supported kubeopsctl Version Supported KOSI plugins Deprecation Date
KubeOps 2.2.X KOSI 2.15.X kubeopsctl 2.2.X enterprise-plugins:2.2.X 01.07.2027
KubeOps 2.1.X KOSI 2.13.X kubeopsctl 2.1.X enterprise-plugins:2.0.X 13.04.2027
KubeOps 2.0.X KOSI 2.13.X kubeopsctl 2.0.X enterprise-plugins:2.0.X 22.12.2026
KubeOps 2.0.X KOSI 2.13.X kubeopsctl 2.0.X enterprise-plugins:2.0.X 22.12.2026

1.2 - KubeOps 2.1.1

KubeOps 2.1.1 - Release Date ??.08.2026

Changelog KubeOpsCtl 2.1.1

Fixes

- fixed missing opensearch-dashboards plugins and wrong version 

Versions KubeOps 2.1.1

1.3 - KubeOps 2.2.0_Beta1

KubeOps 2.2.0_Beta1 - Release Date 02.08.2026

Changelog KubeOpsCtl 2.2.0_Beta1

Whats new?

- Added Traefik support for kubeopsctl
- Added Kubevirt-Manager support for kubeopsctl
- Added Kubernetes 1.36 support
- Added Advanced Parameters for static Registry mount path, check out the file format [Cluster Values YAML](/kubeopsctl-2.0/reference/fileformats/#cluster-valuesyaml)

Fixes

- fixed a podman bug affecting pull packages
- fixed a harbor bug setting up cluster
- added creation of nginx ingressclass, when installing traefik for backwards compatabilty
- fixed default secret for kubeops-dashboard
- kubeopsctl pull command now verifies if the specified tool value file exists
- Added kubeops-harbor-secret for pulling images from the internal private harbor project 'kubeops'
- fixed a bug that prevented to create the kubeops harbor project as private 
- fixed a bug that prevented to change the kubeops harbor project to private 
- fixed a bug that prevented the image push of the kubernetes images to local-registry 
- changed the 'localhost' reference to '127.0.0.1' for enterprise-tools in preperation for the kubernetes 1.36 support
- fix image push in local registry
- fixed duplicated coredns in 1.36.1
- updated kosi versions for consistent installation
- updated Harbor ImagePullSecret with 127.0.0.1 instead of master1 IP
- remove hardcoded plugin versions in cluster prepare node
- fixed a bug in rook delete section
- fixed a bug in nginx ingressclass for traefik
- added default secret for grafana
- added role bindings for the kubevirt roles
- fixed delete ingresses in update process 
- OpenSearch users created in the Dashboards Security UI now persist across package updates 
- OpenSearch TLS certificates are no longer regenerated on every install/update, preventing certificate rotation on running clusters 
- Fixed OpenSearch SSO returning 401 Unauthorized by reliably applying the openid security configuration to the backend after deploy 
- Added a Keycloak protocol mapper so realm roles are propagated to OpenSearch for backend role mapping 
- Added Single Sign-On (SSO) with Keycloak (OpenID Connect) for OpenSearch and OpenSearch Dashboards 
- Added username/password fallback authentication for OpenSearch alongside SSO 
- Made the OpenSearch admin password configurable via the new `adminPassword` package value (opensearch-os & opensearch-dashboards) 
- Added `hostname` package value for opensearch-os to point OpenSearch at the Keycloak SSO endpoint 
- Refresh the Keycloak admin token before each step of the OpenSearch Dashboards OIDC join so long-running joins no longer fail with 401 once the 60s token lifespan is exceeded
- fixed an error in OpenSearch when it was not installed in the `logging` namespace
- fixed an issue in kubeopsctl where `tools-values.yaml` and `cluster-values.yaml` were not always stored as secrets in the cluster
- changed the netpols for traefik-nginx and ingress-nginx to make the dashboards available
- helm-plugin now parses the flags correctly in all possible actions (install, upgrade, delete)
- fixed missing kosi update on nodes, if packageRepository: local
- fixed missing opensearch-dashboards plugins and wrong version
- template network policies with default deny rules
- when installing the tools, apply cluster- and tools-values

Known Issues

Versions KubeOps 2.2.0_Beta1

Tool App Version Chart Version Package Version SHA256 Checksum
kernelmodules kubeops/kernelmodules:2.2.0_Beta1 476f5be30871160d6fef47f791f601f7a090a988dc0dd86de3c237b5aa5ef986
sysctl kubeops/sysctl:2.2.0_Beta1 3361e60dc684be44da3fbf6da355074219c4d03006a77445ec26b524f61ce83e
disable-swap kubeops/disable-swap:2.2.0_Beta1 e7fffe5cb73f9079c5d591293ba6b324314bd579c14dc4ff9a9866c356d11c09
runtime-setup kubeops/runtime-setup:2.2.0_Beta1 08c5d65c06522ef7a96f9218f9cced7969baf1a77170c922dd582c515a767c78
kubeadm-init kubeops/kubeadm-init:2.2.0_Beta1 a42cb150cfd8b722c54736951b1008ef28a52972dd448b03e2b473d8db868f75
local-registry kubeops/local-registry:2.2.0_Beta1 cd184da0d8963c7afa0226b452d5c90223d6c74a51430141f3545f9c1b13f4c2
load-balancer kubeops/load-balancer:2.2.0_Beta1 ee9bf297c642b35e64da3a2ff5b6351a784afd4a50289affdeb881b0fca6a614
initial-controlplane kubeops/initial-controlplane:2.2.0_Beta1 3eeca78df9a2936886a8de3fd34bcd6f13e863a17219e7f971a58f8c1a7bae79
clustersetup kubeops/clustersetup:2.2.0_Beta1 823088a03fa9a79e1098ca79df305fec2a2f40f65c8727d9d2125b99c4adac9d
kubernetes-cni kubeops/kubernetes-cni:2.2.0_Beta1 a95ce6f24430a419541a747d48d7e8647eb970c21f73ffc632e676b6577c9288
join-controlplane kubeops/join-controlplane:2.2.0_Beta1 cce1d2f21ed4fdb5cd5bd8af33a3a17bc63a5b6cf6b2ba8fbaa078f5675c0151
join-worker kubeops/join-worker:2.2.0_Beta1 8ce7e876cd88c6db2ae189d666c1e1cb6dabad09e1ea7e5131bcc852112b4b20
pull-packages kubeops/pull-packages:2.2.0_Beta1 2c1ab9b35d0c56a027471ec83da24a6bdcb1184005a03877aff04379b7ecd13c
prepare-node kubeops/prepare-node:2.2.0_Beta1 9d197abcb9c845f47f6220e44b4be3d7af45e5c06c0ae9734001bd677f338dab
firewall-setup kubeops/firewall-setup:2.2.0_Beta1 2ec1d78c693956e2bf7617d9b8cf695ecfc41c259e45f03e3fc59039f9428483
kube-vip kubeops/kube-vip:2.2.0_Beta1 21db077376cb1c69d6ada941aae9174a479fdbd5e397e8757a1034391a3bc0c6
delete-node kubeops/delete-node:2.2.0_Beta1 6745ba0018a95682a203205313ba5680d23cf26ac2e2b9263eaad2e372c77a4a
auditlog kubeops/auditlog:2.2.0_Beta1 a513f525362fd69bdd82f006f4cda1498ffb32fdd91c079a9a4a90c27475943a
kubeadm-upgrade-initial-controlplane kubeops/kubeadm-upgrade-initial-controlplane:2.2.0_Beta1 240d9754f3221347c352cafbde7d84a818c6a384913626825712f94c6bd04b55
kubeadm-upgrade-nodes kubeops/kubeadm-upgrade-nodes:2.2.0_Beta1 3bfaa2a1142318c3fce2212ef183313dc03d57435e84e4d86f3ede042e32c4a7
kubernetes-tools kubeops/kubernetes-tools:1.30.8 ee9e8e41552be2d90f1f19700c251fd77fe01da31eabec6a3fcab318b01ceb2c
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.30.8 2677d909cd257c0b75de2d4bd9e9d198148310a9ecbbca384996700a54d3a9df
kubernetes-tools kubeops/kubernetes-tools:1.31.6 0af110107067c17851375742d301f1da68aac2f732b626f8210ece17e17fd30b
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.31.6 41ac4282be31a9127ca403be3d0f03bab912e16e66f05febb506479574b3c4f1
kubernetes-tools kubeops/kubernetes-tools:1.32.2 9ddc947d61b69ff6121809d016411ffe50732a78b760e5d307f03dc24294e8da
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.32.2 0b6c07788c320786b5f7cce1c809bd7305e28fecb804c223fc9b1dae6ee7bb1b
kubernetes-tools kubeops/kubernetes-tools:1.32.9 5587a13d33096c92f52ced4947815c44554a82a49091dd9d78c8eaa065534f7c
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.32.9 e4c34ddf29889d6a8f9075752a61a61fc62b7b7efa5e981d0d4ccbfc5cc1a939
kubernetes-tools kubeops/kubernetes-tools:1.33.5 2598dd0c50a7f1d38f1929f34bbfe0ce7efccb614b9f48d417c9285cb3e1b949
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.33.5 1f6000a20f57c17cf8c229269cb4c3abf076f68f336234d79dbb24656f4190f2
kubernetes-tools kubeops/kubernetes-tools:1.34.1 69ea34b7768e8de460f75b6a165a63b8de3e032d584fd43c4da87474d2e046ca
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.34.1 32f294ab19e6a2b3769044a728c0d6a4bebeb1d393aee061d68ebef0a7c83b2b
kubernetes-tools kubeops/kubernetes-tools:1.35.0 00fdeb8f3816b04661c9d866c89a3fa79dd743c1989709a7d7ff581010b9d7e6
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.35.0 64e3c2fbc81d2973cc28d05cc517687570c07d8b3a9194fe0ee33455669efc58
kubernetes-tools kubeops/kubernetes-tools:1.36.1 2b4ce27d375937f71b1760e93e19668de5e3c594ab332521cf7c1109560f0e34
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.36.1 079962600f3b361904d4972b6c59c10396630f62da0a33e6d1889142a10a0540
calico v3.29.1 v3.29.1 kubeops/calico:v3.29.2 3d492518bb31ad078f9e6e091ff2d22e43cac5a8b3f84c127571a1545a891833
calico-airgap kubeops/calico-airgap:v3.29.2 5923f633ea4136a64f0c0ddf56069b109704b61e542a530378a686292b4d034c
cilium 1.18.2 1.18.2 kubeops/cilium:v1.18.3 5451104fd9703d6039b6d6da6912bca5db62d9942f24b76549314a27774f0459
cilium-airgap kubeops/cilium-airgap:v1.18.3 a334071a23cdd2330ea2c723993e18822522c900481fabe7f1ee12b4c849f5ab
multus kubeops/multus:snapshot-thick2 3585956f2b1b1687ba01f2592682fda07dd34005f169666cc815a289b9945130
multus-airgap kubeops/multus-airgap:snapshot-thick2 746eee2272ab13281d7540a21d696226e806c0d13380fdcce554564c7b84e709
wireguard-tools kubeops/wireguard-tools:v1.0.20210914 70a49e1fec74e5c6b977e40264e1a084cd2f25d38a9df034141a9e165aea0f8c
helm kubeops/helm:v3.16.4 8e2def3efd54f2d149235e3ef71116c37514f7dcda81e8c793e081120c16f323
podman kubeops/podman:5.2.2 faa2ca5552df3cf46da6b0c4afc55220bb751e59319c1157e7f3652479bde4e4
ingress-nginx 1.15.6 4.15.6 kubeops/ingress-nginx:2.2.0_Beta1 d9db2892127d3dd895439854c33d0ee7aa6c8280b134e34c0db34bb292a70128
cert-manager v1.18.2 v1.18.2 kubeops/cert-manager:2.2.0_Beta1 2f146fdfc04ed39454d606ac0fdbaef792c9c414c8ae27a589b67320b442a528
opa-gatekeeper v3.17.1 3.17.1 kubeops/opa-gatekeeper:2.2.0_Beta1 ac240161a7e1bcbc7ae62baa9d8af038d01725d6e0a580229730aaa10436a3bf
velero 1.16.2 10.1.0 kubeops/velero:2.2.0_Beta1 b9cf523e5d84b5aba7cf70a106fb38036abfd3182bee0f4b1fbf8450256d3ac9
rook-ceph v1.15.6 v1.15.6 kubeops/rook-ceph:2.2.0_Beta1 8507a3890439307573305c3412ed8a0605d89502b295c2933f5ff0ab3c691784
rook-ceph-airgap kubeops/rook-ceph-airgap:2.2.0_Beta1 63ba9218f2947992fb0878afe645d349c6d7c3c22e6f0c91ea9e2fad43f05101
harbor 2.14.0 1.18.0 kubeops/harbor:2.2.0_Beta1 bed605d28b7ab75076aff6e9cdd4c84e694897fa8b4b8537e515042740a04664
harbor-airgap kubeops/harbor-airgap:2.2.0_Beta1 5f11608c2056e38615655568b53112a3d5436b12c0cf9e6b457f5ea3884d8b70
kube-prometheus-stack v0.85.0 77.0.2 kubeops/kube-prometheus-stack:2.2.0_Beta1 72690ac02de26e89fd22ab5c87ce4cf16b0d6f1e3bfa9c3abf626eb2f91556e6
keycloak 16.8.0 1.2.0 kubeops/keycloak:2.2.0_Beta1 fc50a1ed40b6ec5c57793f0ae5841565925794c4508a9be9fa7351aec0f506d7
kubeops-dashboard 0.26.0 0.26.0 kubeops/kubeops-dashboard:2.2.0_Beta1 ac2e1f7230adc914ec89c5d0ade57aacf917a2aa388b8897126ff7fcf0add526
filebeat-os 8.5.1 8.5.1 kubeops/filebeat-os:2.2.0_Beta1 28e96f41bb3869a2cc360aed2117dc4a60dba115c62f74ef8016334a50b0c9ce
logstash-os 8.4.0 8.4.0 kubeops/logstash-os:2.2.0_Beta1 d73fbac1760df25e7428cb717378fe3e38d98ac7c8f866e025fa9cb1eb7ec9c4
opensearch-os 3.4.0 3.4.0 kubeops/opensearch-os:2.2.0_Beta1 a11a77bb0e952c5269495720655004887ef939164fbe041fc9970c145b264b2a
opensearch-dashboards 3.4.0 3.4.0 kubeops/opensearch-dashboards:2.2.0_Beta1 316d7f0b3a5afa70e4822f1bddb0b14f579e4cd1fd54cb779ea9c0627f7489b9
traefik v3.6.7 39.0.0 kubeops/traefik:2.2.0_Beta1 b53231c94b4b72bdeee41f3dc44effb15937eb4ca78c864611b7fbca7413ed4b
kubevirt-manager kubeops/kubevirt-manager:2.2.0_Beta1 bff3c27b0fa086e1698472af19b5f7dc9f65be01de56c7f9982732418cffbb0c
kubevirt kubeops/kubevirt:2.2.0_Beta1 f569cd38ddeb894eeac4cf65f9758d1c8effc200ec214dcfe80ce569d5e34011

1.4 - KubeOps 2.2.0_Beta0

KubeOps 2.2.0_Beta0 - Release Date 30.07.2026

Changelog KubeOpsCtl 2.2.0_Beta0

Whats new?

- Added Traefik support for kubeopsctl
- Added Kubevirt-Manager support for kubeopsctl
- Added Kubernetes 1.36 support
- Added Advanced Parameters for static Registry mount path, check out the file format [Cluster Values YAML](/kubeopsctl-2.0/reference/fileformats/#cluster-valuesyaml)

Fixes

- fixed a podman bug affecting pull packages
- fixed a harbor bug setting up cluster
- added creation of nginx ingressclass, when installing traefik for backwards compatabilty
- fixed default secret for kubeops-dashboard
- kubeopsctl pull command now verifies if the specified tool value file exists
- Added kubeops-harbor-secret for pulling images from the internal private harbor project 'kubeops'
- fixed a bug that prevented to create the kubeops harbor project as private 
- fixed a bug that prevented to change the kubeops harbor project to private 
- fixed a bug that prevented the image push of the kubernetes images to local-registry 
- changed the 'localhost' reference to '127.0.0.1' for enterprise-tools in preperation for the kubernetes 1.36 support
- fix image push in local registry
- fixed duplicated coredns in 1.36.1
- updated kosi versions for consistent installation
- updated Harbor ImagePullSecret with 127.0.0.1 instead of master1 IP
- remove hardcoded plugin versions in cluster prepare node
- fixed a bug in rook delete section
- fixed a bug in nginx ingressclass for traefik
- added default secret for grafana
- added role bindings for the kubevirt roles
- fixed delete ingresses in update process 
- OpenSearch users created in the Dashboards Security UI now persist across package updates 
- OpenSearch TLS certificates are no longer regenerated on every install/update, preventing certificate rotation on running clusters 
- Fixed OpenSearch SSO returning 401 Unauthorized by reliably applying the openid security configuration to the backend after deploy 
- Added a Keycloak protocol mapper so realm roles are propagated to OpenSearch for backend role mapping 
- Added Single Sign-On (SSO) with Keycloak (OpenID Connect) for OpenSearch and OpenSearch Dashboards 
- Added username/password fallback authentication for OpenSearch alongside SSO 
- Made the OpenSearch admin password configurable via the new `adminPassword` package value (opensearch-os & opensearch-dashboards) 
- Added `hostname` package value for opensearch-os to point OpenSearch at the Keycloak SSO endpoint 
- Refresh the Keycloak admin token before each step of the OpenSearch Dashboards OIDC join so long-running joins no longer fail with 401 once the 60s token lifespan is exceeded

Known Issues

Versions KubeOps 2.2.0_Beta0

Tool App Version Chart Version Package Version SHA256 Checksum
kernelmodules kubeops/kernelmodules:2.2.0_Beta0 68d889dc1af5d7178ba726780002ef6d55632f8983cbde9bbeb6b62226d88715
sysctl kubeops/sysctl:2.2.0_Beta0 9383df73d75b712ba901a908a9164dcf2ee73c24816bc83ed6551576a67c3d48
disable-swap kubeops/disable-swap:2.2.0_Beta0 5a1649104ffd6eef6624a58c7f21f1afec0815b5ded7a377e03f0cb222cec6a9
runtime-setup kubeops/runtime-setup:2.2.0_Beta0 ebb23938d9adba0291efdd452df0a609495a62687d38564639e033d8af6a02ab
kubeadm-init kubeops/kubeadm-init:2.2.0_Beta0 e0cb5a6f290bfcef9d44af0777f2f5f7889973192dcca90af5591bc12915b3c0
local-registry kubeops/local-registry:2.2.0_Beta0 d8be4d7857acb6d4a934ed78f4d189006d7196dbe6b20c9c5641bdcf92c05ac0
load-balancer kubeops/load-balancer:2.2.0_Beta0 1b325d8da7f18dc31baff8f2be372e8c5e425dd30135238e791bfc21c416070f
initial-controlplane kubeops/initial-controlplane:2.2.0_Beta0 fd1f442342336d2d6c728dfe6b0da4e939701014f883042c370d7772df9eeeb8
clustersetup kubeops/clustersetup:2.2.0_Beta0 279fb5152212362d25d1a342d1f277bd231fb9a02f4726b14bcba1cbb0fc864f
kubernetes-cni kubeops/kubernetes-cni:2.2.0_Beta0 95925111bd30f34e620763567012991ade1bdb5f29636ca8591e8e5723f4c864
join-controlplane kubeops/join-controlplane:2.2.0_Beta0 6a4bdd593b15bcc1ca2d8a0283ae860287d17ebc7e83ca802847aa89f59c97b2
join-worker kubeops/join-worker:2.2.0_Beta0 2247094d87204722f2891db7599ebcd1bbdf581467b19d5ed2c2e22a31185086
pull-packages kubeops/pull-packages:2.2.0_Beta0 b4823f7c72cf684f442f9bc2363997f58cb582f36ac9ab0081dfc3842bedca57
prepare-node kubeops/prepare-node:2.2.0_Beta0 f02718afb5ce35561384bc8cda3d541dbf45dc2adfc8a87237813299c1f3adb9
firewall-setup kubeops/firewall-setup:2.2.0_Beta0 f23fb5a14ca317ad6b432c5331048e83176592fb648352df4c8739d73e2f80f1
kube-vip kubeops/kube-vip:2.2.0_Beta0 8c2076a66c589839c1c25da3311248da167a372abdea68d79e3b028691a27851
delete-node kubeops/delete-node:2.2.0_Beta0 f874d4d02b72a3e6d5bce8669df1aa203cb9a9f8caaabe96d67974e8bf115315
auditlog kubeops/auditlog:2.2.0_Beta0 c848ce79a3ab528a853efbcb671eaf1ff200db2319bb05fd167139b1ac31e9ba
kubeadm-upgrade-initial-controlplane kubeops/kubeadm-upgrade-initial-controlplane:2.2.0_Beta0 4506d301c855428cc929156715e3af1c61cba0a33e6d084472b011cf81a812e4
kubeadm-upgrade-nodes kubeops/kubeadm-upgrade-nodes:2.2.0_Beta0 736023f7a1924a40a82f01fc18db3688d114e4329c454970e8c90fd339b29c46
kubernetes-tools kubeops/kubernetes-tools:1.30.8 ee9e8e41552be2d90f1f19700c251fd77fe01da31eabec6a3fcab318b01ceb2c
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.30.8 2677d909cd257c0b75de2d4bd9e9d198148310a9ecbbca384996700a54d3a9df
kubernetes-tools kubeops/kubernetes-tools:1.31.6 0af110107067c17851375742d301f1da68aac2f732b626f8210ece17e17fd30b
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.31.6 41ac4282be31a9127ca403be3d0f03bab912e16e66f05febb506479574b3c4f1
kubernetes-tools kubeops/kubernetes-tools:1.32.2 f7d5191a269dacfa12ad867b28b01bb7a80f506b6b01950c8a34c358bb22c6e3
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.32.2 954093914536cb21f6e8b407bd568210992d59db7ce80464ce12dd49679f4c35
kubernetes-tools kubeops/kubernetes-tools:1.32.9 6baff46de7291b425f42d64d7563a3e3e11acf9abb27b1b8b467bab0fa3b0485
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.32.9 d421afe96680942236f1576f453a9685e99e93496c0ac9cc4d7a61c0dfcf2037
kubernetes-tools kubeops/kubernetes-tools:1.33.5 8b3e5ebbbfb8bdd4ce30990ab80f2a7ffadabeb0890f8fcf7f9365d9a3d2ef20
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.33.5 43960d74ba78ced9112aa5d46f58ffc053764a194e79631560b8ae79e17978ea
kubernetes-tools kubeops/kubernetes-tools:1.34.1 be69bc3240dda743b185b8922e42ef2a535b24d4a01e83162e24c702d2214fea
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.34.1 20bec465d22a385cf72de606a1a7ee599cc4b7e5cc81a7e7b7c4aecbb89606a0
kubernetes-tools kubeops/kubernetes-tools:1.35.0 ff2f7135ca0d3d1ecaa67d8463db4af75b06542024105c2b8fb6d0f02ddefc10
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.35.0 9d4b6dd4c9f9090ab8d20f1614f009b68c3479b07cdb347af57c3b5829932f05
kubernetes-tools kubeops/kubernetes-tools:1.36.1 ed52d7537780edd3c434f9233f875e1a59c73cc2b2b9426bc6f3d43a2ee2d079
kubernetes-tools-airgap kubeops/kubernetes-tools-airgap:1.36.1 e3d89e76f9924d27b7073353fb597442a23aeed8f8d797f5b76537acefb2e8da
calico v3.29.1 v3.29.1 kubeops/calico:v3.29.2 64c1c281c2a87b2a158fd182e14301a8bf6f19f9ea5b07aa8a5d5d7fe94d9698
calico-airgap kubeops/calico-airgap:v3.29.2 5923f633ea4136a64f0c0ddf56069b109704b61e542a530378a686292b4d034c
cilium 1.18.2 1.18.2 kubeops/cilium:v1.18.3 c4913943eaf2bea8e5fc75c57792866a28bbd64e577e6e2b7b049dda69d067f7
cilium-airgap kubeops/cilium-airgap:v1.18.3 a334071a23cdd2330ea2c723993e18822522c900481fabe7f1ee12b4c849f5ab
multus kubeops/multus:snapshot-thick2 186439bca4db89a9e23364bb77d000ccf906262d1db8d06716801563f9f9a72e
multus-airgap kubeops/multus-airgap:snapshot-thick2 5a7f258eca3d534f37547de3c8126fba2c3e5e885fb6710abd62f08f22ede6de
wireguard-tools kubeops/wireguard-tools:v1.0.20210914 a6a521dfef6a550a658a5626cb15ab935cb1bfff99f82a2ced7b21317ab12fed
helm kubeops/helm:v3.16.4 8e2def3efd54f2d149235e3ef71116c37514f7dcda81e8c793e081120c16f323
podman kubeops/podman:5.2.2 309d2cbae83687ef2bf151ad6486824348e807348bcd7cdadbecc1bc40db4f86
ingress-nginx 1.15.6 4.15.6 kubeops/ingress-nginx:2.2.0_Beta0 57640157dbe06f169ab3e6a770a97bc83fb35269096bff37db498c5309e60bd3
cert-manager v1.18.2 v1.18.2 kubeops/cert-manager:2.2.0_Beta0 80870509663ad76eca9d2ec7147f43d1a89e21f1e31cb273d8d534c48621a47c
opa-gatekeeper v3.17.1 3.17.1 kubeops/opa-gatekeeper:2.2.0_Beta0 dae0d519d56b4044c771105047df68c76db61df4e2660309714a118b220b88a8
velero 1.16.2 10.1.0 kubeops/velero:2.2.0_Beta0 0769402efb9aae7f0d3c404aa5123f01d2324b1db167717147da324978a4d199
rook-ceph v1.15.6 v1.15.6 kubeops/rook-ceph:2.2.0_Beta0 0d98891d643524020f7062db66b6142b56d95933e8c118c456c4f24fc74e888d
rook-ceph-airgap kubeops/rook-ceph-airgap:2.2.0_Beta0 de2379884bcc658660706aef4729917f5fe41e093c8d9f5098d17a3dc2dd48b3
harbor 2.14.0 1.18.0 kubeops/harbor:2.2.0_Beta0 34d3b20326be1be7e69d5242730394d4750c2b908378e543bc69b4d7a049db86
harbor-airgap kubeops/harbor-airgap:2.2.0_Beta0 406e9fe9e8a77d900f3126e93c215f82d8dbbb680554f7ce003ecb5dec5f5c4f
kube-prometheus-stack v0.85.0 77.0.2 kubeops/kube-prometheus-stack:2.2.0_Beta0 bc2c5da217a58fa67040535dfbdd50933ee6f84411e7162e6c3de366275aa3c7
keycloak 16.8.0 1.2.0 kubeops/keycloak:2.2.0_Beta0 a18016f2079eab2153a594f17bd0e91706eac6a264bbfabf4bd016d2e7148734
kubeops-dashboard 0.26.0 0.26.0 kubeops/kubeops-dashboard:2.2.0_Beta0 d4922db9d47c5569ae563a96d72524fa8a0e54b5e2578f1c71b91a5e214b484d
filebeat-os 8.5.1 8.5.1 kubeops/filebeat-os:2.2.0_Beta0 c98242a2488b0cd28782ba5435ca8bed6db6dc5a1d78625291192ad06a7db705
logstash-os 8.4.0 8.5.1 kubeops/logstash-os:2.2.0_Beta0 3e07746ce9b02d08ddcc65e111f64435c0603819ae197c14fa0516bf237826c7
opensearch-os 3.4.0 3.4.0 kubeops/opensearch-os:2.2.0_Beta0 755d96edd69433bbb2027833cea3768efc70ae717382b8dc89d2e290a18be3cf
opensearch-dashboards 3.4.0 3.4.0 kubeops/opensearch-dashboards:2.2.0_Beta0 c7dcf941550bd41945cb589721a37f98f2e4593eb4d47d29499e12fd4f9a38ca
traefik v3.6.7 39.0.0 kubeops/traefik:2.2.0_Beta0 a03d24eb8d153edcf4deefd8dd9a605be544e368018b9e9a0be06dcabe7579bf
kubevirt-manager kubeops/kubevirt-manager:2.2.0_Beta0 22b89ccbd8b15fafd8ce25e7ba1b3c4818b81785e8d07d7414f022a1d52757a7
kubevirt kubeops/kubevirt:2.2.0_Beta0 c41a51da0fa7cc21d1fa0f10914acb62e6473fb27c0e34b68d6f4e435c50f361

1.5 - KubeOps 2.1.0

KubeOps 2.1.0 - Release Date 16.06.2026

Changelog KubeOpsCtl 2.1.0

Whats new?

- Added Single Sign-On (SSO) with Keycloak for Rook-Ceph
- Added Single Sign-On (SSO) with Keycloak for Harbor
- Added Single Sign-On (SSO) with Keycloak for Grafana
- Added Single Sign-On (SSO) with Keycloak for KubeOps Dashboard
- Added Single Sign-On (SSO) with Keycloak for OpenSearch Dashboard
- Added Traefik for manual installation
- Added CloudNativePG operator for manual installation
- Added command kubeopsctl check-connections -f cluster-values.yaml
- Added check-connections before kubeopsctl apply
- Improved cert-manager package to install lets-encrypt-staging as inital CA for SSO support
- Improved harbor backup by adding pre.hook.backup.velero.io in harbor package
- Improved keycloak backup by adding pre.hook.backup.velero.io in harbor package
- Improved kubeopsctl apply no longer throws an exception when cluster-values.yaml is missing.
- Added Kubernetes 1.35 support

Fixes

- Implemented fixes for the following CVEs affecting the `rook-ceph` package:
    - CVE-2025-68121
    - CVE-2026-33186
- Implemented fixes for the following CVEs affecting the `ingress-nginx` package:
    - CVE-2025-68121
- Implemented fixes for the `keycloak` package:
    - A Keycloak bug has been fixed where the database was not persistent
- Implemented fixes for the `opensearch-os` package:
    - A bug has been fixed that prevented usernames and passwords from being retained after the upgrade

Versions KubeOps 2.1.0

Tool App Version Chart Version Package Version Package Version SHA256 Checksum
calico 3.29.1 3.29.1 kubeops/calico:v3.29.1 kubeops/calico:v3.29.1 023f1b1e11253ab70589cb4e9c5a5d292059de7a7a905e932d3c9b0d90bb3127
cilium 1.18.2 1.18.2 kubeops/cilium:v1.18.2 kubeops/cilium:v1.18.2 b839b0afbe0b194134fba1948e805e8356d2297ed55bf09f47e739174b021210
multus snapshot-thick kubeops/multus:snapshot-thick kubeops/multus:snapshot-thick a5a0760916e6656beb4970fd9f3fa5484449e4e28d26a2335cae0d65ebbd3ae0
ingress-nginx 1.15.6 4.15.6 kubeops/ingress-nginx:2.1.0_Beta0 kubeops/ingress-nginx:2.1.0 4b2d3ffc940873794be63354c56a1c5641cfeb57d962fb88394024451b60916f
cert-manager 1.18.2 1.18.2 kubeops/cert-manager:2.1.0_Beta0 kubeops/cert-manager:2.1.0 e2e8f3a37d134b0af3571328d657d39c04f18188ffe3d59095089d06f9f0a1ee
opa-gatekeeper 3.17.1 3.17.1 kubeops/opa-gatekeeper:2.1.0_Beta0 kubeops/opa-gatekeeper:2.1.0 43223ba76981d3a9de55830dbf20579c5048279311e7976d0380532cf5015fbf
velero 1.16.2 10.1.0 kubeops/velero:2.1.0_Beta0 kubeops/velero:2.1.0 86a4b333c0c31b870b9affcde72a472c086ebf223b91d9668caac4f63e45f53e
rook-ceph 1.15.6 1.15.6 kubeops/rook-ceph:2.1.0_Beta0 kubeops/rook-ceph:2.1.0 cbf0e6b797f9789405650dff04d0db37bb98aac8c617b79b8ffd8e0772afb243
harbor 2.14.0 1.18.0 kubeops/harbor:2.1.0_Beta0 kubeops/harbor:2.1.0 0d85a7e41d6605484b3e4522af4c557478c145016e6834b7e6b6b8db92bc5a60
kube-prometheus-stack 0.85.0 77.0.2 kubeops/kube-prometheus-stack:2.1.0_Beta0 kubeops/kube-prometheus-stack:2.1.0 1f5329359e6a1ec8dcc8765ccbde110278ae7837afec86085cbf34641745b7a3
keycloak 26.1.0 1.1.0 kubeops/keycloak:2.1.0_Beta0 kubeops/keycloak:2.1.0 443a678db05c0d8721fe7783a978126a862537b4a7699fcaa48499822593dae8
kubeops-dashboard 0.26.0 0.26.0 kubeops/kubeops-dashboard:2.1.0_Beta0 kubeops/kubeops-dashboard:2.1.0 ca6d057649f2cb101d79cc154ad7debee2e6bf8492e3574496c4b2cd896b3333
filebeat-os 8.5.1 8.5.1 kubeops/filebeat-os:2.1.0_Beta0 kubeops/filebeat-os:2.1.0 9895b4fa6a3ea52d3fea660edf83e0de6b3b597d819294e4ec13faa2a4e5ef06
logstash-os 8.4.0 8.5.1 kubeops/logstash-os:2.1.0_Beta0 kubeops/logstash-os:2.1.0 73b435a3e0d8f08f310a629504eb9be28c32a09143710811c0f0951a3253656c
opensearch-os 3.4.0 3.4.0 kubeops/opensearch-os:2.1.0_Beta0 kubeops/opensearch-os:2.1.0 9f7994400e0cd4f04fff9b72ee35d1e9031f4f4dbb238da4849e413ebe1716d4
opensearch-dashboards 3.4.0 3.4.0 kubeops/opensearch-dashboards:2.1.0_Beta0 kubeops/opensearch-dashboards:2.1.0 218c437c4776ff7360ac07699b0801018258392a266f1d65b05c15377f3f5b4c
traefik 3.6.7 39.0.0 kubeops/traefik:2.1.0 kubeops/traefik:2.1.0 172533bca8794382ec00557804ae4b3d3d80828f5ba7921d045df06a9d814c54

1.6 - KubeOps 2.1.0_Beta0

KubeOps 2.1.0_Beta0 - Release Date 13.04.2026

Changelog KubeOpsCtl 2.1.0_Beta0

Whats new?

- Added Single Sign-On (SSO) with Keycloak for Harbor
- Added Single Sign-On (SSO) with Keycloak for Grafana
- Added Single Sign-On (SSO) with Keycloak for KubeOps Dashboard
- Added Traefik for manual installation
- Added CloudNativePG operator for manual installation
- Added command kubeopsctl check-connections -f cluster-values.yaml
- Added check-connections before kubeopsctl apply
- Improved cert-manager package to install lets-encrypt-staging as inital CA for SSO support
- Improved harbor backup by adding pre.hook.backup.velero.io in harbor package
- Improved keycloak backup by adding pre.hook.backup.velero.io in harbor package
- Improved kubeopsctl apply no longer throws an exception when cluster-values.yaml is missing.

Versions KubeOps 2.1.0_Beta0

Tool App Version Chart Version Package Version SHA256 Checksum
calico 3.29.1 3.29.1 kubeops/calico:v3.29.1 063ca2d09ae26610bb386f3ba12a8bb3ecec2a0c52eb7d014a05bd6bed9461b7
cilium 1.18.2 1.18.2 kubeops/cilium:v1.18.2 240e7fd568976f26b885a26daa23c1a3f4c54552554abbf110d8bcef6005a0d0
multus snapshot-thick kubeops/multus:snapshot-thick f3112eb8e49b512033158c358190c6a833dfe4d47b0d2e9bf814946e6e140d5b
ingress-nginx 1.11.5 4.11.5 kubeops/ingress-nginx:2.1.0_Beta0 301c3c4e9d6a1075b467bd1c01c755479b208b126e9b15c48eb0f330e4a4956d
cert-manager 1.18.2 1.18.2 kubeops/cert-manager:2.1.0_Beta0 40bb60bd217624bbdce7499bdd083389f3ce86d858f5eba2ef887d9e2430917b
opa-gatekeeper 3.17.1 3.17.1 kubeops/opa-gatekeeper:2.1.0_Beta0 643b161981306bd847576e22a09be93fdd51eb99cee59d185067519910cd9001
velero 1.16.2 10.1.0 kubeops/velero:2.1.0_Beta0 3aa92d0b07c0110cd7a5ed67c3f4af27f024f802f1ae4140521543831980485e
rook-ceph 1.15.6 1.15.6 kubeops/rook-ceph:2.1.0_Beta0 49f64bdfb4a7e190aa3d9e242ce3408ae64a8c21736eb71822cf61bceb651cf2
harbor 2.14.0 1.18.0 kubeops/harbor:2.1.0_Beta0 7ecbebb32bc8695054d25f39763970155f678e848578a05dcc02110a2497b4f4
kube-prometheus-stack 0.85.0 77.0.2 kubeops/kube-prometheus-stack:2.1.0_Beta0 7e5e6af94b47af9039cce293404762e6de2644de8b0e4fc8e2ebb5a2864ba9b8
keycloak 26.1.0 1.1.0 kubeops/keycloak:2.1.0_Beta0 8553fd9ed05918048406eb8171b30c4963a14bdbd032c7fdd2b29dbf25bdd190
kubeops-dashboard 0.26.0 0.26.0 kubeops/kubeops-dashboard:2.1.0_Beta0 7648148ce645549a1e1de2b32635c0be7e1197f1c472309f2ecd4f17a6e83a65
filebeat-os 8.5.1 8.5.1 kubeops/filebeat-os:2.1.0_Beta0 e5a6256481fa09f3a1a8e69633ab62c0fa97aff5eb67c780e6f857daa9d06636
logstash-os 8.4.0 8.5.1 kubeops/logstash-os:2.1.0_Beta0 0b31b98cdcded952d0f7d52b8c0a4cc51877b4869853c7944021b067d9bd6586
opensearch-os 3.4.0 3.4.0 kubeops/opensearch-os:2.1.0_Beta0 cdb0822b62241306a94e951d2b3e4b7f1a959626eaa53dc61a2e5e5d07b788df
opensearch-dashboards 3.4.0 3.4.0 kubeops/opensearch-dashboards:2.1.0_Beta0 838d51f87aee3d005fa5ae8c2a832b27a3c4cf8fcce66048adc989bad0595ca8
traefik 3.6.7 39.0.0 kubeops/traefik:2.1.0 fe0af58d4d1de42cc1f05d11ed87495ea837ff1bf7dfc28a29aed721b72bb559

1.7 - KubeOps 2.0.5

KubeOps 2.0.5 - Release Date 08.05.2026

Changelog KubeOpsCtl 2.0.5

Fixes

- Implemented fixes for the following CVEs affecting the `rook-ceph` package:
    - CVE-2025-68121
    - CVE-2026-33186
- Implemented fixes for the following CVEs affecting the `ingress-nginx` package:
    - CVE-2025-68121
- Implemented fixes for the `keycloak` package:
    - A Keycloak bug has been fixed where the database was not persistent
- Implemented fixes for the `opensearch-os` package:
    - A bug has been fixed that prevented usernames and passwords from being retained after the upgrade
- Implemented fixes for RHEL:
    - A bug has been fixed that prevented users from using a repository other than “kubeops-repo”

Versions KubeOps 2.0.5

Tool App Version Chart Version Package Version SHA256 Checksum
calico 3.29.1 3.29.1 kubeops/calico:v3.29.1 360d735dd32e80137e8d4b457888a278fe749265e8c068fbae2c2848f0e3293a
cilium 1.18.2 1.18.2 kubeops/cilium:v1.18.2 0877aede4d94c659632eeb70a234cc92054a0b8b31d1c78ed5a6ce2b22879b10
multus snapshot-thick kubeops/multus:snapshot-thick 4656121cbedff935e204a57000d3221504063e2aea7dbb393fa7bce21891cebe
ingress-nginx 1.15.6 4.15.6 kubeops/ingress-nginx:2.0.5 c38d6b97181121efdb423fb6df7a652e37a0b569bd04fd89b2299ddf34514ff4
cert-manager 1.18.2 1.18.2 kubeops/cert-manager:2.0.5 263de2b0ac45dc8b1510ccae22afdb2a8ef891695a017bf8bb2dce632dc507f6
opa-gatekeeper 3.17.1 3.17.1 kubeops/opa-gatekeeper:2.0.5 038f5de87686465af446b85833f4e5988272df38253a8a4c776ffd2080df430c
velero 1.16.2 10.1.0 kubeops/velero:2.0.5 4abd94e3f90b718bd1aec80bd68920f55256c8bca5650c2f9e39c5b9d15ffd36
rook-ceph 1.15.6 1.15.6 kubeops/rook-ceph:2.0.5 c13723f7b5359c099499b136527d5e2cc80ee4d436d29b4422a2b4738ceac27e
harbor 2.14.0 1.18.0 kubeops/harbor:2.0.5 0a3253f8544b6946536ff325c1402635ee3d8b8fe930e791f008471da6e0c7e9
kube-prometheus-stack 0.85.0 77.0.2 kubeops/kube-prometheus-stack:2.0.5 b5c655a935e50b0b80459ea9010d92f16684bcd39abfe3b44cb29eae285f16f0
keycloak 26.1.0 1.1.0 kubeops/keycloak:2.0.5 0fda8de91ac6855430194b89fe90e729466be56b5f25c2370da1e9cdb557186b
kubeops-dashboard 0.26.0 0.26.0 kubeops/kubeops-dashboard:2.0.5 71ab5b8405d5b3bcfa86ee6f53d6358fc2f329fcfa1106bbef6339b55646fa95
filebeat-os 8.5.1 8.5.1 kubeops/filebeat-os:2.0.5 3d7809cb0fc176c049652f0b6d5300e34d9b88411391b3f33c95b956c98cb276
logstash-os 8.4.0 8.5.1 kubeops/logstash-os:2.0.5 2b3550913405f51db18f491e3f268921c54efd6483a7e9463126a47f7cfebc4e
opensearch-os 3.4.0 3.4.0 kubeops/opensearch-os:2.0.5 52ea3777bd5d1c6bdc9a26237de53cac7205d7c84c824df4bf1f5cf19a526a6b
opensearch-dashboards 3.4.0 3.4.0 kubeops/opensearch-dashboards:2.0.5 794b8a658a79729cd4589b9c364c9a7c2739247c8391ca8c364b847d9a4fe10c

1.8 - KubeOps 2.0.4

KubeOps 2.0.4 - Release Date 02.03.2026

Changelog KubeOpsCtl 2.0.4

Fixes

- Implemented fixes for the following CVEs affecting the `harbor` package:
    - CVE-2025-27151
    - CVE-2025-49844
- Implemented fixes for the following CVEs affecting the `opensearch` package:
    - CVE-2025-68428
    - CVE-2025-9288
- Implemented fixes for the following CVEs affecting the `opensearch-dashboards` package:
    - App Version 3.4.0, Chart Version 3.4.0
    - CVE-2025-68428
    - CVE-2025-9288

Versions KubeOps 2.0.4

Tool App Version Chart Version Package Version SHA256 Checksum
calico 3.29.1 3.29.1 kubeops/calico:v3.29.1 731447b3b231258dd636d4a9bd1e96da406c148231c434e21acaab492b00000f
cilium 1.18.2 1.18.2 kubeops/cilium:v1.18.2 240e7fd568976f26b885a26daa23c1a3f4c54552554abbf110d8bcef6005a0d0
multus snapshot-thick kubeops/multus:snapshot-thick cc929a5013323247027bb83f3f9b266fc0e4240c6e00cd2c8898a3796b4783bc
ingress-nginx 1.11.5 4.11.5 kubeops/ingress-nginx:2.0.4 01a5426de06f5b3610c36238fc3d6d60c05d167ad367ed94e11d1851ca7d13bb
cert-manager 1.18.2 1.18.2 kubeops/cert-manager:2.0.4 72674b1a96372d5d69ed11da55d6060ba39af3dc496d4844ae98c2ad841f3f2a
opa-gatekeeper 3.17.1 3.17.1 kubeops/opa-gatekeeper:2.0.4 d7a4616f25de303af5d1aabba57998e1bce6d735375819cc1a002d70453c03e6
velero 1.16.2 10.1.0 kubeops/velero:2.0.4 ccea73765c3aff7d84412fed5fa648c5ccfd26f269192c62f970e862b64682d7
rook-ceph 1.15.6 1.15.6 kubeops/rook-ceph:2.0.4 527582b5b7e24fd3451ae89564decf103559ee90f4048ab89f7f9aedfe98fe52
harbor 2.14.0 1.18.0 kubeops/harbor:2.0.4 56b5895e92f156966b7da487e1b7c5af44b25ce05ae98ac9cca9fe9197f1642c
kube-prometheus-stack 0.85.0 77.0.2 kubeops/kube-prometheus-stack:2.0.4 007256619efe07a33b9311b3ee16431ed4d729f9a4d69e1a9cb8f9947a8e829c
keycloak 26.1.0 1.1.0 kubeops/keycloak:2.0.4 833c4c807f2ffb006fb4731032c868428414214733984b826d65e5f0a504e47c
kubeops-dashboard 0.26.0 0.26.0 kubeops/kubeops-dashboard:2.0.4 0a78fa678e75897283f7a31972da7bca20d8d575d2ef459e0ccdc5c7bbe2847a
filebeat-os 8.5.1 8.5.1 kubeops/filebeat-os:2.0.4 95566a08d33c2a2be0ce89610d397ba85eb4957cc07373e4c258f19aa1f2c2a9
logstash-os 8.4.0 8.5.1 kubeops/logstash-os:2.0.4 0612a97608fe909db99ec5ec8a7ac745cdb3e8a43b792db1234b241d827da978
opensearch-os 3.4.0 3.4.0 kubeops/opensearch-os:2.0.4 312252b352681f086382e6de32439aa19872a03db040b3719ee9f4302d899154
opensearch-dashboards 3.4.0 3.4.0 kubeops/opensearch-dashboards:2.0.4 4096038e5c53d7b7cbf7def0c8cae20cf397b7c7e07c0daa8446fc5bcc1f2a7a

1.9 - KubeOps 2.0.3

KubeOps 2.0.3 - Release Date 10.02.2026

Changelog KubeOpsCtl 2.0.3

Fixes

- Implemented fixes for the following CVEs affecting the `ingress-nginx` package:
    - CVE-2025-15467
    - CVE-2025-49794
    - CVE-2025-49796

Versions KubeOps 2.0.3

Tool App Version Chart Version Package Version SHA256 Checksum
calico 3.29.1 3.29.1 kubeops/calico:v3.29.1 224fd0a2cdaf2ffc3089d425dc2ecac65fdd184e413327ebaf35c3929613a058
cilium 1.18.2 1.18.2 kubeops/cilium:v1.18.2 240e7fd568976f26b885a26daa23c1a3f4c54552554abbf110d8bcef6005a0d0
multus snapshot-thick kubeops/multus:snapshot-thick 2540b63b999e19a64ba46f344ac8071eef47b2822c58f448f7bf61608b175d20
ingress-nginx 1.11.5 4.11.5 kubeops/ingress-nginx:2.0.3 0015a7834927f44e6c8189c812cae8d80256a063906ab75575e44f4e8702fe55
cert-manager 1.18.2 1.18.2 kubeops/cert-manager:2.0.3 0a7080c78e7ab2e7f5dcd58f527584acde06a1b9133313a983eef5a6b242e214
opa-gatekeeper 3.17.1 3.17.1 kubeops/opa-gatekeeper:2.0.3 9a4bee58e844e81eeb9626c46cc98a937944ddca71cfd2920540151050f370a3
velero 1.16.2 10.1.0 kubeops/velero:2.0.3 4d9dddf792da3d6b006c055fc39ded8b9deef8c7ab1a2ee42cf82417eac42396
rook-ceph 1.15.6 1.15.6 kubeops/rook-ceph:2.0.3 c295552e8cc95aa2ae7096df432dc4994be6fb25b2c232faeb25a3c4e111024b
harbor 2.14.0 1.18.0 kubeops/harbor:2.0.3 61ed12ef089dd1a41fc92dfa3b7c3bff4456714a887f19b8c51b23f5f70b088b
kube-prometheus-stack 0.85.0 77.0.2 kubeops/kube-prometheus-stack:2.0.3 b913de20a11ca60fbadd77afc96acd86d6fe0761542135f27cc6eed5e2e68586
keycloak 26.1.0 1.1.0 kubeops/keycloak:2.0.3 f4c8c128e7b56f9b2f2c5e9f9832f3f1c0851dbc0f25edda294d878b70a5a4ca
kubeops-dashboard 0.26.0 0.26.0 kubeops/kubeops-dashboard:2.0.3 d63622486637461363b493dd8932ddc2837d90559e2309f7e28df3fa9a7d69b1
filebeat-os 8.5.1 8.5.1 kubeops/filebeat-os:2.0.3 a07b624662376686a01706de217a5a363ade166dfd5d7637b6c0a8b658aeb5b7
logstash-os 8.4.0 8.5.1 kubeops/logstash-os:2.0.3 bf005cca685c5a07a937ec05bc3a8232bf487b60d9353738da9c836309f081ea
opensearch-os 3.2.0 3.2.1 kubeops/opensearch-os:2.0.3 ed21dec3970d2be84e6f726463e80fef8f45f978353bcd125458c34253b13b85
opensearch-dashboards 3.2.0 3.2.2 kubeops/opensearch-dashboards:2.0.3 3611891a888411215421d1518e27a488cbded4155d49d3bf2ae139a4aa88a754

1.10 - KubeOps 2.0.2

KubeOps 2.0.2 - Release Date 28.01.2026

Changelog KubeOpsCtl 2.0.2

Whats new?

- Added --delete-emptydir-data while draining nodes
- Added Repo support for the KOSI installation packages

Fixes

- Fixed a bug where imagePullSecrets were not created

Versions KubeOps 2.0.2

Tool App Version Chart Version Package Version SHA256 Checksum
calico 3.29.1 3.29.1 kubeops/calico:v3.29.1 3f13159164357f15b2efee927606287dd121f7ec314445c9f6c18e9ae36bc76d
cilium 1.18.2 1.18.2 kubeops/cilium:v1.18.2 eeaf1821ad86d5b59b238c452f31203a2c6d13a027ec270b0984b83a687bbdd6
multus snapshot-thick kubeops/multus:snapshot-thick a07721b3290b4086e76baad09ef981a0eae0b1cc85973a63dfa3df3c01f49027
ingress-nginx 1.11.5 4.11.5 kubeops/ingress-nginx:2.0.2 8e69acc30431cd6f4c92a99dd3e045e32e1214c1c78e8529805960c4b5aca423
cert-manager 1.18.2 1.18.2 kubeops/cert-manager:2.0.2 68976f9bc78d0f590d35d89a33ce65a3fe72a3e83c87f6deecd84bbbbd887e38
opa-gatekeeper 3.17.1 3.17.1 kubeops/opa-gatekeeper:2.0.2 dbc6cad41ca2d9e7c735b2ab2f4383848c62281fe965eb9868e702c3f14e2273
velero 1.16.2 10.1.0 kubeops/velero:2.0.2 7fa039bcf55e2c74b7fda3dbe74282bd2cc262fd443e3ce29ffec6b776864d05
rook-ceph 1.15.6 1.15.6 kubeops/rook-ceph:2.0.2 27b32b7fefb4f0ef8d2c03c53ff0c1cc0c7dd97896e1514b360b826a3a8e0337
harbor 2.14.0 1.18.0 kubeops/harbor:2.0.2 08dcc31bdba365729bf28ba783fed905abd05b822ed0e212b148063356729240
kube-prometheus-stack 0.85.0 77.0.2 kubeops/kube-prometheus-stack:2.0.2 9b9a5be156845c36f56f228cf66c7bd0be8139e72a55bccb83165aba3a5200cd
keycloak 26.1.0 1.1.0 kubeops/keycloak:2.0.2 c8d302be6f6b9c51c54cbb93f55c51d3f5498a14fd73f5f243810e557be7dd03
kubeops-dashboard 0.26.0 0.26.0 kubeops/kubeops-dashboard:2.0.2 eebff5aa0618f0d4b7b709c31cf9fe2c3999a14641758baf2abdf91daabd259e
filebeat-os 8.5.1 8.5.1 kubeops/filebeat-os:2.0.2 0b62b3a7a3fcda8d856e10fcb382803dd962062a22f68877b6f6ce7a92d10aca
logstash-os 8.4.0 8.5.1 kubeops/logstash-os:2.0.2 a214f06de5b0d1b23ef11dd8d7c5ad4c7452e85c8038bfc62e11cd62b515cd78
opensearch-os 3.2.0 3.2.1 kubeops/opensearch-os:2.0.2 00d4fa640e3fe895e628d749c0b2c4b4bb90f2e38b0768c70351d73029dc491c
opensearch-dashboards 3.2.0 3.2.2 kubeops/opensearch-dashboards:2.0.2 753d224de4d28ca6dae774156043da087a05645f05770edf1b6a8c5ac6903197

1.11 - KubeOps 2.0.1

KubeOps 2.0.1 - Release Date 22.12.2025

Changelog KubeOpsCtl 2.0.1

Whats new?

- Supports KubeVIP
- Supports Ubuntu 24.04 LTS
- Supports RHEL 9.6
- Supports Cilium CNI
- Reworked Cluster creation process
- Reworked Cluster upgrade process
- Reworked Compliance application installation process
- Reworked Compliance application update process
- Introduced new value format for cluster-values.yaml
- Introduced new value format for enterprise-values.yaml
- Introduced selfcontained air-gap packages
- Improve the Cluster creation process
- Improve the Cluster upgrade process
- Improve the Compliance application installation process
- Improve the Compliance application update process
- Improve the Cluster creation/upgrade speed
- Improve the Compliance application installation/update speed
- Updated opensearch package from 1.7.6 to 2.0.0
- Updated opensearch-dashboard package from 1.7.6 to 2.0.0
- Updated velero package from 1.7.6 to 2.0.0
- Enterprise packages are only pulled if they are marked as `enabled: true` in the enterprise-values.yaml

Fixes

- "Delete Node" now works over multiple zones
- An invalid cluster-values.yaml is now caught before cluster creation
- If no helm chart is installed the cluster creation process will still run through
- Harbor: fixed missing template for hostname
- nginx-ingress: updated netpols
- opensearch-dashboard: changed issuer to cluster-issuer
- airgap-packages are pulled from locally installed harbor registry instead of public registries

Known Issues

Versions KubeOps 2.0.1

Tool App Version Chart Version Package Version SHA256 Checksum
calico 3.29.1 3.29.1 kubeops/calico:v3.29.1 2f0d00e78a88c52aa057e9257fcbb16015466262e6f464b046af97bc46c039d5
cilium 1.18.2 1.18.2 kubeops/cilium:v1.18.2 240e7fd568976f26b885a26daa23c1a3f4c54552554abbf110d8bcef6005a0d0
multus snapshot-thick kubeops/multus:snapshot-thick 6904c4d157ac5d6ebc956a65affd27a9a11bd64da42cedd600f720789e6cc59c
ingress-nginx 1.11.5 4.11.5 kubeops/ingress-nginx:2.0.1 8b6422ae30448795138b3b939bbb9d86340d11517a9c48ce0d547d5c042aacc2
cert-manager 1.18.2 1.18.2 kubeops/cert-manager:2.0.1 599954bb8bbc400f4e5b4b5772db5269bf511aa6f3f52458fe9dfa724ff02663
opa-gatekeeper 3.17.1 3.17.1 kubeops/opa-gatekeeper:2.0.1 ffdd6ccb5c2237f612e59501f3c5dfc89918de9a77d0fe6f6b138d0981bed5f3
velero 1.16.2 10.1.0 kubeops/velero:2.0.1 c867e0fcd13b82012317b09db5fd8754578e1c6ae3a9b4511c290de3f9aadafd
rook-ceph 1.15.6 1.15.6 kubeops/rook-ceph:2.0.1 f931a3556173739d88199b841e3ff3ac34df1e63303e4ae482eff1bd7465061d
harbor 2.14.0 1.18.0 kubeops/harbor:2.0.1 fe08c1caa8ef1e21ef92c6927bbd8f160567e62d249a5a7d34cf24c0d6bc12cf
kube-prometheus-stack 0.85.0 77.0.2 kubeops/kube-prometheus-stack:2.0.1 4ef5d140ce2fdffad7ba3d51cf408746d64938b23d6b9b46c2182792fdb06850
keycloak 26.1.0 1.1.0 kubeops/keycloak:2.0.1 bc65c71135066eb22298109aa4f573b1b4115c11df1ed0bc995b9f4668d64a47
kubeops-dashboard 0.26.0 0.26.0 kubeops/kubeops-dashboard:2.0.1 7f795a2bc689b8ccbb2bc6a6dfbc40af28bbeed40a9cb5fec26469708687ce43
filebeat-os 8.5.1 8.5.1 kubeops/filebeat-os:2.0.1 6eb2098040870ca6539411b77d1ecb5c4606198ea6cad9e7c6f1173da69ba1f0
logstash-os 8.4.0 8.5.1 kubeops/logstash-os:2.0.1 20095b5d51eee351f26888dfe33ed90ae88571f5b9c6c3827ae0e2bb86aa68f7
opensearch-os 3.2.0 3.2.1 kubeops/opensearch-os:2.0.1 38273e01aff56dbd730509dbab86ac5206d920c4a10f64d99c8935acf95e5490
opensearch-dashboards 3.2.0 3.2.2 kubeops/opensearch-dashboards:2.0.1 7861cd97d6e7adc85f78e4907b9b2caf587667894e3f53ad1e0ca5695280d144

2 - Getting-Started

Begin your exploration of KubeOps Compliance, diving into its robust capabilities and streamlined workflow for Kubernetes infrastructure management.

2.1 - About KubeOps Compliance

This article will give you a little insight into KubeOps Compliance and its advantages.

What is KubeOps Compliance?

kubeopsctl serves as a versatile utility designed specifically to efficiently manage both the configuration and status of a cluster.

With its capabilities, users can articulate their desired cluster state in detail, outlining configurations and specifications.

Subsequently, kubeopsctl orchestrates the creation of a cluster that precisely matches the specified state, ensuring alignment between intentions and operational reality.

Why use KubeOps Compliance?

In kubeopsctl, configuration management involves defining, maintaining, and updating the desired state of a cluster, including configurations for nodes, pods, services, and other resources in the application environment.

The main goal of kubeopsctl is to match the clusters actual state with the desired state specified in the configuration files. With a declarative model, kubeopsctl enables administrators to express their desired system setup, focusing on „what“ they want rather than „how“ to achieve it.

This approach improves flexibility and automation in managing complex systems, making the management process smoother and allowing easy adjustment to changing needs.

kubeopsctl uses YAML files to store configuration data in a human-readable format. These files document important metadata about the objects managed by kubeopsctl, such as pods, services, and deployments.

Highlights

  • creating a cluster
  • adding nodes to your cluster
  • drain nodes
  • updating single nodes
  • label nodes for zones
  • adding platform software into your cluster

2.2 - About KubeOps Compliance Licences

Get to know all about KubeOps Compliance licences

KubeOps Compliance is available with the Compliance licence.

When you create an account, you receive a free 30 day trial version of our licences.

Functions Compliance
Cluster Lifecycle Management
Build Cluster
Build Airgap Cluster
Security Hardening
Price Contact Sales

2.3 - Prerequisites

A total of at least seven machines is required:

  • 1 Admin
  • 3 Control-plane Nodes
  • 3 Worker Nodes

Below are the supported operating systems with the associated minimum requirements for CPU, memory, and disk storage:

OS Minimum Requirements
Red Hat Enterprise Linux 9.6 and 9.7 8 CPU cores, 16 GB memory, 50GB disk storage
Ubuntu 24.04.02 8 CPU cores, 16 GB memory, 50GB disk storage
  • For each worker node, an additional unformatted hard disk of 50 GB is required.
    For more information about the hard disks for Rook-Ceph, visit the rook-ceph prerequisites page

  • Each machine in the cluster must be configured with the same username. Otherwise, the cluster creation and management process will fail.


Prerequisites for admin

The following requirements must be fulfilled on the admin machine.

  1. You need an internet connection to use the default KubeOps Registry.
A local registry can be used in the Airgap environment. KubeOps supports only secure registries. If you use an insecure registry, it is important to configure it accordingly in the registry configuration file (/etc/containers/registries.conf for podman, /etc/docker/deamon.json for docker)

Prerequisites for each node

The following requirements must be fulfilled on each node.

  1. You must assign a unique, lowercase hostname to every machine you use.
It is recommended to use self-explanatory hostnames.

To set the hostname on your machine, use the following command:

sudo hostnamectl set-hostname <name of node>
Example

Use the commands below to set the hostnames on each machine, for example to admin, master, node1 node2 (lowercase letters and numbers only).

sudo hostnamectl set-hostname admin

  1. Optional: To use encrypted traffic inside the cluster, follow these steps:

For RHEL machines, you need to import the ELRepo Secure Boot key into your system. You can find a detailed explanation and comprehensive instructions in our how-to guide:Importing the Secure-Boot key

This is only necessary if your system has Secure Boot enabled. If this is not the case, or if you do not want to use encryption at all, you can skip this step.
  1. Ensure that either iptables or nftables is installed on the system.

2.4 - Prepare Cluster

Prepare Cluster

Before you start with KubeOps Compliance, all cluster nodes must be prepared with a consistent baseline configuration. This Prepare Cluster guide walks you through the required system-level steps on both control-plane and worker nodes, as well as the admin node used to manage the cluster. With these preparations done, you will ensure that all nodes behave predictably, can communicate securely with each other, and meet the prerequisites for the subsequent cluster setup procedure.

1. Include package repo on all nodes

To simplify the installation of the kosi and kubeopsctl packages, add the kubeops package repository to your operating system’s package manager on every node.

wget https://packagerepo.kubeops.net/pgp-key.public
cat pgp-key.public | sudo gpg --dearmor -o /usr/share/keyrings/kubeops.gpg
echo 'deb [arch=amd64 signed-by=/usr/share/keyrings/kubeops.gpg] https://packagerepo.kubeops.net/deb stable main' | sudo tee /etc/apt/sources.list.d/kubeops.list
sudo apt update
sudo dnf config-manager --add-repo https://packagerepo.kubeops.net/rpm/kubeops.repo

2. Special operating system adaptations on all nodes

Prepare all nodes with the following operating system adaptations.

# remove unattended upgrades on all nodes!
sudo apt remove unattended-upgrades
# no special adaptions required 

3. Distribute ssh-keys on all nodes

The hostnames of all nodes must be resolvable via DNS.

If you do not run a DNS server, the simplest solution is to add the IP addresses and hostnames to /etc/hosts. Use the same host list on every node, so that each node can resolve the other nodes by its hostname.

# IMPORTANT: The following command has to be adapted so that every admin, masternode and workernode is included
sudo tee /etc/hosts <<EOL_ETC_HOSTS
127.0.0.1 localhost
<admin ip> <admin hostname>
<master1 ip> <master1 hostname>
<master2 ip> <master2 hostname>
<master3 ip> <master3 hostname>
...
<worker1 ip> <worker1 hostname>
<worker2 ip> <worker2 hostname>
<worker3 ip> <worker3 hostname>
...
EOL_ETC_HOSTS
Full Example
sudo tee /etc/hosts <<EOL_ETC_HOSTS
127.0.0.1 localhost
10.2.10.10 admin
10.2.10.110 master1
10.2.10.120 master2
10.2.10.130 master3
10.2.10.210 worker1
10.2.10.220 worker2
10.2.10.230 worker3
EOL_ETC_HOSTS

Create ssh-keys on all nodes

The ssh-keys must belong to the Linux user that will run kubeopsctl later. Run the following ssh commands as this user and without sudo. Only use root if kubeopsctl will also be run as root. This step is required because kubeopsctl needs passwordless SSH from each node to every node in the cluster.

mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keygen -q -t ed25519 -f ~/.ssh/id_ed25519 -N ""

Copy each node’s public SSH key to all nodes

# IMPORTANT: The following command has to be adapted so that every admin, masternode and workernode is included
ssh-copy-id -i ~/.ssh/id_ed25519.pub <username>@<admin hostname>
ssh-copy-id -i ~/.ssh/id_ed25519.pub <username>@<master1 hostname>
ssh-copy-id -i ~/.ssh/id_ed25519.pub <username>@<master2 hostname>
ssh-copy-id -i ~/.ssh/id_ed25519.pub <username>@<master3 hostname>
...
ssh-copy-id -i ~/.ssh/id_ed25519.pub <username>@<worker1 hostname>
ssh-copy-id -i ~/.ssh/id_ed25519.pub <username>@<worker2 hostname>
ssh-copy-id -i ~/.ssh/id_ed25519.pub <username>@<worker3 hostname>
...
Full Example
ssh-copy-id -i ~/.ssh/id_ed25519.pub myuser@admin
ssh-copy-id -i ~/.ssh/id_ed25519.pub myuser@master1
ssh-copy-id -i ~/.ssh/id_ed25519.pub myuser@master2
ssh-copy-id -i ~/.ssh/id_ed25519.pub myuser@master3
ssh-copy-id -i ~/.ssh/id_ed25519.pub myuser@worker1
ssh-copy-id -i ~/.ssh/id_ed25519.pub myuser@worker2
ssh-copy-id -i ~/.ssh/id_ed25519.pub myuser@worker3

Scan host-keys with name and IP-address on all nodes

This test is important, because kubeopsctl may use either form.

# IMPORTANT: The following command has to be adapted so that every admin, masternode and workernode is included
ssh-keyscan <admin hostname> >> ~/.ssh/known_hosts
ssh-keyscan <admin ip> >> ~/.ssh/known_hosts
ssh-keyscan <master1 hostname> >> ~/.ssh/known_hosts
ssh-keyscan <master1 ip> >> ~/.ssh/known_hosts
ssh-keyscan <master2 hostname> >> ~/.ssh/known_hosts
ssh-keyscan <master2 ip> >> ~/.ssh/known_hosts
ssh-keyscan <master3 hostname> >> ~/.ssh/known_hosts
ssh-keyscan <master3 ip> >> ~/.ssh/known_hosts
...
ssh-keyscan <worker1 hostname> >> ~/.ssh/known_hosts
ssh-keyscan <worker1 ip> >> ~/.ssh/known_hosts
ssh-keyscan <worker2 hostname> >> ~/.ssh/known_hosts
ssh-keyscan <worker2 ip> >> ~/.ssh/known_hosts
ssh-keyscan <worker3 hostname> >> ~/.ssh/known_hosts
ssh-keyscan <worker3 ip> >> ~/.ssh/known_hosts
...
Full Example
ssh-keyscan admin >> ~/.ssh/known_hosts
ssh-keyscan 10.2.10.10 >> ~/.ssh/known_hosts
ssh-keyscan master1 >> ~/.ssh/known_hosts
ssh-keyscan 10.2.10.110 >> ~/.ssh/known_hosts
ssh-keyscan master2 >> ~/.ssh/known_hosts
ssh-keyscan 10.2.10.120 >> ~/.ssh/known_hosts
ssh-keyscan master3 >> ~/.ssh/known_hosts
ssh-keyscan 10.2.10.130 >> ~/.ssh/known_hosts
ssh-keyscan worker1 >> ~/.ssh/known_hosts
ssh-keyscan 10.2.10.210 >> ~/.ssh/known_hosts
ssh-keyscan worker2 >> ~/.ssh/known_hosts
ssh-keyscan 10.2.10.220 >> ~/.ssh/known_hosts
ssh-keyscan worker3 >> ~/.ssh/known_hosts
ssh-keyscan 10.2.10.230 >> ~/.ssh/known_hosts

Test ssh login without password.

Passwordless SSH login must work from each node to all other nodes.

# IMPORTANT: The following command has to be adapted so that every admin, masternode and workernode is included
ssh <username>@<admin hostname> exit
ssh <username>@<admin ip> exit
ssh <username>@<master1 hostname> exit
ssh <username>@<master1 ip> exit
ssh <username>@<master2 hostname> exit
ssh <username>@<master2 ip> exit
ssh <username>@<master3 hostname> exit
ssh <username>@<master3 ip> exit
...
ssh <username>@<worker1 hostname> exit
ssh <username>@<worker1 ip> exit
ssh <username>@<worker2 hostname> exit
ssh <username>@<worker2 ip> exit
ssh <username>@<worker3 hostname> exit
ssh <username>@<worker3 ip> exit
...
Full Example
ssh myuser@admin exit
ssh myuser@10.2.10.10 exit
ssh myuser@master1 exit
ssh myuser@10.2.10.110 exit
ssh myuser@master2 exit
ssh myuser@10.2.10.120 exit
ssh myuser@master3 exit
ssh myuser@10.2.10.130 exit
ssh myuser@worker1 exit
ssh myuser@10.2.10.210 exit
ssh myuser@worker2 exit
ssh myuser@10.2.10.220 exit
ssh myuser@worker3 exit
ssh myuser@10.2.10.230 exit

4. Distribute SUDOERS on all nodes

Replace the username “myuser” with your username, then copy the sudoers file to /etc/sudoers.d/<username> on all nodes.

# Preperation
myuser ALL=(root) NOPASSWD: /usr/bin/gpg --dearmor -o /usr/share/keyrings/kubeops.gpg
myuser ALL=(root) NOPASSWD: /usr/bin/tee /etc/apt/sources.list.d/kubeops.list
myuser ALL=(root) NOPASSWD: /usr/bin/apt update
myuser ALL=(root) NOPASSWD: /usr/bin/apt-get update
myuser ALL=(root) NOPASSWD: /usr/bin/apt remove unattended-upgrades
myuser ALL=(root) NOPASSWD: /usr/bin/tee /etc/hosts
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --remove *
myuser ALL=(root) NOPASSWD: /usr/bin/lsof /var/lib/dpkg/lock*

# Setup
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y kosi*
myuser ALL=(root) NOPASSWD: /usr/bin/apt-get install -y kosi*
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install kosi*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y kubeopsctl*
myuser ALL=(root) NOPASSWD: /usr/bin/apt-get install -y kubeopsctl*
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install kubeopsctl*.deb


# kube-vip image import
myuser ALL=(root) NOPASSWD: /bin/cp kube-vip.yaml /etc/kubernetes/manifests/kube-vip.yaml

# systemctl commands
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl stop kubelet
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl disable kubelet
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl stop containerd
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl disable containerd

# Kubeadm init
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm init --upload-certs --config cluster-config.yaml

# kubeadm reset
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm reset --force

# remove folders
myuser ALL=(root) NOPASSWD: /bin/rm -fr /etc/containerd
myuser ALL=(root) NOPASSWD: /bin/rm -fr /etc/kubernetes
myuser ALL=(root) NOPASSWD: /bin/rm -fr /usr/local/etc/haproxy
myuser ALL=(root) NOPASSWD: /bin/rm -fr /var/lib/etcd
myuser ALL=(root) NOPASSWD: /bin/rm -fr /var/lib/kubelet
myuser ALL=(root) NOPASSWD: /bin/rm -fr /var/kubeops

# reboot
myuser ALL=(root) NOPASSWD: /sbin/reboot now

# disable swap
myuser ALL=(root) NOPASSWD: /usr/sbin/swapoff --all
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl mask swap.target
myuser ALL=(root) NOPASSWD: /bin/sed -e * -i /etc/fstab

# enable UFW
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw reset
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 6443/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 2379\:2380/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 10250/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 10259/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 10257/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 10256/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 30000\:32767/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 179/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 4789/udp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 5473/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 51820/udp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 22/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 5000/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 5001/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw allow 7443/tcp
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw logging low
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw enable
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw reload
myuser ALL=(root) NOPASSWD: /usr/sbin/ufw status
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl restart systemd-networkd
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl disable --now ufw

# nftables enable/restart
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl enable --now nftables
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl restart nftables

# copy nftables configs
myuser ALL=(root) NOPASSWD: /bin/cp nftables.conf /etc/nftables.conf

# firewalld control
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl stop firewalld
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl disable firewalld
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl mask firewalld

# Install/update Helm
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /usr/bin
myuser ALL=(root) NOPASSWD: /bin/cp helm /usr/bin/
myuser ALL=(root) NOPASSWD: /bin/chmod +x /usr/bin/helm

# Delete Helm
myuser ALL=(root) NOPASSWD: /bin/rm -f /usr/bin/helm

# k9s
myuser ALL=(root) NOPASSWD: /bin/cp k9s /usr/bin/
myuser ALL=(root) NOPASSWD: /bin/chmod +x /usr/bin/k9s
myuser ALL=(root) NOPASSWD: /bin/rm -f /usr/bin/k9s

# crictl pull images
myuser ALL=(root) NOPASSWD:SETENV: /usr/bin/crictl pull *

# kubeadm init phase and kubeadm token create commands
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm init phase upload-certs --upload-certs
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm token create --print-join-command --certificate-key *

# kubeadm join
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm join *

# kubernetes admin.conf handling
myuser ALL=(root) NOPASSWD: /bin/cp /etc/kubernetes/admin.conf /home/*/.kube/config
myuser ALL=(root) NOPASSWD: /bin/chown [0-9]*\:[0-9]* /home/*/.kube/config

# scheduler config copy
myuser ALL=(root) NOPASSWD: /bin/cp scheduler-config.yaml /etc/kubernetes/scheduler-config.yaml

# scheduler manifest patching
myuser ALL=(root) NOPASSWD: /usr/bin/grep -q * /etc/kubernetes/manifests/kube-scheduler.yaml
myuser ALL=(root) NOPASSWD: /usr/bin/sed -i * /etc/kubernetes/manifests/kube-scheduler.yaml

# restart services
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl restart containerd
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl restart kubelet
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm token create --print-join-command

# create kubernetes manifests folder
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /etc/kubernetes/manifests

# modeprobe br_netfilter
myuser ALL=(root) NOPASSWD: /bin/cp br_netfilter.conf /etc/modules-load.d/br_netfilter.conf
myuser ALL=(root) NOPASSWD: /bin/chmod 644 /etc/modules-load.d/br_netfilter.conf
myuser ALL=(root) NOPASSWD: /sbin/modprobe br_netfilter
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl daemon-reload

# kubernetes image pull
myuser ALL=(root) NOPASSWD: /usr/bin/ctr *

# kubernetes version upgrade
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm upgrade plan --ignore-preflight-errors=all
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm upgrade apply * --ignore-preflight-errors=all --yes,  !/usr/bin/kubeadm upgrade apply *[[\:space\:]]* --ignore-preflight-errors=all --yes

# upgrade nodes
myuser ALL=(root) NOPASSWD: /bin/cp /home/*/.kube/config /etc/kubernetes/admin.conf
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm upgrade node

# kubernetes-tools-packages
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /opt/cni/bin
myuser ALL=(root) NOPASSWD: /bin/tar xzf cni-* -C /opt/cni/bin
myuser ALL=(root) NOPASSWD: /bin/tar xzf crictl-* -C /usr/bin
myuser ALL=(root) NOPASSWD: /bin/rm -f /etc/cni/net.d/87-podman-bridge.conflist

myuser ALL=(root) NOPASSWD: /usr/bin/dpkg install -y kubeadm*
myuser ALL=(root) NOPASSWD: /bin/cp kubeadm /usr/bin/kubeadm
myuser ALL=(root) NOPASSWD: /bin/chmod +x /usr/bin/kubeadm
myuser ALL=(root) NOPASSWD: /bin/test -f /usr/bin/kubelet

myuser ALL=(root) NOPASSWD: /bin/mv /usr/bin/kubelet /usr/bin/kubelet_*
myuser ALL=(root) NOPASSWD: /bin/cp kubelet /usr/bin/kubelet
myuser ALL=(root) NOPASSWD: /bin/chmod +x /usr/bin/kubelet

myuser ALL=(root) NOPASSWD: /usr/bin/dpkg install -y kubectl*
myuser ALL=(root) NOPASSWD: /bin/cp kubectl /usr/bin/kubectl
myuser ALL=(root) NOPASSWD: /bin/chmod +x /usr/bin/kubectl

myuser ALL=(root) NOPASSWD: /usr/bin/dpkg install -y kubelet*
myuser ALL=(root) NOPASSWD: /bin/cp kubelet.service /usr/lib/systemd/system/kubelet.service
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /usr/lib/systemd/system/kubelet.service.d
myuser ALL=(root) NOPASSWD: /bin/cp 10-kubeadm.conf /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl enable --now kubelet

myuser ALL=(root) NOPASSWD: /usr/bin/apt-mark hold kubelet kubeadm kubectl
myuser ALL=(root) NOPASSWD: /usr/bin/apt-mark unhold kubelet kubeadm kubectl
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y kubelet* kubeadm* kubectl*
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y kubeadm*

# Allow HAProxy and load-balancer
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /usr/local/etc/haproxy
myuser ALL=(root) NOPASSWD: /bin/cp haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
myuser ALL=(root) NOPASSWD: /bin/cp load-balancer.yaml /etc/kubernetes/manifests/load-balancer.yaml
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /mnt/registry
myuser ALL=(root) NOPASSWD: /bin/cp docker-registry.yaml /etc/kubernetes/manifests/docker-registry.yaml
myuser ALL=(root) NOPASSWD: /bin/rm /etc/kubernetes/manifests/docker-registry.yaml
myuser ALL=(root) NOPASSWD: /bin/rm -rf /mnt/registry
myuser ALL=(root) NOPASSWD: /usr/bin/crictl --namespace k8s.io images import local-registry-image.tar

# Podman Installation of local .deb-Package
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install passt_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install conmon_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install catatonit_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install netavark_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install aardvark-dns_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install golang-github-containers-image_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install golang-github-containers-common_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install containernetworking-plugins_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install libsubid4_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install uidmap_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install libslirp0_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install slirp4netns_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install libyajl2_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install crun_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install fuse-overlayfs_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install buildah_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install podman_*.deb

# Podman Remove of local .deb-Package
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --remove podman buildah fuse-overlayfs crun libyajl2 slirp4netns libslirp0 uidmap libsubid4 containernetworking-plugins golang-github-containers-common golang-github-containers-image aardvark-dns netavark catatonit conmon passt

# Podman Installation & Update with apt
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y podman*
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y podman
myuser ALL=(root) NOPASSWD: /usr/bin/apt update
myuser ALL=(root) NOPASSWD: /usr/bin/apt remove -y podman

# Allow prepare-node
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install */pia/kosi_*

# runtime setup
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install conntrack_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install runc_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install containerd_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y containerd

# Enable repo and install containerd.io
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y containerd.io
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y conntrack-tools
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y iproute-tc

# Remove packages
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --remove containerd

# Create directories
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /etc/containerd
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /etc/containerd/certs.d

# Configure containerd
myuser ALL=(root) NOPASSWD: /usr/bin/tee /etc/containerd/config.toml
myuser ALL=(root) NOPASSWD: /bin/sed -i * /etc/containerd/config.toml

# Allow containerd insecure registry
myuser ALL=(root) NOPASSWD: /usr/bin/sed -i -e * /etc/containerd/config.toml

# Enable and start containerd service
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl enable --now containerd

# Allow managing k8s sysctl configuration
myuser ALL=(root) NOPASSWD: /bin/cp k8s.conf /etc/sysctl.d/k8s.conf
myuser ALL=(root) NOPASSWD: /bin/cp kubevirt.conf /etc/sysctl.d/kubevirt.conf
myuser ALL=(root) NOPASSWD: /usr/sbin/sysctl --system
myuser ALL=(root) NOPASSWD: /bin/rm /etc/sysctl.d/k8s.conf
myuser ALL=(root) NOPASSWD: /bin/rm /etc/sysctl.d/kubevirt.conf

# Allow WireGuard package management
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install wireguard_*.deb wireguard-tools_*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --install wireguard-tools-*.deb systemd-resolved-*.deb
myuser ALL=(root) NOPASSWD: /usr/bin/dpkg --remove wireguard wireguard-tools
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y wireguard-tools*
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y systemd-resolved*

# velero install on admin
myuser ALL=(root) NOPASSWD: /usr/bin/cp binary/velero /usr/bin

# chrony installation
myuser ALL=(root) NOPASSWD: /usr/bin/apt install -y chrony
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl enable --now chrony
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl restart chronyd
myuser ALL=(root) NOPASSWD: /usr/bin/vi /etc/chrony/chrony.conf
myuser ALL=(root) NOPASSWD: /usr/bin/vim /etc/chrony/chrony.conf

# update apiserver on control plane
myuser ALL=(root) NOPASSWD: /usr/bin/cp /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/kube-apiserver.yaml.bak
myuser ALL=(root) NOPASSWD: /usr/bin/sed -i /--oidc-/d /etc/kubernetes/manifests/kube-apiserver.yaml
myuser ALL=(root) NOPASSWD: /usr/local/bin/yq e * -i /etc/kubernetes/manifests/kube-apiserver.yaml
# Preperation
myuser ALL=(root) NOPASSWD: /usr/bin/dnf config-manager --add-repo https\://packagerepo.kubeops.net/rpm/kubeops.repo
myuser ALL=(root) NOPASSWD: /usr/bin/tee /etc/hosts

# Setup
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y kosi*, !/usr/bin/dnf install -y kosi*[[\:space\:]]*
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y --disableexcludes=kubeops-repo kosi*, !/usr/bin/dnf install -y --disableexcludes=kubeops-repo kosi*[[\:space\:]]*
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install kosi*.rpm, !/usr/bin/rpm --install kosi*[[\:space\:]]*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y --disableexcludes=kubeops-repo kubeopsctl*, !/usr/bin/dnf install -y --disableexcludes=kubeops-repo kubeopsctl*[[\:space\:]]*
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install kubeopsctl*.rpm, !/usr/bin/rpm --install kubeopsctl*[[\:space\:]]*.rpm

# kube-vip/create-manifest.sh.tmpl
myuser ALL=(root) NOPASSWD: /bin/cp kube-vip.yaml /etc/kubernetes/manifests/kube-vip.yaml

# delete-node/delete-node.sh.tmpl
# systemctl commands
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl stop kubelet
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl disable kubelet
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl stop containerd
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl disable containerd

# kubeadm reset
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm reset --force

# kubeadm-init/kubeadm-init.sh.tmpl
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm init --upload-certs --config cluster-config.yaml

# remove folders
myuser ALL=(root) NOPASSWD: /bin/rm -fr /etc/containerd
myuser ALL=(root) NOPASSWD: /bin/rm -fr /etc/kubernetes
myuser ALL=(root) NOPASSWD: /bin/rm -fr /usr/local/etc/haproxy
myuser ALL=(root) NOPASSWD: /bin/rm -fr /var/lib/etcd
myuser ALL=(root) NOPASSWD: /bin/rm -fr /var/lib/kubelet
myuser ALL=(root) NOPASSWD: /bin/rm -fr /var/kubeops

# reboot
myuser ALL=(root) NOPASSWD: /sbin/reboot now

# disable swap
myuser ALL=(root) NOPASSWD: /usr/sbin/swapoff --all
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl mask swap.target
myuser ALL=(root) NOPASSWD: /bin/sed -e * -i /etc/fstab

# nftables enable/restart
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl enable --now nftables
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl restart nftables

# copy nftables configs
myuser ALL=(root) NOPASSWD: /bin/cp nftables.conf /etc/sysconfig/nftables.conf

# firewalld control
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl stop firewalld
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl disable firewalld
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl mask firewalld

# Install/update Helm
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /usr/bin
myuser ALL=(root) NOPASSWD: /bin/cp helm /usr/bin/
myuser ALL=(root) NOPASSWD: /bin/chmod +x /usr/bin/helm
# if Helm is in repository
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y helm* 

# Delete Helm
myuser ALL=(root) NOPASSWD: /bin/rm -f /usr/bin/helm

# k9s/package.kosi
myuser ALL=(root) NOPASSWD: /bin/cp k9s /usr/bin/
myuser ALL=(root) NOPASSWD: /bin/chmod +x /usr/bin/k9s
myuser ALL=(root) NOPASSWD: /bin/rm -f /usr/bin/k9s

# crictl pull images
myuser ALL=(root) NOPASSWD:SETENV: /usr/bin/crictl pull *

# ssh remote kubeadm commands
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm init phase upload-certs --upload-certs
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm token create --print-join-command --certificate-key *

# local execution of kubeadm join
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm join *

# kubernetes admin.conf handling
myuser ALL=(root) NOPASSWD: /bin/cp /etc/kubernetes/admin.conf /home/*/.kube/config
myuser ALL=(root) NOPASSWD: /bin/chown [0-9]*\:[0-9]* /home/*/.kube/config

# scheduler config copy
myuser ALL=(root) NOPASSWD: /bin/cp scheduler-config.yaml /etc/kubernetes/scheduler-config.yaml

# scheduler manifest patching
myuser ALL=(root) NOPASSWD: /bin/grep -q * /etc/kubernetes/manifests/kube-scheduler.yaml
# Adjustments sed -i * 
myuser ALL=(root) NOPASSWD: /usr/bin/sed -i * /etc/kubernetes/manifests/kube-scheduler.yaml

# restart services
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl restart containerd
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl restart kubelet
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm token create --print-join-command

# create kubernetes manifests folder
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /etc/kubernetes/manifests

# modeprobe br_netfilter
myuser ALL=(root) NOPASSWD: /bin/cp br_netfilter.conf /etc/modules-load.d/br_netfilter.conf
myuser ALL=(root) NOPASSWD: /bin/chmod 644 /etc/modules-load.d/br_netfilter.conf
myuser ALL=(root) NOPASSWD: /sbin/modprobe br_netfilter
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl daemon-reload

# kubernetes image pull
myuser ALL=(root) NOPASSWD: /usr/bin/ctr *

# kubernetes version upgrade
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm upgrade plan --ignore-preflight-errors=all
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm upgrade apply * --ignore-preflight-errors=all --yes,  !/usr/bin/kubeadm upgrade apply *[[\:space\:]]* --ignore-preflight-errors=all --yes

# kubeadm upgrade node
myuser ALL=(root) NOPASSWD: /bin/cp /home/*/.kube/config /etc/kubernetes/admin.conf
myuser ALL=(root) NOPASSWD: /usr/bin/kubeadm upgrade node

# kubernetes-tools-packages
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /opt/cni/bin
myuser ALL=(root) NOPASSWD: /bin/tar xzf cni-* -C /opt/cni/bin, !/bin/tar xzf cni-*[[\:space\:]]* -C /opt/cni/bin
myuser ALL=(root) NOPASSWD: /bin/tar xzf crictl-* -C /usr/bin, !/bin/tar xzf crictl-*[[\:space\:]]* -C /usr/bin
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y kubeadm*, !/usr/bin/dnf install -y kubeadm*[[\:space\:]]*, !/usr/bin/dnf install -y kubeadm*.rpm
myuser ALL=(root) NOPASSWD: /bin/cp kubeadm /usr/bin/kubeadm
myuser ALL=(root) NOPASSWD: /bin/chmod +x /usr/bin/kubeadm
myuser ALL=(root) NOPASSWD: /bin/test -f /usr/bin/kubelet
myuser ALL=(root) NOPASSWD: /bin/mv /usr/bin/kubelet /usr/bin/kubelet_*, !/bin/mv /usr/bin/kubelet /usr/bin/kubelet_*[[\:space\:]]*
myuser ALL=(root) NOPASSWD: /bin/cp kubelet /usr/bin/kubelet
myuser ALL=(root) NOPASSWD: /bin/chmod +x /usr/bin/kubelet
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y kubectl*, !/usr/bin/dnf install -y kubectl*[[\:space\:]]*, !/usr/bin/dnf install -y kubectl*.rpm
myuser ALL=(root) NOPASSWD: /bin/cp kubectl /usr/bin/kubectl
myuser ALL=(root) NOPASSWD: /bin/chmod +x /usr/bin/kubectl
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y kubelet*, !/usr/bin/dnf install -y kubelet*[[\:space\:]]*, !/usr/bin/dnf install -y kubelet*.rpm
myuser ALL=(root) NOPASSWD: /bin/cp kubelet.service /usr/lib/systemd/system/kubelet.service
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /usr/lib/systemd/system/kubelet.service.d
myuser ALL=(root) NOPASSWD: /bin/cp 10-kubeadm.conf /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl enable --now kubelet
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y --disableexcludes=kubeops-repo kubelet-* kubeadm-* kubectl-*
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y --disableexcludes=kubeops-repo kubeadm-*


# Allow HAProxy and load-balancer
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /usr/local/etc/haproxy
myuser ALL=(root) NOPASSWD: /bin/cp haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
myuser ALL=(root) NOPASSWD: /bin/cp load-balancer.yaml /etc/kubernetes/manifests/load-balancer.yaml
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /mnt/registry
myuser ALL=(root) NOPASSWD: /bin/cp docker-registry.yaml /etc/kubernetes/manifests/docker-registry.yaml
myuser ALL=(root) NOPASSWD: /bin/rm /etc/kubernetes/manifests/docker-registry.yaml
myuser ALL=(root) NOPASSWD: /bin/rm -rf /mnt/registry
myuser ALL=(root) NOPASSWD: /usr/bin/crictl --namespace k8s.io images import local-registry-image.tar

# Podman Installation of local .rpm-Package
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install passt-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install passt-selinux-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install aardvark-dns-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install netavark-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install container-selinux-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install libnet-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install criu-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install criu-libs-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install libslirp-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install slirp4netns-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install yajl-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install crun-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install containers-common-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install fuse-overlayfs-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install shadow-utils-subid-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install conmon-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install podman-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install iproute-*.rpm iproute-tc-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install containerd.io-*.rpm

# Podman Remove of local .rpm-Package
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --erase podman shadow-utils-subid fuse-overlayfs crun containers-common yajl slirp4netns libslirp criu-libs criu libnet container-selinux netavark aardvark-dns passt passt-selinux

# Podman Installation & Update with dnf
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y podman*, !/usr/bin/dnf install -y podman*[[\:space\:]]*
myuser ALL=(root) NOPASSWD: /usr/bin/dnf update -y podman*,!/usr/bin/dnf update -y podman*[[\:space\:]]*
myuser ALL=(root) NOPASSWD: /usr/bin/dnf remove -y podman

# Allow prepare-node
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install */pia/kosi-*

# Allow installation of container-runtime
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install conntrack-tools-*.rpm, !/usr/bin/rpm --install conntrack-tools-*[\:space\:]]*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install conntrack-tools-*.rpm libnetfilter_cthelper-*.rpm libnetfilter_cttimeout-*.rpm libnetfilter_queue-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install iproute-tc-*.rpm, !/usr/bin/rpm --install iproute-tc-*[\:space\:]]*.rpm

# Enable repo and install containerd.io
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y containerd.io
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y conntrack-tools
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y iproute-tc

# Remove RPM packages
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --erase containerd.io

# Create directories
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /etc/containerd
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /etc/containerd/certs.d
myuser ALL=(root) NOPASSWD: /bin/mkdir -p /etc/systemd/system/containerd.service.d/
myuser ALL=(root) NOPASSWD: /usr/bin/tee /etc/systemd/system/containerd.service.d/override.conf*

# Configure containerd
myuser ALL=(root) NOPASSWD: /usr/bin/tee /etc/containerd/config.toml
myuser ALL=(root) NOPASSWD: /bin/sed -i * /etc/containerd/config.toml

# Allow containerd insecure registry
myuser ALL=(root) NOPASSWD: /usr/bin/sed -i -e * /etc/containerd/config.toml

# Enable and start containerd service
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl enable --now containerd

# Allow managing k8s sysctl configuration
myuser ALL=(root) NOPASSWD: /bin/cp k8s.conf /etc/sysctl.d/k8s.conf
myuser ALL=(root) NOPASSWD: /bin/cp kubevirt.conf /etc/sysctl.d/kubevirt.conf
myuser ALL=(root) NOPASSWD: /usr/sbin/sysctl --system
myuser ALL=(root) NOPASSWD: /bin/rm /etc/sysctl.d/k8s.conf
myuser ALL=(root) NOPASSWD: /bin/rm /etc/sysctl.d/kubevirt.conf

# Allow WireGuard package management
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --install wireguard-tools-*.rpm systemd-resolved-*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/rpm --erase wireguard-tools
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y wireguard-tools*, !/usr/bin/dnf install -y wireguard-tools*[\:space\:]]*, !/usr/bin/dnf install -y wireguard-tools*.rpm
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y systemd-resolved*, !/usr/bin/dnf install -y systemd-resolved*[\:space\:]]*, !/usr/bin/dnf install -y systemd-resolved*.rpm

# velero install on admin
myuser ALL=(root) NOPASSWD: /usr/bin/cp binary/velero /usr/bin

# chrony installation
myuser ALL=(root) NOPASSWD: /usr/bin/dnf install -y chrony
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl enable --now chronyd
myuser ALL=(root) NOPASSWD: /usr/bin/systemctl restart chronyd
myuser ALL=(root) NOPASSWD: /usr/bin/vi /etc/chrony/chrony.conf
myuser ALL=(root) NOPASSWD: /usr/bin/vim /etc/chrony/chrony.conf

# update apiserver on control plane
myuser ALL=(root) NOPASSWD: /usr/bin/cp /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/kube-apiserver.yaml.bak
myuser ALL=(root) NOPASSWD: /usr/bin/sed -i /--oidc-/d /etc/kubernetes/manifests/kube-apiserver.yaml
myuser ALL=(root) NOPASSWD: /usr/bin/yq e * -i /etc/kubernetes/manifests/kube-apiserver.yaml

5. Configure time synchronization on all nodes

  1. Install chrony

Run on every cluster node:

sudo apt install -y chrony
sudo systemctl enable --now chrony
sudo dnf install -y chrony
sudo systemctl enable --now chronyd

  1. Configure NTP servers

Edit the chrony configuration file and configure the NTP servers. Replace or remove existing entries if required by your setup:

server pool.ntp.org iburst
# or your internal NTP servers:
# server 10.2.10.10 iburst
sudo vi `/etc/chrony/chrony.conf`
sudo vi `/etc/chrony.conf`

Apply changes:

sudo systemctl restart chrony
sudo systemctl restart chronyd
  1. Verify synchronization
chronyc tracking
chronyc sources -v

Expected:

Stratum ≤ 3
Leap Status = Normal
System time offset < 10 ms
One source marked with *

Example:

Reference ID    : 83BC03DC (ntp0.rrze.uni-erlangen.de)
Stratum         : 2
System time     : 0.000718 seconds slow
Last offset     : -0.000214 seconds
RMS offset      : 0.000093 seconds
Leap status     : Normal

Meaning:

  • Reference ID → you are synchronizing with ntp0.rrze.uni-erlangen.de → good
  • Stratum 2 → completely normal for public NTP servers
  • System time slow: 0.0007s → deviation < 1 ms → excellent
  • Load/RMS offset → very stable synchronization
  • Leap status Normal → no time jumps, everything OK

6. Install curl

How to install and configure curl

Install curl

Run on every cluster node:

sudo apt install -y curl
sudo dnf install -y curl


Once all nodes are prepared, you can start setting up the cluster.

2.5 - Setup Cluster

After completing the cluster preparation steps, you are ready to configure the kubeops tooling and create the Kubernetes cluster from your cluster admin host. This Setup Cluster document describes how to install and configure KOSI and kubeopsctl, prepare the cluster configuration, and then trigger the automated cluster deployment.

Important: the following commands have to be executed on your cluster admin

1. Install KOSI

# KOSI-version can be found under : https://packagerepo.kubeops.net/deb/pool/main/
sudo apt update
sudo apt install -y kosi=<kosi-version>
# KOSI-version can be found under : https://packagerepo.kubeops.net/rpm/
sudo dnf install -y --disableexcludes=kubeops-repo <kosi-version>

# KOSI-version can be found under : https://packagerepo.kubeops.net/deb/pool/main/
wget https://packagerepo.kubeops.net/deb/pool/main/<kosi-version>.deb
sudo dpkg --install <kosi-version>.deb
# KOSI-versions can be found under: https://packagerepo.kubeops.net/rpm
sudo rpm kosi
wget https://packagerepo.kubeops.net/rpm/<kosi-version>.rpm
sudo rpm --install <kosi-version>.rpm

2. Set the KUBEOPSROOT env var

Set KUBEOPSROOT and XDG_RUNTIME_DIR in ~/.bashrc

# file ~/.bashrc
# Append these values to the end of your ~/.bashrc file
export KUBEOPSROOT=/home/<yourUser>/kubeops
export XDG_RUNTIME_DIR=$KUBEOPSROOT

Source .bashrc to apply the values

source ~/.bashrc
echo $KUBEOPSROOT
echo $XDG_RUNTIME_DIR

As a result you should see your KUBEOPSROOT-path two times.

3. Adjust KOSI Configuration

This creates a kubeops directory in your home directory and transfers all necessary files, e.g., the kosi-config and the plugins, to it.

mkdir ~/kubeops
cd ~/kubeops
cp -R /var/kubeops/kosi/ .
cp -R /var/kubeops/plugins/ .

The config.yaml is in your KUBEOPSROOT-path (typically in ~/kubeops/kosi)

  • Set hub in your kosi config to hub: https://dispatcher.kubeops.net/v4/dispatcher/
  • Set the “plugins”-entry in your kosi config to plugins: /home/<yourUser>/kubeops/plugins, where is changed to your username
# file $KUBEOPSROOT/kosi/config.yaml
apiversion: kubernative/sina/config/v3

spec:
  hub: https://dispatcher.kubeops.net/v4/dispatcher/ # <-- set hub url
  plugins: <your kubeopsroot>/plugins/ # <-- set the path to your plugin folder (~ for home or $KUBEOPSROOT don't work, it has to be the full path)
  workspace: /tmp/kosi/process/
  logging: info
  housekeeping: false
  proxy: false

4. Install KOSI enterprise plugins

kosi install --hub kosi-enterprise kosi/enterprise-plugins:2.2.0_Beta0

5. Login with your user

kosi login -u <yourUser>

At this point it is normal if you get the following error message:
Error: The login to registry is temporary not available. Please try again later.
The reason for this is that podman is not yet installed.

6. Install kubeopsctl

# kubeopsctl-version can be found under : https://packagerepo.kubeops.net/deb/pool/main/
sudo apt update
sudo apt install -y kubeopsctl=<kubeopsctl-version>
# kubeopsctl-version can be found under : https://packagerepo.kubeops.net/rpm/
sudo dnf install -y --disableexcludes=kubeops-repo <kubeopsctl-version>
# kubeopsctl-version can be found under : https://packagerepo.kubeops.net/deb/pool/main/
wget https://packagerepo.kubeops.net/deb/pool/main/<kubeopsctl-version>.deb
sudo dpkg --install <kubeopsctl-version>.deb
# kubeopsctl-versions can be found under: https://packagerepo.kubeops.net/rpm
sudo rpm kubeopsctl
wget https://packagerepo.kubeops.net/rpm/<kubeopsctl-version>.rpm
sudo rpm --install -v <kubeopsctl-version>.rpm

7. Create a cluster-values.yaml configuration file

# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: false
clusterName: <your cluster name>
clusterUser: <your user name>
kubernetesVersion: <your kubernetesversion>
kubeVipEnabled: false
virtualIP: <your master1 ip>
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: <your kubeopsroot path>
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
packageRepository: local                    # If you have incorporated package repository, replace “local” with "kubeops-repo"
changeCluster: true
zones:
# IMPORTANT: The following part has to be adapted so that every one of your masternodes and workernodes is included
# This file only includes the minimum requirements for the amount of masters and workers and an example usage of zones
# You should adapt this part to your amount of masters and workers and cluster them into as many zones as you like
- name: zone1
  nodes:
  - name: <your master1 hostname>
    iPAddress: <your master1 ip>
    type: controlplane
    kubeVersion: <kubernetesversion from above>
  - name: <your worker1 hostname>
    iPAddress: <your worker1 ip>
    type: worker
    kubeVersion: <kubernetesversion from above>
- name: zone2
  nodes:
  - name: <your master2 hostname>
    iPAddress: <your master2 ip>
    type: controlplane
    kubeVersion: <kubernetesversion from above>
  - name: <your worker2 hostname>
    iPAddress: <your worker2 ip>
    type: worker
    kubeVersion: <kubernetesversion from above>
- name: zone3
  nodes:
  - name: <your master3 hostname>
    iPAddress: <your master3 ip>
    type: controlplane
    kubeVersion: <kubernetesversion from above>
  - name: <your worker3 hostname>
    iPAddress: <your worker3 ip>
    type: worker
    kubeVersion: <kubernetesversion from above>

Full Example
# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: false
clusterName: myCluster
clusterUser: myuser
kubernetesVersion: 1.32.2
kubeVipEnabled: false
virtualIP: 10.2.10.110
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: /home/myuser/kubeops
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
systemCpu: 250m
systemMemory: 256Mi
packageRepository: local                 # If you have incorporated package repository, replace “local” with "kubeops-repo"
changeCluster: true
zones:
- name: zone1
  nodes:
  - name: dev07-master1-ubuntu2404
    iPAddress: 10.2.10.110
    type: controlplane
    kubeVersion: 1.32.2
  - name: dev07-worker1-ubuntu2404
    iPAddress: 10.2.10.210
    type: worker
    kubeVersion: 1.32.2
- name: zone2
  nodes:
  - name: dev07-master2-ubuntu2404
    iPAddress: 10.2.10.120
    type: controlplane
    kubeVersion: 1.32.2
  - name: dev07-worker2-ubuntu2404
    iPAddress: 10.2.10.220
    type: worker
    kubeVersion: 1.32.2
- name: zone3
  nodes:
  - name: dev07-master3-ubuntu2404
    iPAddress: 10.2.10.130
    type: controlplane
    kubeVersion: 1.32.2
  - name: dev07-worker3-ubuntu2404
    iPAddress: 10.2.10.230
    type: worker
    kubeVersion: 1.32.2

7.1 Using KubeVip in your Cluster (optional)

KubeVip provides a highly available virtual IP for the Kubernetes control plane, giving the cluster a stable API endpoint. In multi-control-plane clusters, the virtual IP can move to another control-plane node if the active one fails. For more information, refer to the official KubeVip documentation here.

To enable KubeVip, set kubeVipEnabled to true and configure virtualIP with an unused IP address in the same network as your control-plane nodes.

If KubeVip is disabled, set kubeVipEnabled to false and use the IP address of the first control-plane node as virtualIP in your cluster-values.yaml in the Setup.

Examples:

kubeVipEnabled: true
virtualIP: <IP in your cluster ip range which is not given yet>

or

kubeVipEnabled: false
virtualIP: <master1 ip>

For highly available clusters, enabling KubeVip is recommended. For test environments or single-control-plane clusters, disabling it is usually sufficient.

8. Pull required KOSI packages

If you do not specify a parameter, the current Kubernetes version 1.32.2 will be pulled.
With parameter --kubernetesVersion <your wanted Kubernetesversion> you can pull an older Kubernetes version.
Available Kubernetes versions are

kubeopsctl pull

or

kubeopsctl pull --kubernetesVersion <x.xx.x>

9. Install podman

kosi install -p $KUBEOPSROOT/lima/podman_5.2.2.tgz -f cluster-values.yaml

10. Install helm

kosi install -p $KUBEOPSROOT/lima/helm_v3.16.4.tgz

11. Install kubernetes tools (kubectl)

Make sure the kubernetes version matches the one you pulled before.

kosi install -p $KUBEOPSROOT/lima/kubernetes-tools_<your kubernetes version>.tgz -f cluster-values.yaml

This command also installs kubelet and kubeadm. You can either mask or delete them on your admin as they are not necessary for the cluster creation process. At the first installation there will be an error that shows that the package tries a backup from kublet which does not exists in the moment.

Full Example
kosi install -p $KUBEOPSROOT/lima/kubernetes-tools_1.32.2.tgz -f cluster-values.yaml

12. Cluster Setup

Make sure that you are logged in on hub and registry.

kosi login -u <your username>

Now the login for hub and registry should be successful!


Make sure that you changed the kosi config.yaml.

cat $KUBEOPSROOT/kosi/config.yaml

Make sure that you pulled all required packages.

ll -1 $KUBEOPSROOT/lima

Install Kubernetes Cluster with kubeopsctl. Cluster setup takes about 10 to 15 minutes.

kubeopsctl apply -f cluster-values.yaml

3 - How to Guides

Welcome to our comprehensive How-To Guide for using kubeops. Whether youre a beginner aiming to understand the basics or an experienced user looking to fine-tune your skills, this guide is designed to provide you with detailed step-by-step instructions on how to navigate and utilize all the features of kubeops effectively.

In the following sections, you will find everything from initial setup and configuration, to advanced tips and tricks that will help you get the most out of the software. Our aim is to assist you in becoming proficient with kubeops, enhancing both your productivity and your user experience.

Lets get started on your journey to mastering kubeops!

3.1 - Documentation for production

Learn how to deploy a production ready cluster

3.1.1 - Supported Package Versions — Ubuntu / Debian

The packages and versions provided by the KubeOps package repository for Ubuntu / Debian, and how to pin them.

This page lists the packages and versions available from the KubeOps package repository for Ubuntu 24.04 (the .deb pool). Use it to see which versions are supported and to pin the installed versions so an OS update cannot upgrade them.

Kubernetes

Package Supported versions
kubeadm 1.30.8, 1.31.6, 1.32.2, 1.32.3, 1.32.9, 1.32.10, 1.33.3, 1.33.5, 1.33.10, 1.34.1, 1.34.6, 1.35.0, 1.36.1
kubelet 1.30.8, 1.31.6, 1.32.2, 1.32.3, 1.32.9, 1.32.10, 1.33.3, 1.33.5, 1.33.10, 1.34.1, 1.34.6, 1.35.0, 1.36.1
kubectl 1.30.8, 1.31.6, 1.32.2, 1.32.3, 1.32.9, 1.32.10, 1.33.3, 1.33.5, 1.33.10, 1.34.1, 1.34.6, 1.35.0, 1.36.1
kubernetes-cni 1.4.0, 1.5.1, 1.6.0, 1.7.1, 1.8.0, 1.9.1
cri-tools 1.30.0, 1.31.0, 1.32.0, 1.33.0, 1.34.0, 1.35.0, 1.36.0

KubeOps tools

Package Supported versions
kosi 2.12.1.0, 2.13.0.1, 2.13.0.2
kubeopsctl 2.0.0.0, 2.0.1.0, 2.0.2.0, 2.0.3.0, 2.0.4.0, 2.0.5.0, 2.1.0.0

Helm

Package Supported versions
helm 3.17.4

Container runtime and etcd

Package Supported versions
containerd 1.7.24
etcdctl 3.5.16, 3.5.21
etcdutl 3.5.16, 3.5.21
podman 4.9.3

Pre-release versions

Package Pre-release versions
kosi 2.14.0.4-Beta0, 2.15.0.4-Alpha5, 2.15.0.4-Beta0
kubeopsctl 2.2.0.0-Alpha5, 2.2.0.0-Beta0

Pin the installed versions

After the packages are installed, hold them at the installed version so a later apt upgrade cannot upgrade them and break the cluster:

sudo apt-mark hold \
  containerd podman \
  kubelet kubeadm kubectl kubernetes-cni cri-tools \
  helm kosi kubeopsctl

To release a hold later (for a controlled upgrade):

sudo apt-mark unhold \
  containerd podman \
  kubelet kubeadm kubectl kubernetes-cni cri-tools \
  helm kosi kubeopsctl

3.1.2 - Supported Package Versions — Red Hat Enterprise Linux (RHEL)

The packages and versions provided by the KubeOps package repository for Red Hat Enterprise Linux, and how to pin them.

This page lists the packages and versions available from the KubeOps package repository for RHEL 9.6 / 9.7 (the .rpm pool). Use it to see which versions are supported and to pin the installed versions so an OS update cannot upgrade them.

Kubernetes

Package Supported versions
kubeadm 1.30.8, 1.31.6, 1.32.2, 1.32.3, 1.32.9, 1.32.10, 1.33.3, 1.33.5, 1.33.10, 1.34.1, 1.34.6, 1.35.0, 1.36.1
kubelet 1.30.8, 1.31.6, 1.32.2, 1.32.3, 1.32.9, 1.32.10, 1.33.3, 1.33.5, 1.33.10, 1.34.1, 1.34.6, 1.35.0, 1.36.1
kubectl 1.30.8, 1.31.6, 1.32.2, 1.32.3, 1.32.9, 1.32.10, 1.33.3, 1.33.5, 1.33.10, 1.34.1, 1.34.6, 1.35.0, 1.36.1
kubernetes-cni 1.4.0, 1.5.0, 1.5.1, 1.6.0, 1.7.1, 1.8.0, 1.9.1
cri-tools 1.30.1, 1.31.1, 1.32.0, 1.33.0, 1.34.0, 1.35.0, 1.36.0

Container runtime and etcd

Package Supported versions
containerd.io 2.1.5
podman 5.2.2
etcdctl 3.5.16, 3.5.21
etcdutl 3.5.16, 3.5.21

KubeOps tools

Package Supported versions
kosi 2.12.1.0, 2.13.0.1, 2.13.0.2
kubeopsctl 2.0.1.0, 2.0.2.0, 2.0.3.0, 2.0.4.0, 2.0.5.0, 2.1.0.0

Helm

Package Supported versions
helm 3.17.4

Pre-release versions

Package Pre-release versions
kosi 2.14.0.4_Beta0, 2.15.0.4_Alpha5, 2.15.0.4_Beta0
kubeopsctl 2.2.0.0_Alpha5, 2.2.0.0_Beta0

Pin the installed versions

On RHEL the KubeOps package repository is configured so that its packages are excluded from normal dnf transactions — the install commands have to pass --disableexcludes=kubeops-repo to override that exclusion. As a result a regular dnf update already leaves these packages untouched, so the cluster is protected out of the box.

To lock the installed versions explicitly, use the versionlock plugin after the packages are installed:

sudo dnf install -y python3-dnf-plugin-versionlock
sudo dnf versionlock add \
  containerd.io podman kubelet kubeadm kubectl kubernetes-cni cri-tools \
  etcdctl etcdutl helm kosi kubeopsctl conntrack-tools

Alternatively, exclude them explicitly on each update:

sudo dnf update --exclude=containerd.io,podman,kubelet,kubeadm,kubectl,kubernetes-cni,cri-tools,etcdctl,etcdutl,helm,kosi,kubeopsctl

Dependencies

The repository also provides the following compatibility/dependency packages (32-bit i686 runtime libraries), which are pulled in automatically: conntrack-tools (1.4.7), glibc (2.34), glibc-gconv-extra (2.34), libgcc (11.5.0), libmnl (1.0.4), libnetfilter_cthelper (1.0.0), libnetfilter_cttimeout (1.0.0), libnetfilter_queue (1.0.5), libnfnetlink (1.0.1).

3.2 - Joining a Node in a Kubernetes cluster

This guide outlines the steps to join a nodes to a cluster.

To increase performance or add additional resource capacity to your cluster, adding a node to the cluster is the correct process. This process with kubeopsctl is very easy.
You can use the following steps to join control-plane nodes or worker-nodes to a Kubernetes cluster.

Join Node Process:

Prerequisits

KOSI Login Recommendation

Before performing any action with kubeopsctl, it is recommended to do a login with kosi. Refer to the official KOSI documentation for details here.

ETCD Backup Recommendation

Before performing changes on the control planes, it is recommended to create an ETCD backup. Refer to the official Kubernetes documentation for details here

Example 1: Joining a Control-Plane Node to a Kubernetes Cluster

1. Pull required KOSI packages on your ADMIN

If you do not specify a parameter, the current Kubernetes version 1.32.2 will be pulled.
With parameter --kubernetesVersion 1.34.1 you can pull a specific Kubernetes version.
Available Kubernetes versions are

kubeopsctl pull

2. Add your node definition/specifications in the cluster-values

  - name: demo-controlplaneXX
    iPAddress: 10.2.10.XXX
    type: controlplane
    kubeVersion: 1.31.6 

3. Adjust your cluster-values in zone1
Adjust your cluster-values in comparison to the example below. Be sure to set the actual version in your values, as well as the target version in the nodes. In the snippet below it is just the zone1.

# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: false
clusterName: myCluster
clusterUser: root
kubernetesVersion: 1.31.6       # -> actual version
kubeVipEnabled: false           
virtualIP: 10.2.10.110
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: /home/myuser/kubeops
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
systemCpu: 250m
systemMemory: 256Mi
packageRepository: https://packagerepo.kubeops.net/
changeCluster: true             # -> has to be set
zones:
- name: zone1
  nodes:
  - name: demo-controlplane01
    iPAddress: 10.2.10.110
    type: controlplane
    kubeVersion: 1.31.6       
  - name: demo-controlplaneXX   # -> has to be changed
    iPAddress: 10.2.10.XXX      # -> has to be changed
    type: controlplane
    kubeVersion: 1.31.6         # -> check with actual version
  - name: demo-worker01
    iPAddress: 10.2.10.210
    type: worker
    kubeVersion: 1.31.6       
- name: zone2
  nodes:
  - name: demo-controlplane02
    iPAddress: 10.2.10.120
    type: controlplane
    kubeVersion: 1.31.6       
  - name: demo-worker02
    iPAddress: 10.2.10.220
    type: worker
    kubeVersion: 1.31.6       
- name: zone3
  nodes:
  - name: demo-controlplane03
    iPAddress: 10.2.10.130
    type: controlplane
    kubeVersion: 1.31.6      
  - name: demo-worker03
    iPAddress: 10.2.10.230
    type: worker
    kubeVersion: 1.31.6      

3. Validate your values and join the node to the cluster

Once the cluster-values.yaml is created, check the values once again. If you are ready just start the join node process with the command:

kubeopsctl apply -f cluster-values.yaml

Example 1: Joining a Worker Node to a Kubernetes Cluster

1. Pull required KOSI packages on your ADMIN

If you do not specify a parameter, the current Kubernetes version 1.32.2 will be pulled.
With parameter --kubernetesVersion x.xx.x you can pull other Kubernetes versions.
Available Kubernetes versions are

kubeopsctl pull

2. Add your node definition/specifications in the cluster-values

  - name: demo-workerXX
    iPAddress: 10.2.10.XX
    type: worker
    kubeVersion: 1.31.6      

3. Adjust your cluster-values in zone2
Adjust your cluster-values in comparison to the example below. Be sure to set the actual version in your values, as well as the target version in the nodes. In the snippet below it is just the zone2.

# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: false
clusterName: myCluster
clusterUser: root
kubernetesVersion: 1.31.6        # -> actual version
kubeVipEnabled: false           
virtualIP: 10.2.10.110
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: /home/myuser/kubeops
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
systemCpu: 250m
systemMemory: 256Mi
packageRepository: https://packagerepo.kubeops.net/
changeCluster: true              # -> has to be set
zones:
- name: zone1
  nodes:
  - name: demo-controlplane01
    iPAddress: 10.2.10.110
    type: controlplane
    kubeVersion: 1.31.6       
  - name: demo-worker01
    iPAddress: 10.2.10.210
    type: worker
    kubeVersion: 1.31.6       
- name: zone2
  nodes:
  - name: demo-controlplane02
    iPAddress: 10.2.10.120
    type: controlplane
    kubeVersion: 1.31.6       
  - name: demo-worker02
    iPAddress: 10.2.10.220
    type: worker
    kubeVersion: 1.31.6       
  - name: demo-workerXX          # -> has to be changed
    iPAddress: 10.2.10.XX        # -> has to be changed
    type: worker
    kubeVersion: 1.31.6          # -> check with actual version     
- name: zone3
  nodes:
  - name: demo-controlplane03
    iPAddress: 10.2.10.130
    type: controlplane
    kubeVersion: 1.31.6      
  - name: demo-worker03
    iPAddress: 10.2.10.230
    type: worker
    kubeVersion: 1.31.6      

3. Validate your values and join the node to the cluster

Once the cluster-values.yaml is created, check the values once again. Before joining the node, note the following:

If you are ready, start the join node process with the command:

kubeopsctl apply -f cluster-values.yaml

If you need to apply the CRUSH map adjustment from above, use the following command instead:

kubeopsctl apply -f cluster-values.yaml -f enterprise-values.yaml

3.3 - Deleting a Node from a Kubernetes cluster

This guide outlines the steps to delete worker-nodes from a cluster, specifically how to proceed with rook-ceph and other KubeOps Compliance applications

Deleting a Node from a Kubernetes cluster

In rare cases, it may be necessary to remove nodes from a Kubernetes cluster. This how-to guide explains the prerequisites and the key considerations to keep in mind before starting the node removal process.

You can use the following steps to delete nodes from a Kubernetes cluster.

Prerequisites

  • In order to run rook-ceph stable for a longer period your cluster needs at least 3 zones with each zone containing at least 1 worker-node

  • To check which mon and osd is running on the node you want to delete you can use the command kubectl get pods -n rook-ceph -o wide | grep <node-name> | grep "mon\|osd" | grep -v "osd-prepare" | awk '{print $1}'. As an output you get the mon and the osd running on that node. If you don’t get an output, you don’t have to delete the ressource and can skip to the “delete the node”-section


Worker

Important: Due to rook-ceph, a worker node must not be removed without following the steps below. In this example, worker01 (zone1) is removed from the cluster. Worker01 contains osd.0 and mon-c.

Scale down the rook-ceph-operator deployment to 0

This prevents new MONs or OSDs from being created.

kubectl scale deploy rook-ceph-operator -n rook-ceph --replicas=0

Check which hosts and OSDs belong to each zone

kubectl exec -it deploy/rook-ceph-tools -n rook-ceph -- ceph osd tree
ID   CLASS  WEIGHT   TYPE NAME              STATUS  REWEIGHT  PRI-AFF
 -1         0.21478  root default
 -9         0.04880      zone zone1
 -7         0.04880          host worker01                              # worker01 is being removed
  0    ssd  0.04880              osd.0          up   1.00000  1.00000   # osd.0 is being removed
-15         0.04880          host worker04
  3    ssd  0.04880              osd.3          up   1.00000  1.00000
-11         0.10739      zone zone2
 -3         0.05859          host worker02
  1    ssd  0.05859              osd.1          up   0.95001  1.00000
-13         0.05859      zone zone3
 -5         0.05859          host worker03
  2    ssd  0.05859              osd.2          up   0.95001  1.00000

From this output you can see that osd.0 is part of worker01.

Scale down the OSD deployment

kubectl scale deploy -n rook-ceph rook-ceph-osd-<x> --replicas=0
# Example: kubectl scale deploy -n rook-ceph rook-ceph-osd-0 --replicas=0

Remove the OSD via ceph-tools

kubectl exec -it deploy/rook-ceph-tools -n rook-ceph -- bash
# show OSD tree
ceph osd tree
# mark OSD out
ceph osd out <x>
# Example: ceph osd out 0
ceph osd purge <x> --yes-i-really-mean-it
# Example: ceph osd purge 0 --yes-i-really-mean-it
ceph auth del osd.<x>
# adjust CRUSH map
ceph osd crush remove <nodename>
# exit from ceph-tools
exit
# show OSD tree (now without the deleted node)
kubectl exec -it deploy/rook-ceph-tools -n rook-ceph -- ceph osd tree

Check the MON running on the node

Before deleting a MON deployment, check which MON is running on the node you want to remove.

kubectl -n rook-ceph get pods -l app=rook-ceph-mon -o wide

Delete OSD and MON deployments

After checking the OSD and MON running on the node, delete the corresponding deployments.

kubectl delete deploy -n rook-ceph rook-ceph-osd-<x> rook-ceph-mon-<y>
Example
kubectl delete deploy -n rook-ceph rook-ceph-osd-0 rook-ceph-mon-c

Remove the deleted mon from the ceph tools

kubectl exec -it deploy/rook-ceph-tools -n rook-ceph -- ceph mon dump
kubectl exec -it deploy/rook-ceph-tools -n rook-ceph -- ceph mon rm <y>
# verify
kubectl exec -it deploy/rook-ceph-tools -n rook-ceph -- ceph mon dump
Example
kubectl exec -it deploy/rook-ceph-tools -n rook-ceph -- ceph mon dump
kubectl exec -it deploy/rook-ceph-tools -n rook-ceph -- ceph mon rm c
# verfify
kubectl exec -it deploy/rook-ceph-tools -n rook-ceph -- ceph mon dump

This is the dump before executing the remove:

0: [v2:192.168.231.184:3300/0,v1:192.168.231.184:6789/0] mon.a
1: [v2:192.168.185.9:3300/0,v1:192.168.185.9:6789/0] mon.b
2: [v2:192.168.196.110:3300/0,v1:192.168.196.110:6789/0] mon.c

This is the dump after executing the remove:

0: [v2:192.168.231.184:3300/0,v1:192.168.231.184:6789/0] mon.a
1: [v2:192.168.185.9:3300/0,v1:192.168.185.9:6789/0] mon.b

Delete the node from the kubernetes cluster

  • Remove the node you want to delete from the cluster-values.yaml file.
  • After updating the file, apply the deletion with the following command:
kubeopsctl apply --delete -f cluster-values.yaml
Example

The cluster-values.yaml without node1 but with node4

# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: true
clusterName: myCluster
clusterUser: root
kubernetesVersion: 1.31.6      
kubeVipEnabled: false
virtualIP: 10.2.10.110
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: /home/myuser/kubeops
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
systemCpu: 250m
systemMemory: 256Mi
packageRepository: local
changeCluster: true
zones:
- name: zone1
  nodes:
  - name: controlplane01
    iPAddress: 10.2.10.110
    type: controlplane
    kubeVersion: 1.31.6       
  - name: worker04
    iPAddress: 10.2.10.214
    type: worker
    kubeVersion: 1.31.6       
- name: zone2
  nodes:
  - name: controlplane02
    iPAddress: 10.2.10.120
    type: controlplane
    kubeVersion: 1.31.6       
  - name: worker02
    iPAddress: 10.2.10.220
    type: worker
    kubeVersion: 1.31.6       
- name: zone3
  nodes:
  - name: controlplane03
    iPAddress: 10.2.10.130
    type: controlplane
    kubeVersion: 1.31.6  
  - name: worker03
    iPAddress: 10.2.10.230
    type: worker
    kubeVersion: 1.31.6     

After updating the cluster-values.yaml, execute the delete command:

kubeopsctl apply --delete -f cluster-values.yaml

Scale the rook-ceph-operator deployment back to 1

This allows a new MON to be created automatically in zone2.

kubectl scale deploy rook-ceph-operator -n rook-ceph --replicas=1

Timing and health checks

The total duration depends on cluster size and node performance. Before proceeding, verify Ceph health and placement groups are clean.

kubectl exec -it deploy/rook-ceph-tools -n rook-ceph -- ceph status
kubectl exec -it deploy/rook-ceph-tools -n rook-ceph -- ceph pg stat

Typical duration ranges from 15 to 120 minutes.

If you want to rejoin the same node, reset it to a time prior to joining the cluster. Only this way you can be sure, that no leftovers from the deletion process remain!

3.4 - Single Sign-On with Keycloak

Learn how to configure Keycloak for Single Sign-On, securely expose it using Kubernetes Ingress and TLS, and integrate it with kubeops and other Kubernetes applications.

In this guide, you will learn how to implement Single Sign-On (SSO) using Keycloak. We will walk through the complete flow—from understanding SSO for platforms and services such as Rook Ceph, Harbor, OpenSearch, and other Kubernetes applications, to configuring Keycloak, exposing it securely, and integrating it with kubeops.

By the end of this guide, you will be able to:

  • Understand how Keycloak enables centralized authentication
  • Configure Keycloak for SSO
  • Securely expose Keycloak using Kubernetes Ingress and TLS
  • Integrate Keycloak with kubeops for authentication and authorization
  • Validate and troubleshoot the SSO login flow

Let’s get started on enabling secure and seamless authentication with Keycloak.

3.4.1 - Single Sign-On (SSO) with Keycloak for Harbor

Learn how to configure Single Sign-On (SSO) for Harbor using Keycloak with OIDC in a Kubernetes environment.

This guide describes how to configure Harbor authentication using Keycloak (OIDC) in a kubeops-managed Kubernetes environment.


Prerequisites

Before proceeding, ensure the following requirements are met:

  • A running Kubernetes cluster
  • kubectl installed and configured.
  • Keycloak is already installed and running
  • Keycloak is exposed using Kubernetes Ingress
  • A valid DNS record is configured for Keycloak and Harbor
  • TLS is enabled with a trusted Certificate Authority (CA)

Step 1: Prepare Keycloak (Realm, User, and Client)

In this step, we configure Keycloak for Harbor SSO. Keycloak is assumed to be already installed, exposed via Ingress, and reachable over HTTPS.

Create Realm

Ensure a realm named kubeops-dashboards exists.
If it does not exist, create it in the Keycloak admin console.

  • Realm name: kubeops-dashboards
  • Enabled: true

Create User

Ensure a user named kubeops exists in the kubeops-dashboards realm.
If the user does not exist, create it and set credentials.

  • Username: kubeops
  • Enabled: true
  • Set a permanent password

Create Client (Harbor)

Create a client for Harbor in the kubeops-dashboards realm.

  • Client ID: harbor
  • Client type: OpenID Connect
  • Client authentication: Enabled
  • Standard flow: Enabled
  • Direct access grants: Disabled

Valid Redirect URIs

Add the following redirect URI:

https://<your_DNS_name>/c/oidc/callback

Web Origins

<your_DNS_name>

Client Secret

After creating the client, copy the client secret.
This value will be used in the Harbor configuration:

oidc_client_id: harbor
oidc_client_secret: <CLIENT_SECRET>

Create Secret

kubectl create secret generic oidc-harbor \
    --namespace <your_harbor_namespace> \
    --from-literal=client_id=<your_oidc_client_id> \
    --from-literal=client_secret=<your_oidc_client_secret>

Step 2: Prepare Harbor Values

The following kubeops package configuration enables Harbor and integrates it with Keycloak using OIDC authentication.

apiVersion: kubeops/kubeopsctl/enterprise/beta/v1

deleteNs: false
localRegistry: false

packages:
  - name: harbor
    enabled: true
    values:
      standard:
        namespace: <you_harbor_namespace>
        harborpass: "password"
        databasePassword: "password"
        redisPassword: "password"
        externalURL: https://<your_DNS_name>
        nodePort: 30002
        hostname: <your_DNS_name>
        harborPersistence:
          persistentVolumeClaim:
            registry:
              size: 40Gi
              storageClass: "rook-cephfs"
            jobservice:
              jobLog:
                size: 1Gi
                storageClass: "rook-cephfs"
            database:
              size: 1Gi
              storageClass: "rook-cephfs"
            redis:
              size: 1Gi
              storageClass: "rook-cephfs"
            trivy:
              size: 5Gi
              storageClass: "rook-cephfs"

      advanced:
        core:
          extraEnvVars:
            - name: OIDC_CLIENT_ID
              valueFrom:
                secretKeyRef:
                  name: oidc-harbor 
                  key: client_id
            - name: OIDC_CLIENT_SECRET
              valueFrom:
                secretKeyRef:
                  name: oidc-harbor 
                  key: client_secret
            - name: CONFIG_OVERWRITE_JSON
              value: |
                {
                  "auth_mode": "oidc_auth",
                  "oidc_name": "keycloak",
                  "oidc_endpoint": "https://<your_DNS_name>/keycloak/realms/kubeops-dashboards",
                  "oidc_client_id": "$(OIDC_CLIENT_ID)",
                  "oidc_client_secret": "$(OIDC_CLIENT_SECRET)",
                  "oidc_scope": "openid,profile,email",
                  "oidc_verify_cert": true,
                  "oidc_auto_onboard": true
                }                

Notes

  • Ensure the OIDC client in Keycloak matches the oidc_client_id and oidc_client_secret values.
  • The externalURL and hostname must match the Harbor DNS name exactly.
  • oidc_auto_onboard: true allows users to be created automatically in Harbor upon first login.

3.4.2 - Single Sign-On (SSO) with Keycloak for KubeOps Dashboard

Learn how to configure Single Sign-On (SSO) for KubeOps Dashboard using Keycloak with OIDC.

This guide describes how to configure KubeOps Dashboard using Keycloak (OIDC) in a kubeops-managed Kubernetes environment.


Prerequisites

Before proceeding, ensure the following requirements are met:

  • A running Kubernetes cluster
  • kubectl installed and configured.
  • Keycloak is already installed and running

Step 1: Extract Keycloak CA certificate

Important: Replace all <your_DNS_name> placeholders with your correct DNS name

  • On your admin host, run the OpenSSL command (kept exactly as provided):
  openssl s_client -showcerts -connect <your_DNS_name>:443 /dev/null | openssl x509 -outform PEM > keycloak-ca.crt
  • Copy the CA certificate to each master

    scp @:/etc/kubernetes/pki/

Step 2: Update kube-apiserver yaml

On every master, edit the yaml : /etc/kubernetes/manifests/kube-apiserver.yaml

Important: Replace all <your_DNS_name> placeholders with your correct DNS name

spec:

  containers:

  - command:


    - --oidc-issuer-url=https://<your_DNS_name>/keycloak/realms/master

    - --oidc-client-id=headlamp

    - --oidc-username-claim=preferred_username

    - --oidc-groups-claim=groups

    - "--oidc-username-prefix=oidc:"

    - "--oidc-groups-prefix=oidc:"

    - --oidc-ca-file=/etc/kubernetes/pki/keycloak-ca.crt

Step 3: Create a Keycloak client for Headlamp

Important: Replace all <your_DNS_name> placeholders with your correct DNS name

  • Create a client for headlamp

    • Client ID: headlamp
    • Client type: OpenID Connect
    • Access type: Confidential
    • Client authentication: Enabled
    • Standard flow: Enabled
    • Direct access grants: Disabled
  • Valid Redirect URIs

    Add the following redirect URI:

    https://headlamp/<your_DNS_name>/*
    
  • Web Origins

    <your_DNS_name>
    

Step 4: Create a client scope for Headlamp

  • Create a client scope

    • Assigned Client Scope : headlamp-dedicated
  • For groups, use the Group Mapper in Keycloak:

    • Mapper Type: groups
    • Name: groups
    • Token Claim Name: groups
    • Add to ID token: ON
    • Add to access token: ON
    • Add to user info: ON
    • Add to token introspection: ON

Step 5: Create a user Group and user in Keycloak

Create a group named headlamp (if doesn’t exist already) and user under the group.

Step 6: Create ClusterRoleBinding for Headlamp group

1.Use following yaml to create ClusterRoleBinding

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: headlamp-admin-user
subjects:
- kind: Group
  name: "oidc:headlamp" # Der 'sub' oder 'preferred_username' from the Keycloak-Token
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

The name “oidc:headlamp” needs to be the same as the group name.

  1. Apply the ClusterRoleBinding file
    kubectl apply -f headlamp-clusterrolebinding.yaml

Step 7: Get client secret

After creating the client, copy the client secret.
This value will be used in the next step.

Step 8: Prepare Headlamp values (enterprise.yaml)

configure enterprise-yaml

Important: Replace all <your_DNS_name> placeholders with your correct DNS name

packages:
- name: kubeops-dashboard
  enabled: true
  values:
    standard:
      namespace: monitoring
      service:
        nodePort: 30007
      hostname: "<your_DNS_name>"
      path: "/"
    advanced:
      config:
        extraArgs:
          - "--in-cluster"
          - "--plugins-dir=/headlamp/plugins"
          - "--oidc-client-id=headlamp"
          - "--oidc-idp-issuer-url=https://<your_DNS_name>/keycloak/realms/master"
          - "--oidc-scopes=openid,profile,email"
          - "--insecure-ssl"
          - "--oidc-client-secret=<client-secret>"

Replace with the secret retrieved in Step 7.
-oidc-client-id must match the Keycloak client name (headlamp).

Step 9: Install Headlamp

Deploy Headlamp with the updated enterprise.yaml.

3.4.3 - Single Sign-On (SSO) with Keycloak for OpenSearch

Learn how to log in to OpenSearch and OpenSearch Dashboards with Single Sign-On (SSO) using Keycloak (OIDC).

This guide describes how to log in to OpenSearch Dashboards using Keycloak (OIDC) in a kubeops-managed Kubernetes environment.

Unlike some other integrations, you do not have to create the Keycloak realm, client, roles or mapper by hand — the opensearch-dashboards package provisions them automatically during install/update. Username/password login remains available as a fallback.


Prerequisites

  • A running Kubernetes cluster with kubectl configured
  • Keycloak is installed and running (the keycloak package), exposed via Ingress and reachable over HTTPS
  • A valid DNS record and a trusted TLS certificate (e.g. Let’s Encrypt) for the ingress hostname
  • The OpenSearch hostname is set to that public host and is identical for the opensearch-os and opensearch-dashboards packages

Step 1: Configure the packages

Set the shared hostname and (optionally) the adminPassword for both OpenSearch packages in your enterprise-values.yaml:

apiVersion: kubeops/kubeopsctl/enterprise/beta/v1

deleteNs: false
localRegistry: false

packages:
  - name: opensearch-os
    enabled: true
    values:
      standard:
        namespace: logging
        hostname: <your_DNS_name>          # must match opensearch-dashboards and Keycloak host
        adminPassword: "<admin-password>"  # optional, default Password@@123456
  - name: opensearch-dashboards
    enabled: true
    values:
      standard:
        namespace: logging
        nodePort: 30050
        hostname: <your_DNS_name>          # must match opensearch-os
        adminPassword: "<admin-password>"  # must match opensearch-os

Apply the configuration:

kubeopsctl apply -f enterprise-values.yaml

Step 2: What the package provisions automatically

During install/update the package configures Keycloak and OpenSearch for you:

  • Realm: kubeops-dashboards
  • Client: opensearch-dashboards (OpenID Connect, confidential, standard flow)
  • User: kubeops (default password password)
  • Realm roles: all_access, opensearch_dashboards_user
  • Protocol mapper: exposes the realm roles as a roles claim so OpenSearch can map them
  • OpenSearch backend security config: an openid authentication domain (Keycloak) plus a basic domain (username/password fallback), and a role mapping from the Keycloak realm roles to OpenSearch roles

The Keycloak admin credentials used for this are read from the keycloak-kubeops secret.


Step 3: Grant a user access

To let a Keycloak user log in to OpenSearch, assign them one of the realm roles in the kubeops-dashboards realm:

  • all_access — full access (maps to the OpenSearch all_access role)
  • opensearch_dashboards_user — dashboards access (maps to the kibana_user role)

You can use the pre-created kubeops user, or assign the role to your own Keycloak users.


Step 4: Log in

Open the OpenSearch Dashboards URL:

https://<your_DNS_name>/opensearch/
  • SSO: choose Log in with single sign-on → authenticate in Keycloak.
  • Fallback: use username admin and the adminPassword value (default Password@@123456).

Notes / Troubleshooting

  • hostname mismatch: the opensearch-os and opensearch-dashboards hostnames must be identical and must be the public Keycloak host, otherwise the OpenSearch backend cannot validate the token.

  • 401 Unauthorized on SSO login: the OpenSearch backend could not validate the Keycloak token. Check that hostname is set and reachable from the OpenSearch pods, and that Keycloak’s TLS certificate is trusted (e.g. Let’s Encrypt). Verify the backend security config contains the openid domain:

    curl -k -u admin:<adminPassword> \
      https://opensearch-cluster-master:9200/_plugins/_security/api/securityconfig
    
  • *.local hostname: SSO is intentionally skipped; only username/password login is available.

  • Changing the admin password: see Changing the OpenSearch password.

3.5 - Upgrading a Kubernetes cluster

This guide outlines the steps to upgrade the Kubernetes version of a cluster, specifically demonstrating how to change the version using a configuration file.

Upgrading a Kubernetes cluster is essential to maintain security, stability, and compatibility.Like Kubernetes itself, we adhere to the version skew policy and only allow upgrades between releases that differ by a single minor version. This ensures compatibility between components, reduces the risk of instability, and keeps the cluster in a supported and secure state.

For more information about the Version Skew Policy, see the official Kubernetes documentation:
Click here

Use the following steps to upgrade the Kubernetes version of a cluster.

Kubernetes Version Upgrade Process:

Prerequisites

KOSI Login Recommendation

Before performing any action with kubeopsctl, it is recommended to do a login with kosi. Refer to the official KOSI documentation for details here.

1. Pull required KOSI packages on your ADMIN

If you do not specify a parameter, the Kubernetes version 1.32.2 will be pulled.
With parameter --kubernetesVersion 1.34.1 you can pull an older Kubernetes version.
Available Kubernetes versions are

kubeopsctl pull --kubernetesVersion <x.xx.x>

2. Change your target version inside the cluster-values

3. Start the upgrade

kubeopsctl apply -f cluster-values.yaml

Example 1 - Upgrade all nodes in the cluster to a specific version

In this example, a cluster is upgraded from Kubernetes version v1.33.5 to v1.34.1.

1. Pull required KOSI packages on your ADMIN

Pull the kubernetes v1.34.1 packages on your ADMIN machine.

kubeopsctl pull --kubernetesVersion 1.34.1

2. Update the target version in cluster-values.yaml

Adjust your cluster-values.yaml according to the example below. Make sure you set:

  • The current Kubernetes version in kubernetesVersion.
  • The target Kubernetes version in the kubeVersion field of each node.
# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: true
clusterName: myCluster
clusterUser: root
kubernetesVersion: 1.33.5     # -> actual version
kubeVipEnabled: false
virtualIP: 10.2.10.110
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: /home/myuser/kubeops
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
systemCpu: 250m
systemMemory: 256Mi
packageRepository: local
changeCluster: true           # -> important! Needs to be set for an upgrade
zones:
- name: zone1
  nodes:
  - name: demo-controlplane01
    iPAddress: 10.2.10.110
    type: controlplane
    kubeVersion: 1.34.1       # -> target version
  - name: demo-worker01
    iPAddress: 10.2.10.210
    type: worker
    kubeVersion: 1.34.1       # -> target version
- name: zone2
  nodes:
  - name: demo-controlplane02
    iPAddress: 10.2.10.120
    type: controlplane
    kubeVersion: 1.34.1       # ->target version
  - name: demo-worker02
    iPAddress: 10.2.10.220
    type: worker
    kubeVersion: 1.34.1       # -> target version
- name: zone3
  nodes:
  - name: demo-controlplane03
    iPAddress: 10.2.10.130
    type: controlplane
    kubeVersion: 1.34.1       # -> target version
  - name: demo-worker03
    iPAddress: 10.2.10.230
    type: worker
    kubeVersion: 1.34.1       # -> target version

2. Validate your values and upgrade the cluster

After cluster-values.yaml is updated, review all values carefully.
When you are ready, start the upgrade process:

kubeopsctl apply -f cluster-values.yaml

Example 2 - Tranche upgrade of zones to a specific version

In this example, the cluster is upgraded in tranches. The order is:

  • zone1 (because it contains the initial control plane node),
  • then zone3,
  • and finally zone2.

1. Pull required KOSI packages on your ADMIN

Pull the kubernetes v1.33.5 packages on your ADMIN machine.

kubeopsctl pull --kubernetesVersion 1.33.5

2. Adjust your cluster-values in zone1

Adjust your cluster-values.yaml according to the example below. Make sure you set:

  • The current Kubernetes version in kubernetesVersion.
  • The target Kubernetes version only for the nodes in zone1. In the snippet below, only zone1 is configured with the target version.
# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: true
clusterName: myCluster
clusterUser: root
kubernetesVersion: 1.32.2     # -> actual version
kubeVipEnabled: false           
virtualIP: 10.2.10.110
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: /home/myuser/kubeops
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
systemCpu: 250m
systemMemory: 256Mi
packageRepository: local
changeCluster: true
zones:
- name: zone1
  nodes:
  - name: demo-controlplane01
    iPAddress: 10.2.10.110
    type: controlplane
    kubeVersion: 1.33.5       # -> target version
  - name: demo-worker01
    iPAddress: 10.2.10.210
    type: worker
    kubeVersion: 1.33.5       # -> target version
- name: zone2
  nodes:
  - name: demo-controlplane02
    iPAddress: 10.2.10.120
    type: controlplane
    kubeVersion: 1.32.2       
  - name: demo-worker02
    iPAddress: 10.2.10.220
    type: worker
    kubeVersion: 1.32.2       
- name: zone3
  nodes:
  - name: demo-controlplane03
    iPAddress: 10.2.10.130
    type: controlplane
    kubeVersion: 1.32.2       
  - name: demo-worker03
    iPAddress: 10.2.10.230
    type: worker
    kubeVersion: 1.32.2       

3. Validate your values and upgrade the cluster

After cluster-values.yaml is updated, review all values carefully. When you are ready, start the upgrade process:

kubeopsctl apply -f cluster-values.yaml

4. Adjust your cluster-values.yaml in zone2

Next, change the target version of zone2:

# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: true
clusterName: myCluster
clusterUser: root
kubernetesVersion: 1.32.2     # -> actual version
kubeVipEnabled: false
virtualIP: 10.2.10.110
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: /home/myuser/kubeops
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
systemCpu: 250m
systemMemory: 256Mi
packageRepository: local
changeCluster: true
zones:
- name: zone1
  nodes:
  - name: demo-controlplane01
    iPAddress: 10.2.10.110
    type: controlplane
    kubeVersion: 1.33.5       # -> target version
  - name: demo-worker01
    iPAddress: 10.2.10.210
    type: worker
    kubeVersion: 1.33.5       # -> target version
- name: zone2
  nodes:
  - name: demo-controlplane02
    iPAddress: 10.2.10.120
    type: controlplane
    kubeVersion: 1.33.5       # ->target version
  - name: demo-worker02
    iPAddress: 10.2.10.220
    type: worker
    kubeVersion: 1.33.5       # -> target version
- name: zone3
  nodes:
  - name: demo-controlplane03
    iPAddress: 10.2.10.130
    type: controlplane
    kubeVersion: 1.32.2       
  - name: demo-worker03
    iPAddress: 10.2.10.230
    type: worker
    kubeVersion: 1.32.2       

5. Validate your values and upgrade the cluster

After cluster-values.yaml is updated, review all values carefully. When you are ready, start the upgrade process:

kubeopsctl apply -f cluster-values.yaml

6. Adjust your cluster-values.yaml in zone3

Finally, change the target version of zone 3.

# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: true
clusterName: myCluster
clusterUser: root
kubernetesVersion: 1.32.2     # -> actual version
kubeVipEnabled: false
virtualIP: 10.2.10.110
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: /home/myuser/kubeops
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
systemCpu: 250m
systemMemory: 256Mi
packageRepository: local
changeCluster: true
zones:
- name: zone1
  nodes:
  - name: demo-controlplane01
    iPAddress: 10.2.10.110
    type: controlplane
    kubeVersion: 1.33.5       # -> target version
  - name: demo-worker01
    iPAddress: 10.2.10.210
    type: worker
    kubeVersion: 1.33.5       # -> target version
- name: zone2
  nodes:
  - name: demo-controlplane02
    iPAddress: 10.2.10.120
    type: controlplane
    kubeVersion: 1.33.5       # ->target version
  - name: demo-worker02
    iPAddress: 10.2.10.220
    type: worker
    kubeVersion: 1.33.5       # -> target version
- name: zone3
  nodes:
  - name: demo-controlplane03
    iPAddress: 10.2.10.130
    type: controlplane
    kubeVersion: 1.33.5       # -> target version
  - name: demo-worker03
    iPAddress: 10.2.10.230
    type: worker
    kubeVersion: 1.33.5       # -> target version

7. Validate your values and upgrade the cluster

After cluster-values.yaml is updated, review all values carefully. When you are ready, start the upgrade process:

kubeopsctl apply -f cluster-values.yaml

3.6 - Installing KubeOps Compliance applications

This guide outlines the steps to install KubeOps Compliance applications of a cluster.

There is a predefined selection of applications included with KubeOps Compliance. These applications ensure a production-ready cluster deployment and can be individually configured as needed.

By separating the cluster values from the application values, the application values can be modified independently and installed at a later stage, providing greater flexibility and maintainability.

Prerequisits

KOSI Login Recommendation

Before performing any action with kubeopsctl, it is recommended to do a login with kosi. Refer to the official KOSI documentation for details here.

Example 1: Installing Applications in a non-airgap-environment

To install the KubeOps Compliance Applications in an existing cluster follow the next steps:

1. Define the Enterprise-Value-file

In the example value, the following applications are enabled:

  • opa-gatekeeper
  • rook-ceph
  • harbor
  • kubeops-dashboard

All other applications are disabled and will not be installed. For more information about available packages as well as parameters for each package check here.

The following file is only an example. Make sure to change the necessary values (ips, passwords, …) before usage

apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
deleteNs: false
localRegistry: false
packages:
- name: opa-gatekeeper
  enabled: true
  values:
    standard:
      namespace: gatekeeper-system
    advanced:
- name: rook-ceph
  enabled: true
  values:
    standard:
      namespace: rook-ceph
      cluster:
        resources:
          mgr:
            requests:
              cpu: "500m"
              memory: "512Mi"
          mon:
            requests:
              cpu: "1"
              memory: "1Gi"
          osd:
            requests:
              cpu: "1"
              memory: "1Gi"
        dashboard:
          enabled: true
      operator:
        data:
          rookLogLevel: "DEBUG"
- name: harbor
  enabled: true
  values:
    standard:
      namespace: harbor
      harborpass: "password"
      databasePassword: "password"
      redisPassword: "password"
      externalURL: http://10.2.10.110:30002
      nodePort: 30002
      hostname: harbor.local
      harborPersistence:
        persistentVolumeClaim:
          registry:
            size: 40Gi
            storageClass: "rook-cephfs"
          jobservice:
            jobLog:
              size: 1Gi
              storageClass: "rook-cephfs"
          database:
            size: 1Gi
            storageClass: "rook-cephfs"
          redis:
            size: 1Gi
            storageClass: "rook-cephfs"
          trivy: 
            size: 5Gi
            storageClass: "rook-cephfs"
    advanced:
- name: kubeops-dashboard
  enabled: true
  values:
    standard:
      namespace: monitoring
      hostname: kubeops-dashboard.local
      service:
        nodePort: 30007
    advanced:
- name: filebeat-os
  enabled: false
  values:
    standard:
      namespace: logging
    advanced:

2. Pull the KubeOps Compliance Applications packages
To pull the required application packages in the correct version for the release, use the following commands:

kubeopsctl pull -f enterprise-values.yaml --kubernetesVersion <x.xx.x>

or

kubeopsctl pull --tools enterprise-values.yaml --kubernetesVersion <x.xx.x>

3. The KubeOps Compliance Application installation process
Important for only installation of the tools is that you have set your flag changeCluster to false in your cluster-values.yaml.

The following file is only an example. Make sure to change the necessary values (ips, passwords, …) before usage

# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: false                       # -> important
clusterName: myCluster
clusterUser: root
kubernetesVersion: 1.31.6         
kubeVipEnabled: false
virtualIP: 10.2.10.110
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: /home/myuser/kubeops
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
systemCpu: 250m
systemMemory: 256Mi
packageRepository: https://packagerepo.kubeops.net/
changeCluster: false                # -> important
zones:
- name: zone1
  nodes:
  - name: demo-controlplane01
    iPAddress: 10.2.10.110
    type: controlplane
    kubeVersion: 1.32.2       
  - name: demo-worker01
    iPAddress: 10.2.10.210
    type: worker
    kubeVersion: 1.32.2      
- name: zone2
  nodes:
  - name: demo-controlplane02
    iPAddress: 10.2.10.120
    type: controlplane
    kubeVersion: 1.32.2       
  - name: demo-worker02
    iPAddress: 10.2.10.220
    type: worker
    kubeVersion: 1.32.2       
- name: zone3
  nodes:
  - name: demo-controlplane03
    iPAddress: 10.2.10.130
    type: controlplane
    kubeVersion: 1.32.2       
  - name: demo-worker03
    iPAddress: 10.2.10.230
    type: worker
    kubeVersion: 1.32.2        

4. Validate your values and install the KubeOps Compliance Applications Once you finished defining your values, check them once again. If you are ready, just start the installation process with the command:

kubeopsctl apply -f cluster-values.yaml -f enterprise-values.yaml

Example 2: Installing Applications in an airgap-environment

To install the KubeOps Compliance Applications in an existing cluster follow the next steps:

1. Define the Enterprise-Value-file

In the example value, the following applications are enabled:

  • opa-gatekeeper
  • rook-ceph
  • harbor
  • kubeops-dashboard

All other applications are disabled and will not be installed. Value-parameter will be explained in the references and can be found here.

apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
deleteNs: false
localRegistry: true             # important for airgap, otherwise images are pulled from public registry
packages:
- name: opa-gatekeeper
  enabled: true
  values:
    standard:
      namespace: gatekeeper-system
    advanced:
- name: rook-ceph
  enabled: true
  values:
    standard:
      namespace: rook-ceph
      cluster:
        resources:
          mgr:
            requests:
              cpu: "500m"
              memory: "512Mi"
          mon:
            requests:
              cpu: "1"
              memory: "1Gi"
          osd:
            requests:
              cpu: "1"
              memory: "1Gi"
        dashboard:
          enabled: true
      operator:
        data:
          rookLogLevel: "DEBUG"
- name: harbor
  enabled: true
  values:
    standard:
      namespace: harbor
      harborpass: "password"
      databasePassword: "password"
      redisPassword: "password"
      externalURL: http://10.2.10.110:30002
      nodePort: 30002
      hostname: harbor.local
      harborPersistence:
        persistentVolumeClaim:
          registry:
            size: 40Gi
            storageClass: "rook-cephfs"
          jobservice:
            jobLog:
              size: 1Gi
              storageClass: "rook-cephfs"
          database:
            size: 1Gi
            storageClass: "rook-cephfs"
          redis:
            size: 1Gi
            storageClass: "rook-cephfs"
          trivy: 
            size: 5Gi
            storageClass: "rook-cephfs"
    advanced:
- name: kubeops-dashboard
  enabled: true
  values:
    standard:
      namespace: monitoring
      hostname: kubeops-dashboard.local
      service:
        nodePort: 30007
    advanced:
- name: filebeat-os
  enabled: false
  values:
    standard:
      namespace: logging
    advanced:

2. Pull the KubeOps Compliance Applications packages
To pull the required application packages in the correct version for the release, use the following commands:

kubeopsctl pull -f enterprise-values.yaml --kubernetesVersion <x.xx.x>

or

kubeopsctl pull --tools enterprise-values.yaml --kubernetesVersion <x.xx.x>

3. The KubeOps Compliance Application installation process
Important for only installation of the tools is that you have set your flag changeCluster to false in your cluster-values.yaml.

The following file is only an example. Make sure to change the necessary values (ips, passwords, …) before usage

# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: true                        # -> important
clusterName: myCluster
clusterUser: root
kubernetesVersion: 1.32.2         
kubeVipEnabled: false
virtualIP: 10.2.10.110
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: /home/myuser/kubeops
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
systemCpu: 250m
systemMemory: 256Mi
packageRepository: local
changeCluster: false                # -> important
zones:
- name: zone1
  nodes:
  - name: demo-controlplane01
    iPAddress: 10.2.10.110
    type: controlplane
    kubeVersion: 1.32.2      
  - name: demo-worker01
    iPAddress: 10.2.10.210
    type: worker
    kubeVersion: 1.32.2       
- name: zone2
  nodes:
  - name: demo-controlplane02
    iPAddress: 10.2.10.120
    type: controlplane
    kubeVersion: 1.32.2      
  - name: demo-worker02
    iPAddress: 10.2.10.220
    type: worker
    kubeVersion: 1.32.2      
- name: zone3
  nodes:
  - name: demo-controlplane03
    iPAddress: 10.2.10.130
    type: controlplane
    kubeVersion: 1.32.2      
  - name: demo-worker03
    iPAddress: 10.2.10.230
    type: worker
    kubeVersion: 1.32.2        

4. Validate your values and install the KubeOps Compliance Applications Once you finished defining your values, check them once again. If you are ready, just start the installation process with the command:

kubeopsctl apply -f cluster-values.yaml -f enterprise-values.yaml

3.7 - Updating KubeOps Compliance applications

This guide outlines the steps to update KubeOps Compliance applications of a cluster.

There is a predefined selection of applications included with KubeOps Compliance. These applications ensure a production-ready cluster deployment and can be configured individually as needed.

By separating cluster values from application values, application values can be modified independently and installed later, providing greater flexibility and maintainability.

kubeopsctl automatically detects whether an application is already deployed and updates it accordingly. de]

Prerequisites

KOSI Login Recommendation

Before performing any action with kubeopsctl, it is recommended to do a login with kosi. Refer to the official KOSI documentation for details here.

Updated KubeOpsctl

If you have an older kubeopsctl version installed, update it before starting with updating Compliance appliactions.

# kubeopsctl-version can be found under : https://packagerepo.kubeops.net/deb/pool/main/
sudo apt update
sudo apt install -y kubeopsctl=<kubeopsctl-version>
# kubeopsctl-version can be found under : https://packagerepo.kubeops.net/rpm/
sudo dnf install -y --disableexcludes=kubeops-repo <kubeopsctl-version>
# kubeopsctl-version can be found under : https://packagerepo.kubeops.net/deb/pool/main/
wget https://packagerepo.kubeops.net/deb/pool/main/<kubeopsctl-version>.deb
sudo dpkg --install <kubeopsctl-version>.deb
# kubeopsctl-versions can be found under: https://packagerepo.kubeops.net/rpm
sudo rpm kubeopsctl
wget https://packagerepo.kubeops.net/rpm/<kubeopsctl-version>.rpm
sudo rpm --install <kubeopsctl-version>.rpm

Example 1: Updating Applications in a non-airgap-environment

To update the KubeOps Compliance Applications in an existing cluster follow the next steps:

1. Define the Enterprise-Value-file

In the example value, the following applications are enabled:

  • opa-gatekeeper
  • rook-ceph
  • harbor
  • kubeops-dashboard

All other applications are disabled and will not be updated. Value-parameter will be explained in the references and can be found here.

apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
deleteNs: false
localRegistry: false
packages:
- name: opa-gatekeeper
  enabled: true
  values:
    standard:
      namespace: gatekeeper-system
    advanced:
- name: rook-ceph
  enabled: true
  values:
    standard:
      namespace: rook-ceph
      cluster:
        resources:
          mgr:
            requests:
              cpu: "500m"
              memory: "512Mi"
          mon:
            requests:
              cpu: "1"
              memory: "1Gi"
          osd:
            requests:
              cpu: "1"
              memory: "1Gi"
        dashboard:
          enabled: true
      operator:
        data:
          rookLogLevel: "DEBUG"
- name: harbor
  enabled: true
  values:
    standard:
      namespace: harbor
      harborpass: "password"
      databasePassword: "password"
      redisPassword: "password"
      externalURL: http://10.2.10.110:30002
      nodePort: 30002
      hostname: harbor.local
      harborPersistence:
        persistentVolumeClaim:
          registry:
            size: 40Gi
            storageClass: "rook-cephfs"
          jobservice:
            jobLog:
              size: 1Gi
              storageClass: "rook-cephfs"
          database:
            size: 1Gi
            storageClass: "rook-cephfs"
          redis:
            size: 1Gi
            storageClass: "rook-cephfs"
          trivy: 
            size: 5Gi
            storageClass: "rook-cephfs"
    advanced:
- name: kubeops-dashboard
  enabled: true
  values:
    standard:
      namespace: monitoring
      hostname: kubeops-dashboard.local
      service:
        nodePort: 30007
    advanced:
- name: filebeat-os
  enabled: false
  values:
    standard:
      namespace: logging
    advanced:

2. Pull the KubeOps Compliance Applications packages
To pull the required application packages in the correct version for the release, use the following commands:

kubeopsctl pull -f enterprise-values.yaml --kubernetesVersion <x.xx.x>

or

kubeopsctl pull --tools enterprise-values.yaml --kubernetesVersion <x.xx.x>

3. The KubeOps Compliance Application update process
Important for only update of the tools is that you have set your flag changeCluster to false in your cluster-values.yaml.

# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: false                       # -> important
clusterName: <your cluster name>
clusterUser: <your user name>
kubernetesVersion: <your kubernetesversion>
kubeVipEnabled: false
virtualIP: <your master1 ip>
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: <your kubeopsroot path>
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
packageRepository: local            # If you have incorporated package repository, replace “local” with the URL https://packagerepo.kubeops.net/
changeCluster: false                # -> important
zones:
- name: zone1
  nodes:
  - name: demo-controlplane01
    iPAddress: 10.2.10.110
    type: controlplane
    kubeVersion: 1.31.6       
  - name: demo-worker01
    iPAddress: 10.2.10.210
    type: worker
    kubeVersion: 1.31.6       
- name: zone2
  nodes:
  - name: demo-controlplane02
    iPAddress: 10.2.10.120
    type: controlplane
    kubeVersion: 1.31.6       
  - name: demo-worker02
    iPAddress: 10.2.10.220
    type: worker
    kubeVersion: 1.30.8       
- name: zone3
  nodes:
  - name: demo-controlplane03
    iPAddress: 10.2.10.130
    type: controlplane
    kubeVersion: 1.31.6       
  - name: demo-worker03
    iPAddress: 10.2.10.230
    type: worker
    kubeVersion: 1.31.6        

4. Validate your values and update the KubeOps Compliance Applications Once you finished defining your values, check them once again. If you are ready, just start the update process with the command:

kubeopsctl apply -f cluster-values.yaml -f enterprise-values.yaml

Example 2: Updating Applications in an airgap-environment

To update the KubeOps Compliance Applications in an existing cluster follow the next steps:

1. Define the Enterprise-Value-file

In the example value, the following applications are enabled:

  • opa-gatekeeper
  • rook-ceph
  • harbor
  • kubeops-dashboard

All other applications are disabled and will not be updated. Value-parameter will be explained in the references and can be found here.

apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
deleteNs: false
localRegistry: true             # important for airgap, otherwise images are pulled from public registry
packages:
- name: opa-gatekeeper
  enabled: true
  values:
    standard:
      namespace: gatekeeper-system
    advanced:
- name: rook-ceph
  enabled: true
  values:
    standard:
      namespace: rook-ceph
      cluster:
        resources:
          mgr:
            requests:
              cpu: "500m"
              memory: "512Mi"
          mon:
            requests:
              cpu: "1"
              memory: "1Gi"
          osd:
            requests:
              cpu: "1"
              memory: "1Gi"
        dashboard:
          enabled: true
      operator:
        data:
          rookLogLevel: "DEBUG"
- name: harbor
  enabled: true
  values:
    standard:
      namespace: harbor
      harborpass: "password"
      databasePassword: "password"
      redisPassword: "password"
      externalURL: http://10.2.10.110:30002
      nodePort: 30002
      hostname: harbor.local
      harborPersistence:
        persistentVolumeClaim:
          registry:
            size: 40Gi
            storageClass: "rook-cephfs"
          jobservice:
            jobLog:
              size: 1Gi
              storageClass: "rook-cephfs"
          database:
            size: 1Gi
            storageClass: "rook-cephfs"
          redis:
            size: 1Gi
            storageClass: "rook-cephfs"
          trivy: 
            size: 5Gi
            storageClass: "rook-cephfs"
    advanced:
- name: kubeops-dashboard
  enabled: true
  values:
    standard:
      namespace: monitoring
      hostname: kubeops-dashboard.local
      service:
        nodePort: 30007
    advanced:
- name: filebeat-os
  enabled: false
  values:
    standard:
      namespace: logging
    advanced:

2. Update kubeopsctl

If you have an older kubeopsctl version installed, update it using the following commands.

# kubeopsctl-version can be found under : https://packagerepo.kubeops.net/deb/pool/main/
sudo apt update
sudo apt install -y kubeopsctl=<kubeopsctl-version>
# kubeopsctl-version can be found under : https://packagerepo.kubeops.net/rpm/
sudo dnf install -y --disableexcludes=kubeops-repo <kubeopsctl-version>
# kubeopsctl-version can be found under : https://packagerepo.kubeops.net/deb/pool/main/
wget https://packagerepo.kubeops.net/deb/pool/main/<kubeopsctl-version>.deb
sudo dpkg --install <kubeopsctl-version>.deb
# kubeopsctl-versions can be found under: https://packagerepo.kubeops.net/rpm
sudo rpm kubeopsctl
wget https://packagerepo.kubeops.net/rpm/<kubeopsctl-version>.rpm
sudo rpm --install <kubeopsctl-version>.rpm
2. Pull the KubeOps Compliance Applications packages
To pull the required application packages in the correct version for the release, use the following commands:

kubeopsctl pull -f enterprise-values.yaml --kubernetesVersion <x.xx.x>

or

kubeopsctl pull --tools enterprise-values.yaml --kubernetesVersion <x.xx.x>

3. The KubeOps Compliance Application update process
Important for only the update of the tools is that you have set your flag changeCluster to false in your cluster-values.yaml.

# file cluster-values.yaml
apiVersion: kubeops/kubeopsctl/cluster/beta/v1
imagePullRegistry: registry.kubeops.net/kubeops/kubeops
airgap: true                          # -> important
clusterName: <your cluster name>
clusterUser: <your user name>
kubernetesVersion: <your kubernetesversion>
kubeVipEnabled: false
virtualIP: <your master1 ip>
firewall: nftables
pluginNetwork: calico
containerRuntime: containerd
kubeOpsRoot: <your kubeopsroot path>
serviceSubnet: 192.168.128.0/17
podSubnet: 192.168.0.0/17
debug: true
packageRepository: local            # If you have incorporated package repository, replace “local” with the URL https://packagerepo.kubeops.net/
changeCluster: false                # -> important
zones:
- name: zone1
  nodes:
  - name: demo-controlplane01
    iPAddress: 10.2.10.110
    type: controlplane
    kubeVersion: 1.31.6       
  - name: demo-worker01
    iPAddress: 10.2.10.210
    type: worker
    kubeVersion: 1.31.6       
- name: zone2
  nodes:
  - name: demo-controlplane02
    iPAddress: 10.2.10.120
    type: controlplane
    kubeVersion: 1.31.6       
  - name: demo-worker02
    iPAddress: 10.2.10.220
    type: worker
    kubeVersion: 1.30.8       
- name: zone3
  nodes:
  - name: demo-controlplane03
    iPAddress: 10.2.10.130
    type: controlplane
    kubeVersion: 1.31.6       
  - name: demo-worker03
    iPAddress: 10.2.10.230
    type: worker
    kubeVersion: 1.31.6        

4. Validate your values and update the KubeOps Compliance Applications Once you finished defining your values, check them once again. If you are ready, just start the update process with the command:

kubeopsctl apply -f cluster-values.yaml -f enterprise-values.yaml

3.8 - Harbor Deployment with CloudNativePG

Here is a brief overview of Harbor Deployment with CloudNativePG on Kubernetes using Kosi

This guide describes how to deploy Harbor on Kubernetes using a CloudNativePG (CNPG) PostgreSQL cluster managed by the CloudNativePG operator in an air‑gap and non-airgap environments.

Harbor Deployment with CloudNativePG in Non-airgap enviroment

Prerequisites

  • A running Kubernetes cluster.
  • kubectl, kosi, and kubeopsctl installed and configured.
  • You need to login with kosi . Refer to the official KOSI documentation for details here.

Step 1 — Install CloudNativePG operator

Deploy the operator with Kosi:

kosi install --hub kubeops kubeops/cloudnative-pg-operator:<kubeopsctl_version> --dname cnpg-operator

With this step, it Installs the CloudNativePG operator into the cluster and the operator manages PostgreSQL clusters and their lifecycle.

Step 2 — Create PostgreSQL cluster for Harbor

1. Apply the following Cluster manifest to create a Postgres cluster with 2 instances and 1Gi storage:
cat <<EOF | kubectl apply -f -
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cloudnative-pg
  namespace: harbor
spec:
  instances: 2
  imagePullSecrets:
  - name: registry-pullsecret
  storage:
    size: 1Gi
EOF
2. Services and pods created for the cluster cloudnative-pg:

cloudnative-pg-rw → primary (read/write) cloudnative-pg-ro → replicas (read-only) cloudnative-pg-r → all pods

3. Verify pods are Running:
kubectl get pods -n harbor

Step 3 — Retrieve application user credentials

CNPG automatically creates a Secret named cloudnative-pg-app in the harbor namespace.

1. Verify the Secret exists:
kubectl get secret cloudnative-pg-app -n harbor
2. Decode the base64-encoded fields:
kubectl get secret cloudnative-pg-app -n harbor -o jsonpath="{.data.username}" | base64 -d 
kubectl get secret cloudnative-pg-app -n harbor -o jsonpath="{.data.password}" | base64 -d 
kubectl get secret cloudnative-pg-app -n harbor -o jsonpath="{.data.dbname}" | base64 -d

Example values (for illustration only):

username: app
password: Hw2t7hXuKPfZrVjVDwCc4PeKTevlB7ORmzQeW50JtEqiwHl40xkxuhVHeRIU3fX2
database: app

Important:
Use the non-superuser application credentials from this Secret in Harbor’s configuration.

Step 4 — Update Harbor tools.yaml for an external database

Edit your tools.yaml and set Harbor values under the helm chart configuration.
Example snippet:

- name: harbor
  enabled: true
  values:
    standard:
      namespace: harbor
      harborpass: "password"
      databasePassword: "<DB_PASSWORD>"
      redisPassword: "Redis_Password"
      externalURL: <your_domain_name>
      nodePort: 30002
      hostname: <your_domain_name>
      harborPersistence:
        persistentVolumeClaim:
          registry:
            size: 40Gi
            storageClass: "rook-cephfs"
          jobservice:
            jobLog:
              size: 1Gi
              storageClass: "rook-cephfs"
          database:
            size: 1Gi
            storageClass: "rook-cephfs"
          redis:
            size: 1Gi
            storageClass: "rook-cephfs"
          trivy: 
            size: 5Gi
            storageClass: "rook-cephfs"
    advanced:
      database:
        type: external
        external:
          host: "cloudnative-pg-rw.harbor.svc.cluster.local"
          port: "5432"
          username: "app"
          password: "Hw2t7hXuKPfZrVjVDwCc4PeKTevlB7ORmzQeW50JtEqiwHl40xkxuhVHeRIU3fX2"
          coreDatabase: "app"

Important: Use the -rw service host (cloudnative-pg-rw…) for write operations.
Do not use a superuser account.
Ensure the password matches the CNPG Secret.

Step 5 — Install Harbor with Kosi

1. Deploy Harbor using the updated tools.yaml:
kosi install --hub kubeops kubeops/harbor:2.0.3 -f tools.yaml --dname harbor
2. Verify Harbor pods:
kubectl get pods -n harbor
3. Access Harbor at: <your_domain_name>:30002 (or as configured)

Harbor Deployment with CloudNativePG in Airgap envoirnment

Prerequisites

  • A running Kubernetes cluster.
  • podman, kubectl, kosi, and kubeopsctl installed and configured.
  • You need to login with kosi . Refer to the official KOSI documentation for details here.

Step 1: Login into Harbor

First, log in to your Harbor registry and pull the CloudNativePG operator package using kosi.

podman login <ip_address>:<nodePort> -u <user_name> -p <password> --tls-verify=false   
kosi pull --hub kubeops kubeops/cloudnative-pg-operator:<kubeopsctl_version> -o cloudnative-pg.tgz -r <ip_address>:<NodePort>/kubeops -t localhost:<NodePort>/kubeops

kosi install -p cloudnative-pg.tgz --dname cld-pg

Step 2: Manually Mirror the PostgreSQL Image to the KubeOps Project

In an air‑gapped environment, you must manually pull the PostgreSQL image from the external registry and push it to the KubeOps project in Harbor.

podman pull ghcr.io/cloudnative-pg/postgresql:18.1-system-trixie

podman tag ghcr.io/cloudnative-pg/postgresql:18.1-system-trixie <ip_address>:<NodePort>/kubeops/cloudnative-pg/postgresql:18.1-system-trixie

podman push <ip_address>:<NodePort>/kubeops/cloudnative-pg/postgresql:18.1-system-trixie --tls-verify=false

Step 3: Create the PostgreSQL Cluster for Harbor

Create a CNPG PostgreSQL cluster with two instances and 1Gi of storage in the harbor namespace:

cat <<EOF | kubectl apply -f -
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cloudnative-pg
  namespace: harbor
spec:
  instances: 2
  storage:
    size: 1Gi
EOF

Step 4: Configure the Cluster to Use the Mirrored Image

Update the CNPG cluster to use the image you pushed to Harbor in Step 2.

1.List the cluster:
kubectl get cluster -n harbor
2.Edit the cluster:
kubectl edit cluster -n harbor cloudnative-pg
3.Replace the image name in the editor:

From:

ghcr.io/cloudnative-pg/postgresql:18.1-system-trixie

To:

localhost:<NodePort>/kubeops/cloudnative-pg/postgresql:18.1-system-trixie

Step 5: Retrieve CNPG Application User Credentials

CNPG automatically creates a Secret named cloudnative-pg-app in the harbor namespace.

1. Verify the Secret exists:
kubectl get secret cloudnative-pg-app -n harbor
2. Decode the base64-encoded fields:
kubectl get secret cloudnative-pg-app -n harbor -o jsonpath="{.data.username}" | base64 -d 
kubectl get secret cloudnative-pg-app -n harbor -o jsonpath="{.data.password}" | base64 -d 
kubectl get secret cloudnative-pg-app -n harbor -o jsonpath="{.data.dbname}" | base64 -d

Example values (for illustration only):

username: app
password: Hw2t7hXuKPfZrVjVDwCc4PeKTevlB7ORmzQeW50JtEqiwHl40xkxuhVHeRIU3fX2
database: app

Important:
Use the non-superuser application credentials from this Secret in Harbor’s configuration.

Step 6: Configure Harbor in enterprise.yaml

  1. Update your enterprise-values.yaml to configure Harbor with the external CNPG database.
    Example snippet:
apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
deleteNs: false
localRegistry: false
packages:
  - name: harbor
    enabled: true
    values:
      standard:
        namespace: harbor
        harborpass: "password"
        databasePassword: "<DB_PASSWORD>"
        redisPassword: "Redis_Password"
        externalURL: <your_domain_name>
        nodePort: 30002
        hostname: <your_domain_name>
        harborPersistence:
          persistentVolumeClaim:
            registry:
              size: 40Gi
              storageClass: "rook-cephfs"
            jobservice:
              jobLog:
                size: 1Gi
                storageClass: "rook-cephfs"
            database:
              size: 1Gi
              storageClass: "rook-cephfs"
            redis:
              size: 1Gi
              storageClass: "rook-cephfs"
            trivy: 
              size: 5Gi
              storageClass: "rook-cephfs"
      advanced:
        database:
          type: external
          external:
            host: "cloudnative-pg-rw.harbor.svc.cluster.local"
            port: "5432"
            username: "app"
            password: "Hw2t7hXuKPfZrVjVDwCc4PeKTevlB7ORmzQeW50JtEqiwHl40xkxuhVHeRIU3fX2"
            coreDatabase: "app"

Important: Use the -rw service host (cloudnative-pg-rw…) for write operations.
Do not use a superuser account.
Ensure the password matches the CNPG Secret.

  1. Apply the updated configuration:
kubeopsctl apply -f enterprise-values.yaml

Step 6 — Verify the Harbor Deployment

  1. Check that Harbor pods are running in the harbor namespace:
kubectl get pods -n harbor

All Harbor pods should eventually reach a Running or Ready state

3.9 - Ingress Configuration

Here is a brief overview of how you can configure your ingress manually.

Manual configuration of the Nginx-Ingress-Controller

Right now the Ingress Controller Package is not fully configured. To make complete use of the Ingress capabilities of the cluster, the user needs to manually update some of the settings of the corresponding service.

Choosing an ingress controller. KubeOps ships two ingress controllers: ingress-nginx and traefik. NGINX has reached end of support, so new clusters should prefer Traefik and existing clusters should plan a migration. To replace nginx-ingress with Traefik (including how SSO, certificates and dashboards keep working), follow How to migrate from nginx to traefik ingress. The rest of this page covers the manual nginx service configuration.

Locating the service

The service in question is called “ingress-nginx-controller” and can be found in the same namespace as the ingress package itself. To locate the service across all namespaces, you could use the following command.

kubectl get service -A | grep ingress-nginx-controller

This command should return two entries of services, “ingress-nginx-controller” and “ingress-nginx-controller-admission”, though only the first one needs to be further adjusted.

Setting the Ingress-Controller service to type NodePort

To edit the service, you can use the following command, although the actual namespace may be different. This will change the service type to NodePort.

kubectl patch service ingress-nginx-controller -n ingress -p '{"spec":{"type":"NodePort"}}'

Kubernetes will now automatically assign unused portnumbers for the nodePort to allow http and https connections to the service. These can be retrieved by running the same command, used to locate the service. Alternatively, you can use the following command, which adds the portnumbers 30080 and 30443 for the respective protocols. By doing so, you have to make sure, that these portnumbers are not being used by any other NodePort service.

kubectl patch service ingress-nginx-controller -n ingress --type=json -p '[{"op":"replace","path":"/spec/type","value":"NodePort"}, {"op":"add","path":"/spec/ports/0/nodePort","value":30080}, {"op":"add","path":"/spec/ports/1/nodePort","value":30443}]'

Configuring external IPs

If you have access to external IPs that route to one or more cluster nodes, you can expose your Kubernetes-Services of any type through these addresses. The command below shows how to add an external IP-Adress to the service with the example value of “192.168.0.1”. Keep in mind that this value has to be changed in order to fit your networking settings.

kubectl patch service ingress-nginx-controller -n ingress -p '{"spec":{"externalIPs":["192.168.0.1"]}}'

3.10 - Accessing Dashboards installed with KubeOps

A brief overview of how you can access dashboards.

To access an application dashboard, an SSH tunnel to one of the control planes is needed. The following dashboards are available and configured with the following NodePorts by default:

NodePort

32090 (if not set otherwise in the enterprise-values.yaml)

Connecting via SSH Tunnel

To establish a tunnel, forward the NodePort from one of the control planes to your local machine. You can use the command line, PuTTY, or MobaXterm for this.
After that, the dashboard can be accessed at localhost:32090/prometheus/.

Connecting via Ingress

The dashboard can also be accessed via https://<your-domain>/prometheus/.

Initial login credentials

No credentials are necessary for login.

NodePort

30211 (if not set otherwise in the enterprise-values.yaml)

Connecting via SSH Tunnel

To establish a tunnel, forward the NodePort from one of the control planes to your local machine. You can use the command line, PuTTY, or MobaXterm for this.
After that, the dashboard can be accessed at localhost:30211/grafana/.

Connecting via Ingress

The dashboard can also be accessed via https://<your-domain>/grafana/.

Initial login credentials

  • username: the username set in the enterprise-values.yaml of Prometheus (default: user)
  • password: the password set in the enterprise-values.yaml of Prometheus (default: password)

NodePort

30050 (if not set otherwise in the enterprise-values.yaml)

Connecting via SSH Tunnel

To establish a tunnel, forward the NodePort from one of the control planes to your local machine. You can use the command line, PuTTY, or MobaXterm for this.
After that, the dashboard can be accessed at localhost:30050/.

Connecting via Ingress

The dashboard can also be accessed via https://<your-domain>/opensearch/.

Login

OpenSearch Dashboards supports Single Sign-On (SSO) via Keycloak as the primary login, with username/password as a fallback.

  • SSO (recommended): open https://<your-domain>/opensearch/ and choose Log in with single sign-on. You are redirected to Keycloak. See the SSO for OpenSearch guide for setup and how to grant users access.
  • Username / password (fallback):
    • username: admin
    • password: the value of adminPassword in the enterprise-values.yaml (default: Password@@123456)

NodePort

  • HTTP: 30002
  • HTTPS: 30003

Connecting via SSH Tunnel

To establish a tunnel, forward port 30002 from one of the control planes to your local machine. You can use the command line, PuTTY, or MobaXterm for this.
After that, the dashboard can be accessed at localhost:30002/.

Connecting via Ingress

The dashboard can also be accessed via https://<your-domain>/.

Initial login credentials

  • username: admin
  • password: the password set in the enterprise-values.yaml (default: password)

NodePort

The Rook/Ceph dashboard has no fixed NodePort. To find the NodePort in use, run one of the following:

kubectl get svc -n rook-ceph

Look for the rook-ceph-mgr-dashboard-external-http service:

NAME                                      TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)                                     AGE
rook-ceph-mgr-dashboard-external-http     NodePort    192.168.197.13    <none>        7000:31268/TCP                              21h

Or retrieve the NodePort directly:

echo $(kubectl get -n rook-ceph -o jsonpath="{.spec.ports[0].nodePort}" services rook-ceph-mgr-dashboard-external-http)

In the example above, the NodePort is 31268.

Connecting via SSH Tunnel

To establish a tunnel, forward the NodePort from one of the control planes to your local machine. You can use the command line, PuTTY, or MobaXterm for this.
After that, the dashboard can be accessed at localhost:<NodePort>/ceph-dashboard/.

Connecting via Ingress

The dashboard can also be accessed via https://<your-domain>/ceph-dashboard/.

Initial login credentials

echo Username: admin
echo Password: $(kubectl get secret rook-ceph-dashboard-password -n rook-ceph --template={{.data.password}} | base64 -d)

NodePort

30007 (if not set otherwise in the enterprise-values.yaml)

Connecting via SSH Tunnel

To establish a tunnel, forward the NodePort from one of the control planes to your local machine. You can use the command line, PuTTY, or MobaXterm for this.
After that, the dashboard can be accessed at localhost:30007/kubeops-dashboard/.

Connecting via Ingress

The dashboard can also be accessed via https://<your-domain>/kubeops-dashboard/.

Initial login credentials

kubectl -n monitoring create token headlamp-admin

NodePort

30180

Connecting via SSH Tunnel

To establish a tunnel, forward the NodePort from one of the control planes to your local machine. You can use the command line, PuTTY, or MobaXterm for this.
After that, the dashboard can be accessed at localhost:30180/keycloak/.

Connecting via Ingress

The dashboard can also be accessed via https://<your-domain>/keycloak/.

Initial login credentials

echo Username: $(kubectl get secret --namespace keycloak keycloak-kubeops -o jsonpath="{.data.ADMIN_USER}" | base64 -d)
echo Password: $(kubectl get secret --namespace keycloak keycloak-kubeops -o jsonpath="{.data.ADMIN_PASSWORD}" | base64 -d)

3.11 - Accessing Dashboards with OIDC

A brief overview of how you can access dashboards with OIDC.

This how-to guide explains how to enable OIDC-based access to your Kubernetes application dashboards using kubeopsctl. You will configure a single enterprise-values.yaml file that defines the required components. Once the configuration is applied, the dashboards for Harbor, Grafana, Rook-Ceph, OpenSearch, Keycloak, the KubeOps dashboard, and Prometheus become accessible via their configured hostnames and paths. Following the steps in this guide, you will set up a consistent, centralized OIDC integration and make your dashboards securely available through a browser.

Prerequisites

  • yq should be installed on all master nodes. For more infomration refer yq installation guide.
  • Keycloak should be installed before other packages.
  • Pull all the required packages with ‘kubectl pull’ command. For more information refer Pull Packages with Kubeopsctl

Step 1: Configure enterprise-values.yaml

In order to connect to dashboad with OIDC, you need to configure your enterprise-values.yaml file as below

apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
deleteNs: false
localRegistry: false
packages:
- name: rook-ceph
  enabled: true
  values:
    standard:
      hostname: <domain_name>          # required for OIDC dashboard access
      namespace: rook-ceph
      cluster:
        resources:
          mgr:
            requests:
              cpu: "500m"
              memory: "512Mi"
            mon:
              requests:
                cpu: "1"
                memory: "1Gi"
            osd:
              requests:
                cpu: "1"
                memory: "1Gi"
          dashboard:
            enabled: "true"
        operator:
          data:
            rookLogLevel: "DEBUG"
- name: harbor
  enabled: true
  values:
    standard:
      namespace: harbor
      harborpass: "password"
      databasePassword: "password"
      redisPassword: "password"
      externalURL: http://10.2.10.110:30002
      nodePort: 30002
      hostname: <domain_name>          # required for OIDC dashboard access
      harborPersistence:
        persistentVolumeClaim:
          registry:
            size: 40Gi
            storageClass: "rook-cephfs"
          jobservice:
            jobLog:
              size: 1Gi
              storageClass: "rook-cephfs"
          database:
            size: 1Gi
            storageClass: "rook-cephfs"
          redis:
            size: 1Gi
            storageClass: "rook-cephfs"
          trivy: 
            size: 5Gi
            storageClass: "rook-cephfs"
    advanced:
- name: cert-manager 
  enabled: true
  values:
    standard:
      namespace: cert-manager
      replicaCount: 3
      logLevel: 2
    advanced:
    ca:      
      emailLetsEncrypt: <email>
      ingressName: nginx
- name: ingress-nginx
  enabled: true
  values:
    standard:
      namespace: ingress-nginx
      externalIPs: 
        - <>                 
      advanced:
- name: keycloak
  enabled: true
  values:
    standard:
      namespace: "keycloak"
      storageClass: "rook-cephfs"
      nodePort: "30180"
      hostname: <domain_name>          # required for OIDC dashboard access
      keycloak:
        auth:
          adminUser: admin
          adminPassword: topsecret
      postgresql:
        auth:
          postgresUserPassword: "changeme"
          username: bn_keycloak
          password: "changeme"
          database: bitnami_keycloak
        volumeSize: "8Gi"
    advanced:
- name: filebeat-os
  enabled: true
  values:
    standard:
      namespace: logging
    advanced:
- name: logstash-os
  enabled: true
  values:
    standard:
      namespace: logging
      volumeClaimTemplate:
        accessModes: 
          - ReadWriteMany
        resources:
          requests:
            storage: 1Gi
        storageClass: "rook-cephfs"
    advanced:
- name: opensearch-dashboards
  enabled: true
  values:
    standard:
      hostname: <domain_name>          # required for OIDC dashboard access 
      namespace: logging
      nodePort: 30050
    advanced:
- name: opensearch-os
  enabled: true
  values:
    standard:
      hostname: <domain_name>          # required for OIDC dashboard access
      namespace: logging
      opensearchJavaOpts: "-Xmx512M -Xms512M" # optional, default is -Xmx512M -Xms512M
      resources:
        requests:
          cpu: "250m" # optional, default is 250m
          memory: "1024Mi" # optional, default is 1024Mi
        limits:
           cpu: "300m" # optional, default is 300m
           memory: "3072Mi" # optional, default is 3072Mi
      persistence:
        size: 4Gi # mandatory
        enabled: "true" # optional, default is true
        enableInitChown: "false" # optional, default is false
        labels:
          enabled: "false" # optional, default is false
        storageClass: "rook-cephfs" # optional, default is rook-cephfs
        accessModes:
          - "ReadWriteMany" # optional, default is {ReadWriteMany}
        securityConfig:
          enabled: "false" # optional, default value: false
        replicas: "3" # optional, default is 3
    advanced:
- name: kube-prometheus-stack
  enabled: true
  values:
    standard:
      namespace: monitoring
      grafanaUsername: admin
      grafanaPassword: topsecret
      retentionSize: "24GB"
      grafanaResources:
        hostname: <domain_name>          # required for OIDC dashboard access
        nodePort: 30211
        retention: 10d
        retentionSize: "24GB"
        storageClass: "rook-cephfs"
        storage: 25Gi
      prometheusResources:
        hostname: <domain_name>          # required for OIDC dashboard access
        retentionSize: "24GB"
        storageClass: "rook-cephfs"
        storage: 25Gi
    advanced:
- name: opa-gatekeeper
  enabled: true
  values:
    standard:
      namespace: opa-gatekeeper
    advanced:
- name: kubeops-dashboard
  enabled: true
  values:
    standard:
      namespace: monitoring
      hostname: <domain_name>          # required for OIDC dashboard access
      service:
        nodePort: 30007
    advanced:
- name: velero
  enabled: true
  values:
    standard:
      namespace: "velero"
      accessKeyId: "your_s3_storage_username"
      secretAccessKey: "your_s3_storage_password"
      useNodeAgent: false
      defaultVolumesToFsBackup: false
      provider: "aws"
      bucket: "velero"
      useVolumeSnapshots: false
      backupLocationConfig:
        region: "minio"
        s3ForcePathStyle: true
        s3Url: "http://minio.velero.svc:9000"
    advanced:

step 2: Apply the Configuration with ‘KubeOpctl’

Apply the enterprise-values.yaml configuration using the following command:

kubeopsctl apply -f enterprise-values.yaml

Wait until all components are deployed and running before proceeding.

Step 3: Connect to Dashboards via Hostname

To access the dashboards via OIDC, use the hostnames configured in your enterprise-values.yaml (uservalues). Harbor is an exception: you can access it directly using the base domain name.

Use the following paths, replacing <domain_name> with your configured domain:

  • <domain_name>/ for Harbor
  • <domain_name>/grafana for grafana
  • <domain_name>/ceph-dashboard for rook-ceph
  • <domain_name>/opensearch for opensearch
  • <domain_name>/keycloak for keycloak
  • <domain_name>/kubeops-dashboard for Kubeops Dashboard
  • <domain_name>/prometheus for Prometheus

3.12 - Changing a User Password in OpenSearch

Detailed instructions for changing the OpenSearch password.

This guide explains how to change passwords in OpenSearch.

The OpenSearch admin password is managed through the adminPassword package value. Set it for the opensearch-os package (and the matching opensearch-dashboards package) in your enterprise-values.yaml and run an update:

packages:
  - name: opensearch-os
    enabled: true
    values:
      standard:
        adminPassword: "<your-new-password>" # must match opensearch-dashboards
  - name: opensearch-dashboards
    enabled: true
    values:
      standard:
        adminPassword: "<your-new-password>" # must match opensearch-os

On the next kubeopsctl apply/update the new password is enforced automatically after the deployment. This also works on existing clusters and does not remove any other internal users.


Advanced: Change any user’s password manually via securityadmin

Use this method to change the password of any internal user (for example testuser or kibanaro) without a package update.

This process reads the live internal users from the security index (via securityadmin -backup), so every other user — including users you created in the OpenSearch Dashboards Security UI — is preserved. Do not build the file from the internal-users-config-secret: that secret only holds the packaged baseline users and would remove UI-created users when applied.

Prerequisites

  • Access to the Kubernetes cluster and kubectl.
  • The admin certificate is available in the pod at /usr/share/opensearch/config/certs/ (root-ca.pem, admin.pem, admin-key.pem) in a KubeOps deployment.

Set a shell variable for convenience (adjust the namespace and pod name as needed):

NS=logging; POD=opensearch-cluster-master-0

Step 1: Back up the current internal users (live state)

kubectl exec -it $POD -n $NS -- bash -c "\
    /usr/share/opensearch/plugins/opensearch-security/tools/securityadmin.sh -backup /tmp/os-sec \
    -icl -nhnv \
    -cacert /usr/share/opensearch/config/certs/root-ca.pem \
    -cert /usr/share/opensearch/config/certs/admin.pem \
    -key /usr/share/opensearch/config/certs/admin-key.pem"

This writes the current configuration — including all internal users — to /tmp/os-sec/ in the pod.

Step 2: Generate a new password hash for each user

Run this once per user and note the resulting hash:

kubectl exec -it $POD -n $NS -- bash -c "sh /usr/share/opensearch/plugins/opensearch-security/tools/hash.sh -p <new_password>"

Step 3: Update the hashes in the backup file

Copy the file out, edit it locally, and copy it back:

kubectl cp $NS/$POD:/tmp/os-sec/internal_users.yml ./internal_users.yml
# edit ./internal_users.yml: replace the hash: value under each user you want to change
kubectl cp ./internal_users.yml $NS/$POD:/tmp/os-sec/internal_users.yml

Only change the hash: line of the target users; leave everyone else untouched:

testuser:
  hash: "<new-hash-for-testuser>"
  reserved: false
  backend_roles:
  - "testrole"
kibanaro:
  hash: "<new-hash-for-kibanaro>"
  reserved: false
  backend_roles:
  - "kibanauser"

Step 4: Apply only the internal users configuration

Apply only the internalusers config type. Do not use -cd (the whole directory) here: -cd requires the complete security config set (including nodes_dn.yml, allowlist.yml, audit.yml), which a KubeOps deployment does not ship, so it would fail with nodes_dn.yml ... No such file or directory.

kubectl exec -it $POD -n $NS -- bash -c "\
    /usr/share/opensearch/plugins/opensearch-security/tools/securityadmin.sh \
    -f /tmp/os-sec/internal_users.yml -t internalusers \
    -icl -nhnv \
    -cacert /usr/share/opensearch/config/certs/root-ca.pem \
    -cert /usr/share/opensearch/config/certs/admin.pem \
    -key /usr/share/opensearch/config/certs/admin-key.pem"

The change is written to the security index and takes effect immediately — no pod restart required.

3.13 - Backup and restoring artifacts

In this article, we look at the backup procedure with Velero.

What is Velero?

Velero uses object storage to store backups and associated artifacts. It also optionally integrates supported block storage systems to snapshot your persistent volumes. Before beginning the installation process, you should identify the object storage provider and optional block storage provider(s) you’ll be using from the list of compatible providers.

Velero supports storage providers for both cloud-provider environments and on-premises environments.

Velero prerequisites:

  • Access to a Kubernetes cluster, v1.16 or later, with DNS and container networking enabled.
  • kubectl installed locally
  • Object Storage (S3, Cloud Provider Environment, On-Premises Environment)

Install Velero

This command is an example on how you can install velero into your cluster:

velero install --provider aws --plugins velero/velero-plugin-for-aws:v1.2.1 --bucket velero --secret-file ./credentials-velero --use-volume-snapshots=false --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://minio.velero.svc:9000

NOTE:

  • s3Url has to be the url of your s3 storage login.
  • example for credentials-velero file:
    [default]
    aws_access_key_id = your_s3_storage_username
    aws_secret_access_key = your_s3_storage_password
    

Backup the cluster

Scheduled Backups

This command creates a backup for the cluster every 6 hours:

velero schedule create cluster --schedule "0 */6 * * *"

Get Schedules

This command lists all schedules for backups:

velero schedule get

Delete Schedules

This command deletes the specified schedule:

velero schedule delete cluster

Restore Scheduled Backup

This command restores the backup according to a schedule:

velero restore create --from-backup <SCHEDULE NAME>-<TIMESTAMP>

Backup

This command creates a backup for the cluster

velero backup create cluster

Get Backups

This command lists all created backups:

velero backup get

Delete Backups

This commands deletes the specified backup:

velero backup delete <BACKUP NAME>

Restore Backup

This commands restores the specified backup:

velero restore create <RESOURCE NAME> --from-backup <BACKUP NAME>

Backup a specific deployment

Scheduled Backups

This command creates a backup for the namespace “logging” every 6 hours:

velero schedule create filebeat --schedule "0 */6 * * *" --include-namespaces logging --include-cluster-resources=true

This command creates a backup for the deployment “filebeat” every 6 hours:

velero schedule create filebeat --schedule "0 */6 * * *" --include-namespaces logging --selector app=filebeat-filebeat,release=filebeat --include-resources serviceaccount,deployment,daemonset,configmap,clusterrolebinding,clusterrole --include-cluster-resources=true

Get Schedules

This command lists all schedules for backups:

velero schedule get

Delete Schedules

This command deletes the specified schedule:

velero schedule delete filebeat

Restore Scheduled Backup

This command restores the backup from a schedule:

velero restore create --from-backup <SCHEDULE NAME>-<TIMESTAMP>

Backup

This command creates a backup for the namespace “logging”:

velero backup create filebeat --include-namespaces logging --include-cluster-resources=true

This command creates a backup for the deployment “filebeat”:

velero backup create filebeat --include-namespaces logging --selector app=filebeat-filebeat,release=filebeat --include-resources serviceaccount,deployment,daemonset,configmap,clusterrolebinding,clusterrole --include-cluster-resources=true

Get Backups

This command lists all created backups:

velero backup get

Delete Backups

This commands deletes the specified backup:

velero backup delete <BACKUP NAME>

Restore Backup

This commands restores the specified backup:

velero restore create <RESOURCE NAME> --from-backup <BACKUP NAME>

Scheduled Backups

This command creates a backup for the namespace “logging” every 6 hours:

velero schedule create logstash --schedule "0 */6 * * *" --include-namespaces logging --include-cluster-resources=true

This command creates a backup for the deployment “logstash” every 6 hours:

velero schedule create logstash --schedule "0 */6 * * *" --include-namespaces logging --selector app=logstash-logstash,chart=logstash,release=logstash --include-resources StatefulSet,ServiceAccount,Service,Secret,RoleBinding,Role,PodSecurityPolicy,PodDisruptionBudget,Ingress,ConfigMap --include-cluster-resources=true

Get Schedules

This command lists all schedules for backups:

velero schedule get

Delete Schedules

This command deletes the specified schedule:

velero schedule delete logstash

Restore Scheduled Backup

This command restores the backup from a schedule:

velero restore create --from-backup <SCHEDULE NAME>-<TIMESTAMP>

Backup

This command creates a backup for the namespace “logging”:

velero backup create logstash --include-namespaces logging --include-cluster-resources=true

This command creates a backup for the deployment “logstash”:

velero backup create logstash --include-namespaces logging --selector app=logstash-logstash,chart=logstash,release=logstash --include-resources StatefulSet,ServiceAccount,Service,Secret,RoleBinding,Role,PodSecurityPolicy,PodDisruptionBudget,Ingress,ConfigMap --include-cluster-resources=true

Get Backups

This command lists all created backups:

velero backup get

Delete Backups

This commands deletes the specified backup:

velero backup delete <BACKUP NAME>

Restore Backup

This commands restores the specified backup:

velero restore create <RESOURCE NAME> --from-backup <BACKUP NAME>

Scheduled Backups

This command creates a backup for the namespace “logging” every 6 hours:

velero schedule create opensearch --schedule "0 */6 * * *" --include-namespaces logging --include-cluster-resources=true

This command creates a backup for the deployment “opensearch” every 6 hours:

velero schedule create opensearch --schedule "0 */6 * * *" --include-namespaces logging --selector app.kubernetes.io/instance=opensearch,app.kubernetes.io/name=opensearch --include-resources ConfigMap,Ingress,NetworkPolicy,PodDisruptionBudget,PodSecurityPolicy,Role,RoleBinding,Secret,Service,ServiceAccount,StatefulSet --include-cluster-resources=true

Get Schedules

This command lists all schedules for backups:

velero schedule get

Delete Schedules

This command deletes the specified schedule:

velero schedule delete opensearch

Restore Scheduled Backup

This command restores the backup from a schedule:

velero restore create --from-backup <SCHEDULE NAME>-<TIMESTAMP>

Backup

This command creates a backup for the namespace “logging”:

velero backup create opensearch --include-namespaces logging --include-cluster-resources=true

This command creates a backup for the deployment “opensearch”:

velero backup create opensearch --include-namespaces logging --selector app.kubernetes.io/instance=opensearch,app.kubernetes.io/name=opensearch --include-resources ConfigMap,Ingress,NetworkPolicy,PodDisruptionBudget,PodSecurityPolicy,Role,RoleBinding,Secret,Service,ServiceAccount,StatefulSet --include-cluster-resources=true

Get Backups

This command lists all created backups:

velero backup get

Delete Backups

This commands deletes the specified backup:

velero backup delete <BACKUP NAME>

Restore Backup

This commands restores the specified backup:

velero restore create <RESOURCE NAME> --from-backup <BACKUP NAME>

Scheduled Backups

This command creates a backup for the namespace “monitoring” every 6 hours:

velero schedule create prometheus --schedule "0 */6 * * *" --include-namespaces monitoring --include-cluster-resources=true

This command creates a backup for the deployment “prometheus” every 6 hours:

velero schedule create prometheus --schedule "0 */6 * * *" --include-namespaces monitoring --include-resources Alertmanager,Secret,Ingress,List,PodDisruptionBudget,Role,RoleBinding,PodSecurityPolicy,Service,ServiceAccount,ServiceMonitor,Endpoints,ConfigMap,ConfigMapList,ClusterRole,ClusterRoleBinding,SecretProviderClass,PodMonitor,Prometheus,Job,NetworkPolicy,MutatingWebhookConfiguration,ValidatingWebhookConfiguration,Issuer,Deployment,VerticalPodAutoscaler,ThanosRuler --include-cluster-resources=true

Get Schedules

This command lists all schedules for backups:

velero schedule get

Delete Schedules

This command deletes the specified schedule:

velero schedule delete prometheus

Restore Scheduled Backup

This command restores the backup from a schedule:

velero restore create --from-backup <SCHEDULE NAME>-<TIMESTAMP>

Backup

This command creates a backup for the namespace “monitoring”:

velero backup create prometheus --include-namespaces monitoring --include-cluster-resources=true

This command creates a backup for the deployment “prometheus”:

velero backup create prometheus --include-namespaces monitoring --include-resources Alertmanager,Secret,Ingress,List,PodDisruptionBudget,Role,RoleBinding,PodSecurityPolicy,Service,ServiceAccount,ServiceMonitor,Endpoints,ConfigMap,ConfigMapList,ClusterRole,ClusterRoleBinding,SecretProviderClass,PodMonitor,Prometheus,Job,NetworkPolicy,MutatingWebhookConfiguration,ValidatingWebhookConfiguration,Issuer,Deployment,VerticalPodAutoscaler,ThanosRuler --include-cluster-resources=true

Get Backups

This command lists all created backups:

velero backup get

Delete Backups

This commands deletes the specified backup:

velero backup delete <BACKUP NAME>

Restore Backup

This commands restores the specified backup:

velero restore create <RESOURCE NAME> --from-backup <BACKUP NAME>

Scheduled Backups

This command creates a backup for the namespace “harbor” every 6 hours:

velero schedule create harbor --schedule "0 */6 * * *" --include-namespaces harbor --include-cluster-resources=true

This command creates a backup for the deployment “harbor” every 6 hours:

velero schedule create harbor --schedule "0 */6 * * *" --include-namespaces harbor --include-resources ConfigMap,Deployment,PersistentVolumeClaim,Secret,Service,StatefulSet,Ingress,ServiceMonitor --include-cluster-resources=true

Get Schedules

This command lists all schedules for backups:

velero schedule get

Delete Schedules

This command deletes the specified schedule:

velero schedule delete harbor

Restore Scheduled Backup

This command restores the backup from a schedule:

velero restore create --from-backup <SCHEDULE NAME>-<TIMESTAMP>

Backup

This command creates a backup for the namespace “harbor”:

velero backup create harbor --include-namespaces harbor --include-cluster-resources=true

This command creates a backup for the deployment “harbor”:

velero backup create harbor --include-namespaces harbor --include-resources ConfigMap,Deployment,PersistentVolumeClaim,Secret,Service,StatefulSet,Ingress,ServiceMonitor --include-cluster-resources=true --include-cluster-resources=true

Get Backups

This command lists all created backups:

velero backup get

Delete Backups

This commands deletes the specified backup:

velero backup delete <BACKUP NAME>

Restore Backup

This commands restores the specified backup:

velero restore create <RESOURCE NAME> --from-backup <BACKUP NAME>

Scheduled Backups

This command creates a backup for the namespace “gatekeeper-system” every 6 hours:

velero schedule create gatekeeper --schedule "0 */6 * * *" --include-namespaces gatekeeper-system --include-cluster-resources=true

This command creates a backup for the deployment “gatekeeper” every 6 hours:

velero schedule create gatekeeper --schedule "0 */6 * * *" --include-namespaces gatekeeper-system --include-resources PodSecurityPolicy,ServiceAccount,Deployment,PodDisruptionBudget,ResourceQuota,ClusterRole,Role,ClusterRoleBinding,RoleBinding,MutatingWebhookConfiguration,ValidatingWebhookConfiguration,Secret,Service,Job --include-cluster-resources=true

Get Schedules

This command lists all schedules for backups:

velero schedule get

Delete Schedules

This command deletes the specified schedule:

velero schedule delete gatekeeper

Restore Scheduled Backup

This command restores the backup from a schedule:

velero restore create --from-backup <SCHEDULE NAME>-<TIMESTAMP>

Backup

This command creates a backup for the namespace “gatekeeper-system”:

velero backup create gatekeeper --include-namespaces gatekeeper-system --include-cluster-resources=true

This command creates a backup for the deployment “gatekeeper-system”:

velero backup create gatekeeper --include-namespaces gatekeeper-system --include-resources PodSecurityPolicy,ServiceAccount,Deployment,PodDisruptionBudget,ResourceQuota,ClusterRole,Role,ClusterRoleBinding,RoleBinding,MutatingWebhookConfiguration,ValidatingWebhookConfiguration,Secret,Service,Job --include-cluster-resources=true --include-cluster-resources=true

Get Backups

This command lists all created backups:

velero backup get

Delete Backups

This commands deletes the specified backup:

velero backup delete <BACKUP NAME>

Restore Backup

This commands restores the specified backup:

velero restore create <RESOURCE NAME> --from-backup <BACKUP NAME>

Scheduled Backups

This command creates a backup for the namespace “rook-ceph” every 6 hours:

velero schedule create rook-ceph --schedule "0 */6 * * *" --include-namespaces rook-ceph --include-cluster-resources=true

Get Schedules

This command lists all schedules for backups:

velero schedule get

Delete Schedules

This command deletes the specified schedule:

velero schedule delete rook-ceph

Restore Scheduled Backup

This command restores the backup from a schedule:

velero restore create --from-backup <SCHEDULE NAME>-<TIMESTAMP>

Backup

This command creates a backup for the namespace “rook-ceph”:

velero backup create rook-ceph --include-namespaces rook-ceph --include-cluster-resources=true

Get Backups

This command lists all created backups:

velero backup get

Delete Backups

This commands deletes the specified backup:

velero backup delete <BACKUP NAME>

Restore Backup

This commands restores the specified backup:

velero restore create <RESOURCE NAME> --from-backup <BACKUP NAME>

restore databases

keycloak

  1. create backup of keycloak namespace, in this example the backup is called keycloak1.

This command creates a backup for the namespace “rook-ceph”:

velero backup create keycloak1 --include-namespaces keycloak --include-cluster-resources=true
  1. restore backup, in this example keycloak1
velero restore create keycloak1 --from-backup keycloak1
  1. restore the database dump:
kubectl -n <keycloak-namespace> exec keycloak-postgres-0 -- pg_restore -v --jobs=4 --clean --if-exists -d bitnami_keycloak /backup/keycloak-db.dump

3.14 - Deploy Package on a cluster

This guide explains how to deploy a package to a Kubernetes cluster with KOSI using either the Helm or Kubectl plugin.

You can install artifacts in your cluster in several ways. When creating a package, you can use one of the following plugins:

  • helm
  • kubectl
  • cmd
  • kosi

This guide demonstrates a complete, reproducible deployment of nginx-ingress using Helm and kosi.

Using the Helm Plugin

Pre-requisites

Before you begin, make sure the following tools are available in your environment:

  • helm
  • kosi

This example uses the official NGINX Helm repository and deploys nginx-ingress with Helm and KOSI.

Prepare the Files

In order to install an artifact with the Helm plugin, the Helm chart must first be downloaded.

To keep the environment clean and reproducible, first create a dedicated working directory and change into it:

mkdir nginx-ingress-kosi && cd nginx-ingress-kosi

The example uses the official NGINX Helm repository. Add the repository before performing any Helm operations:

helm repo add nginx-stable https://helm.nginx.com/stable
helm repo update

To verify which chart versions are available, run:

helm search repo nginx-stable/nginx-ingress --versions

This guide uses chart version 0.16.1. Download the chart as a packaged Helm artifact:

helm pull nginx-stable/nginx-ingress --version 0.16.1

This command creates the following file in your working directory:

nginx-ingress-0.16.1.tgz

Create KOSI package

Once the chart is available locally, initialize the kosi package structure. The following command creates the necessary files in the current directory:

kosi create

The Helm chart remains the central input artifact for deployment, while configuration is handled via values.yaml. Helm already includes default values, which can be inspected or exported if needed:

helm show values nginx-stable/nginx-ingress --version 0.16.1 > values.yaml

Review and update values.yaml before packaging and deploying the chart. For example, in environments without a cloud-based LoadBalancer, you may need to change the service type in values.yaml.

controller:
  service:
    type: LoadBalancer

Only required overrides should be defined in the customized values.yaml file. To customize the deployment of the Helm chart, a new values.yaml file in the current directory must be created and edited with this content:

controller:
  service:
    type: NodePort

This override is merged with the chart defaults at runtime.

Helm charts do not directly contain the full list of container images required for deployment. To identify them, render the chart into Kubernetes manifests:

helm template nginx-ingress nginx-stable/nginx-ingress --version 0.16.1 > manifests.yaml

Then extract all referenced images from the rendered manifest:

grep image: manifests.yaml

For this example, the required image is:

nginx/nginx-ingress:3.0.1

With all artifacts identified, the package.kosi file defines what is required for deployment. It explicitly references:

- the Helm chart archive
- the custom values.yaml
- all required container images
nginx-ingress-0.16.1.tgz
values.yaml
package.kosi

All files required by a task in the package must be named in the package.kosi file under files. The container images required by the Helm chart must also be listed in the package.kosi under containers.

In the example below, only two files are required for the installation: the Helm Chart for the nginx-ingress and the values.yaml to configure the deployment. To install nginx-ingress you will also need the nginx/nginx-ingress image with the tag 3.0.1.

To install nginx-ingress with the Helm plugin, call the plugin as shown in the example under install. The deployment configuration file is listed under values and the packed Helm chart is specified with the key tgz. Furthermore, it is also possible to specify the namespace in which the artifact should be deployed and the name of the deployment. The full documentation for the Helm plugin can be found here.

Use the following configuration:

languageversion = "1.0.0";
apiversion = "kubernative/kubeops/sina/user/v4";
name = "deployexample1";
description = "It shows how to deploy an artifact to your cluster using the helm plugin.";
version = "0.1.0";
docs = "docs.tgz";
logo = "logo.png";

files =
{
        valuesFile = "values.yaml";
        nginxHelmChart="nginx-ingress-0.16.1.tgz";
}

containers =
{
        nginx = ["docker.io", "nginx/nginx-ingress", "3.0.1"];
}

install
{
        helm
        (
            command = "install";
            tgz = "nginx-ingress-0.16.1.tgz";
            values = "['values.yaml']";
            namespace = "dev";
            deploymentName = "nginx-ingress"
        );
}

Build the Package

Once the package.kosi file has been fully configured, all files must be combined into a kosi package. To do this, execute the following command in the directory where the package.kosi file is located.

kosi build

Push the Package

To make the generated kosi package available on other machines, it is pushed to the user’s private KubeOps Hub. To do this, the user must first log in to the hub and then push it to hub.

$ kosi login -u <username>
2023-02-04 11:19:43 Info:      KOSI version: 2.13.0
2023-02-04 11:19:43 Info:      Please enter password
****************
2023-02-04 11:19:26 Info:      Login Succeeded to Hub.
$ kosi push --hub kosi
2023-02-04 11:23:18 Info:      KOSI version: 2.13.0
2023-02-04 11:23:19 Info:      Push to Private Registry registry.kubeops.net/<username>/

Deploy the Package

Once the KOSI package has been created and published, it needs to be installed on the admin node. The following command will download and execute the package. The package name and version refer to the values defined in package.kosi with the keys name and version.

kosi install --hub <username> <username>/<packagename>:<version>

For the example package, the command would be: kosi install --hub <username> <username>/deployExample:0.1.0.

Using the Kubectl Plugin

Prerequisites

Before you begin, make sure the following tools and components are available:

  • kosi
  • the kubeops-kubernetes-plugins package installed on the admin node

This example deploys nginx-ingress from a Kubernetes manifest using the Kubectl plugin.

Create KOSI package

First you need to create a KOSI package. The following command creates the necessary files in the current directory:

kosi create

The NGINX ingress controller YAML manifest can either be automatically downloaded and applied directly with kubectl apply or it can be downloaded manually if you want to customize the deployment. The YAML manifest can be downloaded from the NGINX GitHub Repo and must be placed in the same directory as the files for the KOSI package.

All files required by a task in the package must be named in the package.kosi file under files. The container images required by the YAML manifest must also be listed in the package.kosi under containers. In the example below, only one file is required for the installation: the YAML manifest for the nginx-ingress controller. To install nginx-ingress you will also need the registry.k8s.io/ingress-nginx/controller image with the tag v1.5.1 and the image registry.k8s.io/ingress-nginx/kube-webhook-certgen with tag v20220916-gd32f8c343.

To install nginx-ingress with the Kubectl plugin, call the plugin as shown in the example under installs. The full documentation for the Kubectl plugin can be found here.

languageversion = "1.0.0";
apiversion = "kubernative/kubeops/sina/user/v4";
name = "deployexample2";
description = "It shows how to deploy an artifact to your cluster using the helm plugin.";
version = "0.1.0";
docs = "docs.tgz";
logo = "logo.png";

files =
{
     manifest: "deploy.yaml"
}

containers =
{
    nginx = ["registry.k8s.io", "ingress-nginx/controller", "v1.5.1"];
    certgen= ["registry.k8s.io","ingress-nginx/kube-webhook-certgen","v20220916-gd32f8c343"];
}

install
{
    kubectl
    (
      operation="apply",
      flags="-f deploy.yaml";
      sudo = true;
      sudoPassword="toor"
    );
}

Build the Package

Once the package.kosi file has been fully configured, all files must be combined into a KOSI package. To do this, execute the following command in the directory where the package.kosi file is located.

kosi build

Publish the Package

To make the generated KOSI package available on other machines, it is pushed to the user’s private KubeOps Hub. To do this, the user must first log in to the hub.

$ kosi login -u <username>
2023-02-04 11:19:43 Info:      kosi version: 2.13.0
2023-02-04 11:19:43 Info:      Please enter password
****************
2023-02-04 11:19:26 Info:      Login Succeeded to Hub.
$ kosi push --hub kosi
2023-02-04 11:23:18 Info:      kosi version: 2.13.0
2023-02-04 11:23:19 Info:      Push to Private Registry registry.kubeops.net/<username>/

Deploy the Package

Once the KOSI package has been created and published, it needs to be installed on the admin node. The following command will download and execute the package. The package name and version refer to the values defined in package.kosi with the keys name and version.

kosi install --hub <username> <username>/<packagename>:<version>

For the example package, the command would be: kosi install --hub <username> <username>/deployExample:0.1.0.

3.15 - How to migrate from nginx to traefik ingress

Installation

Kubeops supports deploying Traefik as a dynamic ingress controller and reverse proxy. This guide describes a concise, safe migration from an existing nginx-ingress controller to Traefik and explains how to install Traefik and replace a deprecated nginx-ingress deployment. The migration from nginx to Traefik is straightforward; the steps below show the process in order.

Prerequisites

  • A running Kubernetes cluster with an existing nginx-ingress controller.

  • It is recommended to do a login with kosi. Refer to the official KOSI documentation for details here.

1.Create Values file

Create a values.yaml file for the Traefik installation:

# values.yaml
packages:
- name: traefik
  enabled: true
  values:
    standard:
      namespace: traefik
      externalIPs: []
    advanced: {}

Note: Update externalIPs and any other values as required for your environment.

2.Install Traefik

non-airgap-environment

After creating values.yaml, install Traefik:

# get your desired version/s
kosi search --hub kubeops --ps traefik
# install traefik
kosi install --hub kubeops kubeops/traefik:<desired_version> -f values.yaml --dname traefik
Example Non-airgap
kosi install --hub kubeops kubeops/traefik:2.1.0_Beta0 -f values.yaml --dname traefik

Airgap-environment

# log in to Harbor
podman login <ip_address>:<NodePort> -u <username> -p <password> --tls-verify=false
# pull your desired version
kosi pull --hub kubeops kubeops/<desired_version> -o traefik-<desired_version>.tgz -r <ip_address>:<NodePort>/kubeops -t 127.0.0.1:<NodePort>/kubeops
 # install Traefik
kosi install --dname traefik -p traefik-:<desired_version>.tgz -f values.yaml
Example Airgap
kosi pull --hub kubeops kubeops/traefik:2.1.0_Beta0 -o traefik-2.1.0-Beta0.tgz -r 10.2.10.11:30002/kubeops -t 127.0.0.1:30002/kubeops
 
kosi install --dname traefik -p traefik-2.1.0-Beta0.tgz -f values.yaml

3.Verify Deployment

Verify that the Traefik pods and services are running in the traefik namespace:

kubectl get pods -n traefik
kubectl get svc -n traefik

3b. Switch applications to the Traefik ingress class

This is the load-bearing step of the migration. Traefik ships a backwards-compatibility shim (an IngressClass named nginx plus the experimental providers.kubernetesIngressNginx provider) so that existing ingressClassName: nginx ingresses should keep working unchanged. This shim is experimental and does not work reliably for all workloads — Keycloak in particular has been observed to be unreachable through the nginx class while Traefik is the controller. Do not rely on the shim as the primary mechanism; switch each application’s ingress to ingressClassName: traefik.

Every ingress package exposes a uniform standard.ingressClassName key (defaulting to nginx). Set it to traefik on each package, and set the cert-manager solver class:

- name: keycloak
  values:
    standard:
      ingressClassName: traefik
- name: kubeOpsDashboard
  values:
    standard:
      ingressClassName: traefik
- name: kube-prometheus-stack
  values:
    standard:
      ingressClassName: traefik
- name: harbor
  values:
    standard:
      ingressClassName: traefik
- name: rook-ceph
  values:
    standard:
      ingressClassName: traefik
- name: opensearch-dashboards
  values:
    standard:
      ingressClassName: traefik
- name: kubevirt-manager
  values:
    standard:
      ingressClassName: traefik
- name: cert-manager
  values:
    ca:
      ingressName: traefik         # ACME HTTP01 solver ingress class

cert-manager is the only exception to the standard.ingressClassName key: its solver class lives under values.ca.ingressName. Certificates and the cert-manager.io/cluster-issuer annotations are otherwise controller-agnostic.

Note: the plain OpenSearch data package (opensearch-os) and logstash ship their ingress disabled by default, so they need no change. If you enable them, set the class via that package’s advanced block (ingress.ingressClassName / ingress.className).

Apply the updated values and confirm every ingress now uses the Traefik class:

kubectl get ingress -A -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,CLASS:.spec.ingressClassName

SSO / certificates / dashboards: SSO is app-level OIDC (Keycloak reachable at https://<host>/keycloak), so it is not tied to the ingress controller and keeps working once the class is switched. The same is true for cert-manager and dashboard access.

nginx-only annotations do not migrate. Annotations of the form nginx.ingress.kubernetes.io/* are ignored by Traefik. OpenSearch Dashboards ships buffer/ header-size annotations (proxy-buffer-size, large-client-header-buffers, …) that matter for large OIDC headers; if login fails with 4xx/431/502, add an equivalent Traefik buffering middleware / entrypoint transport setting via the package’s advanced block. Harbor auto-injects nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" when internalTLS.enabled — verify Harbor over TLS after the switch.

4.Remove old nginx-ingress deployment and service

# get version of installed nginx-ingress and its deployment name (--dname)
kosi list
# delete old nginx-ingress
kosi delete --hub kubeops kubeops/ingress-nginx:<installed_version> -f enterprise-values.yaml --dname <kosi_deployment_name>
Example

kosi delete --hub kubeops ingress-nginx:2.1.0_Beta0 -f values.yaml --dname ingress-nginx

Clean up the leftover nginx IngressClass. The ingress-nginx chart annotates its IngressClass with helm.sh/resource-policy: keep, so it survives kosi delete. Both ingress-nginx and the Traefik package define an IngressClass named nginx for controller k8s.io/ingress-nginx, so they must not run at the same time. After removing ingress-nginx, delete any leftover class if it is no longer wanted:

kubectl get ingressclass
kubectl delete ingressclass nginx   # only if you no longer need the nginx compat class

Edit Traefik service

If nginx-ingress used specific NodePorts that you need to reuse, update the Traefik Service:

kubectl edit svc traefik -n traefik

Note: Default NodePorts (for example, 31080 / 31443) might not be reachable in your environment. If these ports are not accessible, determine the NodePorts previously used by nginx-ingress (for example, 30080 / 30443) and configure Traefik to use the same ports.

Update the ports:

Adjust the ports section to match the previous nginx NodePorts if required:

ports:
- name: web
  nodePort: 30080
  port: 80
  targetPort: web
- name: websecure
  nodePort: 30443
  port: 443
  targetPort: websecure

Verify Port Change

kubectl get svc -n traefik

Note: Ensure that the nginx Service is removed or that its NodePorts are freed before reusing those NodePorts on the Traefik Service.

4 - Reference

In the reference you will find articles on the Kubeopsctl Commands, Fileformats, KubeOps Version and the Glossary

4.1 - KubeOpsCtl CLI Commands

This documentation shows all commands of the kubeopsctl and how to use them.

General commands

Overview of all KUBEOPSCTL commands

Description:
  kubeopsctl is a kubernetes cluster manager

Usage:
  kubeopsctl [command] [options]

Options:
  --version       Show version information
  -?, -h, --help  Show help and usage information

Commands:
  version  kubeopsctl version information
  login    Login to kubeops hub and registry
  logout   Logout from kubeops hub
  pull     Pull kosi packages for kubernetes cluster setup and plattform tools
  apply    Apply values on kubernetes cluster

Command ‘kubeopsctl –version’

The kubeopsctl --version command shows you the current version of kubeopsctl.

kubeopsctl --version

The output should be:

2.0.3

Command ‘kubeopsctl –help’

The command kubeopsctl --help gives you an overview of all available commands:

kubeopsctl --help

Alternatively, you can also enter kubeopsctl or kubeopsctl -? in the command line.

Command ‘kubeopsctl login’

The command kubeopsctl login performs a login against the KOSI HUB. A valid login session is neccessary to pull the packages.

Description:
  Login to kubeops hub and registry

Usage:
  kubeopsctl login [options]

Options:
  -u, --username <username> (REQUIRED)  Username
  -p, --password <password>             Password
  -?, -h, --help                        Show help and usage information

Example:

kubeopsctl login -u <username> -p <password>

Command ‘kubeopsctl logout’

The command kubeopsctl logout performs a logout from the KOSI HUB.

Description:
  Logout from kubeops hub

Usage:
  kubeopsctl logout [options]

Options:
  -?, -h, --help  Show help and usage information

Example:

kubeopsctl logout

Command ‘kubeopsctl pull’

The command kubeopsctl pull downloads all necessary KOSI packages to the admin node:

Description:
  Pull kosi packages for kubernetes cluster setup and plattform tools

Usage:
  kubeopsctl pull [options]

Options:
  -k, --kubernetesVersion <kubernetesVersion>  Kubernetes version
  -f, --tools <tools>                          Tools values file
  -?, -h, --help                               Show help and usage information

Example:

kubeopsctl pull

If you do not specify a parameter, the latest from kubeopsctl supported Kubernetes version will be pulled.
With parameter --kubernetesVersion 1.30.8 you can pull an older Kubernetes version.

Example:

kubeopsctl pull --kubernetesVersion 1.30.8

Command ‘kubeopsctl apply’

The command kubeopsctl apply is used to set up the kubeops platform with a configuration file.

Description:
  Apply values on kubernetes cluster

Usage:
  kubeopsctl apply [options]

Options:
  -f, --file <file> (REQUIRED)  Values files for cluster, tools and user
  -?, -h, --help                Show help and usage information

-f flag

The -f parameter is used to use value parameter yaml-files

Example:

kubeopsctl apply -f cluster-values.yaml

To install your KubeOps Compliance Applications, you have to use a second value file. It is called enterprise-value.yaml

Example:

kubeopsctl apply -f cluster-values.yaml -f enterprise-values.yaml

–delete flag

The -- delete parameter is used to perform a delete action.

This flag delete all nodes which are not present in the cluster-values.yaml - file Example:

kubeopsctl apply --delete -f cluster-values.yaml

4.2 - FAQs

KubeOps COMPLIANCE Security Hotfix

What is the issue?

Critical security vulnerabilities in NGINX (Rift and PoolSlip) affect the version used in KubeOps COMPLIANCE. These vulnerabilities may allow remote code execution or denial-of-service attacks.

Who is affected?

KubeOps COMPLIANCE users running affected NGINX versions, including:

KubeOps 2.1.0 KubeOps 2.0.3–2.0.6 KubeOps 1.7.6–1.7.8

What action is required?

Install the provided hotfix as soon as possible.

Script Details for KubeOps V2.x.x
  • Step 1: Load the shell environment & define the KOSI Package.

Load the shell environment from the current user’s bashrc file &

source ~/.bashrc

Set the package name for the Nginx hotfix:

kosinginx="kubeops/ingress-nginx:2.1.0_Beta1"

Create the filename that will be used when the package is pulled:

kosinginxfile="ingress-nginx-$(echo $kosinginx | awk -F: '{print $NF}').tgz"

This creates a file name based on the package version, in this example for KubeOps 2.1.0:

ingress-nginx-2.1.0_Beta1.tgz
  • Step 2: Prepare the KOSI Directory

    Temporarily enable housekeeping in the KOSI configuration, run kosi version, and then disable housekeeping again:

    sed -i "s/  housekeeping: false/  housekeeping: true/g" $KUBEOPSROOT/kosi/config.yaml
    kosi version
    sed -i "s/  housekeeping: true/  housekeeping: false/g" $KUBEOPSROOT/kosi/config.yaml
    

    This prepares the KOSI directory before the package update.

  • Step 3: Log In to KOSI

    Log in to KOSI with a valid user account. The following loop prompts for a username and retries until the login is successful:

    while true; do
        read -rp "$(printf "Username for kosi login: ")" KOSI_USER
    
        echo "Please enter the password for user '$KOSI_USER'"
    
        if kosi login -u "$KOSI_USER"; then
            echo "Login successful"
            break
        else
            echo "Login failed. Please try again."
            sleep 1
        fi
    done
    
  • Step 4: Determine the Harbor Configuration

    Retrieve the Harbor namespace, endpoint, port, and password from the KubeOps configuration.

  harborns=$(cat $KUBEOPSROOT/kubeopsctl/tools-values.yaml | grep -A50 "^- name: harbor" | grep -B50 "^- name:" | grep -m 1 "namespace:" | awk '{print $2}')
  harborep=$(kubectl get cm -n"$harborns" harbor-core -oyaml | grep "EXT_ENDPOINT" | awk '{print $2}')
  harborepohnehttp=$(echo "$harborep" | awk -F"//" '{print $2}')
  harborport=$(echo "$harborepohnehttp" | awk -F: '{print $NF}')
  harborpw=$(cat $KUBEOPSROOT/kubeopsctl/tools-values.yaml | grep -A50 "^- name: harbor" | grep -B50 "^- name:" | grep "harborpass" | awk '{print $NF}' | sed 's/"//g')  

Display the Harbor URL and port:

  echo "Harbor URL : $harborepohnehttp"
  echo "Harbor PORT: $harborport"
  • Step 5: Log In to Harbor with Podman

    Log in to Harbor as the admin user by using the password retrieved in the previous step:

    if podman login "$harborepohnehttp" -u admin -p "$harborpw" --tls-verify=false; then
        echo "Podman login successful"
    else
        echo "Podman login to $harborepohnehttp as admin with password $harborpw was not successful"
        exit 1
    fi
    
  • Step 6: Pull the Nginx Hotfix Package

    Pull the ingress-nginx package from the KOSI hub and save it as the local package archive:

    kosi pull --hub kubeops "$kosinginx" -o "$kosinginxfile" -r "$harborepohnehttp/kubeops" -t "localhost:$harborport/kubeops"
    
  • Step 7: Determine the Deployment Name for ingress-nginx

    Retrieve the deployment name for the existing ingress-nginx package:

    dname=$(kosi list | grep ingress-nginx | awk '{print $2}')
    
  • Step 8: Update ingress-nginx

    Run the KOSI update command by using the deployment name, the pulled package file, and the KubeOps values file:

    kosi update --dname="$dname" -p "$kosinginxfile" -f $KUBEOPSROOT/kubeopsctl/tools-values.yaml
    

    This applies the hotfix package to the existing ingress-nginx deployment.

  • Step 9: Remove Local Podman Images

    After the update completes, remove the local Podman images related to ingress-nginx and defaultbackend:

    for i in $(podman images | grep "ingress-nginx\|defaultbackend" | awk '{print $3}'); do
        podman rmi -f $i
    done
    

    This cleans up the local images from the administration host.

Complete Script for 2.1.0
#!/bin/bash
source ~/.bashrc

# kosi package
kosinginx="kubeops/ingress-nginx:2.1.0_Beta1"

# Filename for kosi pull
kosinginxfile="ingress-nginx-$(echo $kosinginx | awk -F: '{print $NF}').tgz"

# Clean up kosi directory
sed -i "s/  housekeeping: false/  housekeeping: true/g" $KUBEOPSROOT/kosi/config.yaml
kosi version
sed -i "s/  housekeeping: true/  housekeeping: false/g" $KUBEOPSROOT/kosi/config.yaml

# kosi login

while true; do
    read -rp "$(printf "Username for kosi login: ")" KOSI_USER

    echo "Please enter the password for user '$KOSI_USER'"

    if kosi login -u "$KOSI_USER"; then
        echo "Login successful"
        break
    else
        echo "Login failed. Please try again."
        sleep 1
    fi
done

# Determine Harbor values
harborns=$(cat $KUBEOPSROOT/kubeopsctl/tools-values.yaml | grep -A50 "^- name: harbor" | grep -B50 "^- name:" | grep -m 1 "namespace:" | awk '{print $2}')
harborep=$(kubectl get cm -n"$harborns" harbor-core -oyaml | grep "EXT_ENDPOINT" | awk '{print $2}')
harborepohnehttp=$(echo "$harborep" | awk -F"//" '{print $2}')
harborport=$(echo "$harborepohnehttp" | awk -F: '{print $NF}')
harborpw=$(cat $KUBEOPSROOT/kubeopsctl/tools-values.yaml | grep -A50 "^- name: harbor" | grep -B50 "^- name:" | grep "harborpass" | awk '{print $NF}' | sed 's/"//g')

echo "Harbor URL : $harborepohnehttp"
echo "Harbor PORT: $harborport"

# Podman login
if podman login "$harborepohnehttp" -u admin -p "$harborpw" --tls-verify=false; then
    echo "Podman login successful"
else
    echo "Podman login to $harborepohnehttp as admin with password $harborpw was not successful"
    exit 1
fi

# kosi pull
kosi pull --hub kubeops "$kosinginx" -o "$kosinginxfile" -r "$harborepohnehttp/kubeops" -t "localhost:$harborport/kubeops"

# Determine dname for ingress-nginx
dname=$(kosi list | grep ingress-nginx | awk '{print $2}')

# kosi update
kosi update --dname="$dname" -p "$kosinginxfile" -f $KUBEOPSROOT/kubeopsctl/tools-values.yaml

# Clean up admin Podman images
for i in $(podman images | grep "ingress-nginx\|defaultbackend" | awk '{print $3}'); do
    podman rmi -f $i
done

Complete Script for 2.0.3-2.0.6
#!/bin/bash
source ~/.bashrc

# kosi package
kosinginx="kubeops/ingress-nginx:2.0.6"

# Filename for kosi pull
kosinginxfile="ingress-nginx-$(echo $kosinginx | awk -F: '{print $NF}').tgz"

# Clean up kosi directory
sed -i "s/  housekeeping: false/  housekeeping: true/g" $KUBEOPSROOT/kosi/config.yaml
kosi version
sed -i "s/  housekeeping: true/  housekeeping: false/g" $KUBEOPSROOT/kosi/config.yaml

# kosi login

while true; do
    read -rp "$(printf "Username for kosi login: ")" KOSI_USER

    echo "Please enter the password for user '$KOSI_USER'"

    if kosi login -u "$KOSI_USER"; then
        echo "Login successful"
        break
    else
        echo "Login failed. Please try again."
        sleep 1
    fi
done

# Determine Harbor values
harborns=$(cat $KUBEOPSROOT/kubeopsctl/tools-values.yaml | grep -A50 "^- name: harbor" | grep -B50 "^- name:" | grep -m 1 "namespace:" | awk '{print $2}')
harborep=$(kubectl get cm -n"$harborns" harbor-core -oyaml | grep "EXT_ENDPOINT" | awk '{print $2}')
harborepohnehttp=$(echo "$harborep" | awk -F"//" '{print $2}')
harborport=$(echo "$harborepohnehttp" | awk -F: '{print $NF}')
harborpw=$(cat $KUBEOPSROOT/kubeopsctl/tools-values.yaml | grep -A50 "^- name: harbor" | grep -B50 "^- name:" | grep "harborpass" | awk '{print $NF}' | sed 's/"//g')

echo "Harbor URL : $harborepohnehttp"
echo "Harbor PORT: $harborport"

# Podman login
if podman login "$harborepohnehttp" -u admin -p "$harborpw" --tls-verify=false; then
    echo "Podman login successful"
else
    echo "Podman login to $harborepohnehttp as admin with password $harborpw was not successful"
    exit 1
fi

# kosi pull
kosi pull --hub kubeops "$kosinginx" -o "$kosinginxfile" -r "$harborepohnehttp/kubeops" -t "localhost:$harborport/kubeops"

# Determine dname for ingress-nginx
dname=$(kosi list | grep ingress-nginx | awk '{print $2}')

# kosi update
kosi update --dname="$dname" -p "$kosinginxfile" -f $KUBEOPSROOT/kubeopsctl/tools-values.yaml

# Clean up admin Podman images
for i in $(podman images | grep "ingress-nginx\|defaultbackend" | awk '{print $3}'); do
    podman rmi -f $i
done

WireGuard Installation with Local Package Repository

What is the issue?

WireGuard installation may fail when the local package repository is used on unsupported Red Hat Enterprise Linux versions.

Who is affected?

KubeOps COMPLIANCE users installing WireGuard with packagerepo: local.

What action is required?

When using packagerepo: local, ensure that all cluster nodes are running Red Hat Enterprise Linux 9.6.

4.3 - Fileformats in kubeopsctl

This documentation shows you all the different kind of fileformats kubeopsctl uses and how to use them.

There are currently 2 different files which can be handled by KubeOpsCtl:

cluster-values.yaml

The cluster-values.yaml defines every aspect of the cluster itself. It has no influence over which applications get installed.

apiVersion: kubeops/kubeopsctl/cluster/beta/v1 # required
imagePullRegistry: registry.kubeops.net/kubeops/kubeops # required
airgap: true # optional, default: true
clusterName: myCluster # required 
clusterUser: root # optional, default: root
kubernetesVersion: 1.32.2 # required
kubeVipEnabled: false # optional, default: true
virtualIP: 10.2.10.110 # required
firewall: nftables # optional, default: nftables
pluginNetwork: calico # optional, default: calico | possible alternative: cilium
containerRuntime: containerd # optional, default: containerd
kubeOpsRoot: /var/kubeops # optional, default: /var/kubeops
serviceSubnet: 192.168.128.0/17 # optional, default: 192.168.128.0/17
podSubnet: 192.168.0.0/17 # optional, default: 192.168.0.0/17
debug: false # optional, default: false
systemCpu: 250m # optional, default: 250m
systemMemory: 256Mi # optional, default: 256Mi
packageRepository: local # optional, default: local
changeCluster: true # optional, default: true

advanced:
  localRegistry:
    mountPath: /mnt/registry

zones: # required
- name: zone1 # required
  nodes: # required
  - name: master1 # required
    iPAddress: 10.2.10.110 # required
    type: controlplane # required
    kubeVersion: 1.32.2 # required
Detailed Parameter Information
Key Possible Values Additional Info
pluginNetwork Calico, Cilium

enterprise-values.yaml

The enterprise-values.yaml defines all enterprise applications currently available for you to install in your cluster via kubeopsctl.
You can append multiple of them into a single enterprise-values.yaml as shown in the first example.

For each application you have 2 ways to change its values:

  • the standard values
  • the advanced values

While the standard values only cover predefined keys, the advanced values let you change every key available in the helm chart. Keep in mind, that the standard values overwrite the advanced values if both are set.

Each as optional marked line can be skipped unless otherwise stated. If a optional line is skipped, its default value will be used instead. If there is no default value, it can just be omitted and won’t affect the cluster and/or the application

apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
deleteNs: false
localRegistry: false
packages:
  - name: opa-gatekeeper
    enabled: true
    values:
      standard:
        namespace: gatekeeper-system # optional, default is gatekeeper-system
      advanced:
  - name: filebeat-os
    enabled: false
    values:
      standard:
        namespace: logging # optional, default is logging
      advanced:
  ### Values for Rook-Ceph ###
  ### For detailed explanation for each key see: https://artifacthub.io/packages/helm/rook/rook-ceph?modal=values ###
  apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
  deleteNs: false
  localRegistry: false
  packages:
  - name: rook-ceph
    enabled: true
    values:
      standard:
        namespace: rook-ceph # optional, default is rook-ceph
        ingressClassName: nginx # optional, default is nginx; set to "traefik" to route the ceph dashboard via Traefik
        cluster:
          spec:
            dataDirHostPath: "/var/lib/rook" # optional, default is /var/lib/rook
          resources:
            mgr:
              requests:
                cpu: "500m" # optional, default is 500m, limit: 1000m
                memory: "512Mi" # optional, default is 1Gi, limit: 1Gi
            mon:
              requests:
                cpu: "1" # optional, default is 1, limit: 2000m
                memory: "1Gi" # optional, default is 1Gi, limit: 2Gi
            osd:
              requests:
                cpu: "1" # optional, default is 1, limit: 2
                memory: "1Gi" # optional, default is 4Gi, limit: 4Gi
        operator:
          data:
            rookLogLevel: "DEBUG" # optional, default is DEBUG
      advanced: 
        cluster: # All values from https://artifacthub.io/packages/helm/rook/rook-ceph-cluster?modal=values are overwritable
        operator: # All values from https://artifacthub.io/packages/helm/rook/rook-ceph?modal=values are overwritable
  ### Values for Harbor deployment ###
  ### For detailed explanation for each key see: https://artifacthub.io/packages/helm/harbor/harbor/1.8.1#configuration ###
  apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
  deleteNs: false
  localRegistry: false
  packages:
  - name: harbor
    enabled: true
    values:
      standard:
        namespace: harbor # optional, default is harbor
        ingressClassName: nginx # optional, default is nginx; set to "traefik" to route via Traefik
        harborpass: "password" # required: set password for harbor access
        databasePassword: "Postgres_Password" # required: set password for database access
        redisPassword: "Redis_Password" # required: set password for redis access
        externalURL: http://10.2.10.11:30002 # required, the ip address and port, from which harbor is accessable outside of the cluster
        nodePort: 30002 # required
        hostname: harbor.local # required
        harborPersistence:
          persistentVolumeClaim:
            registry:
              size: 40Gi # optional, default is 40Gi
              storageClass: "rook-cephfs" #optional, default is rook-cephfs
            jobservice:
              jobLog:
                size: 1Gi # optional, default is 1Gi
                storageClass: "rook-cephfs" #optional, default is rook-cephfs
            database:
              size: 1Gi # optional, default is 1Gi
              storageClass: "rook-cephfs" #optional, default is rook-cephfs
            redis:
              size: 1Gi # optional, default is 1Gi
              storageClass: "rook-cephfs" #optional, default is rook-cephfs
            trivy: 
              size: 5Gi # optional, default is 5Gi
              storageClass: "rook-cephfs" #optional, default is rook-cephfs
      advanced: #  All values from https://artifacthub.io/packages/helm/harbor/harbor/1.8.1#configuration are overwritable
  ### Values for cert-manager deployment ###
  apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
  deleteNs: false
  localRegistry: false
  packages:
  - name: cert-manager
    enabled: true
    values:
      standard:
        namespace: cert-manager # optional, default is cert-manager
        replicaCount: 3
        logLevel: 2
        secretName: root-secret
      advanced: # All values from https://artifacthub.io/packages/helm/cert-manager/cert-manager?modal=values are overwritable
      ## add helm values here
      ca: # LetsEncrypt ClusterIssuer / ACME HTTP01 solver settings
        # emailLetsEncrypt: <your_email@domain.com> # default: example@example.com --> must configure
        # ingressName: <ingress_name> # default: nginx; set to "traefik" to solve ACME HTTP01 via Traefik
  ### Values for ingress-nginx deployment ###
  apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
  deleteNs: false
  localRegistry: false
  packages:
  - name: ingress-nginx
    enabled: true
    values:
      standard:
        namespace: ingress-nginx # optional, default is ingress
      advanced: # All values from https://artifacthub.io/packages/helm/ingress-nginx/ingress-nginx?modal=values are overwritable
### Values for Traefik deployment ###
apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
deleteNs: false 
localRegistry: false
packages:
- name: traefik
  enabled: true
  values:
    standard:
      namespace: traefik # optional default is traefik
    advanced: # All values from https://artifacthub.io/packages/helm/traefik/traefik/39.0.0?modal=values are overwritable
### Values for keycloak deployment ###
apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
deleteNs: false
localRegistry: false
packages:
- name: keycloak
  enabled: true
  values:
    standard:
      namespace: keycloak # Optional, default is "keycloak"
      ingressClassName: nginx # optional, default is nginx; set to "traefik" to route via Traefik
      storageClass: "rook-cephfs" # Optional, default is "rook-cephfs"
      keycloak:
        auth:
          adminUser: admin # Optional, default is admin
          adminPassword: admin # Optional, default is admin, only used during initial installation
          existingSecret: "" # Optional, default is ""
      postgresql:
        auth:
          postgresPassword: "" # Optional, default is ""
          username: bn_keycloak # Optional, default is "bn_keycloak"
          password: "" # Optional, default is ""
          database: bitnami_keycloak # Optional, default is "bitnami_keycloak"
          existingSecret: "" # Optional, default is ""
    advanced: # All values from https://artifacthub.io/packages/helm/bitnami/keycloak?modal=values are overwritable, except values that are only applied during the installation, such as the Keycloak admin password

keycloak.auth.adminPassword is only applied during the installation. After Keycloak has been installed, changing this value in enterprise-values.yaml does not change the Keycloak password. To change the Keycloak password after installation, change it directly in Keycloak.

  ### Values for filebeat deployment ###
  apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
  deleteNs: false
  localRegistry: false
  packages:
  - name: filebeat-os
    enabled: true
    values:
      standard:
        namespace: logging # optional, default is logging   
      advanced: # All values from https://artifacthub.io/packages/helm/elastic/filebeat?modal=values are overwritable
  ### Values for Logstash deployment ###
  ### For detailed explanation for each key see: https://github.com/elastic/helm-charts/releases/tag/v7.16.3 ###
  apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
  deleteNs: false
  localRegistry: false
  packages:
  - name: logstash-os
    enabled: true
    values:
      standard:
        namespace: logging # optional, default is logging
        volumeClaimTemplate:
          accessModes: 
            - ReadWriteMany #optional, default is [ReadWriteMany]
          resources:
            requests:
              storage: 1Gi # required, depending on storage capacity
          storageClass: "rook-cephfs" #optional, default is rook-cephfs
      advanced: # All values from https://artifacthub.io/packages/helm/elastic/logstash?modal=values are overwritable
      
  ### Values for OpenSearch-Dashboards deployment ###
  ### For detailed explanation for each key see: https://github.com/opensearch-project/helm-charts/tree/main/charts/opensearch-dashboards ###
  apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
  deleteNs: false
  localRegistry: false
  packages:
  - name: opensearch-dashboards
    enabled: true
    values:
      standard:
        namespace: logging # optional, default is logging
        ingressClassName: nginx # optional, default is nginx; set to "traefik" to route via Traefik
        nodePort: 30050
        hostname: opensearch-dashboard.local # optional, default is opensearch-dashboard.local; external ingress hostname, determines the Keycloak SSO URL
        adminPassword: "Password@@123456" # optional, default is Password@@123456; must match opensearch-os adminPassword
      advanced: # All values from https://artifacthub.io/packages/helm/opensearch-project-helm-charts/opensearch-dashboards?modal=values are overwritable
  ### Values for OpenSearch deployment ###
  ### For detailed explanation for each key see: https://github.com/opensearch-project/helm-charts/tree/main/charts/opensearch ###
  apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
  deleteNs: false
  localRegistry: false
  packages:
  - name: opensearch-os
    enabled: true
    values:
      standard:
        namespace: logging # optional, default is logging
        hostname: opensearch-dashboard.local # optional, default is opensearch-dashboard.local; Keycloak host for SSO, must match opensearch-dashboards
        adminPassword: "Password@@123456" # optional, default is Password@@123456; OpenSearch admin password, enforced after deploy
        opensearchJavaOpts: "-Xmx512M -Xms512M" # optional, default is -Xmx512M -Xms512M
        resources:
          requests:
            cpu: "250m" # optional, default is 250m
            memory: "1024Mi" # optional, default is 1024Mi
          limits:
            cpu: "300m" # optional, default is 300m
            memory: "3072Mi" # optional, default is 3072Mi
        persistence:
          size: 4Gi # required
          enabled: "true" # optional, default is true
          enableInitChown: "false" # optional, default is false
          labels:
            enabled: "false" # optional, default is false
          storageClass: "rook-cephfs" # optional, default is rook-cephfs
          accessModes:
            - "ReadWriteMany" # optional, default is {ReadWriteMany}
        securityConfig:
          enabled: false # optional, default value: false
          ### Additional values can be set, if securityConfig is enabled:
          # path: "/usr/share/opensearch/plugins/opensearch-security/securityconfig"
          # actionGroupsSecret:
          # configSecret:
          # internalUsersSecret: internal-users-config-secret
          # rolesSecret:
          # rolesMappingSecret:
          # tenantsSecret:
          # config:
          #   securityConfigSecret: ""
          #   dataComplete: true
          #   data: {}
        replicas: "3" # optional, default is 3
      advanced: # All values from https://artifacthub.io/packages/helm/opensearch-project-helm-charts/opensearch?modal=values are overwritable
  ### Values for Prometheus deployment ###
  apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
  deleteNs: false
  localRegistry: false
  packages:
  - name: kube-prometheus-stack
    enabled: true
    values:
      standard:
        namespace: monitoring # optional, default is monitoring
        ingressClassName: nginx # optional, default is nginx; set to "traefik" to route via Traefik
        privateRegistry: false # optional, default is false
        grafanaUsername: "user" # optional, default is user
        grafanaPassword: "password" # optional, default is password
        grafanaResources:
          storageClass: "rook-cephfs" # optional, default is rook-cephfs
          storage: 5Gi # optional, default is 5Gi
          nodePort: 30211 # optional, default is 30211

        prometheusResources:
          storageClass: "rook-cephfs" # optional, default is rook-cephfs
          storage: 25Gi # optional, default is 25Gi
          retention: 10d # optional, default is 10d
          retentionSize: "24GB" # optional, default is 24GB
          nodePort: 32090
      advanced: # All values from https://artifacthub.io/packages/helm/prometheus-community/prometheus?modal=values-schema are overwritable
  ### Values for OPA deployment ###
  apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
  deleteNs: false
  localRegistry: false
  packages:
  - name: opa-gatekeeper
    enabled: true
    values:
      standard:
        namespace: gatekeeper-system # optional, default is gatekeeper-system
      advanced: # All values from https://artifacthub.io/packages/helm/gatekeeper/gatekeeper/3.1.1?modal=values are overwritable
  ### Values for KubeOps-Dashboard (Headlamp) deployment ###
  apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
  deleteNs: false
  localRegistry: false
  packages:
  - name: kubeops-dashboard
    enabled: true
    values:
      standard:
        namespace: monitoring # optional, default is monitoring
        ingressClassName: nginx # optional, default is nginx; set to "traefik" to route via Traefik
        service:
          nodePort: 30007
      advanced: # All values from https://artifacthub.io/packages/helm/headlamp/headlamp?modal=values are overwritable
  ### Values for velero deployment ###
  apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
  deleteNs: false
  localRegistry: false
  packages:
  - name: velero
    enabled: true
    values:
      standard:
        namespace: velero # Optional, default is "velero"
        accessKeyId: "your_s3_storage_username"
        secretAccessKey: "your_s3_storage_password"
        useNodeAgent: false
        defaultVolumesToFsBackup: false
        provider: "aws"
        bucket: "velero"
        useVolumeSnapshots: false
        backupLocationConfig:
          region: "minio"
          s3ForcePathStyle: true
          s3Url: "http://minio.velero.svc:9000"
      advanced: # All values from https://artifacthub.io/packages/helm/vmware-tanzu/velero?modal=values are overwritable
apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
# used in deleteLogstash.sh
deleteNs: false # TODO undocumented values! dangerous if other charts are installed in the namespace :-o
# used in some packages
localRegistry: false # create pull secret for registry 
packages:
- name: kubevirt-manager
  enabled: true
  values:
    standard:
      namespace: kubevirt # optional default is kubevirt
      hostname: kubeops-vms.local
      nodeport: 30733 # optional default is 30733
      ingressClassName: nginx # optional, default is nginx; set to "traefik" to route via Traefik
    advanced: {}
apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
# used in deleteLogstash.sh
deleteNs: false # TODO undocumented values! dangerous if other charts are installed in the namespace :-o
# used in some packages
localRegistry: false # create pull secret for registry 
packages:
- name: kubevirt-manager
  enabled: true
  values:
    standard:
      namespace: kubevirt # optional default is kubevirt
      hostname: kubeops-vms.local
      nodeport: 30733 # optional default is 30733
      ingressClassName: nginx # optional, default is nginx; set to "traefik" to route via Traefik
    advanced: {}
- name: kubevirt
  enabled: true
  hub: kubeops-vm
  values:
    standard:  
      namespace: kubevirt
      imagePullSecretCred:
        registry: registry.kubeops.net
        user: kubeops
        password: changeme # must be CLI Token from harbor 
      kubevirtobject:
        spec:
          configuration:
            developerConfiguration:
              logVerbosity:
                virtLauncher: 2
                virtHandler: 3
                virtController: 4
                virtAPI: 5
                virtOperator: 6
              featureGates:
              - ExpandDisks
              - CPUManager
              - ExperimentalIgnitionSupport
              - HypervStrictCheck
              - Sidecar
              - HostDevices
              - Snapshot
              - VMExport
              - HotplugVolumes
              - HostDisk
              - ExperimentalVirtiofsSupport
              - DownwardMetricsFeatureGate
              - Root
              - ClusterProfiler
              - WorkloadEncryptionSEV
              - VSOCK
              - DisableCustomSELinuxPolicy
              - KubevirtSeccompProfile
              - DisableMDEVConfiguration
              - PersistentReservation
              - VMPersistentState
              - MultiArchitecture
              - AutoResourceLimitsGate
              - AlignCPUs
              - VolumesUpdateStrategy
              - VolumeMigration
              #- NodeRestriction # Forbidden setting: Do not use!
              - InstancetypeReferencePolicy
              useEmulation: false
      cdiobject:
        spec:
          config:
            insecureRegistries:
            - registry.kubeops.net # Need to test if this is really necessary
            scratchSpaceStorageClass: rook-cephfs # Optional; Default: rook-cephfs
apiVersion: kubeops/kubeopsctl/enterprise/beta/v1
deleteNs: false
localRegistry: false
packages:
- name: rook-ceph
 enabled: true
 values:
   standard:
     namespace: rook-ceph
     cluster:
       resources:
         mgr:
           requests:
             cpu: "500m"
             memory: "512Mi"
         mon:
           requests:
             cpu: "1"
             memory: "1Gi"
         osd:
           requests:
             cpu: "1"
             memory: "1Gi"
       dashboard:
         enabled: true
     operator:
       data:
         rookLogLevel: "DEBUG"
- name: harbor
 enabled: true
 values:
   standard:
     namespace: harbor
     harborpass: "password"
     databasePassword: "password"
     redisPassword: "password"
     externalURL: http://10.2.10.11:30002
     nodePort: 30002
     hostname: harbor.local
     harborPersistence:
       persistentVolumeClaim:
         registry:
           size: 40Gi
           storageClass: "rook-cephfs"
         jobservice:
           jobLog:
             size: 1Gi
             storageClass: "rook-cephfs"
         database:
           size: 1Gi
           storageClass: "rook-cephfs"
         redis:
           size: 1Gi
           storageClass: "rook-cephfs"
         trivy: 
           size: 5Gi
           storageClass: "rook-cephfs"
   advanced:
- name: cert-manager
 enabled: true
 values:
   standard:
     namespace: cert-manager
     replicaCount: 3
     logLevel: 2
     secretName: root-secret
   advanced:
- name: ingress-nginx
 enabled: true
 values:
   standard:
     namespace: ingress-nginx
   advanced:
- name: keycloak
 enabled: true
 values:
   standard:
     namespace: keycloak
     storageClass: "rook-cephfs"
     keycloak:
       auth:
         adminUser: admin
         adminPassword: admin
         existingSecret: ""
     postgresql:
       auth:
         postgresPassword: ""
         username: bn_keycloak
         password: ""
         database: bitnami_keycloak
         existingSecret: ""
   advanced:
- name: filebeat-os
 enabled: true
 values:
   standard:
     namespace: logging
   advanced:
- name: logstash-os
 enabled: true
 values:
   standard:
     namespace: logging
     volumeClaimTemplate:
       accessModes: 
         - ReadWriteMany
       resources:
         requests:
           storage: 1Gi
       storageClass: "rook-cephfs"
   advanced:
- name: opensearch-dashboards
 enabled: true
 values:
   standard:
     namespace: logging
     nodePort: 30050
     hostname: opensearch-dashboard.local
     adminPassword: "Password@@123456"
   advanced:
- name: opensearch-os
 enabled: true
 values:
   standard:
     namespace: logging
     hostname: opensearch-dashboard.local
     adminPassword: "Password@@123456"
     opensearchJavaOpts: "-Xmx512M -Xms512M"
     resources:
       requests:
         cpu: "250m"
         memory: "1024Mi"
       limits:
         cpu: "300m"
         memory: "3072Mi"
     persistence:
       size: 4Gi
       enabled: "true"
       enableInitChown: "false"
       labels:
         enabled: "false"
       storageClass: "rook-cephfs"
       accessModes:
         - "ReadWriteMany"
     securityConfig:
       enabled: false
     replicas: "3"
   advanced:
- name: kube-prometheus-stack
 enabled: true
 values:
   standard:
     namespace: monitoring
     privateRegistry: false
     grafanaUsername: "user"
     grafanaPassword: "password"
     grafanaResources:
       storageClass: "rook-cephfs"
       storage: 5Gi
       nodePort: 30211
     prometheusResources:
       storageClass: "rook-cephfs"
       storage: 25Gi
       retention: 10d
       retentionSize: "24GB"
       nodePort: 32090
   advanced:
- name: opa-gatekeeper
 enabled: true
 values:
   standard:
     namespace: opa-gatekeeper
   advanced:
- name: kubeops-dashboard
 enabled: true
 values:
   standard:
     namespace: monitoring
     service:
       nodePort: 30007
   advanced:
- name: velero
 enabled: true
 values:
   standard:
     namespace: velero
     accessKeyId: "your_s3_storage_username"
     secretAccessKey: "your_s3_storage_password"
     useNodeAgent: false
     defaultVolumesToFsBackup: false
     provider: "aws"
     bucket: "velero"
     useVolumeSnapshots: false
     backupLocationConfig:
       region: "minio"
       s3ForcePathStyle: true
       s3Url: "http://minio.velero.svc:9000"
   advanced:
- name: kubevirt-manager
 enabled: true
 values:
   standard:
     namespace: kubevirt
     hostname: kubeops-vms.local
     nodeport: 30733
     ingressClassName: nginx
   advanced: {}
- name: kubevirt
 enabled: true
 hub: kubeops-vm
 values:
   standard:  
     namespace: kubevirt
     imagePullSecretCred:
       registry: registry.kubeops.net
       user: kubeops
       password: changeme
     kubevirtobject:
       spec:
         configuration:
           developerConfiguration:
             logVerbosity:
               virtLauncher: 2
               virtHandler: 3
               virtController: 4
               virtAPI: 5
               virtOperator: 6
             featureGates:
             - ExpandDisks
             - CPUManager
             - ExperimentalIgnitionSupport
             - HypervStrictCheck
             - Sidecar
             - HostDevices
             - Snapshot
             - VMExport
             - HotplugVolumes
             - HostDisk
             - ExperimentalVirtiofsSupport
             - DownwardMetricsFeatureGate
             - Root
             - ClusterProfiler
             - WorkloadEncryptionSEV
             - VSOCK
             - DisableCustomSELinuxPolicy
             - KubevirtSeccompProfile
             - DisableMDEVConfiguration
             - PersistentReservation
             - VMPersistentState
             - MultiArchitecture
             - AutoResourceLimitsGate
             - AlignCPUs
             - VolumesUpdateStrategy
             - VolumeMigration
             - InstancetypeReferencePolicy
             useEmulation: false
     cdiobject:
       spec:
         config:
           insecureRegistries:
           - registry.kubeops.net
           scratchSpaceStorageClass: rook-cephfs

4.4 - Glossary


KOSI package

KOSI package is the .tgz file packaged by bundling package.kosi and other essential yaml files and artifacts. This package is ready to install on your Kubernetes Clusters.

KubeOps Hub

KubeOps Hub is a secure repository where published KOSI packages can be stored and shared. You are welcome to contribute and use public hub also at the same time KubeOps provides you a way to access your own private hub.

Installation Address

It is the distinctive address automatically generated for each published package on KubeOps Hub. It is constructed using name of package creator, package name and package version.
You can use this address at the time of package installation on your Kubernetes Cluster.

It is indicated by the install column in KubeOps Hub.

Deployment name

When a package is installed, KOSI creates a deployment name to track that installation. Alternatively, KOSI also lets you specify the deployment name of your choice during the installation.
A single package may be installed many times into the same cluster and create multiple deployments.
It is indicated by Deployment column in the list of package deployments.

Tasks

As the name suggests, “Tasks” in package.yaml are one or more sets of instructions to be executed. These are defined by utilizing Plugins.

Plugins

KOSI provides many functions which enable you to define tasks to be executed using your package. These are called Plugins. They are the crucial part of your package development.

KUBEOPSROOT Variable

The environment variable KUBEOPSROOT stores the location of the KOSI plugins and the config.yaml. To use the variable, the config.yaml and the plugins have to be copied manually.

apiVersion

It shows the supported KubeOps tool API version. You do not need to change it unless otherwise specified.

Registry

As the name suggests, it is the location where docker images can be stored. You can either use the default KubeOps registry or specify your own local registry for AirGap environments. You need an internet connection to use the default registry provided by KubeOps.

Maintenance Package

KubeOps provides a package for the supported Kubernetes tools. These packages help you update the Kubernetes tools to the desired versions on your clusters along with the dependencies.

Cluster

In computing, a cluster refers to a group of interconnected computers or servers that work together as a single system.

These machines, or nodes, are typically networked and collaborate to execute tasks or provide services. Clusters are commonly used in various fields such as distributed computing, high-performance computing, and cloud computing to improve reliability, scalability, and performance. In the context of technologies like Kubernetes, a cluster consists of multiple nodes managed collectively to deploy, manage, and scale containerized applications.

Container

A container is a lightweight, standalone package that includes everything needed to run a piece of software, including the code, runtime, libraries, and dependencies.

Containers are isolated from each other and from the underlying infrastructure, providing consistency and portability across different environments. Kubernetes manages containers, orchestrating their deployment, scaling, and management across a cluster of nodes. Containers are often used to encapsulate microservices or individual components of an application, allowing for efficient resource utilization and simplified deployment processes.

Drain-node

A Drain Node is a feature in distributed systems, especially prevalent in Kubernetes, used for gracefully removing a node from a cluster.

It allows the system to evict all existing workload from the node and prevent new workload assignments before shutting it down, ensuring minimal disruption to operations.

Kube-proxy

Kube-Proxy, short for Kubernetes Proxy, is a network proxy that runs on each node in a Kubernetes cluster. Its primary responsibility is to manage network connectivity for Kubernetes services. Its main tasks include service proxying and load balancing.

Kubelet

Kubelet is a crucial component of Kubernetes responsible for managing individual nodes in a cluster. It ensures that containers are running in pods as expected, maintaining their health and performance.

Kubelet communicates with the Kubernetes API server to receive instructions about which pods should be scheduled and executed on its node. It also monitors the state of these pods, reporting any issues back to the API server. Kubelet plays a vital role in the orchestration and management of containerized workloads within a Kubernetes cluster.

Node

A Kubernetes node oversees and executes pods.

It serves as the operational unit (virtual or physical machine) for executing assigned tasks. Similar to how pods bring together multiple containers to collaborate, a node gathers complete pods to work in unison. In large-scale operations, the goal is to delegate tasks to nodes with available pods ready to handle them.

Pod

In Kubernetes, a pod groups containers and is the smallest unit managed by the system.

Each pod shares an IP address among its containers and resources like memory and storage. This allows treating the containers as a single application, similar to traditional setups where processes run together on one host. Often, a pod contains just one container for simple tasks, but for more complex operations requiring collaboration among multiple processes with shared data, multi-container pods simplify deployment.

For example, in an image-processing service creating JPEGs, one pod might have containers for resizing images and managing background tasks or data cleanup, all working together.

Registry

Helm registry serves as a centralized repository for Helm charts, facilitating the discovery, distribution, and installation of Kubernetes applications and services.

It allows users to easily find, share, and consume pre-packaged Kubernetes resources, streamlining the deployment process in Kubernetes environments.

Zone

A “zone” typically refers to a subset of the overall cluster that shares certain characteristics, such as geographic location or hardware specifications. Zoning helps distribute resources strategically and can enhance fault tolerance by ensuring redundancy within distinct zones.

4.5 - Software Bill of Materials (SBOM)

KubeOps publishes a Software Software Bill of Materials (SBOM) for the kubeopsctl command-line tooling that ships in the package repositories. It lists every bundled component with its exact version and license, in CycloneDX format. The published document is the authoritative source — link to it rather than copying its contents, so the list never drifts out of date.

Download

The SBOM is served at a fixed path in each package repository. Both repositories ship the same SBOM document, so the only difference is the retrieval URL for your platform.

curl -fsSLO https://packagerepo.kubeops.net/rpm/sbom/kubeopsctl-2.2.0.0_Beta1-0.x86_64.xml

You can checkout all SBOMs here sbom

curl -fsSLO https://packagerepo.kubeops.net/deb/pool/main/sbom/kubeopsctl-2.2.0.0_Beta1-0.x86_64.xml

You can checkout all SBOMs here sbom

Using the SBOM

The CycloneDX document can be fed directly into SBOM-aware vulnerability scanners and license-compliance tooling without re-resolving dependencies, for example:

grype sbom:./kubeopsctl-bom.xml   # vulnerability scan
trivy sbom ./kubeopsctl-bom.xml   # vulnerability scan

Scanner output reflects advisories at the time you run the scan, not at the time the SBOM was generated. Re-run scans regularly rather than relying on a single point-in-time result.