Follow the quickstart guides to learn how to create cluster in a secure, fast way with kubeopsctl.
This is the multi-page printable view of this section. Click here to print.
KubeOps Compliance 2.0
- 1: Release Notes
- 1.1: KubeOps Versions
- 1.2: KubeOps 2.1.1
- 1.3: KubeOps 2.2.0_Beta1
- 1.4: KubeOps 2.2.0_Beta0
- 1.5: KubeOps 2.1.0
- 1.6: KubeOps 2.1.0_Beta0
- 1.7: KubeOps 2.0.5
- 1.8: KubeOps 2.0.4
- 1.9: KubeOps 2.0.3
- 1.10: KubeOps 2.0.2
- 1.11: KubeOps 2.0.1
- 2: Getting-Started
- 2.1: About KubeOps Compliance
- 2.2: About KubeOps Compliance Licences
- 2.3: Prerequisites
- 2.4: Prepare Cluster
- 2.5: Setup Cluster
- 3: How to Guides
- 3.1: Documentation for production
- 3.1.1: Supported Package Versions — Ubuntu / Debian
- 3.1.2: Supported Package Versions — Red Hat Enterprise Linux (RHEL)
- 3.2: Joining a Node in a Kubernetes cluster
- 3.3: Deleting a Node from a Kubernetes cluster
- 3.4: Single Sign-On with Keycloak
- 3.4.1: Single Sign-On (SSO) with Keycloak for Harbor
- 3.4.2: Single Sign-On (SSO) with Keycloak for KubeOps Dashboard
- 3.4.3: Single Sign-On (SSO) with Keycloak for OpenSearch
- 3.5: Upgrading a Kubernetes cluster
- 3.6: Installing KubeOps Compliance applications
- 3.7: Updating KubeOps Compliance applications
- 3.8: Harbor Deployment with CloudNativePG
- 3.9: Ingress Configuration
- 3.10: Accessing Dashboards installed with KubeOps
- 3.11: Accessing Dashboards with OIDC
- 3.12: Changing a User Password in OpenSearch
- 3.13: Backup and restoring artifacts
- 3.14: Deploy Package on a cluster
- 3.15: How to migrate from nginx to traefik ingress
- 4: Reference
- 4.1: KubeOpsCtl CLI Commands
- 4.2: FAQs
- 4.3: Fileformats in kubeopsctl
- 4.4: Glossary
- 4.5: Software Bill of Materials (SBOM)
1 - Release Notes
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
packagerepo: local is used on cluster nodes that are not running Red Hat Enterprise Linux 9.6, due to its dependency on the systemd-resolved version included in the release.
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
packagerepo: local is used on cluster nodes that are not running Red Hat Enterprise Linux 9.6, due to its dependency on the systemd-resolved version included in the release.
logging is used.
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
2.1 - About KubeOps Compliance
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
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.
- 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.conffor podman,/etc/docker/deamon.jsonfor docker)
Prerequisites for each node
The following requirements must be fulfilled on each node.
- 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
- 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.
- Ensure that either iptables or nftables is installed on the system.
2.4 - 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
<username> with the Linux user that will run kubeopsctl.
# 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.
<username> with the Linux user that will run kubeopsctl.
# 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.yaml5. Configure time synchronization on all nodes
Install chrony on all nodes.
How to install and configure chrony (recommended)
- 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
- 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
- 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, whereis 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
apt update or dnf update, might break your cluster.On RHEL9, to update your applications but exclude podman you can run the following command:
sudo dnf update --exclude=podmanOn Ubuntu, you can hold the package with the command
sudo apt-mark hold podman which makes apt skip podman on updates.
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
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
3.1.1 - Supported Package Versions — Ubuntu / Debian
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.
kubernetesVersion in cluster-values.yaml (and kubeopsctl pull --kubernetesVersion <x.y.z>); kubeopsctl then installs the matching kubeadm, kubelet, kubectl, cri-tools and kubernetes-cni. For OIDC (dashboard SSO) you need kubeopsctl 2.1.0.0 or newer.
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
kubelet, kubeadm and kubectl itself (it runs apt-mark hold/unhold on them around installs and upgrades), so for those three the hold is managed for you. The command above additionally covers kubernetes-cni, cri-tools, helm, kosi and 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
containerd is installed from the operating system repository or as a local package. podman is installed as a KOSI lima package. Both packages are included in the hold and unhold commands above. To generate the exact hold list from your repository, run the list-package-versions.sh helper with --pin.
3.1.2 - Supported Package Versions — Red Hat Enterprise Linux (RHEL)
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.
kubernetesVersion in cluster-values.yaml (and kubeopsctl pull --kubernetesVersion <x.y.z>); kubeopsctl then installs the matching kubeadm, kubelet, kubectl, cri-tools and kubernetes-cni. For OIDC (dashboard SSO) you need kubeopsctl 2.1.0.0 or newer.
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.
exclude= configuration in kubeops.repo (and /etc/dnf/dnf.conf) for your release. The versionlock step below is an additional safeguard on top of that exclusion.
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).
glibc and the other system libraries — they should continue to receive OS security updates. Pin only the KubeOps and Kubernetes stack packages listed above.
3.2 - Joining a Node in a Kubernetes cluster
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:
It is recommended if you join worker nodes to a cluster and rook-ceph is installed, to adjust your rook-ceph CRUSH map. Refer to the official rook-ceph documentation for details here. for updating the crush map, you should set in your enterprise-values.yaml:
...
packages:
- name: rook-ceph
enabled: true
...
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
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.yamlfile. - 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
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
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
oidc-harbor secret. If you do so, adapt secretKeyRef.name in the Harbor values accordingly.
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_idandoidc_client_secretvalues. - The
externalURLandhostnamemust match the Harbor DNS name exactly. oidc_auto_onboard: trueallows users to be created automatically in Harbor upon first login.
3.4.2 - Single Sign-On (SSO) with Keycloak for KubeOps Dashboard
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
- Client ID:
-
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.
- 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
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
kubectlconfigured - Keycloak is installed and running (the
keycloakpackage), 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
hostnameis set to that public host and is identical for theopensearch-osandopensearch-dashboardspackages
hostname is a *.local name (not reachable), SSO is skipped automatically
and only username/password login is configured.
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 passwordpassword) - Realm roles:
all_access,opensearch_dashboards_user - Protocol mapper: exposes the realm roles as a
rolesclaim so OpenSearch can map them - OpenSearch backend security config: an
openidauthentication domain (Keycloak) plus abasicdomain (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 OpenSearchall_accessrole)opensearch_dashboards_user— dashboards access (maps to thekibana_userrole)
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
adminand theadminPasswordvalue (defaultPassword@@123456).
Notes / Troubleshooting
-
hostnamemismatch: theopensearch-osandopensearch-dashboardshostnames must be identical and must be the public Keycloak host, otherwise the OpenSearch backend cannot validate the token. -
401 Unauthorizedon SSO login: the OpenSearch backend could not validate the Keycloak token. Check thathostnameis 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 -
*.localhostname: 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
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
kubeVersionfield 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.
zone1, because zone1 contains the initial control plane node.
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, onlyzone1is configured with the target version.
cluster-values.yaml.
# 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
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
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
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
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
- 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.
- Apply the updated configuration:
kubeopsctl apply -f enterprise-values.yaml
Step 6 — Verify the Harbor Deployment
- 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
General Notes and best practices
- Always decode the CNPG app Secret to obtain the correct username, password, and database name used by Harbor.
- Use the cloudnative-pg-rw service for write traffic; use -ro services for reads if required.
- Production recommendations (follow your organizational security policies):
- Create a dedicated DB user (for example, harbor) rather than reusing the default app user.
- Enable TLS for Postgres connections.
- Implement backups (for example, CNPG Barman or object storage like S3).
- To scale the CNPG cluster, update the instances field in the Cluster spec and reapply.
3.9 - Ingress Configuration
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-nginxandtraefik. 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
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:
enterprise-values.yaml.
See Fileformats for details.
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
adminPasswordin the enterprise-values.yaml (default:Password@@123456)
- username:
SSO is only wired up when the OpenSearch hostname points to a reachable Keycloak
(non-.local). For *.local hostnames only the username/password login is available.
See Changing the OpenSearch password to change admin.
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
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
This guide explains how to change passwords in OpenSearch.
Recommended: Change the admin password via the package value
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.
admin password and reapplies the
authentication/authorization configuration; it never overwrites your 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.
securityadmin -backup may end with Configuration for 'audit' failed because of empty source and a non-zero exit code. This is harmless: internal_users.yml is written
before that step, so the file you need is already present.
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
The DN of the certificate specified with -cert must be listed under
plugins.security.authcz.admin_dn in opensearch.yml. In a KubeOps deployment the
admin certificate subject is C=DE,L=test,O=client,OU=client,CN=admin.
More information: Opensearch Documentation.
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.
Important
Once applied withsecurityadmin.sh, credentials are stored in the OpenSearch
security index, which lives on the persistent volume and therefore survives pod and
container restarts as well as package updates. Editing files inside the container
without running securityadmin.sh only changes the local file and is not applied to
the cluster. For the admin user, prefer the adminPassword package value described
above — it is enforced again on every update and keeps all other internal users intact.
3.13 - Backup and restoring artifacts
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
- 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
- restore backup, in this example keycloak1
velero restore create keycloak1 --from-backup keycloak1
- 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
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:
helmkosi
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
- The downloaded Helm chart must also be located in the current directory. To customize the deployment of the Helm chart, the
values.yamlfile must be edited.
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-pluginspackage 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) andlogstashship their ingress disabled by default, so they need no change. If you enable them, set the class via that package’sadvancedblock (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 with4xx/431/502, add an equivalent Traefikbufferingmiddleware / entrypoint transport setting via the package’sadvancedblock. Harbor auto-injectsnginx.ingress.kubernetes.io/backend-protocol: "HTTPS"wheninternalTLS.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
nginxIngressClass. The ingress-nginx chart annotates its IngressClass withhelm.sh/resource-policy: keep, so it surviveskosi delete. Both ingress-nginx and the Traefik package define an IngressClass namednginxfor controllerk8s.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
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
https://dispatcher.kubeops.net/v4/dispatcher/
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"
• For KubeOps 2.1.0 the package name is:
kubeops/ingress-nginx:2.1.0_Beta1
• For KubeOps 2.0.3 to 2.0.6 package name is:
kubeops/ingress-nginx:2.0.6
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.yamlThis 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
adminuser 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-nginxpackage 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-nginxpackage: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.yamlThis applies the hotfix package to the existing
ingress-nginxdeployment. -
Step 9: Remove Local Podman Images
After the update completes, remove the local Podman images related to
ingress-nginxanddefaultbackend:for i in $(podman images | grep "ingress-nginx\|defaultbackend" | awk '{print $3}'); do podman rmi -f $i doneThis 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.adminPasswordis only applied during the installation. After Keycloak has been installed, changing this value inenterprise-values.yamldoes 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.