This guide applies to an existing, operational Kubernetes cluster based on Talos Linux: the control plane is running, worker nodes have joined the cluster, a CNI is installed, and the Kubernetes API is accessible with d8 k.
Deckhouse Platform (DP) is installed on top of the existing Kubernetes cluster in existing-cluster mode. This example uses Deckhouse Platform Open, the EarlyAccess release channel, and the Managed bundle.
In this setup:
- Talos continues to manage the operating system, MachineConfig, kubelet, containerd, etcd, the control plane, Kubernetes PKI, and Kubernetes updates.
- The existing CNI continues to provide Pod networking.
- The external provisioner or the user continues to create and delete machines.
- DP installs and updates platform modules but does not manage Talos or the node lifecycle.
The bundle value is selected during installation and cannot be changed afterwards. You cannot install Managed and then switch it to Minimal or Default with a regular patch.
Prerequisites
The following tools and access are required on the computer from which the installation will be performed:
- Docker
- Deckhouse CLI
yqfor validating YAML- An administrative kubeconfig for the Talos cluster
- Access to the Kubernetes API
- HTTPS access to
registry.deckhouse.iofrom both the computer and the cluster nodes talosctland talosconfig if an administrative kubeconfig has not yet been obtained
SSH access to Talos nodes is not required: the installer communicates with the cluster through the Kubernetes API.
Before installation, it is recommended to create an etcd snapshot using Talos and save the original talosconfig and kubeconfig.
Setting the working paths
Create a separate directory for the installation files and change to it:
mkdir -p "$PWD/talos-deckhouse-install"
cd "$PWD/talos-deckhouse-install"
All subsequent commands assume that this remains the current directory. Set the paths once:
TALOSCONFIG="$PWD/talosconfig"
ADMIN_KUBECONFIG="$PWD/kubeconfig-admin"
INSTALLER_KUBECONFIG="$PWD/kubeconfig-installer"
CONFIG_FILE="$PWD/config.yml"
The files are used as follows:
| Variable | Purpose |
|---|---|
TALOSCONFIG |
talosctl configuration for accessing the Talos API |
ADMIN_KUBECONFIG |
Administrative kubeconfig for running d8 k on the computer |
INSTALLER_KUBECONFIG |
Portable copy of the administrative kubeconfig for the Docker container |
CONFIG_FILE |
Deckhouse Platform installation configuration |
If you open a new terminal, return to the working directory and define the four variables from the block above.
Preparing an administrative kubeconfig
The next steps depend on whether you already have an administrative kubeconfig.
If you already have a kubeconfig
Copy it to the working directory:
cp <ADMIN_KUBECONFIG_PATH> "$ADMIN_KUBECONFIG"
chmod 600 "$ADMIN_KUBECONFIG"
This refers to a kubeconfig for d8 k, not a talosconfig file for talosctl.
If you need to obtain a kubeconfig through Talos
First, copy the existing talosconfig to the working directory:
cp <TALOSCONFIG_PATH> "$TALOSCONFIG"
chmod 600 "$TALOSCONFIG"
Specify the address of a control-plane node:
CONTROL_PLANE_ADDRESS=<CONTROL_PLANE_IP_OR_DNS>
Obtain an administrative kubeconfig:
talosctl kubeconfig "$ADMIN_KUBECONFIG" --talosconfig="$TALOSCONFIG" --nodes="$CONTROL_PLANE_ADDRESS" --merge=false
chmod 600 "$ADMIN_KUBECONFIG"
By default, talosctl uses the Talos API endpoints from the current talosconfig context. If a different endpoint is required, add:
--endpoints=<TALOS_API_ENDPOINT>
Use --force only when you intentionally want to overwrite an existing file.
Verifying permissions
Check how Kubernetes identifies the user:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" auth whoami
Installation requires stable administrative access. A Talos administrative kubeconfig usually uses the system:masters group. Using an OIDC user kubeconfig for the installation is not recommended: after the DP user-authz module is enabled, that user’s access to system namespaces may change.
Verify the required permissions:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" auth can-i '*' '*' --all-namespaces
d8 k --kubeconfig="$ADMIN_KUBECONFIG" auth can-i create customresourcedefinitions.apiextensions.k8s.io
d8 k --kubeconfig="$ADMIN_KUBECONFIG" auth can-i create clusterroles.rbac.authorization.k8s.io
All three commands must return yes.
Verifying the existing cluster
Check the nodes:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get nodes -o wide
All nodes must be in the Ready state.
Check the Kubernetes API:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get --raw='/readyz?verbose'
The response must end with readyz check passed.
Check the system Pods:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" -n kube-system get pods -o wide
Before installing DP, the following components must already be running:
- CNI
- CoreDNS
- kube-proxy, if it is used by the selected network setup
- Control-plane components
Also make sure that the Kubernetes version is supported by the selected DP version.
Verifying component ownership
DP must not manage the same components as Talos or an external provisioner.
The table below lists the components and their owners after installation:
| Component | Owner after installation |
|---|---|
| Talos OS and MachineConfig | Talos |
| etcd and the Kubernetes control plane | Talos |
| Kubernetes PKI | Talos |
| kubelet and containerd | Talos |
| CNI | The existing external CNI |
| CoreDNS and kube-proxy, if used | The existing cluster |
| Machine creation and deletion | The external provisioner or the user |
| Platform modules | DP |
The following DP modules must remain disabled:
control-plane-managernode-managerterraform-managercni-ciliumkube-dnskube-proxycloud-provider-*modulesregistry-packages-proxy
If Cilium is already installed in the Talos cluster, do not enable the DP cni-cilium module: two operators must not manage the same CNI at the same time.
The Managed bundle includes ingress-nginx, cert-manager, local-path-provisioner, VPA, monitoring, and the user-authz module. Before installation, check whether external equivalents are already present in the cluster:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get storageclass
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get ingressclass
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get deployments -A
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get crd
If a component is already installed, choose a single owner before proceeding. Do not run two ingress controllers, two cert-manager installations, or two VPA installations at the same time.
If an external solution remains responsible for the component, explicitly disable the corresponding DP module using a ModuleConfig with spec.enabled: false. If DP is to manage the component, disable or remove the external counterpart before installation.
Preparing a kubeconfig for the installer container
The installer runs inside Docker. It requires a portable kubeconfig that does not reference certificate and key files available only on the user’s computer.
Create a portable copy:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" config view --raw --flatten --minify > "$INSTALLER_KUBECONFIG"
chmod 600 "$INSTALLER_KUBECONFIG"
This command does not create new certificates. The --flatten option reads the CA, client certificate, and key from the paths specified in the source kubeconfig and embeds them in the new file.
Verify the copy:
d8 k --kubeconfig="$INSTALLER_KUBECONFIG" auth whoami
d8 k --kubeconfig="$INSTALLER_KUBECONFIG" auth can-i '*' '*' --all-namespaces
The second command must return yes.
Check the Kubernetes API address:
d8 k --kubeconfig="$INSTALLER_KUBECONFIG" config view --minify -o jsonpath='{.clusters[0].cluster.server}{"\n"}'
This address must be reachable from the Docker container. A reachable Kubernetes API address, a VPN address, or a load balancer address is preferred.
If the address is https://127.0.0.1:6443, the installer cannot use it directly: inside the container, 127.0.0.1 refers to the container itself. Make the Kubernetes API accessible from the container before continuing with the installation.
Creating the configuration file
Create the $CONFIG_FILE file with the following content and replace example.com with your domain:
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: deckhouse
spec:
version: 1
enabled: true
settings:
bundle: Managed
releaseChannel: EarlyAccess
logLevel: Info
---
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: global
spec:
version: 2
settings:
modules:
publicDomainTemplate: "%s.example.com"
The domain in publicDomainTemplate must not match or be a subdomain of the domain specified in clusterDomain. Before using the template, configure DNS services in both the networks where cluster nodes are located and the networks from which clients access the platform service web interfaces.
If the nodes have custom taints and DP components must run on them, add the corresponding values to global.spec.settings.modules.placement.customTolerationKeys. Do not add an example taint unless it exists in the cluster.
Validate the file:
yq eval-all '.' "$CONFIG_FILE" >/dev/null && echo "YAML OK"
grep -n $'\t' "$CONFIG_FILE"
The first command must print YAML OK; the second command must not print anything.
Running the Deckhouse Platform Open installer
The installer tag must match the releaseChannel in the configuration. The early-access tag is used for EarlyAccess.
Check that the files exist:
ls -l "$CONFIG_FILE" "$INSTALLER_KUBECONFIG"
Run the installer:
docker run --pull=always -it -v "$CONFIG_FILE:/config.yml:ro" -v "$INSTALLER_KUBECONFIG:/kubeconfig:ro" registry.deckhouse.io/deckhouse/ce/install:early-access bash
The installer image path still uses the ce designation for Deckhouse Platform Open.
Inside the installer container, run:
dhctl bootstrap-phase install-deckhouse --kubeconfig=/kubeconfig --config=/config.yml
Do not close the terminal until the bootstrap process completes. Installation can take anywhere from 5 to 30 minutes.
Monitoring the installation
In a separate terminal, change to the same working directory and define the variables from the “Setting the working paths” section again. Run the command:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" -n d8-system get deployment,replicaset,pods -w
If the deckhouse Pod is not created, check the events:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" -n d8-system get events --sort-by=.metadata.creationTimestamp
Errors such as ImagePullBackOff, ErrImagePull, 401 Unauthorized, or 403 Forbidden usually indicate a problem with the registry address, registry access, DNS, or routing.
To diagnose a specific Pod, run:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" -n <NAMESPACE> describe pod <POD_NAME>
Verifying the installation
Wait for the main Deployment to become ready:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" -n d8-system rollout status deployment/deckhouse --timeout=10m
d8 k --kubeconfig="$ADMIN_KUBECONFIG" -n d8-system get deployment,pods -o wide
Check the modules:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get modules -o wide
Enabled modules are expected to have PHASE: Ready, ENABLED: True, and READY: True.
The Module status alone is not sufficient: a module may be Ready even if one of its Deployments, StatefulSets, or DaemonSets was not created or is restarting. Check the actual resources:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get deployment,statefulset,daemonset -A
For each DaemonSet, the DESIRED, CURRENT, and READY values must match. For Deployments and StatefulSets, the expected number of replicas must be ready.
Find Pods that are not in the Running or Succeeded phase:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get pods -A --field-selector='status.phase!=Running,status.phase!=Succeeded'
Check recent warnings:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get events -A --field-selector=type=Warning --sort-by=.metadata.creationTimestamp
An old warning does not necessarily indicate a current problem. Consider the event timestamp, repetition count, and the current state of the related resource.
Verifying that DP does not manage Talos components
Verify that DP modules that can manage Talos components remain disabled.
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get modules control-plane-manager node-manager terraform-manager cni-cilium kube-dns kube-proxy registry-packages-proxy -o wide
All listed modules must have ENABLED: False.
Check the cloud provider modules:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get modules -o wide | grep -E '(^NAME|^cloud-provider-)'
All cloud-provider-* modules found by the command must have ENABLED: False.
Check the original cluster components again:
d8 k --kubeconfig="$ADMIN_KUBECONFIG" -n kube-system get pods -o wide
d8 k --kubeconfig="$ADMIN_KUBECONFIG" get nodes -o wide
All Talos nodes must remain Ready. The original CNI, CoreDNS, and control-plane components must continue to run; kube-proxy must also continue to run if it was used before the DP installation.
Successful installation criteria
The installation is considered successful when all of the following conditions are met:
- All Talos nodes remain
Ready. - The original CNI and CoreDNS continue to run; kube-proxy also continues to run if it was used before the DP installation.
- Deployment
deckhouseis ready. - Enabled modules have
READY: True. - The actual module Deployments, StatefulSets, and DaemonSets are ready.
- DP modules that can manage Talos components remain disabled.
- Administrative access through the Talos administrative kubeconfig is preserved.