Welcome to our comprehensive How-To Guide for using kubeops. Whether youre a beginner aiming to understand the basics or an experienced user looking to fine-tune your skills, this guide is designed to provide you with detailed step-by-step instructions on how to navigate and utilize all the features of kubeops effectively.
In the following sections, you will find everything from initial setup and configuration, to advanced tips and tricks that will help you get the most out of the software. Our aim is to assist you in becoming proficient with kubeops, enhancing both your productivity and your user experience.
Lets get started on your journey to mastering kubeops!
The packages and versions provided by the KubeOps package repository for Ubuntu / Debian, and how to pin them.
This page lists the packages and versions available from the KubeOps package repository for Ubuntu 24.04 (the .deb pool). Use it to see which versions are supported and to pin the installed versions so an OS update cannot upgrade them.
Important
Not all of these versions are installed at once. The Kubernetes version is selected with 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.
Note
kubeopsctl already holds 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):
Notecontainerd 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.
1.2 - Supported Package Versions — Red Hat Enterprise Linux (RHEL)
The packages and versions provided by the KubeOps package repository for Red Hat Enterprise Linux, and how to pin them.
This page lists the packages and versions available from the KubeOps package repository for RHEL 9.6 / 9.7 (the .rpm pool). Use it to see which versions are supported and to pin the installed versions so an OS update cannot upgrade them.
Important
Not all of these versions are installed at once. The Kubernetes version is selected with 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.
⚠ Warning
The following are pre-release builds (Alpha / Beta / RC) and are not intended for production.
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.
⚠ Warning
Confirm the exact 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:
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).
Note
These are operating-system libraries. Do not version-lock glibc and the other system libraries — they should continue to receive OS security updates. Pin only the KubeOps and Kubernetes stack packages listed above.
2 - Joining a Node in a Kubernetes cluster
This guide outlines the steps to join a nodes to a cluster.
Note
This guide requires a Compliance enterprise license.
To increase performance or add additional resource capacity to your cluster, adding a node to the cluster is the correct process. This process with kubeopsctl is very easy.
You can use the following steps to join control-plane nodes or worker-nodes to a Kubernetes cluster.
Join Node Process:
Prerequisits
KOSI Login Recommendation
Before performing any action with kubeopsctl, it is recommended to do a login with kosi.
Refer to the official KOSI documentation for details
here.
ETCD Backup Recommendation
Before performing changes on the control planes, it is recommended to create an ETCD backup.
Refer to the official Kubernetes documentation for details
here
Example 1: Joining a Control-Plane Node to a Kubernetes Cluster
1. Pull required KOSI packages on your ADMIN
If you do not specify a parameter, the current Kubernetes version 1.32.2 will be pulled.
With parameter --kubernetesVersion 1.34.1 you can pull a specific Kubernetes version.
Available Kubernetes versions are
kubeopsctl pull
2. Add your node definition/specifications in the cluster-values
Note
If you want to join a node to your cluster the parameter: changeCluster has set to true
Note
The parameter kubeVersion defines the kubernetes version in your cluster for the node. This must set to the same version which exists in your cluster.
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.
Note
Take care of your format an syntax in the cluster-values.yaml
# file cluster-values.yamlapiVersion:kubeops/kubeopsctl/cluster/beta/v1imagePullRegistry:registry.kubeops.net/kubeops/kubeopsairgap:falseclusterName:myClusterclusterUser:rootkubernetesVersion:1.31.6# -> actual versionkubeVipEnabled:falsevirtualIP:10.2.10.110firewall:nftablespluginNetwork:calicocontainerRuntime:containerdkubeOpsRoot:/home/myuser/kubeopsserviceSubnet:192.168.128.0/17podSubnet:192.168.0.0/17debug:truesystemCpu:250msystemMemory:256MipackageRepository:https://packagerepo.kubeops.net/changeCluster:true# -> has to be setzones:- name:zone1nodes:- name:demo-controlplane01iPAddress:10.2.10.110type:controlplanekubeVersion:1.31.6- name:demo-controlplaneXX # -> has to be changediPAddress:10.2.10.XXX # -> has to be changedtype:controlplanekubeVersion:1.31.6# -> check with actual version- name:demo-worker01iPAddress:10.2.10.210type:workerkubeVersion:1.31.6- name:zone2nodes:- name:demo-controlplane02iPAddress:10.2.10.120type:controlplanekubeVersion:1.31.6- name:demo-worker02iPAddress:10.2.10.220type:workerkubeVersion:1.31.6- name:zone3nodes:- name:demo-controlplane03iPAddress:10.2.10.130type:controlplanekubeVersion:1.31.6- name:demo-worker03iPAddress:10.2.10.230type:workerkubeVersion: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
Note
If you want to join a node to your cluster the parameter: changeCluster has set to true
Note
The parameter kubeVersion defines the kubernetes version in your cluster for the node. This must set to the same version which exists in your cluster.
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.
Note
Take care of your format an syntax in the cluster-values.yaml
# file cluster-values.yamlapiVersion:kubeops/kubeopsctl/cluster/beta/v1imagePullRegistry:registry.kubeops.net/kubeops/kubeopsairgap:falseclusterName:myClusterclusterUser:rootkubernetesVersion:1.31.6# -> actual versionkubeVipEnabled:falsevirtualIP:10.2.10.110firewall:nftablespluginNetwork:calicocontainerRuntime:containerdkubeOpsRoot:/home/myuser/kubeopsserviceSubnet:192.168.128.0/17podSubnet:192.168.0.0/17debug:truesystemCpu:250msystemMemory:256MipackageRepository:https://packagerepo.kubeops.net/changeCluster:true# -> has to be setzones:- name:zone1nodes:- name:demo-controlplane01iPAddress:10.2.10.110type:controlplanekubeVersion:1.31.6- name:demo-worker01iPAddress:10.2.10.210type:workerkubeVersion:1.31.6- name:zone2nodes:- name:demo-controlplane02iPAddress:10.2.10.120type:controlplanekubeVersion:1.31.6- name:demo-worker02iPAddress:10.2.10.220type:workerkubeVersion:1.31.6- name:demo-workerXX # -> has to be changediPAddress:10.2.10.XX # -> has to be changedtype:workerkubeVersion:1.31.6# -> check with actual version - name:zone3nodes:- name:demo-controlplane03iPAddress:10.2.10.130type:controlplanekubeVersion:1.31.6- name:demo-worker03iPAddress:10.2.10.230type:workerkubeVersion: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:
Note
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-cephenabled: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:
This guide outlines the steps to delete worker-nodes from a cluster, specifically how to proceed with rook-ceph and other KubeOps Compliance applications
Deleting a Node from a Kubernetes cluster
Note
This guide requires a Compliance enterprise license.
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 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 removed0 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.
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!
4 - Single Sign-On with Keycloak
Learn how to configure Keycloak for Single Sign-On, securely expose it using Kubernetes Ingress and TLS, and integrate it with kubeops and other Kubernetes applications.
In this guide, you will learn how to implement Single Sign-On (SSO) using Keycloak. We will walk through the complete flow—from understanding SSO for platforms and services such as Rook Ceph, Harbor, OpenSearch, and other Kubernetes applications, to configuring Keycloak, exposing it securely, and integrating it with kubeops.
By the end of this guide, you will be able to:
Understand how Keycloak enables centralized authentication
Configure Keycloak for SSO
Securely expose Keycloak using Kubernetes Ingress and TLS
Integrate Keycloak with kubeops for authentication and authorization
Validate and troubleshoot the SSO login flow
Let’s get started on enabling secure and seamless authentication with Keycloak.
4.1 - Single Sign-On (SSO) with Keycloak for Harbor
Learn how to configure Single Sign-On (SSO) for Harbor using Keycloak with OIDC in a Kubernetes environment.
This guide describes how to configure Harbor authentication using Keycloak (OIDC) in a kubeops-managed Kubernetes environment.
Prerequisites
Before proceeding, ensure the following requirements are met:
A running Kubernetes cluster
kubectl installed and configured.
Keycloak is already installed and running
Keycloak is exposed using Kubernetes Ingress
A valid DNS record is configured for Keycloak and Harbor
TLS is enabled with a trusted Certificate Authority (CA)
Step 1: Prepare Keycloak (Realm, User, and Client)
In this step, we configure Keycloak for Harbor SSO. Keycloak is assumed to be already installed, exposed via Ingress, and reachable over HTTPS.
Create Realm
Ensure a realm named kubeops-dashboards exists.
If it does not exist, create it in the Keycloak admin console.
Realm name: kubeops-dashboards
Enabled: true
Create User
Ensure a user named kubeops exists in the kubeops-dashboards realm.
If the user does not exist, create it and set credentials.
Username: kubeops
Enabled: true
Set a permanent password
Create Client (Harbor)
Create a client for Harbor in the kubeops-dashboards realm.
Client ID: harbor
Client type: OpenID Connect
Client authentication: Enabled
Standard flow: Enabled
Direct access grants: Disabled
Valid Redirect URIs
Add the following redirect URI:
https://<your_DNS_name>/c/oidc/callback
Web Origins
<your_DNS_name>
Client Secret
After creating the client, copy the client secret.
This value will be used in the Harbor configuration:
Important: Replace all <your_DNS_name> placeholders with your correct DNS name
Create a client for headlamp
Client ID: headlamp
Client type: OpenID Connect
Access type: Confidential
Client authentication: Enabled
Standard flow: Enabled
Direct access grants: Disabled
Valid Redirect URIs
Add the following redirect URI:
https://headlamp/<your_DNS_name>/*
Web Origins
<your_DNS_name>
Step 4: Create a client scope for Headlamp
Create a client scope
Assigned Client Scope : headlamp-dedicated
For groups, use the Group Mapper in Keycloak:
Mapper Type: groups
Name: groups
Token Claim Name: groups
Add to ID token: ON
Add to access token: ON
Add to user info: ON
Add to token introspection: ON
Step 5: Create a user Group and user in Keycloak
Create a group named headlamp (if doesn’t exist already) and user under the group.
Step 6: Create ClusterRoleBinding for Headlamp group
1.Use following yaml to create ClusterRoleBinding
apiVersion:rbac.authorization.k8s.io/v1kind:ClusterRoleBindingmetadata:name:headlamp-admin-usersubjects:- kind:Groupname:"oidc:headlamp"# Der 'sub' oder 'preferred_username' from the Keycloak-TokenapiGroup:rbac.authorization.k8s.ioroleRef:kind:ClusterRolename:cluster-adminapiGroup: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
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.
4.3 - Single Sign-On (SSO) with Keycloak for OpenSearch
Learn how to log in to OpenSearch and OpenSearch Dashboards with Single Sign-On (SSO) using Keycloak (OIDC).
This guide describes how to log in to OpenSearch Dashboards using Keycloak (OIDC)
in a kubeops-managed Kubernetes environment.
Unlike some other integrations, you do not have to create the Keycloak realm,
client, roles or mapper by hand — the opensearch-dashboards package provisions
them automatically during install/update. Username/password login remains available
as a fallback.
Prerequisites
A running Kubernetes cluster with kubectl configured
Keycloak is installed and running (the keycloak package), exposed via Ingress and reachable over HTTPS
A valid DNS record and a trusted TLS certificate (e.g. Let’s Encrypt) for the ingress hostname
The OpenSearch hostname is set to that public host and is identical for the opensearch-os and opensearch-dashboards packages
Note
If the 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/v1deleteNs:falselocalRegistry:falsepackages:- name:opensearch-osenabled:truevalues:standard:namespace:logginghostname:<your_DNS_name> # must match opensearch-dashboards and Keycloak hostadminPassword:"<admin-password>"# optional, default Password@@123456- name:opensearch-dashboardsenabled:truevalues:standard:namespace:loggingnodePort:30050hostname:<your_DNS_name> # must match opensearch-osadminPassword:"<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)
Protocol mapper: exposes the realm roles as a roles claim so OpenSearch can map them
OpenSearch backend security config: an openid authentication domain (Keycloak) plus a basic domain (username/password fallback), and a role mapping from the Keycloak realm roles to OpenSearch roles
The Keycloak admin credentials used for this are read from the keycloak-kubeops secret.
Step 3: Grant a user access
To let a Keycloak user log in to OpenSearch, assign them one of the realm roles in
the kubeops-dashboards realm:
all_access — full access (maps to the OpenSearch all_access role)
opensearch_dashboards_user — dashboards access (maps to the kibana_user role)
You can use the pre-created kubeops user, or assign the role to your own Keycloak users.
Step 4: Log in
Open the OpenSearch Dashboards URL:
https://<your_DNS_name>/opensearch/
SSO: choose Log in with single sign-on → authenticate in Keycloak.
Fallback: use username admin and the adminPassword value (default Password@@123456).
Notes / Troubleshooting
hostname mismatch: the opensearch-os and opensearch-dashboards hostnames must be identical and must be the public Keycloak host, otherwise the OpenSearch backend cannot validate the token.
401 Unauthorized on SSO login: the OpenSearch backend could not validate the Keycloak token. Check that hostname is set and reachable from the OpenSearch pods, and that Keycloak’s TLS certificate is trusted (e.g. Let’s Encrypt). Verify the backend security config contains the openid domain:
This guide outlines the steps to upgrade the Kubernetes version of a cluster, specifically demonstrating how to change the version using a configuration file.
Note
This guide requires a Compliance enterprise license.
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
Note
The actual version is the current Kubernetes version in your cluster. The target version in the nodes, is version we want to do the upgrade (e.g., see this yaml file)
Note
To upgrade your cluster, the parameter changeCluster must be set to true (e.g., see this yaml file)
3. Start the upgrade
kubeopsctl apply -f cluster-values.yaml
Important
It is important to start the upgrade with the initial controlplane node. It is the first node with which the cluster was created.
Example 1 - Upgrade all nodes in the cluster to a specific version
In this example, a cluster is upgraded from Kubernetes version v1.33.5 to v1.34.1.
1. Pull required KOSI packages on your ADMIN
Pull the kubernetes v1.34.1 packages on your ADMIN machine.
kubeopsctl pull --kubernetesVersion 1.34.1
2. Update the target version in cluster-values.yaml
Adjust your cluster-values.yaml according to the example below. Make sure you set:
The current Kubernetes version in kubernetesVersion.
The target Kubernetes version in the kubeVersion field of each node.
# file cluster-values.yamlapiVersion:kubeops/kubeopsctl/cluster/beta/v1imagePullRegistry:registry.kubeops.net/kubeops/kubeopsairgap:trueclusterName:myClusterclusterUser:rootkubernetesVersion:1.33.5# -> actual versionkubeVipEnabled:falsevirtualIP:10.2.10.110firewall:nftablespluginNetwork:calicocontainerRuntime:containerdkubeOpsRoot:/home/myuser/kubeopsserviceSubnet:192.168.128.0/17podSubnet:192.168.0.0/17debug:truesystemCpu:250msystemMemory:256MipackageRepository:localchangeCluster:true# -> important! Needs to be set for an upgradezones:- name:zone1nodes:- name:demo-controlplane01iPAddress:10.2.10.110type:controlplanekubeVersion:1.34.1# -> target version- name:demo-worker01iPAddress:10.2.10.210type:workerkubeVersion:1.34.1# -> target version- name:zone2nodes:- name:demo-controlplane02iPAddress:10.2.10.120type:controlplanekubeVersion:1.34.1# ->target version- name:demo-worker02iPAddress:10.2.10.220type:workerkubeVersion:1.34.1# -> target version- name:zone3nodes:- name:demo-controlplane03iPAddress:10.2.10.130type:controlplanekubeVersion:1.34.1# -> target version- name:demo-worker03iPAddress:10.2.10.230type:workerkubeVersion: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
Note
Tools like rook-ceph has no pdbs, so if you drain nodes for the kubernetes upgrade, rook ceph is temporarily unavailable. You should drain only one node at a time for the kubernetes upgrade.
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.
Important
It is important to start your tranche upgrade with 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, only zone1 is configured with the target version.
Note
Pay close attention to the format and syntax in cluster-values.yaml.
After cluster-values.yaml is updated, review all values carefully.
When you are ready, start the upgrade process:
kubeopsctl apply -f cluster-values.yaml
Note
Tools like rook-ceph has no pdbs, so if you drain nodes for the kubernetes upgrade, rook ceph is temporarily unavailable. You should drain only one node at a time for the kubernetes upgrade.
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 - Installing KubeOps Compliance applications
This guide outlines the steps to install KubeOps Compliance applications of a cluster.
Note
This guide requires a Compliance enterprise license.
There is a predefined selection of applications included with KubeOps Compliance.
These applications ensure a production-ready cluster deployment and can be individually configured as needed.
By separating the cluster values from the application values, the application values can be modified independently and installed at a later stage, providing greater flexibility and maintainability.
Prerequisits
KOSI Login Recommendation
Before performing any action with kubeopsctl, it is recommended to do a login with kosi.
Refer to the official KOSI documentation for details
here.
⚠ Warning
To ensure proper DNS resolution, all components of the logging stack — Filebeat, Logstash, OpenSearch, and OpenSearch Dashboards—must be deployed within the same Kubernetes namespace (or network domain).
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
2. Pull the KubeOps Compliance Applications packages
To pull the required application packages in the correct version for the release, use the following commands:
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
⚠ Warning
Both, Cluster-values.yaml and enterprise-values.yaml are required!
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:
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/v1deleteNs:falselocalRegistry:true# important for airgap, otherwise images are pulled from public registrypackages:- name:opa-gatekeeperenabled:truevalues:standard:namespace:gatekeeper-systemadvanced:- name:rook-cephenabled:truevalues:standard:namespace:rook-cephcluster:resources:mgr:requests:cpu:"500m"memory:"512Mi"mon:requests:cpu:"1"memory:"1Gi"osd:requests:cpu:"1"memory:"1Gi"dashboard:enabled:trueoperator:data:rookLogLevel:"DEBUG"- name:harborenabled:truevalues:standard:namespace:harborharborpass:"password"databasePassword:"password"redisPassword:"password"externalURL:http://10.2.10.110:30002nodePort:30002hostname:harbor.localharborPersistence:persistentVolumeClaim:registry:size:40GistorageClass:"rook-cephfs"jobservice:jobLog:size:1GistorageClass:"rook-cephfs"database:size:1GistorageClass:"rook-cephfs"redis:size:1GistorageClass:"rook-cephfs"trivy:size:5GistorageClass:"rook-cephfs"advanced:- name:kubeops-dashboardenabled:truevalues:standard:namespace:monitoringhostname:kubeops-dashboard.localservice:nodePort:30007advanced:- name:filebeat-osenabled:falsevalues:standard:namespace:loggingadvanced:
2. Pull the KubeOps Compliance Applications packages
To pull the required application packages in the correct version for the release, use the following commands:
Note
The airgap-packages will be pulled automatically
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
⚠ Warning
Both, Cluster-values.yaml and enterprise-values.yaml are required!
Note
There is the possibility to do an Upgrade of the kubernetes version and do an installation of the KubeOps Compliance Tools
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:
This guide outlines the steps to update KubeOps Compliance applications of a cluster.
Note
This guide requires a Compliance enterprise license.
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]
Important
If you have made changes to your deployments, reapply them afterward or secure them using the advancedValues configuration.
⚠ Warning
To ensure proper DNS resolution, all components of the logging stack — Filebeat, Logstash, OpenSearch, and OpenSearch Dashboards—must be deployed within the same Kubernetes namespace (or network domain).
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/rpmsudo 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:
Note
All KubeOps Compliance applications versions are linked to the specific KubeOps Compliance version. A detailed version reference can be found here.
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.
2. Pull the KubeOps Compliance Applications packages
To pull the required application packages in the correct version for the release, use the following commands:
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.yamlapiVersion:kubeops/kubeopsctl/cluster/beta/v1imagePullRegistry:registry.kubeops.net/kubeops/kubeopsairgap:false# -> importantclusterName:<your cluster name>clusterUser:<your user name>kubernetesVersion:<your kubernetesversion>kubeVipEnabled:falsevirtualIP:<your master1 ip>firewall:nftablespluginNetwork:calicocontainerRuntime:containerdkubeOpsRoot:<your kubeopsroot path>serviceSubnet:192.168.128.0/17podSubnet:192.168.0.0/17debug:truepackageRepository:local # If you have incorporated package repository, replace “local” with the URL https://packagerepo.kubeops.net/changeCluster:false# -> importantzones:- name:zone1nodes:- name:demo-controlplane01iPAddress:10.2.10.110type:controlplanekubeVersion:1.31.6- name:demo-worker01iPAddress:10.2.10.210type:workerkubeVersion:1.31.6- name:zone2nodes:- name:demo-controlplane02iPAddress:10.2.10.120type:controlplanekubeVersion:1.31.6- name:demo-worker02iPAddress:10.2.10.220type:workerkubeVersion:1.30.8- name:zone3nodes:- name:demo-controlplane03iPAddress:10.2.10.130type:controlplanekubeVersion:1.31.6- name:demo-worker03iPAddress:10.2.10.230type:workerkubeVersion:1.31.6
⚠ Warning
Both, Cluster-values.yaml and enterprise-values.yaml are required!
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:
Example 2: Updating Applications in an airgap-environment
To update the KubeOps Compliance Applications in an existing cluster follow the next steps:
Note
All KubeOps Compliance applications versions are linked to the specific KubeOps Compliance version. A detailed version reference can be found here.
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/v1deleteNs:falselocalRegistry:true# important for airgap, otherwise images are pulled from public registrypackages:- name:opa-gatekeeperenabled:truevalues:standard:namespace:gatekeeper-systemadvanced:- name:rook-cephenabled:truevalues:standard:namespace:rook-cephcluster:resources:mgr:requests:cpu:"500m"memory:"512Mi"mon:requests:cpu:"1"memory:"1Gi"osd:requests:cpu:"1"memory:"1Gi"dashboard:enabled:trueoperator:data:rookLogLevel:"DEBUG"- name:harborenabled:truevalues:standard:namespace:harborharborpass:"password"databasePassword:"password"redisPassword:"password"externalURL:http://10.2.10.110:30002nodePort:30002hostname:harbor.localharborPersistence:persistentVolumeClaim:registry:size:40GistorageClass:"rook-cephfs"jobservice:jobLog:size:1GistorageClass:"rook-cephfs"database:size:1GistorageClass:"rook-cephfs"redis:size:1GistorageClass:"rook-cephfs"trivy:size:5GistorageClass:"rook-cephfs"advanced:- name:kubeops-dashboardenabled:truevalues:standard:namespace:monitoringhostname:kubeops-dashboard.localservice:nodePort:30007advanced:- name:filebeat-osenabled:falsevalues:standard:namespace:loggingadvanced:
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/rpmsudo rpm kubeopsctl
wget https://packagerepo.kubeops.net/rpm/<kubeopsctl-version>.rpm
sudo rpm --install <kubeopsctl-version>.rpm
2. Pull the KubeOps Compliance Applications packages
To pull the required application packages in the correct version for the release, use the following commands:
Note
The airgap-packages will be pulled automatically
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.yamlapiVersion:kubeops/kubeopsctl/cluster/beta/v1imagePullRegistry:registry.kubeops.net/kubeops/kubeopsairgap:true# -> importantclusterName:<your cluster name>clusterUser:<your user name>kubernetesVersion:<your kubernetesversion>kubeVipEnabled:falsevirtualIP:<your master1 ip>firewall:nftablespluginNetwork:calicocontainerRuntime:containerdkubeOpsRoot:<your kubeopsroot path>serviceSubnet:192.168.128.0/17podSubnet:192.168.0.0/17debug:truepackageRepository:local # If you have incorporated package repository, replace “local” with the URL https://packagerepo.kubeops.net/changeCluster:false# -> importantzones:- name:zone1nodes:- name:demo-controlplane01iPAddress:10.2.10.110type:controlplanekubeVersion:1.31.6- name:demo-worker01iPAddress:10.2.10.210type:workerkubeVersion:1.31.6- name:zone2nodes:- name:demo-controlplane02iPAddress:10.2.10.120type:controlplanekubeVersion:1.31.6- name:demo-worker02iPAddress:10.2.10.220type:workerkubeVersion:1.30.8- name:zone3nodes:- name:demo-controlplane03iPAddress:10.2.10.130type:controlplanekubeVersion:1.31.6- name:demo-worker03iPAddress:10.2.10.230type:workerkubeVersion:1.31.6
⚠ Warning
Both, Cluster-values.yaml and enterprise-values.yaml are required!
Note
There is the possibility to do an Upgrade of the kubernetes version and do an installation of the KubeOps Compliance Tools
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:
Here is a brief overview of Harbor Deployment with CloudNativePG on Kubernetes using Kosi
This guide describes how to deploy Harbor on Kubernetes using a CloudNativePG (CNPG) PostgreSQL cluster managed by the CloudNativePG operator in an air‑gap and non-airgap environments.
Harbor Deployment with CloudNativePG in Non-airgap enviroment
Prerequisites
A running Kubernetes cluster.
kubectl, kosi, and kubeopsctl installed and configured.
You need to login with kosi . Refer to the official KOSI documentation for details
here.
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.
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.
9 - Ingress Configuration
Here is a brief overview of how you can configure your ingress manually.
Manual configuration of the Nginx-Ingress-Controller
Right now the Ingress Controller Package is not fully configured. To make complete use of the Ingress capabilities of the cluster, the user needs to manually update some of the settings of the corresponding service.
Choosing an ingress controller. KubeOps ships two ingress controllers: ingress-nginx
and traefik. NGINX has reached end of support, so new clusters should prefer Traefik and
existing clusters should plan a migration. To replace nginx-ingress with Traefik (including
how SSO, certificates and dashboards keep working), follow
How to migrate from nginx to traefik ingress. The rest of this page
covers the manual nginx service configuration.
Locating the service
The service in question is called “ingress-nginx-controller” and can be found in the same namespace as the ingress package itself. To locate the service across all namespaces, you could use the following command.
kubectl get service -A | grep ingress-nginx-controller
This command should return two entries of services, “ingress-nginx-controller” and “ingress-nginx-controller-admission”, though only the first one needs to be further adjusted.
Setting the Ingress-Controller service to type NodePort
To edit the service, you can use the following command, although the actual namespace may be different. This will change the service type to NodePort.
kubectl patch service ingress-nginx-controller -n ingress -p '{"spec":{"type":"NodePort"}}'
Kubernetes will now automatically assign unused portnumbers for the nodePort to allow http and https connections to the service. These can be retrieved by running the same command, used to locate the service. Alternatively, you can use the following command, which adds the portnumbers 30080 and 30443 for the respective protocols. By doing so, you have to make sure, that these portnumbers are not being used by any other NodePort service.
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"]}}'
10 - Accessing Dashboards installed with KubeOps
A brief overview of how you can access dashboards.
To access an application dashboard, an SSH tunnel to one of the control planes is needed.
The following dashboards are available and configured with the following NodePorts by default:
⚠ Warning
Change default credentials before going to production.
Note
The NodePorts and hostnames shown on this page reflect the default values.
Both can be configured in the 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 adminPassword in the enterprise-values.yaml
(default: Password@@123456)
Note
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/.
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/.
A brief overview of how you can access dashboards with OIDC.
This how-to guide explains how to enable OIDC-based access to your Kubernetes application dashboards using kubeopsctl. You will configure a single enterprise-values.yaml file that defines the required components.
Once the configuration is applied, the dashboards for Harbor, Grafana, Rook-Ceph, OpenSearch, Keycloak, the KubeOps dashboard, and Prometheus become accessible via their configured hostnames and paths. Following the steps in this guide, you will set up a consistent, centralized OIDC integration and make your dashboards securely available through a browser.
Prerequisites
yq should be installed on all master nodes. For more infomration refer yq installation guide.
Keycloak should be installed before other packages.
Pull all the required packages with ‘kubectl pull’ command. For more information refer Pull Packages with Kubeopsctl
Step 1: Configure enterprise-values.yaml
In order to connect to dashboad with OIDC, you need to configure your enterprise-values.yaml file as below
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
12 - Changing a User Password in OpenSearch
Detailed instructions for changing the OpenSearch password.
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-osenabled:truevalues:standard:adminPassword:"<your-new-password>"# must match opensearch-dashboards- name:opensearch-dashboardsenabled:truevalues: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.
Note
Internal users created in the OpenSearch Dashboards Security UI persist across
package updates. The update only enforces the 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)
This writes the current configuration — including all internal users — to
/tmp/os-sec/ in the pod.
Notesecurityadmin -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:
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 changekubectl 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:
Step 4: Apply only the internal users configuration
Note
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.
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.
The change is written to the security index and takes effect immediately — no pod
restart required.
Important
Once applied with securityadmin.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.
13 - Backup and restoring artifacts
In this article, we look at the backup procedure with Velero.
What is Velero?
Velero uses object storage to store backups and associated artifacts. It also optionally integrates supported block storage systems to snapshot your persistent volumes. Before beginning the installation process, you should identify the object storage provider and optional block storage provider(s) you’ll be using from the list of compatible providers.
Velero supports storage providers for both cloud-provider environments and on-premises environments.
Velero prerequisites:
Access to a Kubernetes cluster, v1.16 or later, with DNS and container networking enabled.
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:
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.tgzvalues.yamlpackage.kosi
Note
The downloaded Helm chart must also be located in the current directory. To customize the deployment of the Helm chart, the values.yaml file 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.
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.
For the example package, the command would be: kosi install --hub <username> <username>/deployExample:0.1.0.
Using the Kubectl Plugin
Prerequisites
Before you begin, make sure the following tools and components are available:
kosi
the kubeops-kubernetes-plugins package installed on the admin node
This example deploys nginx-ingress from a Kubernetes manifest using the Kubectl plugin.
Create KOSI package
First you need to create a KOSI package. The following command creates the necessary files in the current directory:
kosi create
The NGINX ingress controller YAML manifest can either be automatically downloaded and applied directly with kubectl apply or it can be downloaded manually if you want to customize the deployment. The YAML manifest can be downloaded from the NGINX GitHub Repo and must be placed in the same directory as the files for the KOSI package.
All files required by a task in the package must be named in the package.kosi file under files. The container images required by the YAML manifest must also be listed in the package.kosi under containers.
In the example below, only one file is required for the installation: the YAML manifest for the nginx-ingress controller. To install nginx-ingress you will also need the registry.k8s.io/ingress-nginx/controller image with the tag v1.5.1 and the image registry.k8s.io/ingress-nginx/kube-webhook-certgen with tag v20220916-gd32f8c343.
To install nginx-ingress with the Kubectl plugin, call the plugin as shown in the example under installs. The full documentation for the Kubectl plugin can be found here.
languageversion="1.0.0";apiversion="kubernative/kubeops/sina/user/v4";name="deployexample2";description="It shows how to deploy an artifact to your cluster using the helm plugin.";version="0.1.0";docs="docs.tgz";logo="logo.png";files={manifest:"deploy.yaml"}containers={nginx=["registry.k8s.io","ingress-nginx/controller","v1.5.1"];certgen=["registry.k8s.io","ingress-nginx/kube-webhook-certgen","v20220916-gd32f8c343"];}install{kubectl(operation="apply",flags="-f deploy.yaml";sudo=true;sudoPassword="toor");}
Build the Package
Once the package.kosi file has been fully configured, all files must be combined into a KOSI package. To do this, execute the following command in the directory where the package.kosi file is located.
kosi build
Publish the Package
To make the generated KOSI package available on other machines, it is pushed to the user’s private KubeOps Hub. To do this, the user must first log in to the hub.
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.
For the example package, the command would be: kosi install --hub <username> <username>/deployExample:0.1.0.
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:
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:
cert-manager is the only exception to the standard.ingressClassName key: its solver class
lives under values.ca.ingressName. Certificates and the cert-manager.io/cluster-issuer
annotations are otherwise controller-agnostic.
Note: the plain OpenSearch data package (opensearch-os) and logstash ship their ingress
disabled by default, so they need no change. If you enable them, set the class via that
package’s advanced block (ingress.ingressClassName / ingress.className).
Apply the updated values and confirm every ingress now uses the Traefik class:
kubectl get ingress -A -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,CLASS:.spec.ingressClassName
SSO / certificates / dashboards: SSO is app-level OIDC (Keycloak reachable at
https://<host>/keycloak), so it is not tied to the ingress controller and keeps working
once the class is switched. The same is true for cert-manager and dashboard access.
nginx-only annotations do not migrate. Annotations of the form
nginx.ingress.kubernetes.io/* are ignored by Traefik. OpenSearch Dashboards ships buffer/
header-size annotations (proxy-buffer-size, large-client-header-buffers, …) that matter
for large OIDC headers; if login fails with 4xx/431/502, add an equivalent Traefik
buffering middleware / entrypoint transport setting via the package’s advanced block.
Harbor auto-injects nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" when
internalTLS.enabled — verify Harbor over TLS after the switch.
4.Remove old nginx-ingress deployment and service
# get version of installed nginx-ingress and its deployment name (--dname)kosi list
# delete old nginx-ingresskosi delete --hub kubeops kubeops/ingress-nginx:<installed_version> -f enterprise-values.yaml --dname <kosi_deployment_name>
Clean up the leftover nginx IngressClass. The ingress-nginx chart annotates its
IngressClass with helm.sh/resource-policy: keep, so it survives kosi delete. Both
ingress-nginx and the Traefik package define an IngressClass named nginx for controller
k8s.io/ingress-nginx, so they must not run at the same time. After removing ingress-nginx,
delete any leftover class if it is no longer wanted:
kubectl get ingressclass
kubectl delete ingressclass nginx # only if you no longer need the nginx compat class
Edit Traefik service
If nginx-ingress used specific NodePorts that you need to reuse, update the Traefik Service:
kubectl edit svc traefik -n traefik
Note:
Default NodePorts (for example, 31080 / 31443) might not be reachable in your environment.
If these ports are not accessible, determine the NodePorts previously used by nginx-ingress (for example, 30080 / 30443) and configure Traefik to use the same ports.
Update the ports:
Adjust the ports section to match the previous nginx NodePorts if required: