From 09e27344681bc85361722c8960b2b90d60251256 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Tue, 10 Mar 2026 19:13:21 -0600 Subject: [PATCH 01/31] WIP: Embedded Cluster v3 --- docusaurus.config.js | 36 ++++- installer/v3-placeholder.md | 1 + .../embedded-cluster-admin-console.mdx | 0 .../embedded-cluster-completion.mdx | 0 .../embedded-cluster-enable-ha.mdx | 0 .../embedded-cluster-install.mdx | 8 +- .../embedded-cluster-join-print-command.mdx | 0 .../version-2.0.0}/embedded-cluster-join.mdx | 0 .../version-2.0.0}/embedded-cluster-reset.mdx | 0 .../embedded-cluster-restore.mdx | 0 .../version-2.0.0}/embedded-cluster-shell.mdx | 0 .../embedded-cluster-support-bundle.mdx | 0 .../embedded-cluster-update.mdx | 0 .../embedded-cluster-version.mdx | 0 .../version-2.0.0}/embedded-config.mdx | 2 +- .../embedded-disaster-recovery.mdx | 0 .../version-2.0.0}/embedded-manage-nodes.mdx | 4 +- .../version-2.0.0}/embedded-overview.mdx | 4 +- .../version-2.0.0}/embedded-tls-certs.mdx | 0 .../embedded-troubleshooting.mdx | 6 +- .../version-2.0.0}/embedded-using.mdx | 6 +- .../installing-embedded-air-gap.mdx | 10 +- .../installing-embedded-automation.mdx | 6 +- .../installing-embedded-requirements.mdx | 8 +- .../version-2.0.0}/installing-embedded.mdx | 2 +- .../version-2.0.0}/updating-embedded.mdx | 10 +- .../version-2.0.0-sidebars.json | 40 ++++++ installer_versions.json | 3 + sidebarInstaller.js | 5 + sidebars.js | 89 +++++++------ .../InstallerVersionSelector/index.js | 124 ++++++++++++++++++ src/css/navbar.css | 25 +++- src/css/sidebar.css | 74 ++++++++++- src/theme/DocSidebar/Desktop/Content/index.js | 57 ++++++++ .../Desktop/Content/styles.module.css | 20 +++ src/theme/DocSidebar/Mobile/index.js | 54 ++++++++ 36 files changed, 508 insertions(+), 86 deletions(-) create mode 100644 installer/v3-placeholder.md rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-cluster-admin-console.mdx (100%) rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-cluster-completion.mdx (100%) rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-cluster-enable-ha.mdx (100%) rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-cluster-install.mdx (96%) rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-cluster-join-print-command.mdx (100%) rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-cluster-join.mdx (100%) rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-cluster-reset.mdx (100%) rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-cluster-restore.mdx (100%) rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-cluster-shell.mdx (100%) rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-cluster-support-bundle.mdx (100%) rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-cluster-update.mdx (100%) rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-cluster-version.mdx (100%) rename {docs/reference => installer_versioned_docs/version-2.0.0}/embedded-config.mdx (99%) rename {docs/vendor => installer_versioned_docs/version-2.0.0}/embedded-disaster-recovery.mdx (100%) rename {docs/enterprise => installer_versioned_docs/version-2.0.0}/embedded-manage-nodes.mdx (98%) rename {docs/vendor => installer_versioned_docs/version-2.0.0}/embedded-overview.mdx (99%) rename {docs/enterprise => installer_versioned_docs/version-2.0.0}/embedded-tls-certs.mdx (100%) rename {docs/vendor => installer_versioned_docs/version-2.0.0}/embedded-troubleshooting.mdx (96%) rename {docs/vendor => installer_versioned_docs/version-2.0.0}/embedded-using.mdx (97%) rename {docs/enterprise => installer_versioned_docs/version-2.0.0}/installing-embedded-air-gap.mdx (95%) rename {docs/enterprise => installer_versioned_docs/version-2.0.0}/installing-embedded-automation.mdx (94%) rename {docs/enterprise => installer_versioned_docs/version-2.0.0}/installing-embedded-requirements.mdx (88%) rename {docs/enterprise => installer_versioned_docs/version-2.0.0}/installing-embedded.mdx (98%) rename {docs/enterprise => installer_versioned_docs/version-2.0.0}/updating-embedded.mdx (86%) create mode 100644 installer_versioned_sidebars/version-2.0.0-sidebars.json create mode 100644 installer_versions.json create mode 100644 sidebarInstaller.js create mode 100644 src/components/InstallerVersionSelector/index.js create mode 100644 src/theme/DocSidebar/Desktop/Content/index.js create mode 100644 src/theme/DocSidebar/Desktop/Content/styles.module.css create mode 100644 src/theme/DocSidebar/Mobile/index.js diff --git a/docusaurus.config.js b/docusaurus.config.js index b20dec7729..6c48ffdd61 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -7,7 +7,7 @@ const darkTheme = themes.dracula; /** @type {import('@docusaurus/types').Config} */ const config = { - title: 'Replicated Docs', + title: 'Replicated', tagline: 'Technical documentation for Replicated vendors and their enterprise end-customers.', url: 'https://docs.replicated.com', baseUrl: '/', @@ -50,7 +50,36 @@ const config = { }), ], ], - + plugins: [ + [ + '@docusaurus/plugin-content-docs', + { + id: 'installer', + path: 'installer', + routeBasePath: 'installer', + sidebarPath: './sidebarInstaller.js', + breadcrumbs: true, + editUrl: 'https://github.com/replicatedhq/replicated-docs/edit/main/', + // Versioning configuration + lastVersion: 'current', // Make 3.0.0 the default version + includeCurrentVersion: true, // Include the "next" version from installer/ folder + versions: { + current: { + label: 'Embedded Cluster 3.0.0', + path: 'v3', + banner: 'none', + badge: false, + }, + '2.0.0': { + label: 'Embedded Cluster 2.13.3', + path: 'v2', + banner: 'unmaintained', + badge: false, + }, + }, + }, + ], + ], scripts: [ { src: @@ -136,7 +165,8 @@ const config = { }, { type: 'doc', - docId: 'vendor/embedded-overview', + docId: 'v3-placeholder', + docsPluginId: 'installer', label: 'Embedded Cluster', }, { diff --git a/installer/v3-placeholder.md b/installer/v3-placeholder.md new file mode 100644 index 0000000000..aeb4c25e02 --- /dev/null +++ b/installer/v3-placeholder.md @@ -0,0 +1 @@ +# v3 placeholder \ No newline at end of file diff --git a/docs/reference/embedded-cluster-admin-console.mdx b/installer_versioned_docs/version-2.0.0/embedded-cluster-admin-console.mdx similarity index 100% rename from docs/reference/embedded-cluster-admin-console.mdx rename to installer_versioned_docs/version-2.0.0/embedded-cluster-admin-console.mdx diff --git a/docs/reference/embedded-cluster-completion.mdx b/installer_versioned_docs/version-2.0.0/embedded-cluster-completion.mdx similarity index 100% rename from docs/reference/embedded-cluster-completion.mdx rename to installer_versioned_docs/version-2.0.0/embedded-cluster-completion.mdx diff --git a/docs/reference/embedded-cluster-enable-ha.mdx b/installer_versioned_docs/version-2.0.0/embedded-cluster-enable-ha.mdx similarity index 100% rename from docs/reference/embedded-cluster-enable-ha.mdx rename to installer_versioned_docs/version-2.0.0/embedded-cluster-enable-ha.mdx diff --git a/docs/reference/embedded-cluster-install.mdx b/installer_versioned_docs/version-2.0.0/embedded-cluster-install.mdx similarity index 96% rename from docs/reference/embedded-cluster-install.mdx rename to installer_versioned_docs/version-2.0.0/embedded-cluster-install.mdx index f68e5b75ff..9a7e481900 100644 --- a/docs/reference/embedded-cluster-install.mdx +++ b/installer_versioned_docs/version-2.0.0/embedded-cluster-install.mdx @@ -1,7 +1,7 @@ -import ProxyLimitations from "../partials/embedded-cluster/_proxy-install-limitations.mdx" -import ProxyRequirements from "../partials/embedded-cluster/_proxy-install-reqs.mdx" -import ProxyEnvVars from "../partials/embedded-cluster/_proxy-env-vars.mdx" -import DeprecatedPrivateCa from "../partials/embedded-cluster/_deprecated-private-ca.mdx" +import ProxyLimitations from "../../docs/partials/embedded-cluster/_proxy-install-limitations.mdx" +import ProxyRequirements from "../../docs/partials/embedded-cluster/_proxy-install-reqs.mdx" +import ProxyEnvVars from "../../docs/partials/embedded-cluster/_proxy-env-vars.mdx" +import DeprecatedPrivateCa from "../../docs/partials/embedded-cluster/_deprecated-private-ca.mdx" # install diff --git a/docs/reference/embedded-cluster-join-print-command.mdx b/installer_versioned_docs/version-2.0.0/embedded-cluster-join-print-command.mdx similarity index 100% rename from docs/reference/embedded-cluster-join-print-command.mdx rename to installer_versioned_docs/version-2.0.0/embedded-cluster-join-print-command.mdx diff --git a/docs/reference/embedded-cluster-join.mdx b/installer_versioned_docs/version-2.0.0/embedded-cluster-join.mdx similarity index 100% rename from docs/reference/embedded-cluster-join.mdx rename to installer_versioned_docs/version-2.0.0/embedded-cluster-join.mdx diff --git a/docs/reference/embedded-cluster-reset.mdx b/installer_versioned_docs/version-2.0.0/embedded-cluster-reset.mdx similarity index 100% rename from docs/reference/embedded-cluster-reset.mdx rename to installer_versioned_docs/version-2.0.0/embedded-cluster-reset.mdx diff --git a/docs/reference/embedded-cluster-restore.mdx b/installer_versioned_docs/version-2.0.0/embedded-cluster-restore.mdx similarity index 100% rename from docs/reference/embedded-cluster-restore.mdx rename to installer_versioned_docs/version-2.0.0/embedded-cluster-restore.mdx diff --git a/docs/reference/embedded-cluster-shell.mdx b/installer_versioned_docs/version-2.0.0/embedded-cluster-shell.mdx similarity index 100% rename from docs/reference/embedded-cluster-shell.mdx rename to installer_versioned_docs/version-2.0.0/embedded-cluster-shell.mdx diff --git a/docs/reference/embedded-cluster-support-bundle.mdx b/installer_versioned_docs/version-2.0.0/embedded-cluster-support-bundle.mdx similarity index 100% rename from docs/reference/embedded-cluster-support-bundle.mdx rename to installer_versioned_docs/version-2.0.0/embedded-cluster-support-bundle.mdx diff --git a/docs/reference/embedded-cluster-update.mdx b/installer_versioned_docs/version-2.0.0/embedded-cluster-update.mdx similarity index 100% rename from docs/reference/embedded-cluster-update.mdx rename to installer_versioned_docs/version-2.0.0/embedded-cluster-update.mdx diff --git a/docs/reference/embedded-cluster-version.mdx b/installer_versioned_docs/version-2.0.0/embedded-cluster-version.mdx similarity index 100% rename from docs/reference/embedded-cluster-version.mdx rename to installer_versioned_docs/version-2.0.0/embedded-cluster-version.mdx diff --git a/docs/reference/embedded-config.mdx b/installer_versioned_docs/version-2.0.0/embedded-config.mdx similarity index 99% rename from docs/reference/embedded-config.mdx rename to installer_versioned_docs/version-2.0.0/embedded-config.mdx index 4912f7d4e0..710ac36564 100644 --- a/docs/reference/embedded-config.mdx +++ b/installer_versioned_docs/version-2.0.0/embedded-config.mdx @@ -1,4 +1,4 @@ -import DoNotDowngrade from "../partials/embedded-cluster/_warning-do-not-downgrade.mdx" +import DoNotDowngrade from "../../docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx" # Embedded Cluster Config diff --git a/docs/vendor/embedded-disaster-recovery.mdx b/installer_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx similarity index 100% rename from docs/vendor/embedded-disaster-recovery.mdx rename to installer_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx diff --git a/docs/enterprise/embedded-manage-nodes.mdx b/installer_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx similarity index 98% rename from docs/enterprise/embedded-manage-nodes.mdx rename to installer_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx index dd5805538f..69fb03d267 100644 --- a/docs/enterprise/embedded-manage-nodes.mdx +++ b/installer_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx @@ -1,5 +1,5 @@ -import HaArchitecture from "../partials/embedded-cluster/_multi-node-ha-arch.mdx" -import ShellCommand from "../partials/embedded-cluster/_shell-command.mdx" +import HaArchitecture from "../../docs/partials/embedded-cluster/_multi-node-ha-arch.mdx" +import ShellCommand from "../../docs/partials/embedded-cluster/_shell-command.mdx" # Access and manage embedded clusters diff --git a/docs/vendor/embedded-overview.mdx b/installer_versioned_docs/version-2.0.0/embedded-overview.mdx similarity index 99% rename from docs/vendor/embedded-overview.mdx rename to installer_versioned_docs/version-2.0.0/embedded-overview.mdx index cb001d533c..8106d5b96a 100644 --- a/docs/vendor/embedded-overview.mdx +++ b/installer_versioned_docs/version-2.0.0/embedded-overview.mdx @@ -1,5 +1,5 @@ -import EmbeddedCluster from "../partials/embedded-cluster/_definition.mdx" -import HaArchitecture from "../partials/embedded-cluster/_multi-node-ha-arch.mdx" +import EmbeddedCluster from "../../docs/partials/embedded-cluster/_definition.mdx" +import HaArchitecture from "../../docs/partials/embedded-cluster/_multi-node-ha-arch.mdx" # Embedded Cluster overview diff --git a/docs/enterprise/embedded-tls-certs.mdx b/installer_versioned_docs/version-2.0.0/embedded-tls-certs.mdx similarity index 100% rename from docs/enterprise/embedded-tls-certs.mdx rename to installer_versioned_docs/version-2.0.0/embedded-tls-certs.mdx diff --git a/docs/vendor/embedded-troubleshooting.mdx b/installer_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx similarity index 96% rename from docs/vendor/embedded-troubleshooting.mdx rename to installer_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx index 6c1a8faa25..fda8dbb6ba 100644 --- a/docs/vendor/embedded-troubleshooting.mdx +++ b/installer_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx @@ -1,6 +1,6 @@ -import SupportBundleIntro from "../partials/support-bundles/_ec-support-bundle-intro.mdx" -import EmbeddedClusterSupportBundle from "../partials/support-bundles/_generate-bundle-ec.mdx" -import ShellCommand from "../partials/embedded-cluster/_shell-command.mdx" +import SupportBundleIntro from "../../docs/partials/support-bundles/_ec-support-bundle-intro.mdx" +import EmbeddedClusterSupportBundle from "../../docs/partials/support-bundles/_generate-bundle-ec.mdx" +import ShellCommand from "../../docs/partials/embedded-cluster/_shell-command.mdx" import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/docs/vendor/embedded-using.mdx b/installer_versioned_docs/version-2.0.0/embedded-using.mdx similarity index 97% rename from docs/vendor/embedded-using.mdx rename to installer_versioned_docs/version-2.0.0/embedded-using.mdx index bcefc3f41b..74fa000c83 100644 --- a/docs/vendor/embedded-using.mdx +++ b/installer_versioned_docs/version-2.0.0/embedded-using.mdx @@ -1,6 +1,6 @@ -import UpdateOverview from "../partials/embedded-cluster/_update-overview.mdx" -import EcConfig from "../partials/embedded-cluster/_ec-config.mdx" -import ShellCommand from "../partials/embedded-cluster/_shell-command.mdx" +import UpdateOverview from "../../docs/partials/embedded-cluster/_update-overview.mdx" +import EcConfig from "../../docs/partials/embedded-cluster/_ec-config.mdx" +import ShellCommand from "../../docs/partials/embedded-cluster/_shell-command.mdx" # Configure Embedded Cluster diff --git a/docs/enterprise/installing-embedded-air-gap.mdx b/installer_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx similarity index 95% rename from docs/enterprise/installing-embedded-air-gap.mdx rename to installer_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx index d6f8ff581a..4b0c4f172b 100644 --- a/docs/enterprise/installing-embedded-air-gap.mdx +++ b/installer_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx @@ -1,8 +1,8 @@ -import UpdateAirGapAdm from "../partials/embedded-cluster/_update-air-gap-admin-console.mdx" -import UpdateAirGapCli from "../partials/embedded-cluster/_update-air-gap-cli.mdx" -import UpdateAirGapOverview from "../partials/embedded-cluster/_update-air-gap-overview.mdx" -import DoNotDowngrade from "../partials/embedded-cluster/_warning-do-not-downgrade.mdx" -import Prerequisites from "../partials/install/_ec-prereqs.mdx" +import UpdateAirGapAdm from "../../docs/partials/embedded-cluster/_update-air-gap-admin-console.mdx" +import UpdateAirGapCli from "../../docs/partials/embedded-cluster/_update-air-gap-cli.mdx" +import UpdateAirGapOverview from "../../docs/partials/embedded-cluster/_update-air-gap-overview.mdx" +import DoNotDowngrade from "../../docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx" +import Prerequisites from "../../docs/partials/install/_ec-prereqs.mdx" # Air gap installation with Embedded Cluster diff --git a/docs/enterprise/installing-embedded-automation.mdx b/installer_versioned_docs/version-2.0.0/installing-embedded-automation.mdx similarity index 94% rename from docs/enterprise/installing-embedded-automation.mdx rename to installer_versioned_docs/version-2.0.0/installing-embedded-automation.mdx index 422b1d37f7..7aff906b8c 100644 --- a/docs/enterprise/installing-embedded-automation.mdx +++ b/installer_versioned_docs/version-2.0.0/installing-embedded-automation.mdx @@ -1,6 +1,6 @@ -import ConfigValuesExample from "../partials/configValues/_configValuesExample.mdx" -import ConfigValuesProcedure from "../partials/configValues/_config-values-procedure.mdx" -import ConfigValuesRequirements from "../partials/configValues/_requirements.mdx" +import ConfigValuesExample from "../../docs/partials/configValues/_configValuesExample.mdx" +import ConfigValuesProcedure from "../../docs/partials/configValues/_config-values-procedure.mdx" +import ConfigValuesRequirements from "../../docs/partials/configValues/_requirements.mdx" # Automate installation with Embedded Cluster diff --git a/docs/enterprise/installing-embedded-requirements.mdx b/installer_versioned_docs/version-2.0.0/installing-embedded-requirements.mdx similarity index 88% rename from docs/enterprise/installing-embedded-requirements.mdx rename to installer_versioned_docs/version-2.0.0/installing-embedded-requirements.mdx index 3d7508ba9b..6db6c11aec 100644 --- a/docs/enterprise/installing-embedded-requirements.mdx +++ b/installer_versioned_docs/version-2.0.0/installing-embedded-requirements.mdx @@ -1,7 +1,7 @@ -import EmbeddedClusterRequirements from "../partials/embedded-cluster/_requirements.mdx" -import EmbeddedClusterPortRequirements from "../partials/embedded-cluster/_port-reqs.mdx" -import FirewallOpeningsIntro from "../partials/install/_firewall-openings-intro.mdx" -import FirewallOpeningsEc from "../partials/install/_firewall-openings-embedded-cluster.mdx" +import EmbeddedClusterRequirements from "../../docs/partials/embedded-cluster/_requirements.mdx" +import EmbeddedClusterPortRequirements from "../../docs/partials/embedded-cluster/_port-reqs.mdx" +import FirewallOpeningsIntro from "../../docs/partials/install/_firewall-openings-intro.mdx" +import FirewallOpeningsEc from "../../docs/partials/install/_firewall-openings-embedded-cluster.mdx" # Embedded Cluster installation requirements diff --git a/docs/enterprise/installing-embedded.mdx b/installer_versioned_docs/version-2.0.0/installing-embedded.mdx similarity index 98% rename from docs/enterprise/installing-embedded.mdx rename to installer_versioned_docs/version-2.0.0/installing-embedded.mdx index dafb7f5da4..10f19171de 100644 --- a/docs/enterprise/installing-embedded.mdx +++ b/installer_versioned_docs/version-2.0.0/installing-embedded.mdx @@ -1,4 +1,4 @@ -import Prerequisites from "../partials/install/_ec-prereqs.mdx" +import Prerequisites from "../../docs/partials/install/_ec-prereqs.mdx" # Online installation with Embedded Cluster diff --git a/docs/enterprise/updating-embedded.mdx b/installer_versioned_docs/version-2.0.0/updating-embedded.mdx similarity index 86% rename from docs/enterprise/updating-embedded.mdx rename to installer_versioned_docs/version-2.0.0/updating-embedded.mdx index a63f2d7985..e27caa4a11 100644 --- a/docs/enterprise/updating-embedded.mdx +++ b/installer_versioned_docs/version-2.0.0/updating-embedded.mdx @@ -1,8 +1,8 @@ -import UpdateAirGapAdm from "../partials/embedded-cluster/_update-air-gap-admin-console.mdx" -import UpdateAirGapCli from "../partials/embedded-cluster/_update-air-gap-cli.mdx" -import UpdateAirGapOverview from "../partials/embedded-cluster/_update-air-gap-overview.mdx" -import DoNotDowngrade from "../partials/embedded-cluster/_warning-do-not-downgrade.mdx" -import Overview from "../partials/embedded-cluster/_update-overview.mdx" +import UpdateAirGapAdm from "../../docs/partials/embedded-cluster/_update-air-gap-admin-console.mdx" +import UpdateAirGapCli from "../../docs/partials/embedded-cluster/_update-air-gap-cli.mdx" +import UpdateAirGapOverview from "../../docs/partials/embedded-cluster/_update-air-gap-overview.mdx" +import DoNotDowngrade from "../../docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx" +import Overview from "../../docs/partials/embedded-cluster/_update-overview.mdx" # Perform updates in embedded clusters diff --git a/installer_versioned_sidebars/version-2.0.0-sidebars.json b/installer_versioned_sidebars/version-2.0.0-sidebars.json new file mode 100644 index 0000000000..02c2eea51c --- /dev/null +++ b/installer_versioned_sidebars/version-2.0.0-sidebars.json @@ -0,0 +1,40 @@ +{ + "installerSidebar": [ + "embedded-overview", + "embedded-using", + "embedded-config", + { + "type": "category", + "label": "Install with Embedded Cluster", + "items": [ + "installing-embedded-requirements", + "installing-embedded", + "installing-embedded-air-gap", + "installing-embedded-automation" + ] + }, + "embedded-manage-nodes", + "updating-embedded", + "embedded-troubleshooting", + "embedded-tls-certs", + "embedded-disaster-recovery", + { + "type": "category", + "label": "Embedded Cluster Commands", + "items": [ + "embedded-cluster-admin-console", + "embedded-cluster-completion", + "embedded-cluster-enable-ha", + "embedded-cluster-install", + "embedded-cluster-join", + "embedded-cluster-join-print-command", + "embedded-cluster-reset", + "embedded-cluster-restore", + "embedded-cluster-shell", + "embedded-cluster-support-bundle", + "embedded-cluster-update", + "embedded-cluster-version" + ] + } + ] +} diff --git a/installer_versions.json b/installer_versions.json new file mode 100644 index 0000000000..ca7ffcdaa9 --- /dev/null +++ b/installer_versions.json @@ -0,0 +1,3 @@ +[ + "2.0.0" +] \ No newline at end of file diff --git a/sidebarInstaller.js b/sidebarInstaller.js new file mode 100644 index 0000000000..5a3a296127 --- /dev/null +++ b/sidebarInstaller.js @@ -0,0 +1,5 @@ +module.exports = { + installerSidebar: [ + "v3-placeholder", + ], +}; diff --git a/sidebars.js b/sidebars.js index d3e43d3425..e3a1c37c1f 100644 --- a/sidebars.js +++ b/sidebars.js @@ -245,47 +245,52 @@ const sidebars = { }, ], }, - { - type: "category", - label: "Embedded Cluster", - items: [ - "vendor/embedded-overview", - "vendor/embedded-using", - { - type: "category", - label: "Install with Embedded Cluster", - items: [ - "enterprise/installing-embedded-requirements", - "enterprise/installing-embedded", - "enterprise/installing-embedded-air-gap", - "enterprise/installing-embedded-automation", - ], - }, - "enterprise/embedded-manage-nodes", - "enterprise/updating-embedded", - "vendor/embedded-troubleshooting", - "enterprise/embedded-tls-certs", - "vendor/embedded-disaster-recovery", - { - type: "category", - label: "Embedded Cluster commands", - items: [ - "reference/embedded-cluster-admin-console", - "reference/embedded-cluster-completion", - "reference/embedded-cluster-enable-ha", - "reference/embedded-cluster-install", - "reference/embedded-cluster-join", - "reference/embedded-cluster-join-print-command", - "reference/embedded-cluster-reset", - "reference/embedded-cluster-restore", - "reference/embedded-cluster-shell", - "reference/embedded-cluster-support-bundle", - "reference/embedded-cluster-update", - "reference/embedded-cluster-version", - ], - }, - ], - }, + { + type: "link", + href: "/installer/v3/v3-placeholder", + label: "Embedded Cluster", + }, + // { + // type: "category", + // label: "Embedded Cluster", + // items: [ + // "vendor/embedded-overview", + // "vendor/embedded-using", + // { + // type: "category", + // label: "Install with Embedded Cluster", + // items: [ + // "enterprise/installing-embedded-requirements", + // "enterprise/installing-embedded", + // "enterprise/installing-embedded-air-gap", + // "enterprise/installing-embedded-automation", + // ], + // }, + // "enterprise/embedded-manage-nodes", + // "enterprise/updating-embedded", + // "vendor/embedded-troubleshooting", + // "enterprise/embedded-tls-certs", + // "vendor/embedded-disaster-recovery", + // { + // type: "category", + // label: "Embedded Cluster commands", + // items: [ + // "reference/embedded-cluster-admin-console", + // "reference/embedded-cluster-completion", + // "reference/embedded-cluster-enable-ha", + // "reference/embedded-cluster-install", + // "reference/embedded-cluster-join", + // "reference/embedded-cluster-join-print-command", + // "reference/embedded-cluster-reset", + // "reference/embedded-cluster-restore", + // "reference/embedded-cluster-shell", + // "reference/embedded-cluster-support-bundle", + // "reference/embedded-cluster-update", + // "reference/embedded-cluster-version", + // ], + // }, + // ], + // }, { type: "category", label: "KOTS", @@ -610,7 +615,7 @@ const sidebars = { "reference/custom-resource-application", "reference/custom-resource-config", "reference/custom-resource-configvalues", - "reference/embedded-config", + // "reference/embedded-config", "reference/custom-resource-helmchart-v2", "reference/custom-resource-helmchart", "reference/custom-resource-lintconfig", diff --git a/src/components/InstallerVersionSelector/index.js b/src/components/InstallerVersionSelector/index.js new file mode 100644 index 0000000000..7c5fac1fd4 --- /dev/null +++ b/src/components/InstallerVersionSelector/index.js @@ -0,0 +1,124 @@ +/** + * Version selector for the installer docs, displayed at the top of the + * installer sidebar. Uses Docusaurus dropdown styles to match navbar dropdowns. + */ +import React, { useState, useRef, useEffect } from 'react'; +import Link from '@docusaurus/Link'; +import { + useVersions, + useActiveDocContext, + useDocsVersionCandidates, + useDocsPreferredVersion, +} from '@docusaurus/plugin-content-docs/client'; +import { useHistorySelector } from '@docusaurus/theme-common'; +import clsx from 'clsx'; + +const DOCS_PLUGIN_ID = 'installer'; + +function getVersionMainDoc(version) { + return version.docs.find((doc) => doc.id === version.mainDocId); +} + +function getVersionTargetDoc(version, activeDocContext) { + return ( + activeDocContext.alternateDocVersions?.[version.name] ?? + getVersionMainDoc(version) + ); +} + +export default function InstallerVersionSelector() { + const dropdownRef = useRef(null); + const [showDropdown, setShowDropdown] = useState(false); + const search = useHistorySelector((h) => h.location.search); + const hash = useHistorySelector((h) => h.location.hash); + const versions = useVersions(DOCS_PLUGIN_ID); + const activeDocContext = useActiveDocContext(DOCS_PLUGIN_ID); + const { savePreferredVersionName } = useDocsPreferredVersion(DOCS_PLUGIN_ID); + const candidates = useDocsVersionCandidates(DOCS_PLUGIN_ID); + + useEffect(() => { + const handleClickOutside = (event) => { + if (!dropdownRef.current?.contains(event.target)) { + setShowDropdown(false); + } + }; + document.addEventListener('mousedown', handleClickOutside); + document.addEventListener('touchstart', handleClickOutside); + document.addEventListener('focusin', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + document.removeEventListener('touchstart', handleClickOutside); + document.removeEventListener('focusin', handleClickOutside); + }; + }, []); + + if (!versions?.length || versions.length <= 1) { + return null; + } + + const versionItems = versions.map((v) => ({ version: v, label: v.label })); + const displayedCandidate = candidates?.[0]; + const currentItem = versionItems.find( + (vi) => vi.version === displayedCandidate + ) ?? versionItems[0]; + + return ( +
+ + +
+ ); +} \ No newline at end of file diff --git a/src/css/navbar.css b/src/css/navbar.css index ea4be68ca3..d9e6e4df27 100644 --- a/src/css/navbar.css +++ b/src/css/navbar.css @@ -2,19 +2,30 @@ display: none; } +.navbar__title { + display: none; +} + .DocSearch-Footer { justify-content: center !important; } -.dropdown__link:hover, .navbar__link { - background-color: transparent; - color: var(--ifm-dropdown-link-color); - text-decoration: none; +.dropdown__link, +.navbar__link { + background-color: transparent; + text-decoration: none; +} + +.navbar__link:hover, +.dropdown__link:hover { + color: var(--replicated-red); + background-color: transparent; } -.dropdown__link--active, .navbar__link--active { - background-color: transparent; - color: #2f2f2f; +.dropdown__link--active, +.navbar__link--active { + background-color: transparent; + color: #2f2f2f; } .dropdown > .navbar__link:after { diff --git a/src/css/sidebar.css b/src/css/sidebar.css index 7d20320301..51609266d3 100644 --- a/src/css/sidebar.css +++ b/src/css/sidebar.css @@ -15,4 +15,76 @@ .menu__list-item-collapsible > a:hover, .menu__link--active { color: var(--slate-noir); - } \ No newline at end of file + } + +/* Version selector styles for installer sidebar */ +.installer-version-selector { + padding: 0.75rem 0.5rem 0 0.5rem; + margin-bottom: 1rem; + display: block; + width: 100%; +} + +.installer-version-selector .dropdown__menu { + top: 100%; + margin-top: 0.25rem; + min-width: 100%; + left: 0; + right: 0; +} + +.installer-version-selector__trigger { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 0.45rem 0.5rem; + font-size: .9rem; + font-weight: var(--ifm-dropdown-font-weight); + color: var(--ifm-dropdown-link-color); + background-color: var(--ifm-dropdown-background-color); + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: var(--ifm-global-radius); + cursor: pointer; + transition: background-color 0.2s ease, border-color 0.2s ease; + outline: none; +} + +.installer-version-selector__trigger:hover { + background-color: var(--ifm-dropdown-hover-background-color); +} + +.installer-version-selector__trigger:focus { + border-color: var(--ifm-color-emphasis-500); +} + +.installer-version-selector .dropdown__link { + font-size: .9rem; + padding: 0.35rem 0.5rem; +} + +.installer-version-selector .dropdown__link:hover { + color: var(--ifm-dropdown-link-color); + background-color: var(--ifm-dropdown-hover-background-color); +} + +.installer-version-selector .dropdown__link--active, +.installer-version-selector .dropdown__link--active:hover { + color: var(--ifm-font-color-base); +} + +.installer-version-selector__trigger-label { + flex: 1; + text-align: left; +} + +.installer-version-selector__trigger-icon { + width: 1rem; + height: 1rem; + margin-left: 0.25rem; + flex-shrink: 0; +} + +.installer-version-selector.dropdown--show .installer-version-selector__trigger-icon { + transform: rotate(180deg); +} \ No newline at end of file diff --git a/src/theme/DocSidebar/Desktop/Content/index.js b/src/theme/DocSidebar/Desktop/Content/index.js new file mode 100644 index 0000000000..8f2e70e9bb --- /dev/null +++ b/src/theme/DocSidebar/Desktop/Content/index.js @@ -0,0 +1,57 @@ +/** + * Custom DocSidebar Desktop Content: shows the installer version selector + * at the top of the sidebar when the user is on an installer docs page. + */ +import React, { useState } from 'react'; +import clsx from 'clsx'; +import { ThemeClassNames } from '@docusaurus/theme-common'; +import { + useAnnouncementBar, + useScrollPosition, +} from '@docusaurus/theme-common/internal'; +import { translate } from '@docusaurus/Translate'; +import DocSidebarItems from '@theme/DocSidebarItems'; +import InstallerVersionSelector from '@site/src/components/InstallerVersionSelector'; +import styles from './styles.module.css'; + +function useShowAnnouncementBar() { + const { isActive } = useAnnouncementBar(); + const [showAnnouncementBar, setShowAnnouncementBar] = useState(isActive); + useScrollPosition( + ({ scrollY }) => { + if (isActive) { + setShowAnnouncementBar(scrollY === 0); + } + }, + [isActive] + ); + return isActive && showAnnouncementBar; +} + +export default function DocSidebarDesktopContent({ path, sidebar, className }) { + const showAnnouncementBar = useShowAnnouncementBar(); + const isInstallerDocs = path?.startsWith('/installer'); + + return ( + <> + {isInstallerDocs && } + + + ); +} \ No newline at end of file diff --git a/src/theme/DocSidebar/Desktop/Content/styles.module.css b/src/theme/DocSidebar/Desktop/Content/styles.module.css new file mode 100644 index 0000000000..7f6b2fc2fa --- /dev/null +++ b/src/theme/DocSidebar/Desktop/Content/styles.module.css @@ -0,0 +1,20 @@ +/** + * DocSidebar Desktop Content styles + */ + + @media (min-width: 997px) { + .menu { + flex-grow: 1; + padding: 0.5rem; + } + @supports (scrollbar-gutter: stable) { + .menu { + padding: 0.5rem 0 0.5rem 0.5rem; + scrollbar-gutter: stable; + } + } + + .menuWithAnnouncementBar { + margin-bottom: var(--docusaurus-announcement-bar-height); + } + } \ No newline at end of file diff --git a/src/theme/DocSidebar/Mobile/index.js b/src/theme/DocSidebar/Mobile/index.js new file mode 100644 index 0000000000..c210d275d1 --- /dev/null +++ b/src/theme/DocSidebar/Mobile/index.js @@ -0,0 +1,54 @@ +/** + * Custom DocSidebar Mobile: shows the installer version selector + * at the top when the user is on an installer docs page. + */ +import React from 'react'; +import clsx from 'clsx'; +import { + NavbarSecondaryMenuFiller, + ThemeClassNames, +} from '@docusaurus/theme-common'; +import { useNavbarMobileSidebar } from '@docusaurus/theme-common/internal'; +import DocSidebarItems from '@theme/DocSidebarItems'; +import InstallerVersionSelector from '@site/src/components/InstallerVersionSelector'; + +const DocSidebarMobileSecondaryMenu = ({ sidebar, path }) => { + const mobileSidebar = useNavbarMobileSidebar(); + const isInstallerDocs = path?.startsWith('/installer'); + + return ( + <> + {isInstallerDocs && ( +
+ +
+ )} + + + ); +}; + +function DocSidebarMobile(props) { + return ( + + ); +} + +export default React.memo(DocSidebarMobile); \ No newline at end of file From 5e06ae95d212ed0f614adeb612c544eb3abe851a Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Wed, 11 Mar 2026 11:51:37 -0600 Subject: [PATCH 02/31] add product-specific sidebars --- docusaurus.config.js | 14 +- sidebarCompatibilityMatrix.js | 20 ++ sidebarEnterprisePortal.js | 10 + sidebarHelm.js | 10 + sidebarKots.js | 169 +++++++++ sidebarKurl.js | 39 +++ sidebarProxyRegistry.js | 19 + sidebarReplicatedSdk.js | 10 + sidebarSecurityCenter.js | 5 + sidebarTroubleshoot.js | 46 +++ sidebarVendorPortal.js | 110 ++++++ sidebars.js | 631 +++++++--------------------------- 12 files changed, 568 insertions(+), 515 deletions(-) create mode 100644 sidebarCompatibilityMatrix.js create mode 100644 sidebarEnterprisePortal.js create mode 100644 sidebarHelm.js create mode 100644 sidebarKots.js create mode 100644 sidebarKurl.js create mode 100644 sidebarProxyRegistry.js create mode 100644 sidebarReplicatedSdk.js create mode 100644 sidebarSecurityCenter.js create mode 100644 sidebarTroubleshoot.js create mode 100644 sidebarVendorPortal.js diff --git a/docusaurus.config.js b/docusaurus.config.js index 6c48ffdd61..3bf760fddc 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -29,7 +29,7 @@ const config = { docs: { routeBasePath: '/', // Serve the docs at the site's root sidebarPath: require.resolve('./sidebars.js'), - breadcrumbs: false, + breadcrumbs: true, editUrl: 'https://github.com/replicatedhq/replicated-docs/edit/main/', admonitions: { keywords: ['note','important', 'tip', 'info', 'caution', 'danger'], @@ -203,9 +203,19 @@ const config = { }, { type: 'dropdown', - label: 'Developer tools', + label: 'Reference', position: 'left', items: [ + { + type: 'doc', + docId: 'reference/custom-resource-about', + label: 'Custom resources', + }, + { + type: 'doc', + docId: 'reference/template-functions-about', + label: 'Template functions', + }, { type: 'doc', docId: 'reference/kots-cli-getting-started', diff --git a/sidebarCompatibilityMatrix.js b/sidebarCompatibilityMatrix.js new file mode 100644 index 0000000000..41ba20e927 --- /dev/null +++ b/sidebarCompatibilityMatrix.js @@ -0,0 +1,20 @@ +module.exports = { + compatibilityMatrixSidebar: [ + "vendor/testing-about", + "vendor/testing-supported-clusters", + "vendor/testing-how-to", + "vendor/testing-vm-create", + "vendor/testing-ingress", + "vendor/testing-network-policy", + "vendor/testing-cluster-addons", + "vendor/testing-ci-cd", + { + type: "category", + label: "Manage cost and usage", + items: [ + "vendor/testing-pricing", + "vendor/compatibility-matrix-usage", + ], + }, + ], +}; \ No newline at end of file diff --git a/sidebarEnterprisePortal.js b/sidebarEnterprisePortal.js new file mode 100644 index 0000000000..da62b85648 --- /dev/null +++ b/sidebarEnterprisePortal.js @@ -0,0 +1,10 @@ +module.exports = { + enterprisePortalSidebar: [ + "vendor/enterprise-portal-about", + "vendor/enterprise-portal-configure", + "vendor/enterprise-portal-invite", + "vendor/enterprise-portal-self-serve-signup", + "vendor/enterprise-portal-access", + "vendor/enterprise-portal-use", + ], +}; \ No newline at end of file diff --git a/sidebarHelm.js b/sidebarHelm.js new file mode 100644 index 0000000000..6163a74502 --- /dev/null +++ b/sidebarHelm.js @@ -0,0 +1,10 @@ +module.exports = { + helmSidebar: [ + "vendor/helm-install-overview", + "vendor/helm-install-values-schema", + "vendor/install-with-helm", + "vendor/helm-install-airgap", + "vendor/using-third-party-registry-proxy", + "vendor/helm-install-troubleshooting", + ], + }; \ No newline at end of file diff --git a/sidebarKots.js b/sidebarKots.js new file mode 100644 index 0000000000..ef1b29250c --- /dev/null +++ b/sidebarKots.js @@ -0,0 +1,169 @@ +module.exports = { + kotsSidebar: [ + "intro-kots", + { + type: "category", + label: "Configure KOTS", + items: [ + { + type: "category", + label: "Configure the HelmChart Custom Resource", + items: [ + "vendor/helm-native-about", + "vendor/helm-native-v2-using", + "vendor/helm-packaging-airgap-bundles", + "vendor/helm-optional-value-keys", + "vendor/helm-v2-migrate", + ], + }, + { + type: "category", + label: "Customize the Admin Console and Download Portal", + items: [ + "vendor/admin-console-customize-app-icon", + "vendor/admin-console-adding-buttons-links", + "vendor/admin-console-port-forward", + "vendor/admin-console-prometheus-monitoring", + ], + }, + { + type: "category", + label: "Configure the Admin Console Config Screen", + items: [ + "vendor/config-screen-about", + "vendor/admin-console-customize-config-screen", + "vendor/config-screen-map-inputs", + "vendor/config-screen-conditional", + ], + }, + { + type: "category", + label: "Manage Resources and Objects", + items: [ + "vendor/admin-console-display-app-status", + { + type: "category", + label: "Conditionally Deploy Resources", + items: [ + "vendor/packaging-include-resources", + "vendor/tutorial-adding-db-config", + ], + }, + "vendor/resources-annotations-templating", + "vendor/orchestrating-resource-deployment", + "vendor/database-config-adding-options", + "vendor/packaging-cleaning-up-jobs", + "vendor/packaging-ingress", + ], + }, + { + type: "category", + label: "Manage KOTS", + items: [ + "vendor/packaging-kots-versions", + "vendor/packaging-rbac", + "vendor/packaging-air-gap-excluding-minio", + ], + }, + { + type: "category", + label: "Distribute Kubernetes Operators with KOTS", + items: [ + "vendor/operator-packaging-about", + "vendor/operator-defining-additional-images", + "vendor/operator-referencing-images", + "vendor/operator-defining-additional-namespaces", + ], + }, + ], + }, + { + type: "category", + label: "Install in Existing Clusters with KOTS", + items: [ + "enterprise/installing-overview", + "enterprise/installing-general-requirements", + "enterprise/installing-existing-cluster", + "enterprise/installing-existing-cluster-airgapped", + "enterprise/installing-existing-cluster-automation", + "enterprise/installing-stateful-component-requirements", + ], + }, + { + type: "category", + label: "Perform Updates in Existing Cluster KOTS Installations", + items: [ + "enterprise/updating-app-manager", + "enterprise/updating-apps", + "enterprise/updating-patching-with-kustomize", + ], + }, + { + type: "category", + label: "Configure Local Image Registries", + items: [ + "enterprise/image-registry-settings", + "enterprise/image-registry-rate-limits", + ], + }, + "enterprise/updating-licenses", + { + type: "category", + label: "Perform Backup and Restore with Snapshots", + items: [ + "vendor/snapshots-overview", + { + type: "category", + label: "Enable and Configure Snapshots", + items: [ + "vendor/snapshots-configuring-backups", + "reference/custom-resource-backup", + "vendor/snapshots-hooks", + ], + }, + { + type: "category", + label: "Configure Backup Storage for Snaphots", + items: [ + "enterprise/snapshots-velero-cli-installing", + "enterprise/snapshots-configuring-hostpath", + "enterprise/snapshots-configuring-nfs", + "enterprise/snapshots-storage-destinations", + "enterprise/snapshots-velero-installing-config", + ], + }, + "enterprise/snapshots-creating", + "enterprise/snapshots-restoring-full", + "enterprise/snapshots-updating-with-admin-console", + "enterprise/snapshots-troubleshooting-backup-restore", + ], + }, + { + type: "category", + label: "Manage Admin Console User Access", + items: [ + "enterprise/auth-changing-passwords", + "enterprise/auth-identity-provider", + "enterprise/auth-configuring-rbac", + ], + }, + { + type: "category", + label: "Monitor Applications with Prometheus", + items: [ + "enterprise/monitoring-applications", + "enterprise/monitoring-access-dashboards", + ], + }, + "enterprise/status-viewing-details", + "enterprise/delete-admin-console", + { + type: "category", + label: "Use a GitOps Workflow", + items: [ + "enterprise/gitops-workflow", + "enterprise/gitops-managing-secrets", + ], + }, + ], + }; \ No newline at end of file diff --git a/sidebarKurl.js b/sidebarKurl.js new file mode 100644 index 0000000000..aeae834671 --- /dev/null +++ b/sidebarKurl.js @@ -0,0 +1,39 @@ +module.exports = { + kurlSidebar: [ + "vendor/kurl-about", + { + type: "category", + label: "Configure kURL Installers", + items: [ + "vendor/packaging-embedded-kubernetes", + "vendor/packaging-installer-storage", + "vendor/installer-history", + "vendor/kurl-nodeport-services", + ], + }, + { + type: "category", + label: "Install with kURL", + items: [ + "enterprise/installing-kurl-requirements", + "enterprise/installing-kurl", + "enterprise/installing-kurl-airgap", + "enterprise/installing-kurl-automation", + ], + }, + "enterprise/cluster-management-add-nodes", + { + type: "category", + label: "Perform Updates with kURL", + items: [ + "enterprise/updating-kurl-about", + "enterprise/updating-kurl", + ], + }, + "vendor/packaging-using-tls-certs", + "enterprise/updating-tls-cert", + "enterprise/image-registry-kurl", + "enterprise/monitoring-external-prometheus", + "vendor/kurl-reset", + ], + }; \ No newline at end of file diff --git a/sidebarProxyRegistry.js b/sidebarProxyRegistry.js new file mode 100644 index 0000000000..bbb6187b94 --- /dev/null +++ b/sidebarProxyRegistry.js @@ -0,0 +1,19 @@ +module.exports = { + proxyRegistrySidebar: [ + "vendor/private-images-about", + "vendor/packaging-private-images", + "vendor/helm-image-registry", + "vendor/private-images-kots", + "vendor/private-images-tags-digests", + "vendor/packaging-public-images", + { + type: "category", + label: "Replicated Private Registry", + items: [ + "vendor/private-images-replicated", + "vendor/packaging-private-registry-security", + ], + }, + "vendor/tutorial-ecr-private-images", + ], + }; \ No newline at end of file diff --git a/sidebarReplicatedSdk.js b/sidebarReplicatedSdk.js new file mode 100644 index 0000000000..61096504f5 --- /dev/null +++ b/sidebarReplicatedSdk.js @@ -0,0 +1,10 @@ +module.exports = { + replicatedSdkSidebar: [ + "vendor/replicated-sdk-overview", + "vendor/replicated-sdk-installing", + "vendor/replicated-sdk-airgap", + "vendor/replicated-sdk-development", + "vendor/replicated-sdk-customizing", + "reference/replicated-sdk-apis", + ], + }; \ No newline at end of file diff --git a/sidebarSecurityCenter.js b/sidebarSecurityCenter.js new file mode 100644 index 0000000000..65f317313b --- /dev/null +++ b/sidebarSecurityCenter.js @@ -0,0 +1,5 @@ +module.exports = { + securityCenterSidebar: [ + "vendor/security-center-about", + ], + }; \ No newline at end of file diff --git a/sidebarTroubleshoot.js b/sidebarTroubleshoot.js new file mode 100644 index 0000000000..5f3f82ab1a --- /dev/null +++ b/sidebarTroubleshoot.js @@ -0,0 +1,46 @@ +module.exports = { + troubleshootSidebar: [ + "vendor/preflight-support-bundle-about", + { + type: "category", + label: "Preflight checks", + items: [ + "vendor/preflight-defining", + "vendor/preflight-examples", + "vendor/preflight-running", + "vendor/preflight-host-preflights", + ], + }, + { + type: "category", + label: "Support bundles", + items: [ + "vendor/support-bundle-customizing", + "vendor/support-bundle-examples", + "vendor/support-online-support-bundle-specs", + "vendor/support-modular-support-bundle-specs", + { + type: "category", + label: "Generate support bundles", + items: [ + "vendor/support-bundle-generating", + "vendor/support-bundle-embedded", + "enterprise/troubleshooting-an-app", + "vendor/support-host-support-bundles", + ], + }, + "vendor/support-inspecting-support-bundles", + "vendor/support-enabling-direct-bundle-uploads", + ], + }, + "vendor/preflight-sb-helm-templates-about", + { + type: "category", + label: "Troubleshoot custom resources", + items: [ + "reference/custom-resource-preflight", + "reference/custom-resource-redactor", + ], + }, + ], + }; \ No newline at end of file diff --git a/sidebarVendorPortal.js b/sidebarVendorPortal.js new file mode 100644 index 0000000000..dbaf79fb92 --- /dev/null +++ b/sidebarVendorPortal.js @@ -0,0 +1,110 @@ +module.exports = { + vendorPortalSidebar: [ + { + type: "category", + label: "Vendor Portal Teams and Accounts", + items: [ + "vendor/vendor-portal-creating-account", + "vendor/team-management", + "vendor/team-management-github-username", + { + type: "category", + label: "Configure Role-based Access Control", + items: [ + "vendor/team-management-rbac-configuring", + "vendor/team-management-rbac-resource-names", + ], + }, + { + type: "category", + label: "Configure Authentication", + items: [ + "vendor/team-management-two-factor-auth", + "vendor/team-management-google-auth", + "vendor/team-management-saml-auth", + "vendor/team-management-scim-provisioning", + ], + }, + "vendor/team-management-slack-config", + "vendor/replicated-api-tokens", + ], + }, + { + type: "category", + label: "Applications", + items: [ + "vendor/vendor-portal-manage-app", + "vendor/vendor-portal-application-settings", + ], + }, + { + type: "category", + label: "Channels and releases", + items: [ + "vendor/releases-about", + "vendor/releases-creating-channels", + "vendor/releases-creating-releases", + "vendor/releases-creating-cli", + "vendor/helm-install-release", + "vendor/releases-sharing-license-install-script", + "reference/linter", + ], + }, + { + type: "category", + label: "Customers and licenses", + items: [ + "vendor/licenses-about", + "vendor/releases-creating-customer", + "vendor/licenses-adding-custom-fields", + "vendor/licenses-install-types", + "vendor/releases-share-download-portal", + "vendor/licenses-about-types", + "vendor/licenses-download", + { + type: "category", + label: "Query license entitlements", + items: [ + "vendor/licenses-using-builtin-fields", + "vendor/licenses-reference-sdk", + "vendor/licenses-reference-helm", + "vendor/licenses-referencing-fields", + "vendor/licenses-reference-kots-runtime", + "vendor/licenses-verify-fields-sdk-api", + ], + }, + ], + }, + { + type: "category", + label: "Custom domains", + items: ["vendor/custom-domains", "vendor/custom-domains-using"], + }, + { + type: "category", + label: "Insights and telemetry", + items: [ + "vendor/instance-insights-event-data", + "vendor/insights-app-status", + "vendor/custom-metrics", + "vendor/telemetry-air-gap", + "vendor/customer-adoption", + "vendor/customer-reporting", + "vendor/instance-insights-details", + { + type: "category", + label: "Event Notifications (Beta)", + items: [ + "vendor/event-notifications", + "vendor/event-notifications-create", + "vendor/event-notifications-manage", + "vendor/event-notifications-webhooks", + ], + }, + "vendor/instance-notifications-config", + "vendor/instance-data-export", + ], + }, + "vendor/support-submit-request", + ], +}; diff --git a/sidebars.js b/sidebars.js index e3a1c37c1f..1117406e1b 100644 --- a/sidebars.js +++ b/sidebars.js @@ -11,6 +11,18 @@ // @ts-check +// Import modular sidebars +const vendorPlatformSidebar = require('./sidebarVendorPortal'); +const enterprisePortalSidebar = require('./sidebarEnterprisePortal'); +const securityCenterSidebar = require('./sidebarSecurityCenter'); +const compatibilityMatrixSidebar = require('./sidebarCompatibilityMatrix'); +const kotsSidebar = require('./sidebarKots'); +const kurlSidebar = require('./sidebarKurl'); +const helmInstallationsSidebar = require('./sidebarHelm'); +const replicatedSdkSidebar = require('./sidebarReplicatedSdk'); +const preflightSupportSidebar = require('./sidebarTroubleshoot'); +const proxyRegistrySidebar = require('./sidebarProxyRegistry'); + // @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} const sidebars = { // By default, Docusaurus generates a sidebar from the docs folder structure @@ -60,551 +72,131 @@ const sidebars = { }, { type: "category", - label: "Labs", + label: "Add Replicated to CI/CD Workflows", items: [ - { - type: "link", - href: "https://play.instruqt.com/embed/replicated/tracks/distributing-with-replicated?token=em_VHOEfNnBgU3auAnN", - label: "Distributing Your Application with Replicated", - }, - { - type: "link", - href: "https://play.instruqt.com/embed/replicated/tracks/delivering-as-an-appliance?token=em_lUZdcv0LrF6alIa3", - label: "Delivering Your Application as a Kubernetes Appliance", - }, - { - type: "link", - href: "https://play.instruqt.com/embed/replicated/tracks/avoiding-installation-pitfalls?token=em_gJjtIzzTTtdd5RFG", - label: "Avoiding Installation Pitfalls", - }, - { - type: "link", - href: "https://play.instruqt.com/embed/replicated/tracks/closing-information-gap?token=em_MO2XXCz3bAgwtEca", - label: "Closing the Support Information Gap", - }, - { - type: "link", - href: "https://play.instruqt.com/embed/replicated/tracks/protecting-your-assets?token=em_7QjY34G_UHKoREBd", - label: "Protecting Your Assets", - }, + "vendor/ci-overview", + "vendor/ci-workflows", + "vendor/ci-workflows-github-actions", ], }, + // { + // type: "category", + // label: "Labs", + // items: [ + // { + // type: "link", + // href: "https://play.instruqt.com/embed/replicated/tracks/distributing-with-replicated?token=em_VHOEfNnBgU3auAnN", + // label: "Distributing Your Application with Replicated", + // }, + // { + // type: "link", + // href: "https://play.instruqt.com/embed/replicated/tracks/delivering-as-an-appliance?token=em_lUZdcv0LrF6alIa3", + // label: "Delivering Your Application as a Kubernetes Appliance", + // }, + // { + // type: "link", + // href: "https://play.instruqt.com/embed/replicated/tracks/avoiding-installation-pitfalls?token=em_gJjtIzzTTtdd5RFG", + // label: "Avoiding Installation Pitfalls", + // }, + // { + // type: "link", + // href: "https://play.instruqt.com/embed/replicated/tracks/closing-information-gap?token=em_MO2XXCz3bAgwtEca", + // label: "Closing the Support Information Gap", + // }, + // { + // type: "link", + // href: "https://play.instruqt.com/embed/replicated/tracks/protecting-your-assets?token=em_7QjY34G_UHKoREBd", + // label: "Protecting Your Assets", + // }, + // ], + // }, // PRODUCT DOCS { type: "html", value: "
Product docs
", defaultStyle: true }, { - type: "category", + type: "ref", + id: "vendor/vendor-portal-creating-account", label: "Vendor Portal", - items: [ - { - type: "category", - label: "Vendor Portal Teams and Accounts", - items: [ - "vendor/vendor-portal-creating-account", - "vendor/team-management", - "vendor/team-management-github-username", - { - type: "category", - label: "Configure Role-based Access Control", - items: [ - "vendor/team-management-rbac-configuring", - "vendor/team-management-rbac-resource-names", - ], - }, - { - type: "category", - label: "Configure Authentication", - items: [ - "vendor/team-management-two-factor-auth", - "vendor/team-management-google-auth", - "vendor/team-management-saml-auth", - "vendor/team-management-scim-provisioning", - ], - }, - "vendor/team-management-slack-config", - "vendor/replicated-api-tokens", - ], - }, - { - type: "category", - label: "Applications", - items: [ - "vendor/vendor-portal-manage-app", - "vendor/vendor-portal-application-settings", - ], - }, - { - type: "category", - label: "Channels and releases", - items: [ - "vendor/releases-about", - "vendor/releases-creating-channels", - "vendor/releases-creating-releases", - "vendor/releases-creating-cli", - "vendor/helm-install-release", - "vendor/releases-sharing-license-install-script", - "reference/linter", - ], - }, - { - type: "category", - label: "Customers and licenses", - items: [ - "vendor/licenses-about", - "vendor/releases-creating-customer", - "vendor/licenses-adding-custom-fields", - "vendor/licenses-install-types", - "vendor/releases-share-download-portal", - "vendor/licenses-about-types", - "vendor/licenses-download", - { - type: "category", - label: "Query license entitlements", - items: [ - "vendor/licenses-using-builtin-fields", - "vendor/licenses-reference-sdk", - "vendor/licenses-reference-helm", - "vendor/licenses-referencing-fields", - "vendor/licenses-reference-kots-runtime", - "vendor/licenses-verify-fields-sdk-api", - ], - }, - ], - }, - { - type: "category", - label: "Custom domains", - items: ["vendor/custom-domains", "vendor/custom-domains-using"], - }, - { - type: "category", - label: "Insights and telemetry", - items: [ - "vendor/instance-insights-event-data", - "vendor/insights-app-status", - "vendor/custom-metrics", - "vendor/telemetry-air-gap", - "vendor/customer-adoption", - "vendor/customer-reporting", - "vendor/instance-insights-details", - { - type: "category", - label: "Event Notifications (Beta)", - items: [ - "vendor/event-notifications", - "vendor/event-notifications-create", - "vendor/event-notifications-manage", - "vendor/event-notifications-webhooks", - ], - }, - "vendor/instance-notifications-config", - "vendor/instance-data-export", - ], - }, - "vendor/support-submit-request", - ], + customProps: { + sidebar: "vendorPortalSidebar" + } }, { - type: "category", + type: "ref", + id: "vendor/enterprise-portal-about", label: "Enterprise Portal", - items: [ - "vendor/enterprise-portal-about", - "vendor/enterprise-portal-configure", - "vendor/enterprise-portal-invite", - "vendor/enterprise-portal-self-serve-signup", - "vendor/enterprise-portal-access", - "vendor/enterprise-portal-use", - ], + customProps: { + sidebar: "enterprisePortalSidebar" + } }, { - type: "category", + type: "ref", + id: "vendor/security-center-about", label: "Security Center (Alpha)", - items: ["vendor/security-center-about"], + customProps: { + sidebar: "securityCenterSidebar" + } }, { - type: "category", + type: "ref", + id: "vendor/testing-about", label: "Compatibility Matrix", - items: [ - "vendor/testing-about", - "vendor/testing-supported-clusters", - "vendor/testing-how-to", - "vendor/testing-vm-create", - // "vendor/testing-vm-transfer-files", - "vendor/testing-ingress", - // "vendor/testing-vm-about", - // "vendor/testing-vm-networking", - "vendor/testing-network-policy", - "vendor/testing-cluster-addons", - "vendor/testing-ci-cd", - { - type: "category", - label: "Manage cost and usage", - items: [ - "vendor/testing-pricing", - "vendor/compatibility-matrix-usage", - ], - }, - ], + customProps: { + sidebar: "compatibilityMatrixSidebar" + } }, { type: "link", - href: "/installer/v3/v3-placeholder", + href: "/installer/v3/embedded-overview", label: "Embedded Cluster", }, - // { - // type: "category", - // label: "Embedded Cluster", - // items: [ - // "vendor/embedded-overview", - // "vendor/embedded-using", - // { - // type: "category", - // label: "Install with Embedded Cluster", - // items: [ - // "enterprise/installing-embedded-requirements", - // "enterprise/installing-embedded", - // "enterprise/installing-embedded-air-gap", - // "enterprise/installing-embedded-automation", - // ], - // }, - // "enterprise/embedded-manage-nodes", - // "enterprise/updating-embedded", - // "vendor/embedded-troubleshooting", - // "enterprise/embedded-tls-certs", - // "vendor/embedded-disaster-recovery", - // { - // type: "category", - // label: "Embedded Cluster commands", - // items: [ - // "reference/embedded-cluster-admin-console", - // "reference/embedded-cluster-completion", - // "reference/embedded-cluster-enable-ha", - // "reference/embedded-cluster-install", - // "reference/embedded-cluster-join", - // "reference/embedded-cluster-join-print-command", - // "reference/embedded-cluster-reset", - // "reference/embedded-cluster-restore", - // "reference/embedded-cluster-shell", - // "reference/embedded-cluster-support-bundle", - // "reference/embedded-cluster-update", - // "reference/embedded-cluster-version", - // ], - // }, - // ], - // }, - { - type: "category", - label: "KOTS", - items: [ - "intro-kots", - { - type: "category", - label: "Configure KOTS", - items: [ - { - type: "category", - label: "Configure the HelmChart custom resource", - items: [ - "vendor/helm-native-about", - "vendor/helm-native-v2-using", - "vendor/helm-packaging-airgap-bundles", - "vendor/helm-optional-value-keys", - "vendor/helm-v2-migrate", - ], - }, - { - type: "category", - label: "Customize the Admin Console and Download Portal", - items: [ - "vendor/admin-console-customize-app-icon", - "vendor/admin-console-adding-buttons-links", - "vendor/admin-console-port-forward", - "vendor/admin-console-prometheus-monitoring", - ], - }, - { - type: "category", - label: "Configure the Admin Console config screen", - items: [ - "vendor/config-screen-about", - "vendor/admin-console-customize-config-screen", - "vendor/config-screen-map-inputs", - "vendor/config-screen-conditional", - ], - }, - { - type: "category", - label: "Manage resources and objects", - items: [ - "vendor/admin-console-display-app-status", - { - type: "category", - label: "Conditionally deploy resources", - items: [ - "vendor/packaging-include-resources", - "vendor/tutorial-adding-db-config", - ], - }, - "vendor/resources-annotations-templating", - "vendor/orchestrating-resource-deployment", - "vendor/database-config-adding-options", - "vendor/packaging-cleaning-up-jobs", - "vendor/packaging-ingress", - ], - }, - { - type: "category", - label: "Manage KOTS", - items: [ - "vendor/packaging-kots-versions", - "vendor/packaging-rbac", - "vendor/packaging-air-gap-excluding-minio", - ], - }, - { - type: "category", - label: "Distribute Kubernetes Operators with KOTS", - items: [ - "vendor/operator-packaging-about", - "vendor/operator-defining-additional-images", - "vendor/operator-referencing-images", - "vendor/operator-defining-additional-namespaces", - ], - }, - ], - }, - { - type: "category", - label: "Install in existing clusters with KOTS", - items: [ - "enterprise/installing-overview", - "enterprise/installing-general-requirements", - "enterprise/installing-existing-cluster", - "enterprise/installing-existing-cluster-airgapped", - "enterprise/installing-existing-cluster-automation", - "enterprise/installing-stateful-component-requirements", - ], - }, - { - type: "category", - label: "Perform updates in existing cluster KOTS installations", - items: [ - "enterprise/updating-app-manager", - "enterprise/updating-apps", - "enterprise/updating-patching-with-kustomize", - ], - }, - { - type: "category", - label: "Configure local image registries", - items: [ - "enterprise/image-registry-settings", - "enterprise/image-registry-rate-limits", - ], - }, - "enterprise/updating-licenses", - { - type: "category", - label: "Perform backup and restore with snapshots", - items: [ - "vendor/snapshots-overview", - { - type: "category", - label: "Enable and configure snapshots", - items: [ - "vendor/snapshots-configuring-backups", - "reference/custom-resource-backup", - "vendor/snapshots-hooks", - ], - }, - { - type: "category", - label: "Configure backup storage for snapshots", - items: [ - "enterprise/snapshots-velero-cli-installing", - "enterprise/snapshots-configuring-hostpath", - "enterprise/snapshots-configuring-nfs", - "enterprise/snapshots-storage-destinations", - "enterprise/snapshots-velero-installing-config", - ], - }, - "enterprise/snapshots-creating", - "enterprise/snapshots-restoring-full", - "enterprise/snapshots-updating-with-admin-console", - "enterprise/snapshots-troubleshooting-backup-restore", - ], - }, - { - type: "category", - label: "Manage Admin Console user access", - items: [ - "enterprise/auth-changing-passwords", - "enterprise/auth-identity-provider", - "enterprise/auth-configuring-rbac", - ], - }, - { - type: "category", - label: "Monitor applications with Prometheus", - items: [ - "enterprise/monitoring-applications", - "enterprise/monitoring-access-dashboards", - ], - }, - "enterprise/status-viewing-details", - "enterprise/delete-admin-console", - { - type: "category", - label: "Use a GitOps workflow", - items: [ - "enterprise/gitops-workflow", - "enterprise/gitops-managing-secrets", - ], - }, - ], - }, - { - type: "category", - label: "kURL", - items: [ - "vendor/kurl-about", - { - type: "category", - label: "Configure kURL Installers", - items: [ - "vendor/packaging-embedded-kubernetes", - "vendor/packaging-installer-storage", - "vendor/installer-history", - "vendor/kurl-nodeport-services", - ], - }, - { - type: "category", - label: "Install with kURL", - items: [ - "enterprise/installing-kurl-requirements", - "enterprise/installing-kurl", - "enterprise/installing-kurl-airgap", - "enterprise/installing-kurl-automation", - ], - }, - "enterprise/cluster-management-add-nodes", - { - type: "category", - label: "Perform updates with kURL", - items: [ - "enterprise/updating-kurl-about", - "enterprise/updating-kurl", - ], - }, - "vendor/packaging-using-tls-certs", - "enterprise/updating-tls-cert", - "enterprise/image-registry-kurl", - "enterprise/monitoring-external-prometheus", - "vendor/kurl-reset", - ], - }, { - type: "category", - label: "Helm installations with Replicated", - items: [ - "vendor/helm-install-overview", - "vendor/helm-install-values-schema", - "vendor/install-with-helm", - "vendor/helm-install-airgap", - "vendor/using-third-party-registry-proxy", - "vendor/helm-install-troubleshooting", - ], + type: "ref", + id: "vendor/helm-install-overview", + label: "Helm Installations with Replicated", + customProps: { + sidebar: "helmSidebar" + } }, { - type: "category", - label: "Replicated SDK", - items: [ - "vendor/replicated-sdk-overview", - "vendor/replicated-sdk-installing", - "vendor/replicated-sdk-airgap", - "vendor/replicated-sdk-development", - "vendor/replicated-sdk-customizing", - ], + type: "ref", + id: "intro-kots", + label: "KOTS", + customProps: { + sidebar: "kotsSidebar" + } }, { - type: "category", - label: "Preflight checks and support bundles", - items: [ - "vendor/preflight-support-bundle-about", - { - type: "category", - label: "Preflight checks", - items: [ - "vendor/preflight-defining", - "vendor/preflight-examples", - "vendor/preflight-running", - "vendor/preflight-host-preflights", - ], - }, - { - type: "category", - label: "Support bundles", - items: [ - "vendor/support-bundle-customizing", - "vendor/support-bundle-examples", - "vendor/support-online-support-bundle-specs", - "vendor/support-modular-support-bundle-specs", - { - type: "category", - label: "Generate support bundles", - items: [ - "vendor/support-bundle-generating", - "vendor/support-bundle-embedded", - "enterprise/troubleshooting-an-app", - "vendor/support-host-support-bundles", - ], - }, - "vendor/support-inspecting-support-bundles", - "vendor/support-enabling-direct-bundle-uploads", - ], - }, - "vendor/preflight-sb-helm-templates-about", - { - type: "category", - label: "Troubleshoot custom resources", - items: [ - "reference/custom-resource-preflight", - "reference/custom-resource-redactor", - ], - }, - ], + type: "ref", + id: "vendor/kurl-about", + label: "kURL", + customProps: { + sidebar: "kurlSidebar" + } }, { - type: "category", + type: "ref", + id: "vendor/private-images-about", label: "Replicated proxy registry", - items: [ - "vendor/private-images-about", - "vendor/packaging-private-images", - "vendor/helm-image-registry", - "vendor/private-images-kots", - "vendor/private-images-tags-digests", - { - type: "category", - label: "Replicated Private Registry", - items: [ - "vendor/private-images-replicated", - "vendor/packaging-private-registry-security", - ], - }, - "vendor/packaging-public-images", - "vendor/tutorial-ecr-private-images", - ], + customProps: { + sidebar: "proxyRegistrySidebar" + } }, { - type: "category", - label: "Add Replicated to CI/CD workflows", - items: [ - "vendor/ci-overview", - "vendor/ci-workflows", - "vendor/ci-workflows-github-actions", - ], + type: "ref", + id: "vendor/replicated-sdk-overview", + label: "Replicated SDK", + customProps: { + sidebar: "replicatedSdkSidebar" + } + }, + { + type: "ref", + id: "vendor/preflight-support-bundle-about", + label: "Preflight Checks and support bundles", + customProps: { + sidebar: "troubleshootSidebar" + } }, - // Reference { type: "html", value: "
Reference
", defaultStyle: true }, { @@ -937,6 +529,19 @@ const sidebars = { ], }, ], + + // Product-specific sidebars + ...vendorPlatformSidebar, + ...enterprisePortalSidebar, + ...securityCenterSidebar, + ...compatibilityMatrixSidebar, + ...kotsSidebar, + ...kurlSidebar, + ...helmInstallationsSidebar, + ...replicatedSdkSidebar, + ...preflightSupportSidebar, + ...proxyRegistrySidebar, + }; module.exports = sidebars; \ No newline at end of file From 8d16c38e2e98ef017e6268ba3028e8da30b25d68 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Wed, 11 Mar 2026 13:13:13 -0600 Subject: [PATCH 03/31] add headings to each product sidebar --- sidebarCompatibilityMatrix.js | 2 + sidebarEnterprisePortal.js | 2 + sidebarHelm.js | 1 + sidebarInstaller.js | 1 + sidebarKots.js | 1 + sidebarKurl.js | 1 + sidebarProxyRegistry.js | 1 + sidebarReplicatedSdk.js | 1 + sidebarSecurityCenter.js | 1 + sidebarTroubleshoot.js | 1 + sidebarVendorPortal.js | 1 + sidebars.js | 2 +- src/css/sidebar.css | 10 ++ src/theme/DocSidebar/Desktop/Content/index.js | 21 +++-- .../Desktop/Content/styles.module.css | 80 +++++++++++++--- src/theme/DocSidebar/Mobile/index.js | 12 ++- src/utils/sidebarProductFromPath.js | 94 +++++++++++++++++++ 17 files changed, 207 insertions(+), 25 deletions(-) create mode 100644 src/utils/sidebarProductFromPath.js diff --git a/sidebarCompatibilityMatrix.js b/sidebarCompatibilityMatrix.js index 41ba20e927..2dd355bf43 100644 --- a/sidebarCompatibilityMatrix.js +++ b/sidebarCompatibilityMatrix.js @@ -1,3 +1,5 @@ +// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG + module.exports = { compatibilityMatrixSidebar: [ "vendor/testing-about", diff --git a/sidebarEnterprisePortal.js b/sidebarEnterprisePortal.js index da62b85648..9430f1e1b4 100644 --- a/sidebarEnterprisePortal.js +++ b/sidebarEnterprisePortal.js @@ -1,3 +1,5 @@ +// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG + module.exports = { enterprisePortalSidebar: [ "vendor/enterprise-portal-about", diff --git a/sidebarHelm.js b/sidebarHelm.js index 6163a74502..effd545ec3 100644 --- a/sidebarHelm.js +++ b/sidebarHelm.js @@ -1,3 +1,4 @@ +// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG module.exports = { helmSidebar: [ "vendor/helm-install-overview", diff --git a/sidebarInstaller.js b/sidebarInstaller.js index 5a3a296127..108acff285 100644 --- a/sidebarInstaller.js +++ b/sidebarInstaller.js @@ -1,3 +1,4 @@ +// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG module.exports = { installerSidebar: [ "v3-placeholder", diff --git a/sidebarKots.js b/sidebarKots.js index ef1b29250c..a8a4483bc0 100644 --- a/sidebarKots.js +++ b/sidebarKots.js @@ -1,3 +1,4 @@ +// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG module.exports = { kotsSidebar: [ "intro-kots", diff --git a/sidebarKurl.js b/sidebarKurl.js index aeae834671..bcb6478932 100644 --- a/sidebarKurl.js +++ b/sidebarKurl.js @@ -1,3 +1,4 @@ +// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG module.exports = { kurlSidebar: [ "vendor/kurl-about", diff --git a/sidebarProxyRegistry.js b/sidebarProxyRegistry.js index bbb6187b94..2fc0cd7ee0 100644 --- a/sidebarProxyRegistry.js +++ b/sidebarProxyRegistry.js @@ -1,3 +1,4 @@ +// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG module.exports = { proxyRegistrySidebar: [ "vendor/private-images-about", diff --git a/sidebarReplicatedSdk.js b/sidebarReplicatedSdk.js index 61096504f5..ee9af0164e 100644 --- a/sidebarReplicatedSdk.js +++ b/sidebarReplicatedSdk.js @@ -1,3 +1,4 @@ +// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG module.exports = { replicatedSdkSidebar: [ "vendor/replicated-sdk-overview", diff --git a/sidebarSecurityCenter.js b/sidebarSecurityCenter.js index 65f317313b..ecdc75a3ec 100644 --- a/sidebarSecurityCenter.js +++ b/sidebarSecurityCenter.js @@ -1,3 +1,4 @@ +// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG module.exports = { securityCenterSidebar: [ "vendor/security-center-about", diff --git a/sidebarTroubleshoot.js b/sidebarTroubleshoot.js index 5f3f82ab1a..748775b227 100644 --- a/sidebarTroubleshoot.js +++ b/sidebarTroubleshoot.js @@ -1,3 +1,4 @@ +// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG module.exports = { troubleshootSidebar: [ "vendor/preflight-support-bundle-about", diff --git a/sidebarVendorPortal.js b/sidebarVendorPortal.js index dbaf79fb92..3048ce0c31 100644 --- a/sidebarVendorPortal.js +++ b/sidebarVendorPortal.js @@ -1,3 +1,4 @@ +// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG module.exports = { vendorPortalSidebar: [ { diff --git a/sidebars.js b/sidebars.js index 1117406e1b..9568593697 100644 --- a/sidebars.js +++ b/sidebars.js @@ -146,7 +146,7 @@ const sidebars = { }, { type: "link", - href: "/installer/v3/embedded-overview", + href: "installer/v3/v3-placeholder", label: "Embedded Cluster", }, { diff --git a/src/css/sidebar.css b/src/css/sidebar.css index 51609266d3..d0bb723300 100644 --- a/src/css/sidebar.css +++ b/src/css/sidebar.css @@ -87,4 +87,14 @@ .installer-version-selector.dropdown--show .installer-version-selector__trigger-icon { transform: rotate(180deg); +} + +/* Product name heading (mobile sidebar, padding aligned with menu) */ +.sidebar-product-heading-mobile { + font-size: 0.95rem; + font-weight: 600; + margin: 0 0 0.5rem 0; + padding: 0.75rem 1rem 0 1rem; + color: var(--ifm-font-color-base); + line-height: 1.3; } \ No newline at end of file diff --git a/src/theme/DocSidebar/Desktop/Content/index.js b/src/theme/DocSidebar/Desktop/Content/index.js index 8f2e70e9bb..a26b8def2a 100644 --- a/src/theme/DocSidebar/Desktop/Content/index.js +++ b/src/theme/DocSidebar/Desktop/Content/index.js @@ -1,6 +1,6 @@ /** - * Custom DocSidebar Desktop Content: shows the installer version selector - * at the top of the sidebar when the user is on an installer docs page. + * Custom DocSidebar Desktop Content: product heading, installer version selector, + * and slide+fade transition when switching between main and product sidebars. */ import React, { useState } from 'react'; import clsx from 'clsx'; @@ -12,6 +12,7 @@ import { import { translate } from '@docusaurus/Translate'; import DocSidebarItems from '@theme/DocSidebarItems'; import InstallerVersionSelector from '@site/src/components/InstallerVersionSelector'; +import { getProductForPath } from '@site/src/utils/sidebarProductFromPath'; import styles from './styles.module.css'; function useShowAnnouncementBar() { @@ -30,11 +31,19 @@ function useShowAnnouncementBar() { export default function DocSidebarDesktopContent({ path, sidebar, className }) { const showAnnouncementBar = useShowAnnouncementBar(); - const isInstallerDocs = path?.startsWith('/installer'); + const product = getProductForPath(path); + const sidebarKey = product?.key ?? 'main'; return ( - <> - {isInstallerDocs && } +
+ {product && ( +

{product.name}

+ )} + {product?.key === 'installer' && } - +
); } \ No newline at end of file diff --git a/src/theme/DocSidebar/Desktop/Content/styles.module.css b/src/theme/DocSidebar/Desktop/Content/styles.module.css index 7f6b2fc2fa..875ba9ea43 100644 --- a/src/theme/DocSidebar/Desktop/Content/styles.module.css +++ b/src/theme/DocSidebar/Desktop/Content/styles.module.css @@ -2,19 +2,71 @@ * DocSidebar Desktop Content styles */ - @media (min-width: 997px) { +/* Wrapper: flex column so the nav can fill and scroll; min-height: 0 allows overflow */ +.sidebarContentTransition { + display: flex; + flex-direction: column; + flex: 1; + min-height: 0; + overflow: hidden; +} + +/* Product sidebars (installer + main-docs product sidebars) slide in from right */ +.sidebarContentTransition[data-sidebar]:not([data-sidebar='main']) { + animation: sidebarSlideInFromRight 0.2s ease-out forwards; +} + +.sidebarContentTransition[data-sidebar='main'] { + animation: sidebarSlideInFromLeft 0.2s ease-out forwards; +} + +@keyframes sidebarSlideInFromRight { + from { + opacity: 0; + transform: translateX(12px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes sidebarSlideInFromLeft { + from { + opacity: 0; + transform: translateX(-12px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +/* Product name heading at top of product-specific sidebars */ +.sidebarProductHeading { + font-size: 0.9rem; + font-weight: 600; + margin: 0; + padding: 18px 12px 8px 18px; + color: var(--ifm-font-color-base); + line-height: 1.3; +} + +@media (min-width: 997px) { + .menu { + flex: 1; + min-height: 0; + overflow-y: auto; + padding: 0.5rem; + } + @supports (scrollbar-gutter: stable) { .menu { - flex-grow: 1; - padding: 0.5rem; - } - @supports (scrollbar-gutter: stable) { - .menu { - padding: 0.5rem 0 0.5rem 0.5rem; - scrollbar-gutter: stable; - } + padding: 0.5rem 0 0.5rem 0.5rem; + scrollbar-gutter: stable; } - - .menuWithAnnouncementBar { - margin-bottom: var(--docusaurus-announcement-bar-height); - } - } \ No newline at end of file + } + + .menuWithAnnouncementBar { + margin-bottom: var(--docusaurus-announcement-bar-height); + } +} \ No newline at end of file diff --git a/src/theme/DocSidebar/Mobile/index.js b/src/theme/DocSidebar/Mobile/index.js index c210d275d1..138c3c7efd 100644 --- a/src/theme/DocSidebar/Mobile/index.js +++ b/src/theme/DocSidebar/Mobile/index.js @@ -1,6 +1,6 @@ /** - * Custom DocSidebar Mobile: shows the installer version selector - * at the top when the user is on an installer docs page. + * Custom DocSidebar Mobile: product heading and installer version selector + * when the user is on an installer docs page. */ import React from 'react'; import clsx from 'clsx'; @@ -11,14 +11,18 @@ import { import { useNavbarMobileSidebar } from '@docusaurus/theme-common/internal'; import DocSidebarItems from '@theme/DocSidebarItems'; import InstallerVersionSelector from '@site/src/components/InstallerVersionSelector'; +import { getProductForPath } from '@site/src/utils/sidebarProductFromPath'; const DocSidebarMobileSecondaryMenu = ({ sidebar, path }) => { const mobileSidebar = useNavbarMobileSidebar(); - const isInstallerDocs = path?.startsWith('/installer'); + const product = getProductForPath(path); return ( <> - {isInstallerDocs && ( + {product && ( +

{product.name}

+ )} + {product?.key === 'installer' && (
diff --git a/src/utils/sidebarProductFromPath.js b/src/utils/sidebarProductFromPath.js new file mode 100644 index 0000000000..6736c6dd11 --- /dev/null +++ b/src/utils/sidebarProductFromPath.js @@ -0,0 +1,94 @@ +/** + * Maps current doc path to a product name for the sidebar heading. + * Built from the same sidebar configs as sidebars.js so product boundaries stay in sync. + * + * Order matters: first sidebar that contains a doc id wins (main sidebar is not listed, + * so main docs get no product heading). + */ + +function extractDocIds(items, ids = new Set()) { + if (!items || !Array.isArray(items)) return ids; + for (const item of items) { + if (typeof item === 'string') { + ids.add(item); + } else if (item && typeof item === 'object' && item.items) { + extractDocIds(item.items, ids); + } + } + return ids; +} + +// Sidebar module path (from repo root) -> display name +const SIDEBAR_CONFIG = [ + ['vendorPortalSidebar', 'Vendor Portal'], + ['enterprisePortalSidebar', 'Enterprise Portal'], + ['securityCenterSidebar', 'Security Center (Alpha)'], + ['compatibilityMatrixSidebar', 'Compatibility Matrix'], + ['kotsSidebar', 'KOTS'], + ['kurlSidebar', 'kURL'], + ['helmSidebar', 'Helm installations with Replicated'], + ['replicatedSdkSidebar', 'Replicated SDK'], + ['troubleshootSidebar', 'Troubleshoot'], + ['proxyRegistrySidebar', 'Replicated proxy registry'], +]; + +// Lazy-build docId -> product name (avoids require at module load if not needed) +let docIdToProduct = null; + +function buildDocIdMap() { + if (docIdToProduct) return docIdToProduct; + docIdToProduct = {}; + try { + const sidebars = [ + require('../../sidebarVendorPortal'), + require('../../sidebarEnterprisePortal'), + require('../../sidebarSecurityCenter'), + require('../../sidebarCompatibilityMatrix'), + require('../../sidebarKots'), + require('../../sidebarKurl'), + require('../../sidebarHelm'), + require('../../sidebarReplicatedSdk'), + require('../../sidebarTroubleshoot'), + require('../../sidebarProxyRegistry'), + ]; + SIDEBAR_CONFIG.forEach(([key, name], i) => { + const items = sidebars[i]?.[key]; + if (!items) return; + const ids = extractDocIds(items); + ids.forEach((id) => { + if (!docIdToProduct[id]) docIdToProduct[id] = name; + }); + }); + } catch (e) { + console.warn('[sidebarProductFromPath] Could not load sidebars:', e.message); + } + return docIdToProduct; +} + +/** + * Path prefix for the installer docs (separate plugin). Takes precedence over main-docs mapping. + */ +const INSTALLER_PREFIX = '/installer'; +const INSTALLER_NAME = 'Embedded Cluster'; + +/** + * @param {string} path - Current doc path (e.g. /vendor/kurl-about or /intro-kots) + * @returns {{ name: string } | null} Product to show in sidebar heading, or null for main/generic docs + */ +export function getProductForPath(path) { + if (!path || typeof path !== 'string') return null; + + // Installer (separate docs plugin) has its own path prefix + if (path.startsWith(INSTALLER_PREFIX)) { + return { key: 'installer', name: INSTALLER_NAME }; + } + + const docId = path.replace(/^\//, ''); + const map = buildDocIdMap(); + const name = map[docId]; + if (!name) return null; + + // Use a stable key for main-docs product sidebars (for transition/animation) + const key = docId.split('/')[0] + '-' + name.replace(/\s+/g, '-').toLowerCase().slice(0, 12); + return { key, name }; +} From 9b297ecdc75f5091ff103d0254d861168ad3597f Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Wed, 11 Mar 2026 14:30:38 -0600 Subject: [PATCH 04/31] adjust sidebar styles for installer --- src/theme/DocSidebar/Desktop/Content/index.js | 2 +- src/theme/DocSidebar/Mobile/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/theme/DocSidebar/Desktop/Content/index.js b/src/theme/DocSidebar/Desktop/Content/index.js index a26b8def2a..6f0a813a42 100644 --- a/src/theme/DocSidebar/Desktop/Content/index.js +++ b/src/theme/DocSidebar/Desktop/Content/index.js @@ -40,7 +40,7 @@ export default function DocSidebarDesktopContent({ path, sidebar, className }) { data-sidebar={sidebarKey} className={styles.sidebarContentTransition} > - {product && ( + {product && product.key !== 'installer' && (

{product.name}

)} {product?.key === 'installer' && } diff --git a/src/theme/DocSidebar/Mobile/index.js b/src/theme/DocSidebar/Mobile/index.js index 138c3c7efd..ad326b9382 100644 --- a/src/theme/DocSidebar/Mobile/index.js +++ b/src/theme/DocSidebar/Mobile/index.js @@ -19,7 +19,7 @@ const DocSidebarMobileSecondaryMenu = ({ sidebar, path }) => { return ( <> - {product && ( + {product && product.key !== 'installer' && (

{product.name}

)} {product?.key === 'installer' && ( From f5745dfc8016537f6ef21f3ea7448505ed4c0c8f Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Wed, 18 Mar 2026 12:18:58 -0600 Subject: [PATCH 05/31] fix sidebar link --- sidebars.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sidebars.js b/sidebars.js index 9568593697..b4ed86d834 100644 --- a/sidebars.js +++ b/sidebars.js @@ -146,7 +146,7 @@ const sidebars = { }, { type: "link", - href: "installer/v3/v3-placeholder", + href: "/installer/v3/v3-placeholder", label: "Embedded Cluster", }, { From 0e43c3117d721604c8a8b411da44fede3c9fa759 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Wed, 25 Mar 2026 14:23:45 -0600 Subject: [PATCH 06/31] merge latest vp sidebar changes from main --- sidebarVendorPortal.js | 211 +++++++++++++++++++++-------------------- 1 file changed, 106 insertions(+), 105 deletions(-) diff --git a/sidebarVendorPortal.js b/sidebarVendorPortal.js index 3048ce0c31..1943a1c4e5 100644 --- a/sidebarVendorPortal.js +++ b/sidebarVendorPortal.js @@ -2,110 +2,111 @@ module.exports = { vendorPortalSidebar: [ { - type: "category", - label: "Vendor Portal Teams and Accounts", - items: [ - "vendor/vendor-portal-creating-account", - "vendor/team-management", - "vendor/team-management-github-username", - { - type: "category", - label: "Configure Role-based Access Control", - items: [ - "vendor/team-management-rbac-configuring", - "vendor/team-management-rbac-resource-names", - ], - }, - { - type: "category", - label: "Configure Authentication", - items: [ - "vendor/team-management-two-factor-auth", - "vendor/team-management-google-auth", - "vendor/team-management-saml-auth", - "vendor/team-management-scim-provisioning", - ], - }, - "vendor/team-management-slack-config", - "vendor/replicated-api-tokens", - ], - }, - { - type: "category", - label: "Applications", - items: [ - "vendor/vendor-portal-manage-app", - "vendor/vendor-portal-application-settings", - ], - }, - { - type: "category", - label: "Channels and releases", - items: [ - "vendor/releases-about", - "vendor/releases-creating-channels", - "vendor/releases-creating-releases", - "vendor/releases-creating-cli", - "vendor/helm-install-release", - "vendor/releases-sharing-license-install-script", - "reference/linter", - ], - }, - { - type: "category", - label: "Customers and licenses", - items: [ - "vendor/licenses-about", - "vendor/releases-creating-customer", - "vendor/licenses-adding-custom-fields", - "vendor/licenses-install-types", - "vendor/releases-share-download-portal", - "vendor/licenses-about-types", - "vendor/licenses-download", - { - type: "category", - label: "Query license entitlements", - items: [ - "vendor/licenses-using-builtin-fields", - "vendor/licenses-reference-sdk", - "vendor/licenses-reference-helm", - "vendor/licenses-referencing-fields", - "vendor/licenses-reference-kots-runtime", - "vendor/licenses-verify-fields-sdk-api", - ], - }, - ], - }, - { - type: "category", - label: "Custom domains", - items: ["vendor/custom-domains", "vendor/custom-domains-using"], - }, - { - type: "category", - label: "Insights and telemetry", - items: [ - "vendor/instance-insights-event-data", - "vendor/insights-app-status", - "vendor/custom-metrics", - "vendor/telemetry-air-gap", - "vendor/customer-adoption", - "vendor/customer-reporting", - "vendor/instance-insights-details", - { - type: "category", - label: "Event Notifications (Beta)", - items: [ - "vendor/event-notifications", - "vendor/event-notifications-create", - "vendor/event-notifications-manage", - "vendor/event-notifications-webhooks", - ], - }, - "vendor/instance-notifications-config", - "vendor/instance-data-export", - ], - }, - "vendor/support-submit-request", +           type: "category", +           label: "Vendor Portal Teams and Accounts", +           items: [ +             "vendor/vendor-portal-creating-account", +             "vendor/team-management", +             "vendor/team-management-github-username", +             { +               type: "category", +               label: "Configure Role-based Access Control", +               items: [ +                 "vendor/team-management-rbac-configuring", +                 "vendor/team-management-rbac-resource-names", +               ], +             }, +             { +               type: "category", +               label: "Configure Authentication", +               items: [ +                 "vendor/team-management-two-factor-auth", +                 "vendor/team-management-google-auth", +                 "vendor/team-management-saml-auth", +                 "vendor/team-management-scim-provisioning", +               ], +             }, +             "vendor/team-management-slack-config", +             "vendor/replicated-api-tokens", +           ], +         }, +         { +           type: "category", +           label: "Applications", +           items: [ +             "vendor/vendor-portal-manage-app", +             "vendor/vendor-portal-application-settings", +           ], +         }, +         { +           type: "category", +           label: "Channels and releases", +           items: [ +             "vendor/releases-about", +             "vendor/releases-creating-channels", +             "vendor/releases-creating-releases", +             "vendor/releases-creating-cli", +             "vendor/helm-install-release", +             "vendor/releases-sharing-license-install-script", +             "reference/linter", +           ], +         }, +         { +           type: "category", +           label: "Customers and licenses", +           items: [ +             "vendor/licenses-about", +             "vendor/releases-creating-customer", +             "vendor/licenses-adding-custom-fields", +             "vendor/licenses-install-types", +             "vendor/releases-share-download-portal", +             "vendor/licenses-about-types", +             "vendor/licenses-download", +             { +               type: "category", +               label: "Query license entitlements", +               items: [ +                 "vendor/licenses-using-builtin-fields", +                 "vendor/licenses-reference-sdk", +                 "vendor/licenses-reference-helm", +                 "vendor/licenses-referencing-fields", +                 "vendor/licenses-reference-kots-runtime", +                 "vendor/licenses-verify-fields-sdk-api", +               ], +             }, +           ], +         }, +         { +           type: "category", +           label: "Custom domains", +           items: ["vendor/custom-domains", "vendor/custom-domains-using"], +         }, +         { +           type: "category", +           label: "Insights and telemetry", +           items: [ +             "vendor/instance-insights-event-data", +             "vendor/insights-app-status", +             "vendor/custom-metrics", +             "vendor/telemetry-air-gap", +             "vendor/customer-adoption", +             "vendor/customer-reporting", +             "vendor/instance-insights-details", +             { +               type: "category", +               label: "Event Notifications (Beta)", +               items: [ +                 "vendor/event-notifications", +                 "vendor/event-notifications-create", +                 "reference/notifications-events-filters", +                 "vendor/event-notifications-webhooks", +                 "vendor/event-notifications-manage", +               ], +             }, +             "vendor/instance-notifications-config", +             "vendor/instance-data-export", +           ], +         }, +         "vendor/support-submit-request", ], }; From bc5a511cc42cd37e53b70629fd54afa6434eee79 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Wed, 25 Mar 2026 15:14:15 -0600 Subject: [PATCH 07/31] remove separate product sidebars and rename ec instance --- docusaurus.config.js | 10 +- .../v3-placeholder.md | 0 .../embedded-cluster-admin-console.mdx | 0 .../embedded-cluster-completion.mdx | 0 .../embedded-cluster-enable-ha.mdx | 0 .../embedded-cluster-install.mdx | 0 .../embedded-cluster-join-print-command.mdx | 0 .../version-2.0.0/embedded-cluster-join.mdx | 0 .../version-2.0.0/embedded-cluster-reset.mdx | 0 .../embedded-cluster-restore.mdx | 0 .../version-2.0.0/embedded-cluster-shell.mdx | 0 .../embedded-cluster-support-bundle.mdx | 0 .../version-2.0.0/embedded-cluster-update.mdx | 0 .../embedded-cluster-version.mdx | 0 .../version-2.0.0/embedded-config.mdx | 0 .../embedded-disaster-recovery.mdx | 0 .../version-2.0.0/embedded-manage-nodes.mdx | 0 .../version-2.0.0/embedded-overview.mdx | 0 .../version-2.0.0/embedded-tls-certs.mdx | 0 .../embedded-troubleshooting.mdx | 0 .../version-2.0.0/embedded-using.mdx | 0 .../installing-embedded-air-gap.mdx | 0 .../installing-embedded-automation.mdx | 0 .../installing-embedded-requirements.mdx | 0 .../version-2.0.0/installing-embedded.mdx | 0 .../version-2.0.0/updating-embedded.mdx | 0 .../version-2.0.0-sidebars.json | 2 +- ...ons.json => embedded-cluster_versions.json | 0 sidebarCompatibilityMatrix.js | 22 - sidebarEmbeddedCluster.js | 5 + sidebarEnterprisePortal.js | 12 - sidebarHelm.js | 11 - sidebarInstaller.js | 6 - sidebarKots.js | 170 ------ sidebarKurl.js | 40 -- sidebarProxyRegistry.js | 20 - sidebarReplicatedSdk.js | 11 - sidebarSecurityCenter.js | 6 - sidebarTroubleshoot.js | 47 -- sidebarVendorPortal.js | 112 ---- sidebars.js | 508 +++++++++++++++--- .../InstallerVersionSelector/index.js | 2 +- src/css/sidebar.css | 10 - src/theme/DocSidebar/Desktop/Content/index.js | 45 +- .../Desktop/Content/styles.module.css | 18 +- src/theme/DocSidebar/Mobile/index.js | 10 +- src/utils/sidebarProductFromPath.js | 92 +--- 47 files changed, 497 insertions(+), 662 deletions(-) rename {installer => embedded-cluster}/v3-placeholder.md (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-cluster-admin-console.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-cluster-completion.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-cluster-enable-ha.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-cluster-install.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-cluster-join-print-command.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-cluster-join.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-cluster-reset.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-cluster-restore.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-cluster-shell.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-cluster-support-bundle.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-cluster-update.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-cluster-version.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-config.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-disaster-recovery.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-manage-nodes.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-overview.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-tls-certs.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-troubleshooting.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/embedded-using.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/installing-embedded-air-gap.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/installing-embedded-automation.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/installing-embedded-requirements.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/installing-embedded.mdx (100%) rename {installer_versioned_docs => embedded-cluster_versioned_docs}/version-2.0.0/updating-embedded.mdx (100%) rename {installer_versioned_sidebars => embedded-cluster_versioned_sidebars}/version-2.0.0-sidebars.json (97%) rename installer_versions.json => embedded-cluster_versions.json (100%) delete mode 100644 sidebarCompatibilityMatrix.js create mode 100644 sidebarEmbeddedCluster.js delete mode 100644 sidebarEnterprisePortal.js delete mode 100644 sidebarHelm.js delete mode 100644 sidebarInstaller.js delete mode 100644 sidebarKots.js delete mode 100644 sidebarKurl.js delete mode 100644 sidebarProxyRegistry.js delete mode 100644 sidebarReplicatedSdk.js delete mode 100644 sidebarSecurityCenter.js delete mode 100644 sidebarTroubleshoot.js delete mode 100644 sidebarVendorPortal.js diff --git a/docusaurus.config.js b/docusaurus.config.js index 3bf760fddc..66ef839156 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -54,10 +54,10 @@ const config = { [ '@docusaurus/plugin-content-docs', { - id: 'installer', - path: 'installer', - routeBasePath: 'installer', - sidebarPath: './sidebarInstaller.js', + id: 'embedded-cluster', + path: 'embedded-cluster', + routeBasePath: 'embedded-cluster', + sidebarPath: './sidebarEmbeddedCluster.js', breadcrumbs: true, editUrl: 'https://github.com/replicatedhq/replicated-docs/edit/main/', // Versioning configuration @@ -166,7 +166,7 @@ const config = { { type: 'doc', docId: 'v3-placeholder', - docsPluginId: 'installer', + docsPluginId: 'embedded-cluster', label: 'Embedded Cluster', }, { diff --git a/installer/v3-placeholder.md b/embedded-cluster/v3-placeholder.md similarity index 100% rename from installer/v3-placeholder.md rename to embedded-cluster/v3-placeholder.md diff --git a/installer_versioned_docs/version-2.0.0/embedded-cluster-admin-console.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-admin-console.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-cluster-admin-console.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-admin-console.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-cluster-completion.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-completion.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-cluster-completion.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-completion.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-cluster-enable-ha.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-enable-ha.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-cluster-enable-ha.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-enable-ha.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-cluster-install.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-install.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-cluster-install.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-install.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-cluster-join-print-command.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-join-print-command.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-cluster-join-print-command.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-join-print-command.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-cluster-join.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-join.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-cluster-join.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-join.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-cluster-reset.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-reset.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-cluster-reset.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-reset.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-cluster-restore.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-restore.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-cluster-restore.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-restore.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-cluster-shell.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-shell.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-cluster-shell.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-shell.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-cluster-support-bundle.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-support-bundle.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-cluster-support-bundle.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-support-bundle.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-cluster-update.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-update.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-cluster-update.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-update.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-cluster-version.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-version.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-cluster-version.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-version.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-config.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-config.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-config.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-config.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-overview.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-overview.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-tls-certs.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-tls-certs.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-tls-certs.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-tls-certs.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx diff --git a/installer_versioned_docs/version-2.0.0/embedded-using.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/embedded-using.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx diff --git a/installer_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx diff --git a/installer_versioned_docs/version-2.0.0/installing-embedded-automation.mdx b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-automation.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/installing-embedded-automation.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-automation.mdx diff --git a/installer_versioned_docs/version-2.0.0/installing-embedded-requirements.mdx b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-requirements.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/installing-embedded-requirements.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-requirements.mdx diff --git a/installer_versioned_docs/version-2.0.0/installing-embedded.mdx b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/installing-embedded.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/installing-embedded.mdx diff --git a/installer_versioned_docs/version-2.0.0/updating-embedded.mdx b/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx similarity index 100% rename from installer_versioned_docs/version-2.0.0/updating-embedded.mdx rename to embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx diff --git a/installer_versioned_sidebars/version-2.0.0-sidebars.json b/embedded-cluster_versioned_sidebars/version-2.0.0-sidebars.json similarity index 97% rename from installer_versioned_sidebars/version-2.0.0-sidebars.json rename to embedded-cluster_versioned_sidebars/version-2.0.0-sidebars.json index 02c2eea51c..79bcb0084a 100644 --- a/installer_versioned_sidebars/version-2.0.0-sidebars.json +++ b/embedded-cluster_versioned_sidebars/version-2.0.0-sidebars.json @@ -1,5 +1,5 @@ { - "installerSidebar": [ + "embeddedClusterSidebar": [ "embedded-overview", "embedded-using", "embedded-config", diff --git a/installer_versions.json b/embedded-cluster_versions.json similarity index 100% rename from installer_versions.json rename to embedded-cluster_versions.json diff --git a/sidebarCompatibilityMatrix.js b/sidebarCompatibilityMatrix.js deleted file mode 100644 index 2dd355bf43..0000000000 --- a/sidebarCompatibilityMatrix.js +++ /dev/null @@ -1,22 +0,0 @@ -// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG - -module.exports = { - compatibilityMatrixSidebar: [ - "vendor/testing-about", - "vendor/testing-supported-clusters", - "vendor/testing-how-to", - "vendor/testing-vm-create", - "vendor/testing-ingress", - "vendor/testing-network-policy", - "vendor/testing-cluster-addons", - "vendor/testing-ci-cd", - { - type: "category", - label: "Manage cost and usage", - items: [ - "vendor/testing-pricing", - "vendor/compatibility-matrix-usage", - ], - }, - ], -}; \ No newline at end of file diff --git a/sidebarEmbeddedCluster.js b/sidebarEmbeddedCluster.js new file mode 100644 index 0000000000..d00bb5a1b9 --- /dev/null +++ b/sidebarEmbeddedCluster.js @@ -0,0 +1,5 @@ +module.exports = { + embeddedClusterSidebar: [ + "v3-placeholder", + ], +}; diff --git a/sidebarEnterprisePortal.js b/sidebarEnterprisePortal.js deleted file mode 100644 index 9430f1e1b4..0000000000 --- a/sidebarEnterprisePortal.js +++ /dev/null @@ -1,12 +0,0 @@ -// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG - -module.exports = { - enterprisePortalSidebar: [ - "vendor/enterprise-portal-about", - "vendor/enterprise-portal-configure", - "vendor/enterprise-portal-invite", - "vendor/enterprise-portal-self-serve-signup", - "vendor/enterprise-portal-access", - "vendor/enterprise-portal-use", - ], -}; \ No newline at end of file diff --git a/sidebarHelm.js b/sidebarHelm.js deleted file mode 100644 index effd545ec3..0000000000 --- a/sidebarHelm.js +++ /dev/null @@ -1,11 +0,0 @@ -// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG -module.exports = { - helmSidebar: [ - "vendor/helm-install-overview", - "vendor/helm-install-values-schema", - "vendor/install-with-helm", - "vendor/helm-install-airgap", - "vendor/using-third-party-registry-proxy", - "vendor/helm-install-troubleshooting", - ], - }; \ No newline at end of file diff --git a/sidebarInstaller.js b/sidebarInstaller.js deleted file mode 100644 index 108acff285..0000000000 --- a/sidebarInstaller.js +++ /dev/null @@ -1,6 +0,0 @@ -// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG -module.exports = { - installerSidebar: [ - "v3-placeholder", - ], -}; diff --git a/sidebarKots.js b/sidebarKots.js deleted file mode 100644 index a8a4483bc0..0000000000 --- a/sidebarKots.js +++ /dev/null @@ -1,170 +0,0 @@ -// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG -module.exports = { - kotsSidebar: [ - "intro-kots", - { - type: "category", - label: "Configure KOTS", - items: [ - { - type: "category", - label: "Configure the HelmChart Custom Resource", - items: [ - "vendor/helm-native-about", - "vendor/helm-native-v2-using", - "vendor/helm-packaging-airgap-bundles", - "vendor/helm-optional-value-keys", - "vendor/helm-v2-migrate", - ], - }, - { - type: "category", - label: "Customize the Admin Console and Download Portal", - items: [ - "vendor/admin-console-customize-app-icon", - "vendor/admin-console-adding-buttons-links", - "vendor/admin-console-port-forward", - "vendor/admin-console-prometheus-monitoring", - ], - }, - { - type: "category", - label: "Configure the Admin Console Config Screen", - items: [ - "vendor/config-screen-about", - "vendor/admin-console-customize-config-screen", - "vendor/config-screen-map-inputs", - "vendor/config-screen-conditional", - ], - }, - { - type: "category", - label: "Manage Resources and Objects", - items: [ - "vendor/admin-console-display-app-status", - { - type: "category", - label: "Conditionally Deploy Resources", - items: [ - "vendor/packaging-include-resources", - "vendor/tutorial-adding-db-config", - ], - }, - "vendor/resources-annotations-templating", - "vendor/orchestrating-resource-deployment", - "vendor/database-config-adding-options", - "vendor/packaging-cleaning-up-jobs", - "vendor/packaging-ingress", - ], - }, - { - type: "category", - label: "Manage KOTS", - items: [ - "vendor/packaging-kots-versions", - "vendor/packaging-rbac", - "vendor/packaging-air-gap-excluding-minio", - ], - }, - { - type: "category", - label: "Distribute Kubernetes Operators with KOTS", - items: [ - "vendor/operator-packaging-about", - "vendor/operator-defining-additional-images", - "vendor/operator-referencing-images", - "vendor/operator-defining-additional-namespaces", - ], - }, - ], - }, - { - type: "category", - label: "Install in Existing Clusters with KOTS", - items: [ - "enterprise/installing-overview", - "enterprise/installing-general-requirements", - "enterprise/installing-existing-cluster", - "enterprise/installing-existing-cluster-airgapped", - "enterprise/installing-existing-cluster-automation", - "enterprise/installing-stateful-component-requirements", - ], - }, - { - type: "category", - label: "Perform Updates in Existing Cluster KOTS Installations", - items: [ - "enterprise/updating-app-manager", - "enterprise/updating-apps", - "enterprise/updating-patching-with-kustomize", - ], - }, - { - type: "category", - label: "Configure Local Image Registries", - items: [ - "enterprise/image-registry-settings", - "enterprise/image-registry-rate-limits", - ], - }, - "enterprise/updating-licenses", - { - type: "category", - label: "Perform Backup and Restore with Snapshots", - items: [ - "vendor/snapshots-overview", - { - type: "category", - label: "Enable and Configure Snapshots", - items: [ - "vendor/snapshots-configuring-backups", - "reference/custom-resource-backup", - "vendor/snapshots-hooks", - ], - }, - { - type: "category", - label: "Configure Backup Storage for Snaphots", - items: [ - "enterprise/snapshots-velero-cli-installing", - "enterprise/snapshots-configuring-hostpath", - "enterprise/snapshots-configuring-nfs", - "enterprise/snapshots-storage-destinations", - "enterprise/snapshots-velero-installing-config", - ], - }, - "enterprise/snapshots-creating", - "enterprise/snapshots-restoring-full", - "enterprise/snapshots-updating-with-admin-console", - "enterprise/snapshots-troubleshooting-backup-restore", - ], - }, - { - type: "category", - label: "Manage Admin Console User Access", - items: [ - "enterprise/auth-changing-passwords", - "enterprise/auth-identity-provider", - "enterprise/auth-configuring-rbac", - ], - }, - { - type: "category", - label: "Monitor Applications with Prometheus", - items: [ - "enterprise/monitoring-applications", - "enterprise/monitoring-access-dashboards", - ], - }, - "enterprise/status-viewing-details", - "enterprise/delete-admin-console", - { - type: "category", - label: "Use a GitOps Workflow", - items: [ - "enterprise/gitops-workflow", - "enterprise/gitops-managing-secrets", - ], - }, - ], - }; \ No newline at end of file diff --git a/sidebarKurl.js b/sidebarKurl.js deleted file mode 100644 index bcb6478932..0000000000 --- a/sidebarKurl.js +++ /dev/null @@ -1,40 +0,0 @@ -// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG -module.exports = { - kurlSidebar: [ - "vendor/kurl-about", - { - type: "category", - label: "Configure kURL Installers", - items: [ - "vendor/packaging-embedded-kubernetes", - "vendor/packaging-installer-storage", - "vendor/installer-history", - "vendor/kurl-nodeport-services", - ], - }, - { - type: "category", - label: "Install with kURL", - items: [ - "enterprise/installing-kurl-requirements", - "enterprise/installing-kurl", - "enterprise/installing-kurl-airgap", - "enterprise/installing-kurl-automation", - ], - }, - "enterprise/cluster-management-add-nodes", - { - type: "category", - label: "Perform Updates with kURL", - items: [ - "enterprise/updating-kurl-about", - "enterprise/updating-kurl", - ], - }, - "vendor/packaging-using-tls-certs", - "enterprise/updating-tls-cert", - "enterprise/image-registry-kurl", - "enterprise/monitoring-external-prometheus", - "vendor/kurl-reset", - ], - }; \ No newline at end of file diff --git a/sidebarProxyRegistry.js b/sidebarProxyRegistry.js deleted file mode 100644 index 2fc0cd7ee0..0000000000 --- a/sidebarProxyRegistry.js +++ /dev/null @@ -1,20 +0,0 @@ -// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG -module.exports = { - proxyRegistrySidebar: [ - "vendor/private-images-about", - "vendor/packaging-private-images", - "vendor/helm-image-registry", - "vendor/private-images-kots", - "vendor/private-images-tags-digests", - "vendor/packaging-public-images", - { - type: "category", - label: "Replicated Private Registry", - items: [ - "vendor/private-images-replicated", - "vendor/packaging-private-registry-security", - ], - }, - "vendor/tutorial-ecr-private-images", - ], - }; \ No newline at end of file diff --git a/sidebarReplicatedSdk.js b/sidebarReplicatedSdk.js deleted file mode 100644 index ee9af0164e..0000000000 --- a/sidebarReplicatedSdk.js +++ /dev/null @@ -1,11 +0,0 @@ -// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG -module.exports = { - replicatedSdkSidebar: [ - "vendor/replicated-sdk-overview", - "vendor/replicated-sdk-installing", - "vendor/replicated-sdk-airgap", - "vendor/replicated-sdk-development", - "vendor/replicated-sdk-customizing", - "reference/replicated-sdk-apis", - ], - }; \ No newline at end of file diff --git a/sidebarSecurityCenter.js b/sidebarSecurityCenter.js deleted file mode 100644 index ecdc75a3ec..0000000000 --- a/sidebarSecurityCenter.js +++ /dev/null @@ -1,6 +0,0 @@ -// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG -module.exports = { - securityCenterSidebar: [ - "vendor/security-center-about", - ], - }; \ No newline at end of file diff --git a/sidebarTroubleshoot.js b/sidebarTroubleshoot.js deleted file mode 100644 index 748775b227..0000000000 --- a/sidebarTroubleshoot.js +++ /dev/null @@ -1,47 +0,0 @@ -// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG -module.exports = { - troubleshootSidebar: [ - "vendor/preflight-support-bundle-about", - { - type: "category", - label: "Preflight checks", - items: [ - "vendor/preflight-defining", - "vendor/preflight-examples", - "vendor/preflight-running", - "vendor/preflight-host-preflights", - ], - }, - { - type: "category", - label: "Support bundles", - items: [ - "vendor/support-bundle-customizing", - "vendor/support-bundle-examples", - "vendor/support-online-support-bundle-specs", - "vendor/support-modular-support-bundle-specs", - { - type: "category", - label: "Generate support bundles", - items: [ - "vendor/support-bundle-generating", - "vendor/support-bundle-embedded", - "enterprise/troubleshooting-an-app", - "vendor/support-host-support-bundles", - ], - }, - "vendor/support-inspecting-support-bundles", - "vendor/support-enabling-direct-bundle-uploads", - ], - }, - "vendor/preflight-sb-helm-templates-about", - { - type: "category", - label: "Troubleshoot custom resources", - items: [ - "reference/custom-resource-preflight", - "reference/custom-resource-redactor", - ], - }, - ], - }; \ No newline at end of file diff --git a/sidebarVendorPortal.js b/sidebarVendorPortal.js deleted file mode 100644 index 1943a1c4e5..0000000000 --- a/sidebarVendorPortal.js +++ /dev/null @@ -1,112 +0,0 @@ -// sidebar heading is set in src/utils/sidebarProductFromPath.js in SIDEBAR_CONFIG -module.exports = { - vendorPortalSidebar: [ - { -           type: "category", -           label: "Vendor Portal Teams and Accounts", -           items: [ -             "vendor/vendor-portal-creating-account", -             "vendor/team-management", -             "vendor/team-management-github-username", -             { -               type: "category", -               label: "Configure Role-based Access Control", -               items: [ -                 "vendor/team-management-rbac-configuring", -                 "vendor/team-management-rbac-resource-names", -               ], -             }, -             { -               type: "category", -               label: "Configure Authentication", -               items: [ -                 "vendor/team-management-two-factor-auth", -                 "vendor/team-management-google-auth", -                 "vendor/team-management-saml-auth", -                 "vendor/team-management-scim-provisioning", -               ], -             }, -             "vendor/team-management-slack-config", -             "vendor/replicated-api-tokens", -           ], -         }, -         { -           type: "category", -           label: "Applications", -           items: [ -             "vendor/vendor-portal-manage-app", -             "vendor/vendor-portal-application-settings", -           ], -         }, -         { -           type: "category", -           label: "Channels and releases", -           items: [ -             "vendor/releases-about", -             "vendor/releases-creating-channels", -             "vendor/releases-creating-releases", -             "vendor/releases-creating-cli", -             "vendor/helm-install-release", -             "vendor/releases-sharing-license-install-script", -             "reference/linter", -           ], -         }, -         { -           type: "category", -           label: "Customers and licenses", -           items: [ -             "vendor/licenses-about", -             "vendor/releases-creating-customer", -             "vendor/licenses-adding-custom-fields", -             "vendor/licenses-install-types", -             "vendor/releases-share-download-portal", -             "vendor/licenses-about-types", -             "vendor/licenses-download", -             { -               type: "category", -               label: "Query license entitlements", -               items: [ -                 "vendor/licenses-using-builtin-fields", -                 "vendor/licenses-reference-sdk", -                 "vendor/licenses-reference-helm", -                 "vendor/licenses-referencing-fields", -                 "vendor/licenses-reference-kots-runtime", -                 "vendor/licenses-verify-fields-sdk-api", -               ], -             }, -           ], -         }, -         { -           type: "category", -           label: "Custom domains", -           items: ["vendor/custom-domains", "vendor/custom-domains-using"], -         }, -         { -           type: "category", -           label: "Insights and telemetry", -           items: [ -             "vendor/instance-insights-event-data", -             "vendor/insights-app-status", -             "vendor/custom-metrics", -             "vendor/telemetry-air-gap", -             "vendor/customer-adoption", -             "vendor/customer-reporting", -             "vendor/instance-insights-details", -             { -               type: "category", -               label: "Event Notifications (Beta)", -               items: [ -                 "vendor/event-notifications", -                 "vendor/event-notifications-create", -                 "reference/notifications-events-filters", -                 "vendor/event-notifications-webhooks", -                 "vendor/event-notifications-manage", -               ], -             }, -             "vendor/instance-notifications-config", -             "vendor/instance-data-export", -           ], -         }, -         "vendor/support-submit-request", - ], -}; diff --git a/sidebars.js b/sidebars.js index b4ed86d834..e0f1629c7b 100644 --- a/sidebars.js +++ b/sidebars.js @@ -11,18 +11,6 @@ // @ts-check -// Import modular sidebars -const vendorPlatformSidebar = require('./sidebarVendorPortal'); -const enterprisePortalSidebar = require('./sidebarEnterprisePortal'); -const securityCenterSidebar = require('./sidebarSecurityCenter'); -const compatibilityMatrixSidebar = require('./sidebarCompatibilityMatrix'); -const kotsSidebar = require('./sidebarKots'); -const kurlSidebar = require('./sidebarKurl'); -const helmInstallationsSidebar = require('./sidebarHelm'); -const replicatedSdkSidebar = require('./sidebarReplicatedSdk'); -const preflightSupportSidebar = require('./sidebarTroubleshoot'); -const proxyRegistrySidebar = require('./sidebarProxyRegistry'); - // @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} const sidebars = { // By default, Docusaurus generates a sidebar from the docs folder structure @@ -113,90 +101,470 @@ const sidebars = { // PRODUCT DOCS { type: "html", value: "
Product docs
", defaultStyle: true }, { - type: "ref", - id: "vendor/vendor-portal-creating-account", + type: "category", label: "Vendor Portal", - customProps: { - sidebar: "vendorPortalSidebar" - } + items: [ + { + type: "category", + label: "Vendor Portal Teams and Accounts", + items: [ + "vendor/vendor-portal-creating-account", + "vendor/team-management", + "vendor/team-management-github-username", + { + type: "category", + label: "Configure Role-based Access Control", + items: [ + "vendor/team-management-rbac-configuring", + "vendor/team-management-rbac-resource-names", + ], + }, + { + type: "category", + label: "Configure Authentication", + items: [ + "vendor/team-management-two-factor-auth", + "vendor/team-management-google-auth", + "vendor/team-management-saml-auth", + "vendor/team-management-scim-provisioning", + ], + }, + "vendor/team-management-slack-config", + "vendor/replicated-api-tokens", + ], + }, + { + type: "category", + label: "Applications", + items: [ + "vendor/vendor-portal-manage-app", + "vendor/vendor-portal-application-settings", + ], + }, + { + type: "category", + label: "Channels and releases", + items: [ + "vendor/releases-about", + "vendor/releases-creating-channels", + "vendor/releases-creating-releases", + "vendor/releases-creating-cli", + "vendor/helm-install-release", + "vendor/releases-sharing-license-install-script", + "reference/linter", + ], + }, + { + type: "category", + label: "Customers and licenses", + items: [ + "vendor/licenses-about", + "vendor/releases-creating-customer", + "vendor/licenses-adding-custom-fields", + "vendor/licenses-install-types", + "vendor/releases-share-download-portal", + "vendor/licenses-about-types", + "vendor/licenses-download", + { + type: "category", + label: "Query license entitlements", + items: [ + "vendor/licenses-using-builtin-fields", + "vendor/licenses-reference-sdk", + "vendor/licenses-reference-helm", + "vendor/licenses-referencing-fields", + "vendor/licenses-reference-kots-runtime", + "vendor/licenses-verify-fields-sdk-api", + ], + }, + ], + }, + { + type: "category", + label: "Custom domains", + items: ["vendor/custom-domains", "vendor/custom-domains-using"], + }, + { + type: "category", + label: "Insights and telemetry", + items: [ + "vendor/instance-insights-event-data", + "vendor/insights-app-status", + "vendor/custom-metrics", + "vendor/telemetry-air-gap", + "vendor/customer-adoption", + "vendor/customer-reporting", + "vendor/instance-insights-details", + { + type: "category", + label: "Event Notifications (Beta)", + items: [ + "vendor/event-notifications", + "vendor/event-notifications-create", + "reference/notifications-events-filters", + "vendor/event-notifications-webhooks", + "vendor/event-notifications-manage", + ], + }, + "vendor/instance-notifications-config", + "vendor/instance-data-export", + ], + }, + "vendor/support-submit-request", + ], }, { - type: "ref", - id: "vendor/enterprise-portal-about", + type: "category", label: "Enterprise Portal", - customProps: { - sidebar: "enterprisePortalSidebar" - } + items: [ + "vendor/enterprise-portal-about", + "vendor/enterprise-portal-configure", + "vendor/enterprise-portal-invite", + "vendor/enterprise-portal-self-serve-signup", + "vendor/enterprise-portal-access", + "vendor/enterprise-portal-use", + ], }, { - type: "ref", - id: "vendor/security-center-about", + type: "category", label: "Security Center (Alpha)", - customProps: { - sidebar: "securityCenterSidebar" - } + items: [ + "vendor/security-center-about", + ], }, { - type: "ref", - id: "vendor/testing-about", + type: "category", label: "Compatibility Matrix", - customProps: { - sidebar: "compatibilityMatrixSidebar" - } + items: [ + "vendor/testing-about", + "vendor/testing-supported-clusters", + "vendor/testing-how-to", + "vendor/testing-vm-create", + "vendor/testing-ingress", + "vendor/testing-network-policy", + "vendor/testing-cluster-addons", + "vendor/testing-ci-cd", + { + type: "category", + label: "Manage cost and usage", + items: [ + "vendor/testing-pricing", + "vendor/compatibility-matrix-usage", + ], + }, + ], }, { type: "link", - href: "/installer/v3/v3-placeholder", + href: "/embedded-cluster/v3/v3-placeholder", label: "Embedded Cluster", }, { - type: "ref", - id: "vendor/helm-install-overview", + type: "category", label: "Helm Installations with Replicated", - customProps: { - sidebar: "helmSidebar" - } + items: [ + "vendor/helm-install-overview", + "vendor/helm-install-values-schema", + "vendor/install-with-helm", + "vendor/helm-install-airgap", + "vendor/using-third-party-registry-proxy", + "vendor/helm-install-troubleshooting", + ], }, { - type: "ref", - id: "intro-kots", + type: "category", label: "KOTS", - customProps: { - sidebar: "kotsSidebar" - } + items: [ + "intro-kots", + { + type: "category", + label: "Configure KOTS", + items: [ + { + type: "category", + label: "Configure the HelmChart Custom Resource", + items: [ + "vendor/helm-native-about", + "vendor/helm-native-v2-using", + "vendor/helm-packaging-airgap-bundles", + "vendor/helm-optional-value-keys", + "vendor/helm-v2-migrate", + ], + }, + { + type: "category", + label: "Customize the Admin Console and Download Portal", + items: [ + "vendor/admin-console-customize-app-icon", + "vendor/admin-console-adding-buttons-links", + "vendor/admin-console-port-forward", + "vendor/admin-console-prometheus-monitoring", + ], + }, + { + type: "category", + label: "Configure the Admin Console Config Screen", + items: [ + "vendor/config-screen-about", + "vendor/admin-console-customize-config-screen", + "vendor/config-screen-map-inputs", + "vendor/config-screen-conditional", + ], + }, + { + type: "category", + label: "Manage Resources and Objects", + items: [ + "vendor/admin-console-display-app-status", + { + type: "category", + label: "Conditionally Deploy Resources", + items: [ + "vendor/packaging-include-resources", + "vendor/tutorial-adding-db-config", + ], + }, + "vendor/resources-annotations-templating", + "vendor/orchestrating-resource-deployment", + "vendor/database-config-adding-options", + "vendor/packaging-cleaning-up-jobs", + "vendor/packaging-ingress", + ], + }, + { + type: "category", + label: "Manage KOTS", + items: [ + "vendor/packaging-kots-versions", + "vendor/packaging-rbac", + "vendor/packaging-air-gap-excluding-minio", + ], + }, + { + type: "category", + label: "Distribute Kubernetes Operators with KOTS", + items: [ + "vendor/operator-packaging-about", + "vendor/operator-defining-additional-images", + "vendor/operator-referencing-images", + "vendor/operator-defining-additional-namespaces", + ], + }, + ], + }, + { + type: "category", + label: "Install in Existing Clusters with KOTS", + items: [ + "enterprise/installing-overview", + "enterprise/installing-general-requirements", + "enterprise/installing-existing-cluster", + "enterprise/installing-existing-cluster-airgapped", + "enterprise/installing-existing-cluster-automation", + "enterprise/installing-stateful-component-requirements", + ], + }, + { + type: "category", + label: "Perform Updates in Existing Cluster KOTS Installations", + items: [ + "enterprise/updating-app-manager", + "enterprise/updating-apps", + "enterprise/updating-patching-with-kustomize", + ], + }, + { + type: "category", + label: "Configure Local Image Registries", + items: [ + "enterprise/image-registry-settings", + "enterprise/image-registry-rate-limits", + ], + }, + "enterprise/updating-licenses", + { + type: "category", + label: "Perform Backup and Restore with Snapshots", + items: [ + "vendor/snapshots-overview", + { + type: "category", + label: "Enable and Configure Snapshots", + items: [ + "vendor/snapshots-configuring-backups", + "reference/custom-resource-backup", + "vendor/snapshots-hooks", + ], + }, + { + type: "category", + label: "Configure Backup Storage for Snaphots", + items: [ + "enterprise/snapshots-velero-cli-installing", + "enterprise/snapshots-configuring-hostpath", + "enterprise/snapshots-configuring-nfs", + "enterprise/snapshots-storage-destinations", + "enterprise/snapshots-velero-installing-config", + ], + }, + "enterprise/snapshots-creating", + "enterprise/snapshots-restoring-full", + "enterprise/snapshots-updating-with-admin-console", + "enterprise/snapshots-troubleshooting-backup-restore", + ], + }, + { + type: "category", + label: "Manage Admin Console User Access", + items: [ + "enterprise/auth-changing-passwords", + "enterprise/auth-identity-provider", + "enterprise/auth-configuring-rbac", + ], + }, + { + type: "category", + label: "Monitor Applications with Prometheus", + items: [ + "enterprise/monitoring-applications", + "enterprise/monitoring-access-dashboards", + ], + }, + "enterprise/status-viewing-details", + "enterprise/delete-admin-console", + { + type: "category", + label: "Use a GitOps Workflow", + items: [ + "enterprise/gitops-workflow", + "enterprise/gitops-managing-secrets", + ], + }, + ], }, { - type: "ref", - id: "vendor/kurl-about", + type: "category", label: "kURL", - customProps: { - sidebar: "kurlSidebar" - } + items: [ + "vendor/kurl-about", + { + type: "category", + label: "Configure kURL Installers", + items: [ + "vendor/packaging-embedded-kubernetes", + "vendor/packaging-installer-storage", + "vendor/installer-history", + "vendor/kurl-nodeport-services", + ], + }, + { + type: "category", + label: "Install with kURL", + items: [ + "enterprise/installing-kurl-requirements", + "enterprise/installing-kurl", + "enterprise/installing-kurl-airgap", + "enterprise/installing-kurl-automation", + ], + }, + "enterprise/cluster-management-add-nodes", + { + type: "category", + label: "Perform Updates with kURL", + items: [ + "enterprise/updating-kurl-about", + "enterprise/updating-kurl", + ], + }, + "vendor/packaging-using-tls-certs", + "enterprise/updating-tls-cert", + "enterprise/image-registry-kurl", + "enterprise/monitoring-external-prometheus", + "vendor/kurl-reset", + ], }, { - type: "ref", - id: "vendor/private-images-about", + type: "category", label: "Replicated proxy registry", - customProps: { - sidebar: "proxyRegistrySidebar" - } + items: [ + "vendor/private-images-about", + "vendor/packaging-private-images", + "vendor/helm-image-registry", + "vendor/private-images-kots", + "vendor/private-images-tags-digests", + "vendor/packaging-public-images", + { + type: "category", + label: "Replicated Private Registry", + items: [ + "vendor/private-images-replicated", + "vendor/packaging-private-registry-security", + ], + }, + "vendor/tutorial-ecr-private-images", + ], }, { - type: "ref", - id: "vendor/replicated-sdk-overview", + type: "category", label: "Replicated SDK", - customProps: { - sidebar: "replicatedSdkSidebar" - } + items: [ + "vendor/replicated-sdk-overview", + "vendor/replicated-sdk-installing", + "vendor/replicated-sdk-airgap", + "vendor/replicated-sdk-development", + "vendor/replicated-sdk-customizing", + "reference/replicated-sdk-apis", + ], }, { - type: "ref", - id: "vendor/preflight-support-bundle-about", + type: "category", label: "Preflight Checks and support bundles", - customProps: { - sidebar: "troubleshootSidebar" - } + items: [ + "vendor/preflight-support-bundle-about", + { + type: "category", + label: "Preflight checks", + items: [ + "vendor/preflight-defining", + "vendor/preflight-examples", + "vendor/preflight-running", + "vendor/preflight-host-preflights", + ], + }, + { + type: "category", + label: "Support bundles", + items: [ + "vendor/support-bundle-customizing", + "vendor/support-bundle-examples", + "vendor/support-online-support-bundle-specs", + "vendor/support-modular-support-bundle-specs", + { + type: "category", + label: "Generate support bundles", + items: [ + "vendor/support-bundle-generating", + "vendor/support-bundle-embedded", + "enterprise/troubleshooting-an-app", + "vendor/support-host-support-bundles", + ], + }, + "vendor/support-inspecting-support-bundles", + "vendor/support-enabling-direct-bundle-uploads", + ], + }, + "vendor/preflight-sb-helm-templates-about", + { + type: "category", + label: "Troubleshoot custom resources", + items: [ + "reference/custom-resource-preflight", + "reference/custom-resource-redactor", + ], + }, + ], }, + // Reference { type: "html", value: "
Reference
", defaultStyle: true }, { @@ -530,18 +898,6 @@ const sidebars = { }, ], - // Product-specific sidebars - ...vendorPlatformSidebar, - ...enterprisePortalSidebar, - ...securityCenterSidebar, - ...compatibilityMatrixSidebar, - ...kotsSidebar, - ...kurlSidebar, - ...helmInstallationsSidebar, - ...replicatedSdkSidebar, - ...preflightSupportSidebar, - ...proxyRegistrySidebar, - }; -module.exports = sidebars; \ No newline at end of file +module.exports = sidebars; diff --git a/src/components/InstallerVersionSelector/index.js b/src/components/InstallerVersionSelector/index.js index 7c5fac1fd4..425098b985 100644 --- a/src/components/InstallerVersionSelector/index.js +++ b/src/components/InstallerVersionSelector/index.js @@ -13,7 +13,7 @@ import { import { useHistorySelector } from '@docusaurus/theme-common'; import clsx from 'clsx'; -const DOCS_PLUGIN_ID = 'installer'; +const DOCS_PLUGIN_ID = 'embedded-cluster'; function getVersionMainDoc(version) { return version.docs.find((doc) => doc.id === version.mainDocId); diff --git a/src/css/sidebar.css b/src/css/sidebar.css index d0bb723300..51609266d3 100644 --- a/src/css/sidebar.css +++ b/src/css/sidebar.css @@ -87,14 +87,4 @@ .installer-version-selector.dropdown--show .installer-version-selector__trigger-icon { transform: rotate(180deg); -} - -/* Product name heading (mobile sidebar, padding aligned with menu) */ -.sidebar-product-heading-mobile { - font-size: 0.95rem; - font-weight: 600; - margin: 0 0 0.5rem 0; - padding: 0.75rem 1rem 0 1rem; - color: var(--ifm-font-color-base); - line-height: 1.3; } \ No newline at end of file diff --git a/src/theme/DocSidebar/Desktop/Content/index.js b/src/theme/DocSidebar/Desktop/Content/index.js index 6f0a813a42..f3052baf2a 100644 --- a/src/theme/DocSidebar/Desktop/Content/index.js +++ b/src/theme/DocSidebar/Desktop/Content/index.js @@ -1,8 +1,8 @@ /** - * Custom DocSidebar Desktop Content: product heading, installer version selector, - * and slide+fade transition when switching between main and product sidebars. + * Custom DocSidebar Desktop Content: version selector for embedded cluster docs + * and slide+fade transition when switching between main and embedded cluster sidebars. */ -import React, { useState } from 'react'; +import React, { useState, useRef, useEffect } from 'react'; import clsx from 'clsx'; import { ThemeClassNames } from '@docusaurus/theme-common'; import { @@ -15,6 +15,8 @@ import InstallerVersionSelector from '@site/src/components/InstallerVersionSelec import { getProductForPath } from '@site/src/utils/sidebarProductFromPath'; import styles from './styles.module.css'; +const ANIMATION_MS = 200; + function useShowAnnouncementBar() { const { isActive } = useAnnouncementBar(); const [showAnnouncementBar, setShowAnnouncementBar] = useState(isActive); @@ -29,21 +31,46 @@ function useShowAnnouncementBar() { return isActive && showAnnouncementBar; } +const SIDEBAR_KEY_STORAGE = 'docsSidebarKey'; + +function useSidebarTransition(sidebarKey) { + const [animate, setAnimate] = useState(() => { + if (typeof sessionStorage === 'undefined') return false; + const prev = sessionStorage.getItem(SIDEBAR_KEY_STORAGE); + if (!prev || prev === sidebarKey) return false; + const wasMain = prev === 'main'; + const isMain = sidebarKey === 'main'; + return wasMain || isMain; + }); + + useEffect(() => { + if (typeof sessionStorage !== 'undefined') { + sessionStorage.setItem(SIDEBAR_KEY_STORAGE, sidebarKey); + } + }, [sidebarKey]); + + useEffect(() => { + if (!animate) return; + const id = setTimeout(() => setAnimate(false), ANIMATION_MS); + return () => clearTimeout(id); + }, [animate]); + + return animate; +} + export default function DocSidebarDesktopContent({ path, sidebar, className }) { const showAnnouncementBar = useShowAnnouncementBar(); const product = getProductForPath(path); const sidebarKey = product?.key ?? 'main'; + const shouldAnimate = useSidebarTransition(sidebarKey); return (
- {product && product.key !== 'installer' && ( -

{product.name}

- )} - {product?.key === 'installer' && } + {product?.key === 'embedded-cluster' && }
); -} \ No newline at end of file +} diff --git a/src/theme/DocSidebar/Desktop/Content/styles.module.css b/src/theme/DocSidebar/Desktop/Content/styles.module.css index 875ba9ea43..e05a331618 100644 --- a/src/theme/DocSidebar/Desktop/Content/styles.module.css +++ b/src/theme/DocSidebar/Desktop/Content/styles.module.css @@ -11,12 +11,12 @@ overflow: hidden; } -/* Product sidebars (installer + main-docs product sidebars) slide in from right */ -.sidebarContentTransition[data-sidebar]:not([data-sidebar='main']) { +/* Only animate when crossing between main and embedded cluster sidebar (data-animate set by JS) */ +.sidebarContentTransition[data-animate='true'][data-sidebar]:not([data-sidebar='main']) { animation: sidebarSlideInFromRight 0.2s ease-out forwards; } -.sidebarContentTransition[data-sidebar='main'] { +.sidebarContentTransition[data-animate='true'][data-sidebar='main'] { animation: sidebarSlideInFromLeft 0.2s ease-out forwards; } @@ -42,16 +42,6 @@ } } -/* Product name heading at top of product-specific sidebars */ -.sidebarProductHeading { - font-size: 0.9rem; - font-weight: 600; - margin: 0; - padding: 18px 12px 8px 18px; - color: var(--ifm-font-color-base); - line-height: 1.3; -} - @media (min-width: 997px) { .menu { flex: 1; @@ -69,4 +59,4 @@ .menuWithAnnouncementBar { margin-bottom: var(--docusaurus-announcement-bar-height); } -} \ No newline at end of file +} diff --git a/src/theme/DocSidebar/Mobile/index.js b/src/theme/DocSidebar/Mobile/index.js index ad326b9382..37bf79f258 100644 --- a/src/theme/DocSidebar/Mobile/index.js +++ b/src/theme/DocSidebar/Mobile/index.js @@ -1,6 +1,5 @@ /** - * Custom DocSidebar Mobile: product heading and installer version selector - * when the user is on an installer docs page. + * Custom DocSidebar Mobile: version selector for embedded cluster docs. */ import React from 'react'; import clsx from 'clsx'; @@ -19,10 +18,7 @@ const DocSidebarMobileSecondaryMenu = ({ sidebar, path }) => { return ( <> - {product && product.key !== 'installer' && ( -

{product.name}

- )} - {product?.key === 'installer' && ( + {product?.key === 'embedded-cluster' && (
@@ -55,4 +51,4 @@ function DocSidebarMobile(props) { ); } -export default React.memo(DocSidebarMobile); \ No newline at end of file +export default React.memo(DocSidebarMobile); diff --git a/src/utils/sidebarProductFromPath.js b/src/utils/sidebarProductFromPath.js index 6736c6dd11..8895858e1e 100644 --- a/src/utils/sidebarProductFromPath.js +++ b/src/utils/sidebarProductFromPath.js @@ -1,94 +1,22 @@ /** - * Maps current doc path to a product name for the sidebar heading. - * Built from the same sidebar configs as sidebars.js so product boundaries stay in sync. - * - * Order matters: first sidebar that contains a doc id wins (main sidebar is not listed, - * so main docs get no product heading). + * Maps current doc path to a product identifier for the sidebar. + * Used by Desktop/Mobile DocSidebar to show the version selector + * and drive the slide transition when entering/leaving the embedded cluster docs. */ -function extractDocIds(items, ids = new Set()) { - if (!items || !Array.isArray(items)) return ids; - for (const item of items) { - if (typeof item === 'string') { - ids.add(item); - } else if (item && typeof item === 'object' && item.items) { - extractDocIds(item.items, ids); - } - } - return ids; -} - -// Sidebar module path (from repo root) -> display name -const SIDEBAR_CONFIG = [ - ['vendorPortalSidebar', 'Vendor Portal'], - ['enterprisePortalSidebar', 'Enterprise Portal'], - ['securityCenterSidebar', 'Security Center (Alpha)'], - ['compatibilityMatrixSidebar', 'Compatibility Matrix'], - ['kotsSidebar', 'KOTS'], - ['kurlSidebar', 'kURL'], - ['helmSidebar', 'Helm installations with Replicated'], - ['replicatedSdkSidebar', 'Replicated SDK'], - ['troubleshootSidebar', 'Troubleshoot'], - ['proxyRegistrySidebar', 'Replicated proxy registry'], -]; - -// Lazy-build docId -> product name (avoids require at module load if not needed) -let docIdToProduct = null; - -function buildDocIdMap() { - if (docIdToProduct) return docIdToProduct; - docIdToProduct = {}; - try { - const sidebars = [ - require('../../sidebarVendorPortal'), - require('../../sidebarEnterprisePortal'), - require('../../sidebarSecurityCenter'), - require('../../sidebarCompatibilityMatrix'), - require('../../sidebarKots'), - require('../../sidebarKurl'), - require('../../sidebarHelm'), - require('../../sidebarReplicatedSdk'), - require('../../sidebarTroubleshoot'), - require('../../sidebarProxyRegistry'), - ]; - SIDEBAR_CONFIG.forEach(([key, name], i) => { - const items = sidebars[i]?.[key]; - if (!items) return; - const ids = extractDocIds(items); - ids.forEach((id) => { - if (!docIdToProduct[id]) docIdToProduct[id] = name; - }); - }); - } catch (e) { - console.warn('[sidebarProductFromPath] Could not load sidebars:', e.message); - } - return docIdToProduct; -} +const EC_PREFIX = '/embedded-cluster'; +const EC_NAME = 'Embedded Cluster'; /** - * Path prefix for the installer docs (separate plugin). Takes precedence over main-docs mapping. - */ -const INSTALLER_PREFIX = '/installer'; -const INSTALLER_NAME = 'Embedded Cluster'; - -/** - * @param {string} path - Current doc path (e.g. /vendor/kurl-about or /intro-kots) - * @returns {{ name: string } | null} Product to show in sidebar heading, or null for main/generic docs + * @param {string} path - Current doc path (e.g. /embedded-cluster/v2/embedded-overview) + * @returns {{ key: string, name: string } | null} */ export function getProductForPath(path) { if (!path || typeof path !== 'string') return null; - // Installer (separate docs plugin) has its own path prefix - if (path.startsWith(INSTALLER_PREFIX)) { - return { key: 'installer', name: INSTALLER_NAME }; + if (path.startsWith(EC_PREFIX)) { + return { key: 'embedded-cluster', name: EC_NAME }; } - const docId = path.replace(/^\//, ''); - const map = buildDocIdMap(); - const name = map[docId]; - if (!name) return null; - - // Use a stable key for main-docs product sidebars (for transition/animation) - const key = docId.split('/')[0] + '-' + name.replace(/\s+/g, '-').toLowerCase().slice(0, 12); - return { key, name }; + return null; } From 2902619801da5f53f6ac17c50ecfb51115348b6e Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Wed, 25 Mar 2026 15:25:19 -0600 Subject: [PATCH 08/31] fix script to generate llms txt file --- static/js/generate-llms.js | 58 ++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/static/js/generate-llms.js b/static/js/generate-llms.js index e5eb239f34..8be01d03d5 100644 --- a/static/js/generate-llms.js +++ b/static/js/generate-llms.js @@ -22,6 +22,7 @@ const fs = require('fs'); const path = require('path'); const DOCS_DIR = path.join(__dirname, "../../docs"); +const EC_DOCS_DIR = path.join(__dirname, "../../embedded-cluster_versioned_docs/version-2.0.0"); const STATIC_DIR = path.join(__dirname, "../../static"); const OUTPUT_FILE = path.join(STATIC_DIR, "llms.txt"); const OUTPUT_FULL_FILE = path.join(STATIC_DIR, "llms-full.txt"); @@ -41,14 +42,14 @@ const INCLUDED_FILES = [ 'vendor/testing-about.md', 'vendor/testing-how-to.md', 'vendor/testing-supported-clusters.md', - // Embedded Cluster docs - 'enterprise/embedded-manage-nodes.mdx', - 'enterprise/installing-embedded-air-gap.mdx', - 'enterprise/installing-embedded-automation.mdx', - 'enterprise/installing-embedded-requirements.mdx', - 'enterprise/installing-embedded.mdx', - 'reference/embedded-cluster-install.mdx', - 'vendor/embedded-overview.mdx', + // Embedded Cluster docs (in embedded-cluster plugin, prefixed with ec:) + 'ec:embedded-manage-nodes.mdx', + 'ec:installing-embedded-air-gap.mdx', + 'ec:installing-embedded-automation.mdx', + 'ec:installing-embedded-requirements.mdx', + 'ec:installing-embedded.mdx', + 'ec:embedded-cluster-install.mdx', + 'ec:embedded-overview.mdx', // Helm Install docs 'vendor/helm-install-airgap.mdx', 'vendor/helm-install-overview.mdx', @@ -79,7 +80,7 @@ const INCLUDED_FILES = [ 'reference/template-functions-license-context.md', 'reference/template-functions-static-context.md', 'vendor/helm-native-about.mdx', - 'vendor/helm-native-v2-using.md', + 'vendor/helm-native-v2-using.mdx', 'vendor/helm-packaging-airgap-bundles.mdx', 'vendor/resources-annotations-templating.md', 'vendor/snapshots-overview.mdx', @@ -109,7 +110,7 @@ const INCLUDED_FILES = [ 'reference/replicated-sdk-apis.md', 'vendor/replicated-sdk-installing.mdx', 'vendor/replicated-sdk-overview.mdx', - 'vendor/replicated-sdk-customizing.md', + 'vendor/replicated-sdk-customizing.mdx', // Vendor Portal docs 'vendor/custom-domains-using.md', 'vendor/custom-domains.md', @@ -117,7 +118,7 @@ const INCLUDED_FILES = [ 'vendor/insights-app-status.md', 'vendor/instance-insights-event-data.mdx', 'vendor/licenses-about.mdx', - 'vendor/licenses-adding-custom-fields.md', + 'vendor/licenses-adding-custom-fields.mdx', 'vendor/licenses-install-types.mdx', 'vendor/licenses-reference-sdk.mdx', 'vendor/releases-about.mdx', @@ -205,7 +206,10 @@ function shouldSkipDirectory(filePath, excludedDirs = ['.history', 'templates', return excludedDirs.some(dir => filePath.includes(dir)); } -function getAllMarkdownFiles(dir, fileList = [], excludeReleaseNotes = true) { +function getAllMarkdownFiles(dir, fileList = [], excludeReleaseNotes = true, baseDir = null) { + if (!baseDir) baseDir = dir; + const urlPrefix = (baseDir === EC_DOCS_DIR) ? 'embedded-cluster/v2/' : ''; + fs.readdirSync(dir).forEach(file => { const filePath = path.join(dir, file); @@ -219,7 +223,7 @@ function getAllMarkdownFiles(dir, fileList = [], excludeReleaseNotes = true) { } if (fs.statSync(filePath).isDirectory()) { - getAllMarkdownFiles(filePath, fileList, excludeReleaseNotes); + getAllMarkdownFiles(filePath, fileList, excludeReleaseNotes, baseDir); } else if ((path.extname(file) === '.md' || path.extname(file) === '.mdx') && !file.startsWith('_')) { const content = fs.readFileSync(filePath, 'utf8'); @@ -229,8 +233,8 @@ function getAllMarkdownFiles(dir, fileList = [], excludeReleaseNotes = true) { const titleMatch = processedContent.match(/^#\s+(.+)$/m); const title = titleMatch ? titleMatch[1] : file.replace(/\.(md|mdx)$/, ''); - const relativePath = filePath - .replace(`${DOCS_DIR}/`, '') + const relativePath = urlPrefix + filePath + .replace(`${baseDir}/`, '') .replace(/\.(md|mdx)$/, ''); fileList.push({ @@ -243,15 +247,22 @@ function getAllMarkdownFiles(dir, fileList = [], excludeReleaseNotes = true) { return fileList; } -// New function to get all markdown files including release-notes (only for static folder) +// Get all markdown files including release-notes (only for static folder) function getAllMarkdownFilesForStatic(dir, fileList = []) { - return getAllMarkdownFiles(dir, fileList, false); + return getAllMarkdownFiles(dir, fileList, false, dir); } function getCuratedFiles(dir) { const fileList = []; INCLUDED_FILES.forEach(relativePath => { - const filePath = path.join(dir, relativePath); + // Files prefixed with ec: live in the embedded cluster docs directory + const isEC = relativePath.startsWith('ec:'); + const actualRelPath = isEC ? relativePath.slice(3) : relativePath; + const filePath = isEC ? path.join(EC_DOCS_DIR, actualRelPath) : path.join(dir, actualRelPath); + // For URL paths, embedded cluster docs are under embedded-cluster/v2/ + const urlPath = isEC + ? `embedded-cluster/v2/${actualRelPath.replace(/\.(md|mdx)$/, '')}` + : actualRelPath.replace(/\.(md|mdx)$/, ''); try { const content = fs.readFileSync(filePath, 'utf8'); @@ -260,12 +271,12 @@ function getCuratedFiles(dir) { const processedContent = processContent(content, filePath); const titleMatch = processedContent.match(/^#\s+(.+)$/m); - const title = titleMatch ? titleMatch[1] : path.basename(relativePath).replace(/\.(md|mdx)$/, ''); + const title = titleMatch ? titleMatch[1] : path.basename(actualRelPath).replace(/\.(md|mdx)$/, ''); const description = extractFirstSentence(processedContent); fileList.push({ - path: relativePath.replace(/\.(md|mdx)$/, ''), + path: urlPath, title: title, description: description, content: processedContent @@ -375,10 +386,15 @@ function generateLLMsTxt(files) { // Update the main execution loadPartials(DOCS_DIR); -// Get files for llms-full.txt (excluding release-notes) + +// Get files for llms-full.txt (excluding release-notes) from both docs sources const allFiles = getAllMarkdownFiles(DOCS_DIR); +getAllMarkdownFiles(EC_DOCS_DIR, allFiles); + // Get all files including release-notes for copying to static const allFilesForStatic = getAllMarkdownFilesForStatic(DOCS_DIR); +getAllMarkdownFilesForStatic(EC_DOCS_DIR, allFilesForStatic); + const curatedFiles = getCuratedFiles(DOCS_DIR); // Generate llms-full.txt (excluding release-notes) From 77f3bc60afc52721c63a0652c7ffbd29dd10db82 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Thu, 2 Apr 2026 11:35:29 -0600 Subject: [PATCH 09/31] adding in v3 docs --- .../embedded-cluster/_ec-config-v3.mdx | 6 + docusaurus.config.js | 2 +- embedded-cluster/embedded-config.mdx | 330 ++++++++++++++++++ embedded-cluster/embedded-overview.mdx | 98 ++++++ embedded-cluster/embedded-troubleshooting.mdx | 202 +++++++++++ embedded-cluster/embedded-using.mdx | 117 +++++++ .../installing-embedded-air-gap.mdx | 155 ++++++++ .../installing-embedded-automation.mdx | 92 +++++ .../installing-embedded-requirements.mdx | 90 +++++ embedded-cluster/installing-embedded.mdx | 97 +++++ embedded-cluster/updating-embedded.mdx | 94 +++++ embedded-cluster/v3-placeholder.md | 1 - .../embedded-disaster-recovery.mdx | 2 +- .../version-2.0.0/embedded-manage-nodes.mdx | 8 +- .../version-2.0.0/embedded-overview.mdx | 18 +- .../version-2.0.0/embedded-using.mdx | 16 +- .../installing-embedded-air-gap.mdx | 8 +- .../version-2.0.0/updating-embedded.mdx | 4 - scripts/fix-installer-links.js | 123 +++++++ sidebarEmbeddedCluster.js | 10 +- sidebars.js | 2 +- 21 files changed, 1437 insertions(+), 38 deletions(-) create mode 100644 docs/partials/embedded-cluster/_ec-config-v3.mdx create mode 100644 embedded-cluster/embedded-config.mdx create mode 100644 embedded-cluster/embedded-overview.mdx create mode 100644 embedded-cluster/embedded-troubleshooting.mdx create mode 100644 embedded-cluster/embedded-using.mdx create mode 100644 embedded-cluster/installing-embedded-air-gap.mdx create mode 100644 embedded-cluster/installing-embedded-automation.mdx create mode 100644 embedded-cluster/installing-embedded-requirements.mdx create mode 100644 embedded-cluster/installing-embedded.mdx create mode 100644 embedded-cluster/updating-embedded.mdx delete mode 100644 embedded-cluster/v3-placeholder.md create mode 100644 scripts/fix-installer-links.js diff --git a/docs/partials/embedded-cluster/_ec-config-v3.mdx b/docs/partials/embedded-cluster/_ec-config-v3.mdx new file mode 100644 index 0000000000..34c38132f7 --- /dev/null +++ b/docs/partials/embedded-cluster/_ec-config-v3.mdx @@ -0,0 +1,6 @@ +```yaml +apiVersion: embeddedcluster.replicated.com/v1beta1 +kind: Config +spec: + version: 3.0.0-alpha-27+k8s-1.34 +``` diff --git a/docusaurus.config.js b/docusaurus.config.js index 66ef839156..b762c069b4 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -165,7 +165,7 @@ const config = { }, { type: 'doc', - docId: 'v3-placeholder', + docId: 'embedded-overview', docsPluginId: 'embedded-cluster', label: 'Embedded Cluster', }, diff --git a/embedded-cluster/embedded-config.mdx b/embedded-cluster/embedded-config.mdx new file mode 100644 index 0000000000..90ff89e52e --- /dev/null +++ b/embedded-cluster/embedded-config.mdx @@ -0,0 +1,330 @@ +import DoNotDowngrade from "../docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx" + +# Embedded Cluster Config + +This topic is a reference for the Replicated Embedded Cluster Config custom resource. For more information about Embedded Cluster, see [Use Embedded Cluster](/vendor/embedded-overview). + +## Overview + +To install your application with Embedded Cluster, an Embedded Cluster Config must be included in the release. Embedded Cluster installation artifacts are available only for releases that include an Embedded Cluster Config. + +The Embedded Cluster Config lets you define several aspects of the Kubernetes cluster that will be created. + +### Limitations + +* The Embedded Cluster Config does not support the use of Go template functions, including [Replicated template functions](/reference/template-functions-about). + +* There are additional, property-specific limitations. For more information, see the sections below. + +### Example + +```yaml +apiVersion: embeddedcluster.replicated.com/v1beta1 +kind: Config +spec: + version: 3.0.0-alpha-27+k8s-1.34 + roles: + controller: + name: app + labels: + app: "true" + custom: + - name: gpu + labels: + gpu: "true" + - name: database + labels: + database: "true" + domains: + proxyRegistryDomain: proxy.yourcompany.com + replicatedAppDomain: updates.yourcompany.com + extensions: + helm: + repositories: + - name: ingress-nginx + url: https://kubernetes.github.io/ingress-nginx + charts: + - name: ingress-nginx + chartname: ingress-nginx/ingress-nginx + namespace: ingress-nginx + version: "4.8.3" + values: | + controller: + service: + type: NodePort + nodePorts: + http: "80" + https: "443" + # Known issue: Only use image tags for multi-architecture images. + # Set digest to empty string to ensure the air gap builder uses + # single-architecture images. + image: + digest: "" + digestChroot: "" + admissionWebhooks: + patch: + image: + digest: "" +``` + +## version + +Specify the versions of Embedded Cluster and Kubernetes to install. The version of Kubernetes is appended to the Embedded Cluster version in the format `+k8s-1.34`. For example, Embedded Cluster 3.0.0-alpha-27+k8s-1.34 uses Embedded Cluster 3.0.0-alpha-27 and Kubernetes 1.34. + +Each version of Embedded Cluster includes specific versions of components like KOTS (Admin Console) and OpenEBS. +For more information, see the [Embedded Cluster Release Notes](/release-notes/rn-embedded-cluster). + +Replicated recommends that you update the version frequently to ensure that you are using the latest version of Embedded Cluster. + + + +## roles (Beta) {#roles} + +You can optionally customize node roles in the Embedded Cluster Config using the `roles` key. + +A common use case for customizing node roles is to assign workloads to specific nodes. For example, if your application has graphics processing unit (GPU) workloads, you could create a `custom` role that will add a `gpu=true` label to any node that is assigned the role. This allows you to then schedule GPU workloads on nodes labled `gpu=true`. + +When the `roles` key is configured, users select one or more roles to assign to a node when it is joined to the cluster. For more information, see [Managing Multi-Node Clusters with Embedded Cluster](/enterprise/embedded-manage-nodes). + +If the `roles` key is _not_ configured, all nodes joined to the cluster are assigned the `controller` role. The `controller` role designates nodes that run the Kubernetes control plane. Controller nodes can also run other workloads, such as application or Replicated KOTS workloads. + +#### Example + +```yaml +apiVersion: embeddedcluster.replicated.com/v1beta1 +kind: Config +spec: + roles: + controller: + # Optionally change the name for the default controller role + name: app + labels: + app: "true" # Label applied to "app" nodes + # Custom roles + custom: + - name: db + labels: + db: "true" # Label applied to "db" nodes + - name: gpu + labels: + gpu: "true" # Label applied to "gpu" nodes +``` + +### Limitations + +* Defining node roles with the `roles` key is Beta. + +* The first node added to the cluster is always a controller and cannot be assigned any custom roles. You can add custom labels to the first node by setting the `labels` field in the `roles.controller` key. + +### roles.controller + +In the `roles.controller` key, you can set the following fields to customize the default controller role: +* `name`: Set the name that is assigned to controller nodes. By default, controller nodes are named “controller”. + :::note + If you plan to create any custom roles, Replicated recommends that you change the default name for the controller role to a term that is easy to understand, such as "app". This is because, when you add custom roles, both the name of the controller role and the names of any custom roles are displayed to the user when they join a node. + ::: +* `labels`: Kubernetes labels that Embedded Cluster will apply to any node in the cluster that is assigned the given role. + + +### roles.custom + +In the `roles.custom` key, you can add custom roles. Each custom role includes the following fields: +* `name`: (Required) A name for the custom role. +* `labels`: Kubernetes labels that Embedded Cluster will apply to any node in the cluster that is assigned the given role. + +## domains + +Configure the `domains` key so that Embedded Cluster uses your custom domains for the Replicated proxy registry and Replicated app service. + +When `domains.proxyRegistryDomain` and `domains.replicatedAppDomain` are set, Embedded Cluster uses the custom domains specified when making requests to the given service. Embedded Cluster also passes the values to KOTS to ensure that KOTS uses the same domains for these services. + +The custom domains that you specify in the `domains.proxyRegistryDomain` and `domains.replicatedAppDomain` fields must be added to the Vendor Portal before they can be used by Embedded Cluster. For more information, see [Add a Custom Domain in the Vendor Portal](/vendor/custom-domains-using#add-domain) in _Using Custom Domains_. + +If `domains.proxyRegistryDomain` and `domains.replicatedAppDomain` are not set, Embedded Cluster uses the default Replicated domains. For more information about aliasing Replicated endpoints with custom domains, see [About Custom Domains](/vendor/custom-domains). + +#### Example + +```yaml +apiVersion: embeddedcluster.replicated.com/v1beta1 +kind: Config +spec: + domains: + # Your proxy registry custom domain + proxyRegistryDomain: proxy.yourcompany.com + # Your app service custom domain + replicatedAppDomain: updates.yourcompany.com +``` + +## extensions + +If you need to install Helm charts before your application and as part of the Embedded Cluster itself, you can do this with Helm extensions. One situation where this is useful is if you want to ship an ingress controller, because Embedded Cluster does not yet include one. + +Helm extensions are updated when new versions of your application are deployed from the Admin Console. So, for example, you can change the values for a Helm extension from one release to another, and those changes will be applied to the cluster when the new release is deployed. + +The format for specifying Helm extensions uses the same k0s Helm extensions format from the k0s configuration. For more information about these fields, see the [k0s documentation](https://docs.k0sproject.io/stable/helm-charts/#example). + +#### Example + +```yaml +apiVersion: embeddedcluster.replicated.com/v1beta1 +kind: Config +spec: + extensions: + helm: + repositories: + - name: ingress-nginx + url: https://kubernetes.github.io/ingress-nginx + charts: + - name: ingress-nginx + chartname: ingress-nginx/ingress-nginx + namespace: ingress-nginx + version: "4.8.3" + values: | + controller: + service: + type: NodePort + nodePorts: + http: "80" + https: "443" + # Known issue: Only use image tags for multi-architecture images. + # Set digest to empty string to ensure the air gap builder uses + # single-architecture images. + image: + digest: "" + digestChroot: "" + admissionWebhooks: + patch: + image: + digest: "" +``` + +### Requirements + +* The `version` field is required. Failing to specify a chart version will cause problems for upgrades. + +* If you need to install multiple charts in a particular order, set the `order` field to a value greater than or equal to 10. Numbers below 10 are reserved for use by Embedded Cluster to deploy things like a storage provider and the Admin Console. If an `order` is not provided, Helm extensions are installed with order 10. + +## unsupportedOverrides + +:::important +This feature should be used with caution by advanced users who understand the risks and ramifications of changing the default configuration. +::: + +Unsupported overrides allow you to override Embedded Cluster's default configuration, including the k0s config and the Helm values for extensions like KOTS and OpenEBS. This should be used with caution because changes here are untested and can disrupt or break Embedded Clusters. Any issues that are caused by unsupported overrides are not supported. + +While they should be used with caution, unsupported overrides are useful if you need to make changes that are not otherwise exposed by Embedded Cluster. + +### Override the k0s Config + +By default, Embedded Cluster uses a k0s config that is tested and known to work for Embedded Clusters. In some circumstances, you might want to change the k0s config. + +For more information on the k0s config, see [Configuration options](https://docs.k0sproject.io/stable/configuration/#configuration-file-reference) in the k0s documentation. + +For example, you can do the following to enable WireGuard-based encryption. Note that other configuration might be necessary. See [`spec.network.calico`](https://docs.k0sproject.io/stable/configuration/#specnetworkcalico) in the k0s documentation for more details. +```yaml +apiVersion: embeddedcluster.replicated.com/v1beta1 +kind: Config +spec: + unsupportedOverrides: + k0s: | + config: + spec: + network: + calico: + wireguard: true +``` + +#### Limitations + +* The `spec.api` and `spec.storage` keys in the k0s config cannot be changed after installation. Whereas most keys in the k0s config apply to the whole cluster, these two keys are set for each node. Embedded Cluster cannot update these keys on each individual node during updates, so they cannot be changed after installation. + +* Overrides overwrite the corresponding fields in the k0s configuration. They are not merged into Embedded Cluster’s default configuration. When using overrides to override a list, for example, ensure that you include other elements in the list that Embedded Cluster includes by default. + +### Override the Helm Values for Built-In Extensions + +Embedded Cluster deploys built-in extensions like KOTS and OpenEBS to provide capabilities like storage and application management. These extensions are deployed with Helm, and the Helm values for each can be modified if necessary. + +To modify these values, you can use the `unsupportedOverrides.builtInExtensions` key of the Embedded Cluster Config. Each chart you want to modify is an item in the array. The `name` key identifies the Helm chart that you want to modify, and the `values` key is a string where you specify your modified Helm values. Your modified values are merged into the values used by Embedded Cluster. + +The following are the built-in extensions available for modification: + +- `openebs` +- `admin-console` +- `velero` +- `embedded-cluster-operator` + +#### Example + +```yaml +apiVersion: embeddedcluster.replicated.com/v1beta1 +kind: Config +spec: + unsupportedOverrides: + builtInExtensions: + - name: openebs + values: | + key: value +``` + +### Configure Velero Plugins + +> Introduced in Embedded Cluster v2.13.0 + +If the customer license has the **Allow Disaster Recovery (Alpha)** option enabled, you can add custom Velero plugins in the `extensions.velero.plugins` key to extend Velero's backup and restore capabilities. For example, you can add support for backing up databases like PostgreSQL, MySQL, or other stateful applications that require advanced disaster recovery capabilities. + +Each plugin that you add to the `extensions.velero.plugins` key must have a name and a publicly accessible container image. For more information about the Velero plugin system, including how to create custom plugins, see [Velero plugin system](https://velero.io/docs/v1.17/overview-plugins/) in the Velero documentation. + +#### Requirements + +* The image for the Velero plugin must be available publicly. Images behind authentication are not supported. +* The **Allow Disaster Recovery (Alpha)** option must be enabled in the license for Velero plugins to work. For more information about how to enable the Embedded Cluster disaster recovery feature, see [Disaster Recovery for Embedded Cluster (Alpha)](/vendor/embedded-disaster-recovery). + +#### Example + +```yaml +apiVersion: embeddedcluster.replicated.com/v1beta1 +kind: Config +spec: + extensions: + velero: + # Each plugin requires a name and publicly accessible container image + plugins: + - name: velero-plugin-postgresql + image: myvendor/velero-postgresql:v1.0.0 + imagePullPolicy: Always +``` + +### Configure the Kubelet + +You can configure the Kubelet to customize your worker nodes with Embedded Cluster. One common use case for configuring the Kubelet is that you need more pods on a single node than the default limit of 100. In this case, you could set the `maxPods` Kubelet configuration option to 150. Another common example is reducing startup time by setting `maxParallelImagePulls` to increase the maximum number of image pulls that can be done in parallel. + +You can customize the Kubelet configuration settings by adding a _worker profile_ in the Embedded Cluster Config under `unsupportedOverrides.k0s.config.spec.workerProfiles[]`. When a worker profile is defined, Embedded Cluster uses the profile for every node in the cluster during initial installation and when joining nodes to the cluster. + +The worker profile has the following required fields: +* `name`: The name of the worker profile. Do not use the name `default` for your custom worker profile. `default` is reserved by k0s. +* `values`: The Kubelet configuration settings for the profile. For a complete list of the available Kubelet configuration options that you can set in a worker profile, see [KubeletConfiguration](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/#kubelet-config-k8s-io-v1beta1-KubeletConfiguration) in the Kubernetes documentation. + +For more information about how to define worker profiles, see [spec.workerProfiles](https://docs.k0sproject.io/stable/configuration/#specworkerprofiles) in the k0s documentation. + +#### Limitations + +* The worker profile is set during initial installation. Worker profiles cannot be changed or added on upgrade. +* Embedded Cluster supports only one worker profile that is used for all nodes. If you add more than one worker profile in the `workerProfiles[]` array in the Embedded Cluster Config, only the first profile is used. + +#### Example + +```yaml +apiVersion: embeddedcluster.replicated.com/v1beta1 +kind: Config +spec: + unsupportedOverrides: + k0s: | + config: + spec: + # Define a profile that sets maxPods to 150 + workerProfiles: + # Note: Do not use the name "default" + - name: custom-maxpods + values: + maxPods: 150 +``` diff --git a/embedded-cluster/embedded-overview.mdx b/embedded-cluster/embedded-overview.mdx new file mode 100644 index 0000000000..6bc0465543 --- /dev/null +++ b/embedded-cluster/embedded-overview.mdx @@ -0,0 +1,98 @@ +import EmbeddedCluster from "../docs/partials/embedded-cluster/_definition.mdx" +import HaArchitecture from "../docs/partials/embedded-cluster/_multi-node-ha-arch.mdx" + +# Embedded Cluster overview + +This topic provides an introduction to Replicated Embedded Cluster. + +## Overview + + + +## Comparison to Embedded Cluster v2 + +### Breaking changes + +Embedded Cluster v3 introduces the following breaking changes compared to Embedded Cluster v2: + +* **Removal of KOTS:** Embedded Cluster 3.x removes KOTS from the architecture. That simplifies install and upgrade, but the KOTS CLI no longer works with Embedded Cluster, and there is no KOTS Admin Console in the previous form. The new installer provides the UI instead. Benefits include increased reliability, simpler feature work, and fewer dependencies running in the cluster. + +* **Helm only with HelmChart v1beta2:** Embedded Cluster 3.x supports installing Helm charts only when each chart has a corresponding [HelmChart custom resource](/reference/custom-resource-helmchart-v2) that uses API version `helmchart/v1beta2`. Kustomize, plain Kubernetes manifests, and `HelmChart` `v1beta1` are not supported. + +* **Replicated SDK required for status reporting:** Because KOTS is removed, you must include the [Replicated SDK](/vendor/replicated-sdk-overview) in your application to get reporting from application status informers (for example, for notifications and visibility in the Vendor Portal and Enterprise Portal). + +* **Some template functions not available:** Some Replicated template functions are not implemented in Embedded Cluster v3, either because they are discouraged in this model or because they are not yet ported. Contact Replicated if a missing template function blocks your release. + +* **Troubleshoot Preflight `v1beta3` required:** Preflight checks must use Troubleshoot `v1beta3`. `v1beta2` preflight specs are not supported. For more information, see [v1beta3 overview](https://troubleshoot.sh/docs/preflight/v1beta3-overview) in the Troubleshoot documentation. + +### Non-breaking change + +The default paths change from `/var/lib/embedded-cluster` and `/var/log/embedded-cluster` to `/var/lib/APP_SLUG` and `/var/log/APP_SLUG`, where `APP_SLUG` is your application slug. This better matches your brand and avoids Replicated-specific paths in the default layout. The change applies only to **new** installations. Upgrades from Embedded Cluster 2.x do not migrate or change existing data and log directories. + +## About installing with Embedded Cluster + +Embedded Cluster supports installations in online (internet-connected) environments and air gap environments with no outbound internet access. + +The Embedded Cluster Config is included in the application release in the Replicated Vendor Portal and is used to generate the Embedded Cluster installation assets. Users can download these installation assets from the Replicated app service (`replicated.app`) on the command line, then run the Embedded Cluster installation command to install Kubernetes. Finally, users can install the application using the UI or CLI. During installation, users can optionally add nodes to the cluster and configure the application. + +For more information about how to install with Embedded Cluster, see: +* [Online Installation wtih Embedded Cluster](/enterprise/installing-embedded) +* [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap) + +### Embedded Cluster host preflight checks {#about-host-preflight-checks} + +During installation, Embedded Cluster automatically runs a default set of _host preflight checks_. The default host preflight checks are designed to verify that the installation environment meets the requirements for Embedded Cluster, such as: +* The system has sufficient disk space +* The system has at least 2G of memory and 2 CPU cores +* The system clock is synchronized + +If any of the Embedded Cluster host preflight checks fail, installation is blocked and a message describing the failure is displayed. + +For the full default host preflight spec for Embedded Cluster, see [`host-preflight.yaml`](https://github.com/replicatedhq/embedded-cluster/blob/main/pkg/preflights/host-preflight.yaml) in the `embedded-cluster` repository in GitHub. + +#### Limitations + +Embedded Cluster host preflight checks have the following limitations: + +* The default host preflight checks for Embedded Cluster cannot be modified, and vendors cannot provide their own custom host preflight spec for Embedded Cluster. +* Host preflight checks do not check that any application-specific requirements are met. For more information about defining preflight checks for your application, see [Define Preflight Checks](/vendor/preflight-defining). + +### Multi-node installations + +Embedded Cluster supports installations in mutli-node clusters. Your end customers can add nodes to a cluster during or after installation from the Admin Console. For more information, see [Manage Multi-Node Clusters with Embedded Cluster](/enterprise/embedded-manage-nodes). + +#### High availability + +Multi-node clusters are not highly available by default. Enabling high availability (HA) requires that at least three controller nodes are present in the cluster. Users can enable HA when joining the third node. + +For more information about creating HA multi-node clusters with Embedded Cluster, see [Enable High Availability](/enterprise/embedded-manage-nodes#ha) in _Managing Multi-Node Clusters with Embedded Cluster_. + +#### Node roles + +You can optionally define node roles in the Embedded Cluster Config. For multi-node clusters, roles can be useful for the purpose of assigning specific application workloads to nodes. If nodes roles are defined, users assign one or more roles to a node when it is joined to the cluster. + +For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. + +## About configuring Embedded Cluster + +To support installations with Embedded Cluster, an Embedded Cluster Config must be present in the application release. The Embedded Cluster Config lets you define several characteristics about the cluster that will be created. + +For more information, see [Embedded Cluster Config](embedded-config). + +## Built-in extensions {#built-in-extensions} + +Embedded Cluster includes several built-in extensions. The built-in extensions provide capabilities such as application management and storage. Each built-in extension is installed in its own namespace. + +The built-in extensions installed by Embedded Cluster include: + +* **Embedded Cluster Operator**: The Operator is used for reporting purposes as well as some clean up operations. + +* **OpenEBS:** Embedded Cluster uses OpenEBS to provide local PersistentVolume (PV) storage, including the PV storage for rqlite used by KOTS. For more information, see the [OpenEBS](https://openebs.io/docs/) documentation. + +* **(Air Gap Only) Image registry:** For air gap installations in environments with limited or no outbound internet access, Embedded Cluster installs an image registry where the images required to install and run the application are pushed. For more information about installing in air-gapped environments, see [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap). + +## Limtiations + +* No disaster recovery support + +* diff --git a/embedded-cluster/embedded-troubleshooting.mdx b/embedded-cluster/embedded-troubleshooting.mdx new file mode 100644 index 0000000000..dfbe838405 --- /dev/null +++ b/embedded-cluster/embedded-troubleshooting.mdx @@ -0,0 +1,202 @@ +import SupportBundleIntro from "../docs/partials/support-bundles/_ec-support-bundle-intro.mdx" +import EmbeddedClusterSupportBundle from "../docs/partials/support-bundles/_generate-bundle-ec.mdx" +import ShellCommand from "../docs/partials/embedded-cluster/_shell-command.mdx" +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Troubleshoot Embedded Cluster + +This topic provides information about troubleshooting Replicated Embedded Cluster installations. For more information about Embedded Cluster, including built-in extensions and architecture, see [Embedded Cluster Overview](/vendor/embedded-overview). + +## Troubleshoot with support bundles + +This section includes information about how to collect support bundles for Embedded Cluster installations. For more information about support bundles, see [About Preflight Checks and Support Bundles](/vendor/preflight-support-bundle-about). + +### About the default Embedded Cluster support bundle spec + + + + + +## View logs + +You can view logs for both Embedded Cluster and the k0s systemd service to help troubleshoot Embedded Cluster deployments. + +### View installation logs for Embedded Cluster + +To view installation logs for Embedded Cluster: + +1. SSH onto a controller node. + +1. Navigate to `/var/log/embedded-cluster` and open the `.log` file to view logs. + +### View K0s logs + +You can use the journalctl command line tool to access logs for systemd services, including k0s. For more information about k0s, see the [k0s documentation](https://docs.k0sproject.io/stable/). + +To use journalctl to view k0s logs: + +1. SSH onto a controller node or a worker node. + +1. Use journalctl to view logs for the k0s systemd service that was deployed by Embedded Cluster. + + **Examples:** + + ```bash + journalctl -u k0scontroller + ``` + ```bash + journalctl -u k0sworker + ``` + +## Access the cluster + +When troubleshooting, it can be useful to list the cluster and view logs using the kubectl command line tool. For additional suggestions related to troubleshooting applications, see [Troubleshooting Applications](https://kubernetes.io/docs/tasks/debug/debug-application/) in the Kubernetes documentation. + + + +## Troubleshoot errors + +This section provides troubleshooting advice for common errors. + +### Installation failure when NVIDIA gpu operator is included as Helm extension {#nvidia} + +#### Symptom + +A release that includes that includes the NVIDIA GPU Operator as a Helm extension fails to install. + +#### Cause + +If there are any containerd services on the host, the NVIDIA GPU Operator will generate an invalid containerd config, causing the installation to fail. + +This is the result of a known issue with v24.9.x of the NVIDIA GPU Operator. For more information about the known issue, see [container-toolkit does not modify the containerd config correctly when there are multiple instances of the containerd binary](https://github.com/NVIDIA/nvidia-container-toolkit/issues/982) in the nvidia-container-toolkit repository in GitHub. + +For more information about including the GPU Operator as a Helm extension, see [NVIDIA GPU Operator](/vendor/embedded-using#nvidia-gpu-operator) in _Configure Embedded Cluster_. + +#### Solution + +To troubleshoot: + +1. Remove any existing containerd services that are running on the host (such as those deployed by Docker). + +1. Reset and reboot the node: + + ```bash + sudo ./APP_SLUG reset + ``` + Where `APP_SLUG` is the unique slug for the application. + + For more information, see [Reset a Node](/enterprise/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. + +1. Re-install with Embedded Cluster. + +### Calico networking issues + +#### Symptom + +Symptoms of Calico networking issues can include: + +* The pod is stuck in a CrashLoopBackOff state with failed health checks: + + ``` + Warning Unhealthy 6h51m (x3 over 6h52m) kubelet Liveness probe failed: Get "http:///readyz": dial tcp : connect: no route to host + Warning Unhealthy 6h51m (x19 over 6h52m) kubelet Readiness probe failed: Get "http:///readyz": dial tcp : connect: no route to host + .... + Unhealthy pod/registry-dc699cbcf-pkkbr Readiness probe failed: Get "https:///": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) + Unhealthy pod/registry-dc699cbcf-pkkbr Liveness probe failed: Get "https:///": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) + ... + ``` + +* The pod log contains an I/O timeout: + + ``` + server APIs: config.k8ssandra.io/v1beta1: Get \"https://***HIDDEN***:443/apis/config.k8ssandra.io/v1beta1\": dial tcp ***HIDDEN***:443: i/o timeout"} + ``` + +#### Cause + +Reasons can include: + +* Pod CIDR and service CIDR overlap with the host network CIDR. + +* Incorrect kernel parameters values. + +* VXLAN traffic getting dropped. By default, Calico uses VXLAN as the overlay networking protocol, with Always mode. This mode encapsulates all pod-to-pod traffic in VXLAN packets. If for some reasons, the VXLAN packets get filtered by the network, the pod will not able to communicate with other pods. + +#### Solution + + + + To troubleshoot pod CIDR and service CIDR overlapping with the host network CIDR: + 1. Run the following command to verify the pod and service CIDR: + ``` + cat /etc/k0s/k0s.yaml | grep -i cidr + podCIDR: 10.244.0.0/17 + serviceCIDR: 10.244.128.0/17 + ``` + The default pod CIDR is 10.244.0.0/16 and service CIDR is 10.96.0.0/12. + + 1. View pod network interfaces excluding Calico interfaces, and ensure there are no overlapping CIDRs. + ``` + ip route | grep -v cali + default via 10.152.0.1 dev ens4 proto dhcp src 10.152.0.4 metric 100 + 10.152.0.1 dev ens4 proto dhcp scope link src 10.152.0.4 metric 100 + blackhole 10.244.101.192/26 proto 80 + 169.254.169.254 via 10.152.0.1 dev ens4 proto dhcp src 10.152.0.4 metric 100 + ``` + + 1. Reset and reboot the installation: + + ```bash + sudo ./APP_SLUG reset + ``` + Where `APP_SLUG` is the unique slug for the application. + + For more information, see [Reset a Node](/enterprise/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. + + 1. Reinstall the application with different CIDRs using the `--cidr` flag: + + ```bash + sudo ./APP_SLUG install --license license.yaml --cidr 172.16.136.0/16 + ``` + + For more information, see [Embedded Cluster Install Options](/reference/embedded-cluster-install). + + + Embedded Cluster 1.19.0 and later automatically sets the `net.ipv4.conf.default.arp_filter`, `net.ipv4.conf.default.arp_ignore`, and `net.ipv4.ip_forward` kernel parameters. Additionally, host preflight checks automatically run during installation to verify that the kernel parameters were set correctly. For more information about the Embedded Cluster preflight checks, see [About Host Preflight Checks](/vendor/embedded-overview#about-host-preflight-checks) in _Embedded Cluster Overview_. + + If kernel parameters are not set correctly and these preflight checks fail, you might see a message such as `IP forwarding must be enabled.` or `ARP filtering must be disabled by default for newly created interfaces.`. + + To troubleshoot incorrect kernel parameter values: + + 1. Use sysctl to set the kernel parameters to the correct values: + + ```bash + echo "net.ipv4.conf.default.arp_filter=0" >> /etc/sysctl.d/99-embedded-cluster.conf + echo "net.ipv4.conf.default.arp_ignore=0" >> /etc/sysctl.d/99-embedded-cluster.conf + echo "net.ipv4.ip_forward=1" >> /etc/sysctl.d/99-embedded-cluster.conf + + sysctl --system + ``` + + 1. Reset and reboot the installation: + + ```bash + sudo ./APP_SLUG reset + ``` + Where `APP_SLUG` is the unique slug for the application. + For more information, see [Reset a Node](/enterprise/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. + + 1. Re-install with Embedded Cluster. + + + + As a temporary troubleshooting measure, set the mode to CrossSubnet and see if the issue persists. This mode only encapsulates traffic between pods across different subnets with VXLAN. + + ```bash + kubectl patch ippool default-ipv4-ippool --type=merge -p '{"spec": {"vxlanMode": "CrossSubnet"}}' + ``` + + If this resolves the connectivity issues, there is likely an underlying network configuration problem with VXLAN traffic that should be addressed. + + \ No newline at end of file diff --git a/embedded-cluster/embedded-using.mdx b/embedded-cluster/embedded-using.mdx new file mode 100644 index 0000000000..cfac836ced --- /dev/null +++ b/embedded-cluster/embedded-using.mdx @@ -0,0 +1,117 @@ +import UpdateOverview from "../docs/partials/embedded-cluster/_update-overview.mdx" +import EcConfigV3 from "../docs/partials/embedded-cluster/_ec-config-v3.mdx" +import ShellCommand from "../docs/partials/embedded-cluster/_shell-command.mdx" + +# Configure Embedded Cluster + +This topic provides information about how to configure your application releases to support installations with Replicated Embedded Cluster. For an introduction to Embedded Cluster, see [Embedded Cluster Overview](embedded-overview). + +## Add the Embedded Cluster Config resource + +An [Embedded Cluster Config](embedded-config) must be present in the release to support installation with Embedded Cluster. The Embedded Cluster Config sets the version of Embedded Cluster to install, and lets you define additional characteristics about the cluster. + +To add the Embedded Cluster Config: + +1. Create a new release that includes your application and a unique [HelmChart v2](/reference/custom-resource-helmchart-v2) custom resource for each Helm chart in the release. + + If you have not yet configured the HelmChart custom resource for your application, see [Onboard to the Replicated Platform](/vendor/replicated-onboarding) for more detailed instructions on how to configure releases that support installation with a Replicated installer. + +1. In the release, add an [Embedded Cluster Config](embedded-config) manifest that specifies the Embedded Cluster version to use: + + + +1. If your application requires that certain components are deployed before the application and as part of the Embedded Cluster itself, update the Embedded Cluster Config to add [extensions](embedded-config#extensions). + +1. Save the release and promote it to the channel that you use for testing internally. + +1. Install with Embedded Cluster in a development environment to test: + + 1. Go to the **Manage customer** page for a new or existing Development customer. + + 1. Under **Install types**, enable the **Embedded Cluster (current generation product)** option. Click **Save**. + + 1. At the top right of the customer page, click **Install instructions** and choose **Embedded Cluster**. A dialog appears with instructions on how to download the Embedded Cluster installation assets and install your application. + + ![Customer install instructions drop down button](/images/customer-install-instructions-dropdown.png) + + [View a larger version of this image](/images/customer-install-instructions-dropdown.png) + + 1. On your VM, run the commands in the **Embedded Cluster install instructions** dialog. + + Embedded cluster install instruction dialog + + [View a larger version of this image](/images/embedded-cluster-install-dialog-latest.png) + + 1. Enter an Admin Console password when prompted. + + The Admin Console URL is printed when the installation finishes. Access the Admin Console and follow the instructions in the wizard to install your application. + +1. After successfully installing your application with Embedded Cluster, customize the [Embedded Cluster Config](embedded-config) as desired: + * Add your custom domain for the Replicated proxy registry and Replicated app service. See [domains](embedded-config#domains). + * Add custom Helm extensions. Extensions allow you to provide Helm charts that are deployed before your application. For example, you can add a Helm extension to ship an ingress controller. See [extensions](embedded-config#extensions). + * Define roles to assign workloads to specific nodes in multi-node installations. See [roles](embedded-config#roles). + + Replicated recommends that you work in small iterations and test your changes frequently in your development environment. + +## (Optional) Serve installation assets using the vendor API + +To install with Embedded Cluster, your end customers need to download the Embedded Cluster installer binary and their license. Air gap installations also require an air gap bundle. End customers can download all these installation assets using a curl command by following the installation steps available in the [Replicated Enterprise Portal](/vendor/enterprise-portal-about). + +However, some vendors already have a portal where their customers can log in to access documentation or download artifacts. In cases like this, you can serve the Embedded Cluster installation assets yourself using the Replicated Vendor API, rather than having customers download the assets from the Replicated app service using a curl command during installation. + +To serve Embedded Cluster installation assets with the Vendor API: + +1. If you have not done so already, create an API token for the Vendor API. See [Use the Vendor API v3](/reference/vendor-api-using#api-token-requirement). + +1. Call the [Get an Embedded Cluster release](https://replicated-vendor-api.readme.io/reference/getembeddedclusterrelease) endpoint to download the assets needed to install your application with Embedded Cluster. Your customers must take this binary and their license and copy them to the machine where they will install your application. + + Note the following: + + * (Recommended) Provide the `customerId` query parameter so that the customer’s license is included in the downloaded tarball. This mirrors what is returned when a customer downloads the binary directly using the Replicated app service and is the most useful option. Excluding the `customerId` is useful if you plan to distribute the license separately. + + * If you do not provide any query parameters, this endpoint downloads the Embedded Cluster binary for the latest release on the specified channel. You can provide the `channelSequence` query parameter to download the binary for a particular release. + +## Distribute the NVIDIA gpu operator with Embedded Cluster {#nvidia-gpu-operator} + +:::note +Distributing the NVIDIA GPU Operator with Embedded Cluster is not an officially supported feature from Replicated. However, it is a common use case. +::: + +The NVIDIA GPU Operator uses the operator framework within Kubernetes to automate the management of all NVIDIA software components needed to provision GPUs. For more information about this operator, see the [NVIDIA GPU Operator](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/overview.html) documentation. + +### Include the NVIDIA gpu operator and configure containerd options + +You can include the NVIDIA GPU Operator in your release as an additional Helm chart, or using Embedded Cluster Helm extensions. For information about adding Helm extensions, see [extensions](embedded-config#extensions) in _Embedded Cluster Config_. + +Using the NVIDIA GPU Operator with Embedded Cluster requires configuring the containerd options in the operator as follows: + +```yaml +# Embedded Cluster Config + + extensions: + helm: + repositories: + - name: nvidia + url: https://nvidia.github.io/gpu-operator + charts: + - name: gpu-operator + chartname: nvidia/gpu-operator + namespace: gpu-operator + version: "v24.9.1" + values: | + # configure the containerd options + toolkit: + env: + - name: CONTAINERD_CONFIG + value: /etc/k0s/containerd.d/nvidia.toml + - name: CONTAINERD_SOCKET + value: /run/k0s/containerd.sock +``` + +### containerd known issue + +When the containerd options are configured as shown above, the NVIDIA GPU Operator automatically creates the required configurations in the `/etc/k0s/containerd.d/nvidia.toml` file. It is not necessary to create this file manually, or modify any other configuration on the hosts. + +If you include the NVIDIA GPU Operator as a Helm extension, remove any existing containerd services that are running on the host (such as those deployed by Docker) before attempting to install the release with Embedded Cluster. If there are any containerd services on the host, the NVIDIA GPU Operator will generate an invalid containerd config, causing the installation to fail. For more information, see [Installation failure when NVIDIA GPU Operator is included as Helm extension](#nvidia-gpu-operator) in _Troubleshooting Embedded Cluster_. + +This is the result of a known issue with v24.9.x of the NVIDIA GPU Operator. For more information about the known issue, see [container-toolkit does not modify the containerd config correctly when there are multiple instances of the containerd binary](https://github.com/NVIDIA/nvidia-container-toolkit/issues/982) in the nvidia-container-toolkit repository in GitHub. diff --git a/embedded-cluster/installing-embedded-air-gap.mdx b/embedded-cluster/installing-embedded-air-gap.mdx new file mode 100644 index 0000000000..f03e6267b5 --- /dev/null +++ b/embedded-cluster/installing-embedded-air-gap.mdx @@ -0,0 +1,155 @@ +import Prerequisites from "../docs/partials/install/_ec-prereqs.mdx" + +# Air gap installation with Embedded Cluster + +This topic describes how to install an application with Replicated Embedded Cluster 3.x on a virtual machine (VM) or bare metal server with no outbound internet access. For online installations, see [Online installation with Embedded Cluster](installing-embedded). For an introduction to Embedded Cluster, see [Embedded Cluster overview](embedded-overview). + +During installation, Embedded Cluster runs a default set of [host preflight checks](embedded-overview#about-host-preflight-checks) that verify the environment meets installer requirements. + +For supported CLI flags, see [install](/reference/embedded-cluster-install). + +## Overview + +When an air gap bundle is built for a release containing an Embedded Cluster Config, both an application air gap bundle and an Embedded Cluster air gap bundle are built. The application air gap bundle can be used for air gap installations with Replicated kURL or with Replicated KOTS in an existing cluster. The Embedded Cluster air gap bundle is used for air gap installations with Embedded Cluster. + +The Embedded Cluster air gap bundle not only contains the assets normally contained in an application air gap bundle (`airgap.yaml`, `app.tar.gz`, and an images directory), but it also contains an `embedded-cluster` directory with the assets needed to install the infrastructure (Embedded Cluster/k0s and [extensions](embedded-config#extensions)). + +During installation with Embedded Cluster in air gap environments, a Docker registry is deployed to the cluster to store application images. Infrastructure images (for Embedded Cluster and Helm extensions) and the Helm charts are preloaded on each node at installation time. + +## Requirement + +Air gap installations are supported with Embedded Cluster version 1.3.0 or later. + +## Limitations and known issues + +Embedded Cluster installations in air gap environments have the following limitations and known issues: + +* If you pass `?airgap=true` to the `replicated.app` endpoint but an air gap bundle is not built for the latest release, the API will not return a 404. Instead it will return the tarball without the air gap bundle (as in, with the installer and the license in it, like for online installations). + +* Images used by Helm extensions must not refer to a multi-architecture image by digest. Only x64 images are included in air gap bundles, and the digest for the x64 image will be different from the digest for the multi-architecture image, preventing the image from being discovered in the bundle. An example of a chart that does this is ingress-nginx/ingress-nginx chart. For an example of how the digests should be set to empty string to pull by tag only, see [extensions](embedded-config#extensions) in _Embedded Cluster Config_. + +* Images for Helm extensions are loaded directly into containerd so that they are available without internet access. But if an image used by a Helm extension has **Always** set as the image pull policy, Kubernetes will try to pull the image from the internet. If necessary, use the Helm values to set `IfNotPresent` as the image pull policy to ensure the extension works in air gap environments. + +* On the channel release history page, the links for **Download air gap bundle**, **Copy download URL**, and **View bundle contents** pertain to the application air gap bundle only, not the Embedded Cluster bundle. + +## Prerequisites + +Before you install, complete the following prerequisites: + + + +## Install using the UI + +These steps assume you download installation assets on a host that has internet access, then copy them into the air-gapped environment where Embedded Cluster will run. + +### Use the Enterprise Portal for a guided install + +To use the guided install experience in the Enterprise Portal: + +1. Log in to the [Replicated Enterprise Portal](/vendor/enterprise-portal-about) with a user for your test customer. + +1. Follow the Linux install instructions for Embedded Cluster in an air gap environment. + +### Install using the Replicated Vendor Portal + +To install from the Vendor Portal: + +1. In the [Vendor Portal](https://vendor.replicated.com), open the channel where the target release was promoted so the air gap bundle can be built. Do one of the following: + + * If **Automatically create airgap builds for newly promoted releases in this channel** is enabled on the channel, wait until the build completes. + * If automatic air gap builds are not enabled, open the **Release history** page for the channel and build the air gap bundle manually. + + :::note + Errors from building the application air gap bundle or the Embedded Cluster infrastructure appear in the Vendor Portal when present. + ::: + +1. Open **Customers** and select the target customer. + +1. On the **Manage customer** tab, under **License options**, enable **Airgap Download Enabled**. + +1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The control may appear as **Embedded Cluster install instructions**.) + + :::note + You can also open the Enterprise Portal to get install and upgrade instructions. + ::: + +1. In the **Embedded Cluster install instructions** dialog, enable **Install in an air gap environment**. + + ![Customer install instructions drop down button](/images/customer-install-instructions-dropdown.png) + + [View a larger version of this image](/images/customer-install-instructions-dropdown.png) + + Embedded cluster install instruction dialog + + [View a larger version of this image](/images/embedded-cluster-install-dialog-airgap.png) + +1. Under **Select a version** (or equivalent), choose the application version you promoted to that channel for testing, or leave the latest version selected if that is what you want to install. + +1. On a machine **with internet access**, run the download command from the dialog to save the air gap installation assets as a `.tgz` archive. + +1. Copy the `.tgz` file to the air-gapped machine where you will install. + +1. On the air-gapped machine, extract the `.tgz` using the command from the install instructions dialog. You should have at least: + + * The installer binary + * The license file + * The air gap bundle (`APP_SLUG.airgap`) + + After extraction, you may see additional binaries and artifacts compared to Embedded Cluster 2.x. Embedded Cluster uses these internally. You can ignore them. + +1. On the air-gapped machine, run the `install` command from the dialog. It must include `--airgap-bundle` pointing at your `.airgap` file. For example: + + ```bash + sudo ./APP_SLUG install --license license.yaml --airgap-bundle APP_SLUG.airgap + ``` + + Replace `APP_SLUG` with your application slug and use the correct paths for your license and bundle files. Add any other flags you need. For the full set of flags, see [install](/reference/embedded-cluster-install). + +1. Complete any prompts from the install command (for example, acceptance of a self-signed certificate and installer password). + +1. On a machine with browser access to the installer (often the same air-gapped host, or another host on the same network), open the URL from the install output to open the installer UI. + +1. Log in to the installer with the password you set when you ran the install command. + +1. On the **Configure** page, enter the configuration values for your application. This page serves the same role as the config screen in KOTS Admin Console, with an updated design. + +1. On the **Set Up** page, provide any information required for the cluster installation. This corresponds to values you previously passed with install flags in Embedded Cluster 2.x (for example, proxy settings), where those options apply in your air gap environment. + +1. On the **Run** page, start the installation and wait for it to complete. + +1. On the **Finish** page, confirm completion. If your KOTS Application custom resource defines links, they appear here. + + :::note + Links to port-forwarded services are not available on this page. + ::: + +## Install using the CLI (headless) + +To install headlessly in an air gap environment, download and extract assets on a machine with internet access, transfer them to the air-gapped host, then run `install` there with air gap and headless flags. + +1. Complete the Vendor Portal steps to build the air gap bundle, enable **Airgap Download Enabled** for the customer, and open **Install instructions** with **Install in an air gap environment** selected. For more detail, see steps 1 through 6 in [Install using the Replicated Vendor Portal](#install-using-the-replicated-vendor-portal). + +1. Under **Select a version** (or equivalent), choose the application version to install. + +1. On a machine **with internet access**, run the first two commands from the dialog (download the archive, then extract it). + + After extraction, you may see additional binaries and artifacts compared to Embedded Cluster 2.x. Embedded Cluster uses these internally. You can ignore them. + +1. Copy the extracted directory (or the `.tgz` and extract on the air-gapped host) to the air-gapped machine. + +1. On the air-gapped machine, run `install` with: + + * `--airgap-bundle` and the path to the `APP_SLUG.airgap` file. + * `--headless` to skip the interactive installer UI. + * `--config-values` with the path to your [ConfigValues](/reference/custom-resource-configvalues) file. + * `--installer-password` with the password you will use to access the installer later. + + Example: + + ```bash + sudo ./APP_SLUG install --license license.yaml --airgap-bundle APP_SLUG.airgap --headless --config-values PATH_TO_CONFIGVALUES --installer-password INSTALLER_PASSWORD + ``` + + Replace placeholders with values for your environment. Add any other flags you need. For the full set of flags, see [install](/reference/embedded-cluster-install). + +1. Monitor the command output until the install completes, then access your application as you normally do. diff --git a/embedded-cluster/installing-embedded-automation.mdx b/embedded-cluster/installing-embedded-automation.mdx new file mode 100644 index 0000000000..1afb377fd3 --- /dev/null +++ b/embedded-cluster/installing-embedded-automation.mdx @@ -0,0 +1,92 @@ +import ConfigValuesExample from "../docs/partials/configValues/_configValuesExample.mdx" +import ConfigValuesProcedure from "../docs/partials/configValues/_config-values-procedure.mdx" +import ConfigValuesRequirements from "../docs/partials/configValues/_requirements.mdx" + +# Automate installation with Embedded Cluster + +This topic describes how to install an application with Replicated Embedded Cluster from the command line, without needing to access the Replicated KOTS Admin Console. + +## Overview + +A common use case for installing with Embedded Cluster from the command line is to automate installation, such as performing headless installations as part of CI/CD pipelines. + +With headless installation, you provide all the necessary installation assets, such as the license file and the application config values, with the installation command rather than through the Admin Console UI. Any preflight checks defined for the application run automatically during headless installations from the command line rather than being displayed in the Admin Console. + +## Prerequisite + +Create a ConfigValues resource to define the configuration values for the application. The ConfigValues resource allows you to pass the configuration values for an application from the command line with the install command, rather than through the Admin Console UI. For air-gapped environments, ensure that the ConfigValues file can be accessed from the installation environment. + +The ConfigValues resource includes the fields that are defined in the Replicated KOTS Config custom resource for the release, along with the user-supplied and default values for each field, as shown in the example below: + + + +#### ConfigValues requirements + + + +For more information, see [ConfigValues](/reference/custom-resource-configvalues). + +## Limitation + +Automating deployment with Embedded Cluster is supported only for the initial installation. Performing automated (headless) updates of existing installations with Embedded Cluster is not supported. For information about how to update an existing installation through the Admin Console UI, see [Perform Updates in Embedded Clusters](/enterprise/updating-embedded). + +## Online (internet-connected) installation + +To install with Embedded Cluster in an online environment: + +1. Follow the steps provided in the Vendor Portal to download and untar the Embedded Cluster installation assets. For more information, see [Online Installation with Embedded Cluster](/enterprise/installing-embedded). + +1. Run the following command to install: + + ```bash + sudo ./APP_SLUG install --license PATH_TO_LICENSE \ + --config-values PATH_TO_CONFIGVALUES \ + --admin-console-password ADMIN_CONSOLE_PASSWORD + ``` + + Where: + * `APP_SLUG` is the unique slug for the application. + * `PATH_TO_LICENSE` is the path to the customer license. + * `ADMIN_CONSOLE_PASSWORD` is a password for accessing the Admin Console. + * `PATH_TO_CONFIGVALUES` is the path to the ConfigValues file. + + For more information about the `install` command options, see [install](/reference/embedded-cluster-install). + +## Air gap installation + +To install with Embedded Cluster in an air-gapped environment: + +1. Follow the steps provided in the Vendor Portal to download and untar the Embedded Cluster air gap installation assets. For more information, see [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap). + +1. Ensure that the Embedded Cluster installation assets are available on the air-gapped machine, then run the following command to install: + + ```bash + sudo ./APP_SLUG install --license PATH_TO_LICENSE \ + --config-values PATH_TO_CONFIGVALUES \ + --admin-console-password ADMIN_CONSOLE_PASSWORD \ + --airgap-bundle PATH_TO_AIRGAP_BUNDLE + ``` + + Replace: + * `APP_SLUG` with the unique slug for the application. + * `PATH_TO_LICENSE` with the path to the customer license. + * `PATH_TO_CONFIGVALUES` with the path to the ConfigValues file. + * `ADMIN_CONSOLE_PASSWORD` with a password for accessing the Admin Console. + * `PATH_TO_AIRGAP_BUNDLE` with the path to the Embedded Cluster `.airgap` bundle for the release. + + For the complete list of `install` options, see [install](/reference/embedded-cluster-install). + +## (Optional) Ignore preflight checks during installation + +You can ignore both application-level preflight checks and Embedded Cluster host preflight checks during installation. When you ignore preflight checks, the installation proceeds despite any preflight failures. This is useful for automated installations in development environments. For more information about the `--ignore-host-preflights` and `--ignore-app-preflights` options, see [install](/reference/embedded-cluster-install). + +Ignoring host preflight checks is _not_ recommended for production installations. + +* To ignore preflight checks: + + ```bash + sudo ./APP_SLUG install --license license.yaml --ignore-host-preflights --ignore-app-preflights --yes + ``` + Where: + * `APP_SLUG` is the unique slug for the application + * The `--yes` flag addresses the prompt for `--ignore-host-preflights` to continue with installation diff --git a/embedded-cluster/installing-embedded-requirements.mdx b/embedded-cluster/installing-embedded-requirements.mdx new file mode 100644 index 0000000000..77f1f9d200 --- /dev/null +++ b/embedded-cluster/installing-embedded-requirements.mdx @@ -0,0 +1,90 @@ +import EmbeddedClusterRequirements from "../docs/partials/embedded-cluster/_requirements.mdx" +import EmbeddedClusterPortRequirements from "../docs/partials/embedded-cluster/_port-reqs.mdx" +import FirewallOpeningsIntro from "../docs/partials/install/_firewall-openings-intro.mdx" +import FirewallOpeningsEc from "../docs/partials/install/_firewall-openings-embedded-cluster.mdx" + +# Embedded Cluster installation requirements + +This topic lists the installation requirements for Replicated Embedded Cluster. Ensure that the installation environment meets these requirements before attempting to install. + +## System requirements + + + +## Port requirements + + + +## Unix accounts for Kubernetes components + +During installation, Embedded Cluster automatically creates the following Unix accounts that are required by internal Kubernetes components: + +* **etcd**: Used by the Kubernetes etcd database, which stores cluster state. +* **konnectivity-server**: Used by the Konnectivity service, which facilitates secure communication between internal components. +* **kube-apiserver**: Used by the Kubernetes API server. +* **kube-scheduler**: Used by the Kubernetes scheduler to schedule workloads such as pods. + +No action is required to create these roles. Removing them will make the cluster non-functional. + +For more information about the internal Kubernetes components, see [Kubernetes Components](https://kubernetes.io/docs/concepts/overview/components/) in the Kubernetes documentation. + +For more information about the Konnectivity service, see [Set up Konnectivity service](https://kubernetes.io/docs/tasks/extend-kubernetes/setup-konnectivity/) in the Kubernetes documentation. + +## Firewall openings for online installations with Embedded Cluster {#firewall} + + + + + +:::note +If you monitor the outbound traffic attempts made by Embedded Cluster, you might see an attempted call to `updates.k0sproject.io` approximately every 30 minutes. These calls are made by a feature of the upstream k0s project called `update-prober`, which checks for k0s updates. Embedded Cluster does not use the `update-prober` feature and blocking it in your firewall rules will not affect Replicated product functionality. +::: + +## About firewalld configuration + +When Firewalld is enabled in the installation environment, Embedded Cluster modifies the Firewalld config to allow traffic over the pod and service networks and to open the required ports on the host. No additional configuration is required. + +The following rule is added to Firewalld: + +```xml + + + + + + + + + + + +``` + +The following ports are opened in the default zone: + + + + + + + + + + + + + + + + + + + + + + + + + + +
PortProtocol
6443TCP
10250TCP
9443TCP
2380TCP
4789UDP
diff --git a/embedded-cluster/installing-embedded.mdx b/embedded-cluster/installing-embedded.mdx new file mode 100644 index 0000000000..23da11c6e4 --- /dev/null +++ b/embedded-cluster/installing-embedded.mdx @@ -0,0 +1,97 @@ +import Prerequisites from "../docs/partials/install/_ec-prereqs.mdx" + +# Online installation with Embedded Cluster + +This topic describes how to install an application in an online (internet-connected) environment with Replicated Embedded Cluster 3.x. For air gap installations, see [Air gap installation with Embedded Cluster](installing-embedded-air-gap). For an introduction to Embedded Cluster, see [Embedded Cluster overview](embedded-overview). + +During installation, Embedded Cluster runs a default set of [host preflight checks](embedded-overview#about-host-preflight-checks) that verify the environment meets installer requirements. + +For supported CLI flags (proxy, network interface, and more), see [install](/reference/embedded-cluster-install). + +## Prerequisites + +Before you install, complete the following prerequisites: + + + +* Ensure that the required domains are reachable from the installation host. See [Firewall openings for online installations](installing-embedded-requirements#firewall). + +## Install using the UI + +### Use the Enterprise Portal for a guided install + +To use the guided install experience in the Enterprise Portal: + +1. Log in to the [Replicated Enterprise Portal](/vendor/enterprise-portal-about) with a user for your test customer. + +1. Follow the Linux install instructions for Embedded Cluster. + +### Install using the Replicated Vendor Portal + +To install from the Vendor Portal: + +1. In the [Vendor Portal](https://vendor.replicated.com), open the **Customers** page and select a customer that is assigned to the channel you use for testing. + +1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The control may appear as **Embedded Cluster install instructions**.) + + :::note + You can also open the Enterprise Portal to get install and upgrade instructions. + ::: + +1. Under **Select a version** (or equivalent), choose the application version you promoted to that channel for testing, or leave the latest version selected if that is what you want to install. + +1. On a Linux machine, run the three commands from the dialog in order: download the archive, extract it, then run the install command. + + After extraction, you may see additional binaries and artifacts compared to Embedded Cluster 2.x. Embedded Cluster uses these internally. You can ignore them. + +1. Complete any prompts from the install command (for example, acceptance of a self-signed certificate and installer password). + +1. Open the URL from the install output in a browser to open the installer UI. + +1. Log in to the installer with the password you set when you ran the install command. + +1. On the **Configure** page, enter the configuration values for your application. This page serves the same role as the config screen in KOTS Admin Console, with an updated design. + +1. On the **Set Up** page, provide any information required for the cluster installation. This corresponds to values you previously passed with install flags in Embedded Cluster 2.x (for example, proxy settings). + +1. On the **Run** page, start the installation and wait for it to complete. + +1. On the **Finish** page, confirm completion. If your KOTS Application custom resource defines links, they appear here. + + :::note + Links to port-forwarded services are not available on this page. + ::: + +## Install using the CLI (headless) + +Embedded Cluster 3.x supports headless installs. The way you start a headless install is slightly different from Embedded Cluster 2.x. + +1. In the Vendor Portal, open the **Customers** page and select a customer that is assigned to the channel you use for testing. + +1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The control may appear as **Embedded Cluster install instructions**.) + + :::note + You can also open the Enterprise Portal to get install and upgrade instructions. + ::: + +1. Under **Select a version** (or equivalent), choose the application version you promoted to that channel for testing, or leave the latest version selected if that is what you want to install. + +1. On a Linux machine, run the first two commands from the dialog (download the archive, then extract it). + + After extraction, you may see additional binaries and artifacts compared to Embedded Cluster 2.x. Embedded Cluster uses these internally. You can ignore them. + +1. For the third command, run `install` with the following flags: + + * `--headless` to run without the interactive installer UI. + * `--config-values` with the path to your [ConfigValues](/reference/custom-resource-configvalues) file. + * `--installer-password` with the password you will use to access the installer later. + + Example: + + ```bash + sudo ./APP_SLUG install --license LICENSE_FILE --headless --config-values PATH_TO_CONFIGVALUES --installer-password INSTALLER_PASSWORD + ``` + + Replace `APP_SLUG`, `LICENSE_FILE`, `PATH_TO_CONFIGVALUES`, and `INSTALLER_PASSWORD` with the values for your environment. Add any other flags you need. For the full set of flags, see [install](/reference/embedded-cluster-install). + +1. Monitor the command output until the install completes, then access your application as you normally do. diff --git a/embedded-cluster/updating-embedded.mdx b/embedded-cluster/updating-embedded.mdx new file mode 100644 index 0000000000..9d0d99fd95 --- /dev/null +++ b/embedded-cluster/updating-embedded.mdx @@ -0,0 +1,94 @@ +# Perform updates in embedded clusters + +This topic describes how to upgrade, redeploy, or reconfigure an application installed with Replicated Embedded Cluster 3.x. For an introduction to Embedded Cluster, see [Embedded Cluster overview](embedded-overview). + +## Overview + +Each Embedded Cluster binary that you download is built for a particular application version. Running `install` or `upgrade` with that binary installs or upgrades to that version. Upgrades can update both your application and cluster infrastructure (including Kubernetes and Embedded Cluster components), depending on what changed in the release. + +You can upgrade interactively in the browser or headlessly from the command line. To change configuration or redeploy without moving to a newer application version, run `upgrade` using the binary for the version that is already installed. + +## Upgrade using the UI + +### Use the Enterprise Portal for a guided upgrade + +To use the guided upgrade experience in the Enterprise Portal: + +1. Log in to the [Replicated Enterprise Portal](/vendor/enterprise-portal-about) with a user for your test customer. + +1. Open the **Update** tab and follow the instructions to upgrade the instance. + +### Upgrade using the Replicated Vendor Portal + +To upgrade more directly from the Vendor Portal: + +1. In the [Vendor Portal](https://vendor.replicated.com), open the **Customers** page and select a customer that is assigned to the channel you use for testing. + +1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The control may appear as **Embedded Cluster install instructions**.) + + :::note + You can also open the Enterprise Portal to get install and upgrade instructions. + ::: + +1. Under **Select a version** (or equivalent), choose the application version to upgrade to. + +1. On a Linux machine, run the first two commands from the dialog (download the archive, then extract it). + +1. For the third command, use `upgrade` instead of `install`, then run the command. For example: + + ```bash + sudo ./APP_SLUG upgrade --license LICENSE_FILE + ``` + + Replace `APP_SLUG` with your application slug and `LICENSE_FILE` with the path to the license file. Add any other flags you use for this environment. For the full set of flags, see [install](/reference/embedded-cluster-install). + +1. When prompted, enter the password you set during installation to log in to the installer. To set a different password for the installer, use the `--installer-password` flag. + +1. On the **Configure** page, change any application configuration you need. + +1. On the **Upgrade** page, start the upgrade and wait for it to finish. + +1. On the **Finish** page, confirm completion. Use the provided links to open your application if needed. + +## Upgrade using the CLI (headless) + +Embedded Cluster 3.x supports headless upgrades. + +1. In the Vendor Portal, open the **Customers** page and select a customer that is assigned to the channel you use for testing. + +1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The control may appear as **Embedded Cluster install instructions**.) + + :::note + You can also open the Enterprise Portal to get install and upgrade instructions. + ::: + +1. Under **Select a version** (or equivalent), choose the application version to upgrade to. + +1. On a Linux machine, run the first two commands from the dialog (download the archive, then extract it). + +1. For the third command, do the following: + + * Use `upgrade` instead of `install`. + * Pass `--headless` to run without the interactive installer UI. + * (Optional) Pass `--config-values` with the path to your [ConfigValues](/reference/custom-resource-configvalues) file to change configuration. + * (Optional) Pass `--installer-password` to change the installer password. + + Example: + + ```bash + sudo ./APP_SLUG upgrade --license LICENSE_FILE --headless + ``` + +1. Monitor the command output until the upgrade completes, then access your application as you normally do. + +## Redeploy or reconfigure without changing the application version + +Installing or upgrading with a given binary always targets the application version that binary was built for. + +To redeploy or reconfigure without upgrading to a newer application version, run the `upgrade` command using the binary for the version that is **already** installed. For example, if version 1.2.3 is installed, download and run `upgrade` with the 1.2.3 assets. That redeploys the release. + +To change configuration without a version change, pass updated values with `--config-values` (headless) or change values on the **Configure** page (interactive upgrade). + +## Upgrade in air gap clusters + +For air gap environments, enable air gap in the **Install instructions** dialog, download the assets to a machine with internet access, transfer them to the air-gapped host, then run `upgrade` with the same air gap flags you use for `install` (for example, `--airgap-bundle`). For more information about air gap assets, see [Air gap installation with Embedded Cluster](installing-embedded-air-gap). diff --git a/embedded-cluster/v3-placeholder.md b/embedded-cluster/v3-placeholder.md deleted file mode 100644 index aeb4c25e02..0000000000 --- a/embedded-cluster/v3-placeholder.md +++ /dev/null @@ -1 +0,0 @@ -# v3 placeholder \ No newline at end of file diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx index d616ddb49e..aecf12ae69 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx @@ -166,7 +166,7 @@ To configure Velero Backup and Restore custom resources for Embedded Cluster dis You can extend Velero's backup and restore capabilities by configuring custom Velero plugins in the Embedded Cluster Config. This is useful if you need to add support for specific backup scenarios, such as backing up databases like PostgreSQL, MySQL, or other stateful applications that require advanced disaster recovery capabilities. -To configure custom Velero plugins, use the `extensions.velero.plugins` key in the Embedded Cluster Config. For more information, see [Configure Velero Plugins](/reference/embedded-config#configure-velero-plugins) in _Embedded Cluster Config_. +To configure custom Velero plugins, use the `extensions.velero.plugins` key in the Embedded Cluster Config. For more information, see [Configure Velero Plugins](embedded-config#configure-velero-plugins) in _Embedded Cluster Config_. ### Enable the disaster recovery feature for your customers diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx index 69fb03d267..1768d6022e 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx @@ -19,9 +19,9 @@ This section describes how to join nodes to a cluster with Embedded Cluster. Multi-node clusters with Embedded Cluster have the following limitations: -* Setting node roles with the Embedded Cluster Config [roles](/reference/embedded-config#roles-beta) key is Beta. +* Setting node roles with the Embedded Cluster Config [roles](embedded-config#roles-beta) key is Beta. -* The first node added to the cluster is always a controller and cannot be assigned any custom roles. For more information about configuring node roles, see [roles](/reference/embedded-config#roles-beta) in _Embedded Cluster Config_. +* The first node added to the cluster is always a controller and cannot be assigned any custom roles. For more information about configuring node roles, see [roles](embedded-config#roles-beta) in _Embedded Cluster Config_. * The same Embedded Cluster data directory used at installation is used for all nodes joined to the cluster. This is either the default `/var/lib/embedded-cluster` directory or the directory set with the [`--data-dir`](/reference/embedded-cluster-install#flags) flag. You cannot choose a different data directory for Embedded Cluster when joining nodes. @@ -39,7 +39,7 @@ This section describes how to add nodes to a cluster with Embedded Cluster. To add a node to a cluster with Embedded Cluster: -1. (Optional) In the Embedded Cluster Config, configure the `roles` key to customize node roles. For more information, see [roles](/reference/embedded-config#roles-beta) in _Embedded Cluster Config_. When you are done, create and promote a new release with the updated Config. +1. (Optional) In the Embedded Cluster Config, configure the `roles` key to customize node roles. For more information, see [roles](embedded-config#roles-beta) in _Embedded Cluster Config_. When you are done, create and promote a new release with the updated Config. 1. Do one of the following: @@ -126,7 +126,7 @@ Enabling high availability has the following requirements: Consider the following best practices and recommendations for creating HA clusters: -* At least three _controller_ nodes that run the Kubernetes control plane are required for HA. This is because clusters use a quorum system, in which more than half the nodes must be up and reachable. In clusters with three controller nodes, the Kubernetes control plane can continue to operate if one node fails because a quorum can still be reached by the remaining two nodes. By default, with Embedded Cluster, all new nodes added to a cluster are controller nodes. For information about customizing the controller node role, see [roles](/reference/embedded-config#roles-beta) in _Embedded Cluster Config_. +* At least three _controller_ nodes that run the Kubernetes control plane are required for HA. This is because clusters use a quorum system, in which more than half the nodes must be up and reachable. In clusters with three controller nodes, the Kubernetes control plane can continue to operate if one node fails because a quorum can still be reached by the remaining two nodes. By default, with Embedded Cluster, all new nodes added to a cluster are controller nodes. For information about customizing the controller node role, see [roles](embedded-config#roles-beta) in _Embedded Cluster Config_. * Always use an odd number of controller nodes in HA clusters. Using an odd number of controller nodes ensures that the cluster can make decisions efficiently with quorum calculations. Clusters with an odd number of controller nodes also avoid split-brain scenarios where the cluster runs as two, independent groups of nodes, resulting in inconsistencies and conflicts. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx index 77f1a8aeaa..0cbff2bfba 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx @@ -5,10 +5,6 @@ import HaArchitecture from "../../docs/partials/embedded-cluster/_multi-node-ha- This topic provides an introduction to Replicated Embedded Cluster. -:::note -If you are instead looking for information about creating Kubernetes Installers with Replicated kURL, see the [Replicated kURL](/vendor/packaging-embedded-kubernetes) section. -::: - ## Overview @@ -21,7 +17,7 @@ Embedded Cluster is a successor to Replicated kURL. Compared to kURL, Embedded C * Improved support for multi-node clusters * One-click updates of both the application and the cluster at the same time -Additionally, Embedded Cluster automatically deploys several built-in extensions like KOTS and OpenEBS to provide capabilities such as application management and storage. This represents an improvement over kURL because vendors distributing their application with Embedded Cluster no longer need choose and define various add-ons in the installer spec. For additional functionality that is not included in the built-in extensions, such as an ingress controller, vendors can provide their own [`extensions`](/reference/embedded-config#extensions) that will be deployed alongside the application. +Additionally, Embedded Cluster automatically deploys several built-in extensions like KOTS and OpenEBS to provide capabilities such as application management and storage. This represents an improvement over kURL because vendors distributing their application with Embedded Cluster no longer need choose and define various add-ons in the installer spec. For additional functionality that is not included in the built-in extensions, such as an ingress controller, vendors can provide their own [`extensions`](embedded-config#extensions) that will be deployed alongside the application. ## About installing with Embedded Cluster @@ -71,13 +67,13 @@ For more information about creating HA multi-node clusters with Embedded Cluster You can optionally define node roles in the Embedded Cluster Config. For multi-node clusters, roles can be useful for the purpose of assigning specific application workloads to nodes. If nodes roles are defined, users assign one or more roles to a node when it is joined to the cluster. -For more information, see [roles](/reference/embedded-config#roles) in _Embedded Cluster Config_. +For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. ## About configuring Embedded Cluster To support installations with Embedded Cluster, an Embedded Cluster Config must be present in the application release. The Embedded Cluster Config lets you define several characteristics about the cluster that will be created. -For more information, see [Embedded Cluster Config](/reference/embedded-config). +For more information, see [Embedded Cluster Config](embedded-config). ## Architecture @@ -97,7 +93,7 @@ When the user runs the Embedded Cluster install command, the Embedded Cluster bi After all the Kubernetes components for the cluster are available, the Embedded Cluster binary then installs the Embedded Cluster built-in extensions. -Any Helm extensions that were included in the [`extensions`](/reference/embedded-config#extensions) field of the Embedded Cluster Config are also installed. The namespace or namespaces where Helm extensions are installed is defined by the vendor in the Embedded Cluster Config. +Any Helm extensions that were included in the [`extensions`](embedded-config#extensions) field of the Embedded Cluster Config are also installed. The namespace or namespaces where Helm extensions are installed is defined by the vendor in the Embedded Cluster Config. Finally, Embedded Cluster also installs Local Artifact Mirror (LAM). In air gap installations, LAM is used to store and update images. @@ -113,7 +109,7 @@ As shown in the diagram above, in multi-node installations, the Embedded Cluster For installations that include disaster recovery with Velero, the Velero Node Agent runs on each node in the cluster. The Node Agent is a Kubernetes DaemonSet that performs backup and restore tasks such as creating snapshots and transferring data during restores. -Additionally, any Helm [`extensions`](/reference/embedded-config#extensions) that you include in the Embedded Cluster Config are installed in the cluster depending on the given chart and how it is configured to be deployed. +Additionally, any Helm [`extensions`](embedded-config#extensions) that you include in the Embedded Cluster Config are installed in the cluster depending on the given chart and how it is configured to be deployed. ### Multi-node architecture with high availability @@ -143,7 +139,7 @@ Embedded Cluster has the following limitations: * **Disaster recovery is in alpha**: Disaster Recovery for Embedded Cluster installations is in alpha. For more information, see [Disaster Recovery for Embedded Cluster (Alpha)](/vendor/embedded-disaster-recovery). -* **Partial rollback support**: In Embedded Cluster 1.17.0 and later, rollbacks are supported only when rolling back to a version where there is no change to the [Embedded Cluster Config](/reference/embedded-config) compared to the currently-installed version. For example, users can roll back to release version 1.0.0 after upgrading to 1.1.0 only if both 1.0.0 and 1.1.0 use the same Embedded Cluster Config. For more information about how to enable rollbacks for your application in the KOTS Application custom resource, see [allowRollback](/reference/custom-resource-application#allowrollback) in _Application_. +* **Partial rollback support**: In Embedded Cluster 1.17.0 and later, rollbacks are supported only when rolling back to a version where there is no change to the [Embedded Cluster Config](embedded-config) compared to the currently-installed version. For example, users can roll back to release version 1.0.0 after upgrading to 1.1.0 only if both 1.0.0 and 1.1.0 use the same Embedded Cluster Config. For more information about how to enable rollbacks for your application in the KOTS Application custom resource, see [allowRollback](/reference/custom-resource-application#allowrollback) in _Application_. * **Changing node hostnames is not supported**: After a host is added to a cluster, Kubernetes assumes that the hostname and IP address of the host will not change. If you need to change the hostname or IP address of a node, you must first remove the node from the cluster, reset it, and then rejoin it. For information about how to reset nodes with Embedded Cluster, see [Reset a Node](/enterprise/embedded-manage-nodes#reset-a-node). For information about the requirements for naming nodes, see [Node name uniqueness](https://kubernetes.io/docs/concepts/architecture/nodes/#node-name-uniqueness) in the Kubernetes documentation. @@ -165,7 +161,7 @@ Embedded Cluster has the following limitations: * **Upgrading by more than one Kubernetes version at a time not supported**: Kubernetes does not support upgrading by more than one minor version at a time. To upgrade Kubernetes by more than one minor version, promote multiple releases, incrementing the version of Kubernetes by one minor version in each release. -* **Templating not supported in Embedded Cluster Config**: The [Embedded Cluster Config](/reference/embedded-config) resource does not support the use of Go template functions, including [Replicated template functions](/reference/template-functions-about). This only applies to the Embedded Cluster Config. You can still use template functions in the rest of your release as usual. +* **Templating not supported in Embedded Cluster Config**: The [Embedded Cluster Config](embedded-config) resource does not support the use of Go template functions, including [Replicated template functions](/reference/template-functions-about). This only applies to the Embedded Cluster Config. You can still use template functions in the rest of your release as usual. * **Policy enforcement on Embedded Cluster workloads is not supported**: The Embedded Cluster runs workloads that require higher levels of privilege. If your application installs a policy enforcement engine such as Gatekeeper or Kyverno, ensure that its policies are not enforced in the namespaces used by Embedded Cluster. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx index 74fa000c83..0c1a8e2749 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx @@ -8,7 +8,7 @@ This topic provides information about how to configure your application releases ## Add the Embedded Cluster Config resource -An [Embedded Cluster Config](/reference/embedded-config) must be present in the release to support installation with Embedded Cluster. The Embedded Cluster Config sets the version of Embedded Cluster to install, and lets you define additional characteristics about the cluster. +An [Embedded Cluster Config](embedded-config) must be present in the release to support installation with Embedded Cluster. The Embedded Cluster Config sets the version of Embedded Cluster to install, and lets you define additional characteristics about the cluster. To add the Embedded Cluster Config: @@ -16,11 +16,11 @@ To add the Embedded Cluster Config: If you have not yet configured the HelmChart custom resource for your application, see [Onboard to the Replicated Platform](/vendor/replicated-onboarding) for more detailed instructions on how to configure releases that support installation with a Replicated installer. -1. In the release, add an [Embedded Cluster Config](/reference/embedded-config) manifest that specifies the Embedded Cluster version to use: +1. In the release, add an [Embedded Cluster Config](embedded-config) manifest that specifies the Embedded Cluster version to use: -1. If your application requires that certain components are deployed before the application and as part of the Embedded Cluster itself, update the Embedded Cluster Config to add [extensions](/reference/embedded-config#extensions). +1. If your application requires that certain components are deployed before the application and as part of the Embedded Cluster itself, update the Embedded Cluster Config to add [extensions](embedded-config#extensions). 1. Save the release and promote it to the channel that you use for testing internally. @@ -46,10 +46,10 @@ To add the Embedded Cluster Config: The Admin Console URL is printed when the installation finishes. Access the Admin Console and follow the instructions in the wizard to install your application. -1. After successfully installing your application with Embedded Cluster, customize the [Embedded Cluster Config](/reference/embedded-config) as desired: - * Add your custom domain for the Replicated proxy registry and Replicated app service. See [domains](/reference/embedded-config#domains). - * Add custom Helm extensions. Extensions allow you to provide Helm charts that are deployed before your application. For example, you can add a Helm extension to ship an ingress controller. See [extensions](/reference/embedded-config#extensions). - * Define roles to assign workloads to specific nodes in multi-node installations. See [roles](/reference/embedded-config#roles). +1. After successfully installing your application with Embedded Cluster, customize the [Embedded Cluster Config](embedded-config) as desired: + * Add your custom domain for the Replicated proxy registry and Replicated app service. See [domains](embedded-config#domains). + * Add custom Helm extensions. Extensions allow you to provide Helm charts that are deployed before your application. For example, you can add a Helm extension to ship an ingress controller. See [extensions](embedded-config#extensions). + * Define roles to assign workloads to specific nodes in multi-node installations. See [roles](embedded-config#roles). Replicated recommends that you work in small iterations and test your changes frequently in your development environment. @@ -81,7 +81,7 @@ The NVIDIA GPU Operator uses the operator framework within Kubernetes to automat ### Include the NVIDIA gpu operator and configure containerd options -You can include the NVIDIA GPU Operator in your release as an additional Helm chart, or using Embedded Cluster Helm extensions. For information about adding Helm extensions, see [extensions](/reference/embedded-config#extensions) in _Embedded Cluster Config_. +You can include the NVIDIA GPU Operator in your release as an additional Helm chart, or using Embedded Cluster Helm extensions. For information about adding Helm extensions, see [extensions](embedded-config#extensions) in _Embedded Cluster Config_. Using the NVIDIA GPU Operator with Embedded Cluster requires configuring the containerd options in the operator as follows: diff --git a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx index 4b0c4f172b..5bd6af5901 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx @@ -1,7 +1,3 @@ -import UpdateAirGapAdm from "../../docs/partials/embedded-cluster/_update-air-gap-admin-console.mdx" -import UpdateAirGapCli from "../../docs/partials/embedded-cluster/_update-air-gap-cli.mdx" -import UpdateAirGapOverview from "../../docs/partials/embedded-cluster/_update-air-gap-overview.mdx" -import DoNotDowngrade from "../../docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx" import Prerequisites from "../../docs/partials/install/_ec-prereqs.mdx" # Air gap installation with Embedded Cluster @@ -12,7 +8,7 @@ This topic describes how to install applications with Embedded Cluster on a virt When an air gap bundle is built for a release containing an Embedded Cluster Config, both an application air gap bundle and an Embedded Cluster air gap bundle are built. The application air gap bundle can be used for air gap installations with Replicated kURL or with Replicated KOTS in an existing cluster. The Embedded Cluster air gap bundle is used for air gap installations with Embedded Cluster. -The Embedded Cluster air gap bundle not only contains the assets normally contained in an application air gap bundle (`airgap.yaml`, `app.tar.gz`, and an images directory), but it also contains an `embedded-cluster` directory with the assets needed to install the infrastructure (Embedded Cluster/k0s and [extensions](/reference/embedded-config#extensions). +The Embedded Cluster air gap bundle not only contains the assets normally contained in an application air gap bundle (`airgap.yaml`, `app.tar.gz`, and an images directory), but it also contains an `embedded-cluster` directory with the assets needed to install the infrastructure (Embedded Cluster/k0s and [extensions](embedded-config#extensions)). During installation with Embedded Cluster in air gap environments, a Docker registry is deployed to the cluster to store application images. Infrastructure images (for Embedded Cluster and Helm extensions) and the Helm charts are preloaded on each node at installation time. @@ -26,7 +22,7 @@ Embedded Cluster installations in air gap environments have the following limita * If you pass `?airgap=true` to the `replicated.app` endpoint but an air gap bundle is not built for the latest release, the API will not return a 404. Instead it will return the tarball without the air gap bundle (as in, with the installer and the license in it, like for online installations). -* Images used by Helm extensions must not refer to a multi-architecture image by digest. Only x64 images are included in air gap bundles, and the digest for the x64 image will be different from the digest for the multi-architecture image, preventing the image from being discovered in the bundle. An example of a chart that does this is ingress-nginx/ingress-nginx chart. For an example of how the digests should be set to empty string to pull by tag only, see [extensions](/reference/embedded-config#extensions) in _Embedded Cluster Config_. +* Images used by Helm extensions must not refer to a multi-architecture image by digest. Only x64 images are included in air gap bundles, and the digest for the x64 image will be different from the digest for the multi-architecture image, preventing the image from being discovered in the bundle. An example of a chart that does this is ingress-nginx/ingress-nginx chart. For an example of how the digests should be set to empty string to pull by tag only, see [extensions](embedded-config#extensions) in _Embedded Cluster Config_. * Images for Helm extensions are loaded directly into containerd so that they are available without internet access. But if an image used by a Helm extension has **Always** set as the image pull policy, Kubernetes will try to pull the image from the internet. If necessary, use the Helm values to set `IfNotPresent` as the image pull policy to ensure the extension works in air gap environments. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx b/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx index 41cfb98177..6374b5769a 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx @@ -8,10 +8,6 @@ import Overview from "../../docs/partials/embedded-cluster/_update-overview.mdx" This topic describes how to perform updates for [Replicated Embedded Cluster](/vendor/embedded-overview) installations. -:::note -If you are instead looking for information about Replicated kURL, see [Perform Updates in kURL Clusters](updating-kurl). -::: - ## Overview diff --git a/scripts/fix-installer-links.js b/scripts/fix-installer-links.js new file mode 100644 index 0000000000..9fdb6f0aec --- /dev/null +++ b/scripts/fix-installer-links.js @@ -0,0 +1,123 @@ +#!/usr/bin/env node +/** + * Fix broken links that point to docs which were moved to the installer docs instance. + * + * Mappings: old path prefix → new doc id (under /installer/{version}/) + * - /vendor/embedded-* and /enterprise/embedded-* and /enterprise/installing-embedded* + * and /enterprise/updating-embedded and /reference/embedded-* + * + * Skips: release-notes (per user request) + * + * Usage: node scripts/fix-installer-links.js [--dry-run] + * --dry-run Log changes without writing files + */ + +const fs = require('fs'); +const path = require('path'); + +const DRY_RUN = process.argv.includes('--dry-run'); +const ROOT = path.resolve(__dirname, '..'); + +// Old path (without leading slash) → new doc id in installer +const MAPPINGS = [ + ['vendor/embedded-overview', 'embedded-overview'], + ['vendor/embedded-disaster-recovery', 'embedded-disaster-recovery'], + ['vendor/embedded-troubleshooting', 'embedded-troubleshooting'], + ['vendor/embedded-using', 'embedded-using'], + ['enterprise/installing-embedded', 'installing-embedded'], + ['enterprise/installing-embedded-air-gap', 'installing-embedded-air-gap'], + ['enterprise/installing-embedded-automation', 'installing-embedded-automation'], + ['enterprise/installing-embedded-requirements', 'installing-embedded-requirements'], + ['enterprise/embedded-manage-nodes', 'embedded-manage-nodes'], + ['enterprise/updating-embedded', 'updating-embedded'], + ['reference/embedded-config', 'embedded-config'], + ['reference/embedded-cluster-install', 'embedded-cluster-install'], + ['reference/embedded-cluster-reset', 'embedded-cluster-reset'], +]; + +function getAllDocFiles(dir, files = []) { + if (!fs.existsSync(dir)) return files; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const e of entries) { + const full = path.join(dir, e.name); + if (e.isDirectory()) { + if (e.name === 'release-notes') continue; // skip release notes + if (e.name === '.history') continue; // skip local history + getAllDocFiles(full, files); + } else if (/\.(md|mdx)$/i.test(e.name)) { + files.push(full); + } + } + return files; +} + +function getVersionForFile(filePath) { + // All installer doc content lives under v2; v3 is placeholder-only. Use v2 so links resolve. + return 'v2'; +} + +function fixContent(content, version) { + let updated = content; + let changeCount = 0; + + for (const [oldPath, newDocId] of MAPPINGS) { + // Match: optional leading /, oldPath, optional .md or .mdx, optional #anchor + // Capture hash so we can preserve it + const escaped = oldPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const regex = new RegExp( + `(/?)(?:${escaped})(\\.mdx?)?(#[^)\\s"'\\]]*)?`, + 'gi' + ); + + const newPath = `/installer/${version}/${newDocId}`; + updated = updated.replace(regex, (match, slash, ext, hash) => { + changeCount++; + return newPath + (hash || ''); + }); + } + + return { content: updated, changeCount }; +} + +function main() { + const docsDir = path.join(ROOT, 'docs'); + const installerDir = path.join(ROOT, 'installer'); + const versionedDir = path.join(ROOT, 'installer_versioned_docs'); + + const files = [ + ...getAllDocFiles(docsDir), + ...getAllDocFiles(installerDir), + ...getAllDocFiles(versionedDir), + ]; + + console.log(`Found ${files.length} doc files (excluding release-notes).`); + if (DRY_RUN) console.log('DRY RUN - no files will be modified.\n'); + + let totalReplacements = 0; + let filesModified = 0; + + for (const file of files) { + const content = fs.readFileSync(file, 'utf8'); + const version = getVersionForFile(file); + const { content: updated, changeCount } = fixContent(content, version); + + if (changeCount > 0) { + const rel = path.relative(ROOT, file); + console.log(`${rel} (version=${version}): ${changeCount} link(s) updated`); + totalReplacements += changeCount; + filesModified++; + if (!DRY_RUN) { + fs.writeFileSync(file, updated, 'utf8'); + } + } + } + + console.log('\n---'); + console.log(`Files with changes: ${filesModified}`); + console.log(`Total link replacements: ${totalReplacements}`); + if (DRY_RUN && totalReplacements > 0) { + console.log('\nRun without --dry-run to apply changes.'); + } +} + +main(); diff --git a/sidebarEmbeddedCluster.js b/sidebarEmbeddedCluster.js index d00bb5a1b9..fb0ebd19d0 100644 --- a/sidebarEmbeddedCluster.js +++ b/sidebarEmbeddedCluster.js @@ -1,5 +1,13 @@ module.exports = { embeddedClusterSidebar: [ - "v3-placeholder", + "embedded-overview", + "embedded-using", + "embedded-config", + "installing-embedded-requirements", + "installing-embedded", + "installing-embedded-air-gap", + "installing-embedded-automation", + "updating-embedded", + "embedded-troubleshooting", ], }; diff --git a/sidebars.js b/sidebars.js index e0f1629c7b..8085183beb 100644 --- a/sidebars.js +++ b/sidebars.js @@ -256,7 +256,7 @@ const sidebars = { }, { type: "link", - href: "/embedded-cluster/v3/v3-placeholder", + href: "/embedded-cluster/v3/embedded-overview", label: "Embedded Cluster", }, { From e3167d57b0b9508617bf96fad5c1c89c5737ce48 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Thu, 2 Apr 2026 12:32:06 -0600 Subject: [PATCH 10/31] add cli docs and fix broken links in ec docs plugin --- .../embedded-cluster/_multi-node-ha-arch.mdx | 2 +- docs/partials/embedded-cluster/_port-reqs.mdx | 4 +- .../_proxy-install-limitations.mdx | 2 +- .../embedded-cluster/_requirements.mdx | 2 +- .../_update-air-gap-admin-console.mdx | 2 +- .../embedded-cluster/_update-air-gap-cli.mdx | 2 +- .../_warning-do-not-downgrade.mdx | 2 +- docs/partials/install/_ec-prereqs.mdx | 4 +- docusaurus.config.js | 6 +- .../embedded-cluster-completion.mdx | 49 ++++++++ .../embedded-cluster-create-join-bundle.mdx | 39 ++++++ ...embedded-cluster-create-upgrade-bundle.mdx | 29 +++++ .../embedded-cluster-enable-ha.mdx | 29 +++++ embedded-cluster/embedded-cluster-install.mdx | 114 ++++++++++++++++++ .../embedded-cluster-node-join.mdx | 34 ++++++ .../embedded-cluster-node-upgrade.mdx | 26 ++++ .../embedded-cluster-remove-node.mdx | 36 ++++++ embedded-cluster/embedded-cluster-reset.mdx | 29 +++++ embedded-cluster/embedded-cluster-shell.mdx | 29 +++++ embedded-cluster/embedded-cluster-status.mdx | 29 +++++ .../embedded-cluster-support-bundle.mdx | 29 +++++ embedded-cluster/embedded-cluster-upgrade.mdx | 84 +++++++++++++ embedded-cluster/embedded-cluster-version.mdx | 24 ++++ embedded-cluster/embedded-config.mdx | 6 +- embedded-cluster/embedded-overview.mdx | 32 ++--- embedded-cluster/embedded-troubleshooting.mdx | 14 +-- .../installing-embedded-air-gap.mdx | 10 +- .../installing-embedded-automation.mdx | 12 +- embedded-cluster/installing-embedded.mdx | 4 +- embedded-cluster/updating-embedded.mdx | 2 +- .../embedded-cluster-install.mdx | 14 +-- .../embedded-cluster-join-print-command.mdx | 2 +- .../version-2.0.0/embedded-cluster-join.mdx | 2 +- .../embedded-cluster-support-bundle.mdx | 2 +- .../version-2.0.0/embedded-cluster-update.mdx | 2 +- .../version-2.0.0/embedded-config.mdx | 6 +- .../embedded-disaster-recovery.mdx | 12 +- .../version-2.0.0/embedded-manage-nodes.mdx | 22 ++-- .../version-2.0.0/embedded-overview.mdx | 16 +-- .../embedded-troubleshooting.mdx | 14 +-- .../installing-embedded-air-gap.mdx | 10 +- .../installing-embedded-automation.mdx | 12 +- .../version-2.0.0/installing-embedded.mdx | 12 +- .../version-2.0.0/updating-embedded.mdx | 2 +- sidebarEmbeddedCluster.js | 20 +++ 45 files changed, 709 insertions(+), 125 deletions(-) create mode 100644 embedded-cluster/embedded-cluster-completion.mdx create mode 100644 embedded-cluster/embedded-cluster-create-join-bundle.mdx create mode 100644 embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx create mode 100644 embedded-cluster/embedded-cluster-enable-ha.mdx create mode 100644 embedded-cluster/embedded-cluster-install.mdx create mode 100644 embedded-cluster/embedded-cluster-node-join.mdx create mode 100644 embedded-cluster/embedded-cluster-node-upgrade.mdx create mode 100644 embedded-cluster/embedded-cluster-remove-node.mdx create mode 100644 embedded-cluster/embedded-cluster-reset.mdx create mode 100644 embedded-cluster/embedded-cluster-shell.mdx create mode 100644 embedded-cluster/embedded-cluster-status.mdx create mode 100644 embedded-cluster/embedded-cluster-support-bundle.mdx create mode 100644 embedded-cluster/embedded-cluster-upgrade.mdx create mode 100644 embedded-cluster/embedded-cluster-version.mdx diff --git a/docs/partials/embedded-cluster/_multi-node-ha-arch.mdx b/docs/partials/embedded-cluster/_multi-node-ha-arch.mdx index d17db84bac..cfca0aff3e 100644 --- a/docs/partials/embedded-cluster/_multi-node-ha-arch.mdx +++ b/docs/partials/embedded-cluster/_multi-node-ha-arch.mdx @@ -11,4 +11,4 @@ As shown in the diagram above, in HA installations with Embedded Cluster: * For installations that include disaster recovery, the Velero pod is deployed on one node. The Velero Node Agent runs on each node in the cluster. The Node Agent is a Kubernetes DaemonSet that performs backup and restore tasks such as creating snapshots and transferring data during restores. * For air gap installations, two replicas of the air gap image registry are deployed. -Any Helm [`extensions`](/reference/embedded-config#extensions) that you include in the Embedded Cluster Config are installed in the cluster depending on the given chart and whether or not it is configured to be deployed with high availability. \ No newline at end of file +Any Helm [`extensions`](embedded-config#extensions) that you include in the Embedded Cluster Config are installed in the cluster depending on the given chart and whether or not it is configured to be deployed with high availability. \ No newline at end of file diff --git a/docs/partials/embedded-cluster/_port-reqs.mdx b/docs/partials/embedded-cluster/_port-reqs.mdx index dfbc2542b7..4113c8ac9e 100644 --- a/docs/partials/embedded-cluster/_port-reqs.mdx +++ b/docs/partials/embedded-cluster/_port-reqs.mdx @@ -34,10 +34,10 @@ The KOTS Admin Console requires that port 30000/TCP is open and available. Creat Additionally, port 30000 must be accessible by nodes joining the cluster. -If port 30000 is occupied, you can select a different port for the Admin Console during installation. For more information, see [install](/reference/embedded-cluster-install). +If port 30000 is occupied, you can select a different port for the Admin Console during installation. For more information, see [install](/embedded-cluster/v3/embedded-cluster-install). #### LAM port The Local Artifact Mirror (LAM) requires that port 50000/TCP is open and available. -If port 50000 is occupied, you can select a different port for the LAM during installation. For more information, see [install](/reference/embedded-cluster-install). +If port 50000 is occupied, you can select a different port for the LAM during installation. For more information, see [install](/embedded-cluster/v3/embedded-cluster-install). diff --git a/docs/partials/embedded-cluster/_proxy-install-limitations.mdx b/docs/partials/embedded-cluster/_proxy-install-limitations.mdx index c34a5ebc2b..d9a806f314 100644 --- a/docs/partials/embedded-cluster/_proxy-install-limitations.mdx +++ b/docs/partials/embedded-cluster/_proxy-install-limitations.mdx @@ -1,5 +1,5 @@ **Limitations:** -* If any of your [Helm extensions](/reference/embedded-config#extensions) make requests to the internet, the given charts need to be manually configured so that those requests are made to the user-supplied proxy server instead. Typically, this requires updating the Helm values to set HTTP proxy, HTTPS proxy, and no proxy. Note that this limitation applies only to network requests made by your Helm extensions. The proxy settings supplied to the install command are used to pull the containers required to run your Helm extensions. +* If any of your [Helm extensions](embedded-config#extensions) make requests to the internet, the given charts need to be manually configured so that those requests are made to the user-supplied proxy server instead. Typically, this requires updating the Helm values to set HTTP proxy, HTTPS proxy, and no proxy. Note that this limitation applies only to network requests made by your Helm extensions. The proxy settings supplied to the install command are used to pull the containers required to run your Helm extensions. * Proxy settings cannot be changed after installation or during upgrade. \ No newline at end of file diff --git a/docs/partials/embedded-cluster/_requirements.mdx b/docs/partials/embedded-cluster/_requirements.mdx index d5581cac1a..5090e81621 100644 --- a/docs/partials/embedded-cluster/_requirements.mdx +++ b/docs/partials/embedded-cluster/_requirements.mdx @@ -10,7 +10,7 @@ * The user performing the installation must have root access to the machine, such as with `sudo`. -* The data directory used by Embedded Cluster must have 40Gi or more of total space and be less than 80% full. By default, the data directory is `/var/lib/embedded-cluster`. The directory can be changed by passing the `--data-dir` flag with the Embedded Cluster `install` command. For more information, see [install](/reference/embedded-cluster-install). +* The data directory used by Embedded Cluster must have 40Gi or more of total space and be less than 80% full. By default, the data directory is `/var/lib/embedded-cluster`. The directory can be changed by passing the `--data-dir` flag with the Embedded Cluster `install` command. For more information, see [install](/embedded-cluster/v3/embedded-cluster-install). Note that in addition to the primary data directory, Embedded Cluster creates directories and files in the following locations: diff --git a/docs/partials/embedded-cluster/_update-air-gap-admin-console.mdx b/docs/partials/embedded-cluster/_update-air-gap-admin-console.mdx index dab72c9f0d..0159a8951f 100644 --- a/docs/partials/embedded-cluster/_update-air-gap-admin-console.mdx +++ b/docs/partials/embedded-cluster/_update-air-gap-admin-console.mdx @@ -3,7 +3,7 @@ ```bash curl -f https://replicated.app/embedded/APP_SLUG/CHANNEL_SLUG?airgap=true -H "Authorization: LICENSE_ID" -o APP_SLUG-CHANNEL_SLUG.tgz ``` - For more information, see [Install](/enterprise/installing-embedded-air-gap#install). + For more information, see [Install](installing-embedded-air-gap#install). 1. Untar the tarball. For example: diff --git a/docs/partials/embedded-cluster/_update-air-gap-cli.mdx b/docs/partials/embedded-cluster/_update-air-gap-cli.mdx index ac96fab4c3..2a0b707ba9 100644 --- a/docs/partials/embedded-cluster/_update-air-gap-cli.mdx +++ b/docs/partials/embedded-cluster/_update-air-gap-cli.mdx @@ -4,7 +4,7 @@ curl -f https://replicated.app/embedded/APP_SLUG/CHANNEL_SLUG?airgap=true -H "Authorization: LICENSE_ID" -o APP_SLUG-CHANNEL_SLUG.tgz ``` - For more information, see [Install](/enterprise/installing-embedded-air-gap#install). + For more information, see [Install](installing-embedded-air-gap#install). 1. Untar the tarball. For example: diff --git a/docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx b/docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx index 1777e6b18c..5417f04188 100644 --- a/docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx +++ b/docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx @@ -1,3 +1,3 @@ :::important -Don't downgrade the Embedded Cluster version or the Kubernetes version. Also, only increase the Kubernetes version by one minor version at a time. For more information, see [Limitations](/vendor/embedded-overview#ec-limitations) in _Embedded Cluster Overview_. +Don't downgrade the Embedded Cluster version or the Kubernetes version. Also, only increase the Kubernetes version by one minor version at a time. For more information, see [Limitations](embedded-overview#ec-limitations) in _Embedded Cluster Overview_. ::: \ No newline at end of file diff --git a/docs/partials/install/_ec-prereqs.mdx b/docs/partials/install/_ec-prereqs.mdx index 33e12fa8a1..e7de78b75b 100644 --- a/docs/partials/install/_ec-prereqs.mdx +++ b/docs/partials/install/_ec-prereqs.mdx @@ -1,5 +1,5 @@ -* Ensure that your installation environment meets the Embedded Cluster requirements. See [Embedded Cluster Requirements](/enterprise/installing-embedded-requirements). +* Ensure that your installation environment meets the Embedded Cluster requirements. See [Embedded Cluster Requirements](installing-embedded-requirements). -* The application release that you want to install must include an [Embedded Cluster Config](/reference/embedded-config). +* The application release that you want to install must include an [Embedded Cluster Config](embedded-config). * The license used to install must have the **Embedded Cluster Enabled** license field enabled. See [Create and Manage Customers](/vendor/releases-creating-customer). \ No newline at end of file diff --git a/docusaurus.config.js b/docusaurus.config.js index b762c069b4..a9b4351b0d 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -61,17 +61,17 @@ const config = { breadcrumbs: true, editUrl: 'https://github.com/replicatedhq/replicated-docs/edit/main/', // Versioning configuration - lastVersion: 'current', // Make 3.0.0 the default version + lastVersion: 'current', // v3 is the default version includeCurrentVersion: true, // Include the "next" version from installer/ folder versions: { current: { - label: 'Embedded Cluster 3.0.0', + label: 'Embedded Cluster v3', path: 'v3', banner: 'none', badge: false, }, '2.0.0': { - label: 'Embedded Cluster 2.13.3', + label: 'Embedded Cluster v2', path: 'v2', banner: 'unmaintained', badge: false, diff --git a/embedded-cluster/embedded-cluster-completion.mdx b/embedded-cluster/embedded-cluster-completion.mdx new file mode 100644 index 0000000000..5639a8d1ae --- /dev/null +++ b/embedded-cluster/embedded-cluster-completion.mdx @@ -0,0 +1,49 @@ +# completion + +This topic describes the options available with the Embedded Cluster `completion` command. + +## Usage + +```bash +sudo ./ completion [command] +``` + +## Subcommands + + + + + + + + + + + + + + + + + + + + + + +
CommandDescription
`bash`Generate the autocompletion script for bash.
`fish`Generate the autocompletion script for fish.
`powershell`Generate the autocompletion script for PowerShell.
`zsh`Generate the autocompletion script for zsh.
+ +## Flags + + + + + + + + + + + + +
FlagTypeDescription
`-h`, `--help`Help for `completion`.
diff --git a/embedded-cluster/embedded-cluster-create-join-bundle.mdx b/embedded-cluster/embedded-cluster-create-join-bundle.mdx new file mode 100644 index 0000000000..365243a760 --- /dev/null +++ b/embedded-cluster/embedded-cluster-create-join-bundle.mdx @@ -0,0 +1,39 @@ +# create-join-bundle + +This topic describes the options available with the Embedded Cluster `create-join-bundle` command. Use this command to produce a bundle that nodes can use to join the cluster with a given role. + +## Usage + +```bash +sudo ./ create-join-bundle [flags] +``` + +## Flags + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FlagTypeDescription
`--output`stringOutput path for the bundle. **Default:** A path of the form `./cli-join-ROLE-TIMESTAMP.tar.gz` (role and timestamp are filled in by the CLI).
`--role`stringNode role: `controller` or `worker`. **Required.**
`--ttl`stringToken expiration time (for example, `24h`, `48h`, `168h`). **Default:** `24h`
`-h`, `--help`Help for `create-join-bundle`.
diff --git a/embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx b/embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx new file mode 100644 index 0000000000..2deb1b9c15 --- /dev/null +++ b/embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx @@ -0,0 +1,29 @@ +# create-upgrade-bundle + +This topic describes the options available with the Embedded Cluster `create-upgrade-bundle` command. Use this command to produce a bundle used for offline or constrained-path upgrades. + +## Usage + +```bash +sudo ./ create-upgrade-bundle [flags] +``` + +## Flags + + + + + + + + + + + + + + + + + +
FlagTypeDescription
`--output`stringOutput path for the bundle. **Default:** A path of the form `./cli-upgrade-TIMESTAMP.tar.gz` (timestamp is filled in by the CLI).
`-h`, `--help`Help for `create-upgrade-bundle`.
diff --git a/embedded-cluster/embedded-cluster-enable-ha.mdx b/embedded-cluster/embedded-cluster-enable-ha.mdx new file mode 100644 index 0000000000..ddb6fe958f --- /dev/null +++ b/embedded-cluster/embedded-cluster-enable-ha.mdx @@ -0,0 +1,29 @@ +# enable-ha + +This topic describes the options available with the Embedded Cluster `enable-ha` command. + +## Usage + +```bash +sudo ./ enable-ha [flags] +``` + +## Flags + + + + + + + + + + + + + + + + + +
FlagTypeDescription
`--force`Re-run the migration even if high availability (HA) is already complete.
`-h`, `--help`Help for `enable-ha`.
diff --git a/embedded-cluster/embedded-cluster-install.mdx b/embedded-cluster/embedded-cluster-install.mdx new file mode 100644 index 0000000000..d8d58cac8d --- /dev/null +++ b/embedded-cluster/embedded-cluster-install.mdx @@ -0,0 +1,114 @@ +# install + +This topic describes the options available with the Embedded Cluster `install` command. For procedural steps, see [Online installation with Embedded Cluster](installing-embedded), [Air gap installation with Embedded Cluster](installing-embedded-air-gap), and [Automate installation with Embedded Cluster](installing-embedded-automation). + +## Usage + +```bash +sudo ./ install --license [flags] +``` + +## Flags + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FlagTypeDescription
`--airgap`Perform an air gap installation. For more information, see [Air gap installation with Embedded Cluster](installing-embedded-air-gap).
`--cidr`stringCIDR range for Pod and Service IP addresses. **Default:** `10.244.0.0/16`
`--config-values`stringPath to the [ConfigValues](/reference/custom-resource-configvalues) file for headless installs.
`--data-dir`stringData directory for Embedded Cluster. **Default:** `/data-dir` (confirm with `install --help` for your binary).
`--headless`Run installation without the interactive installer UI.
`--hostname`stringHostname to use for this node.
`--http-proxy`stringHTTP proxy URL.
`--https-proxy`stringHTTPS proxy URL.
`--ignore-app-preflights`Skip application preflight checks.
`--ignore-host-preflights`Skip Embedded Cluster host preflight checks.
`--installer-password`stringPassword for the installer UI.
`--installer-port`intPort for the installer UI. **Default:** `30080`
`-l`, `--license`stringPath to the license file.
`--network-interface`stringNetwork interface to use.
`--no-proxy`stringComma-separated list of hosts that should not use the proxy.
`--tls-cert`stringPath to a TLS certificate file for the installer.
`--tls-key`stringPath to a TLS private key file for the installer.
`-y`, `--yes`Assume yes to prompts (for example, when skipping preflights).
`-h`, `--help`Help for `install`.
diff --git a/embedded-cluster/embedded-cluster-node-join.mdx b/embedded-cluster/embedded-cluster-node-join.mdx new file mode 100644 index 0000000000..3b0ca7b23c --- /dev/null +++ b/embedded-cluster/embedded-cluster-node-join.mdx @@ -0,0 +1,34 @@ +# node join + +This topic describes the options available with the Embedded Cluster `node join` command. + +## Usage + +```bash +sudo ./ node join [flags] +``` + +## Flags + + + + + + + + + + + + + + + + + + + + + + +
FlagTypeDescription
`--ignore-host-preflights`Skip Embedded Cluster host preflight checks.
`--network-interface`stringNetwork interface to use.
`-h`, `--help`Help for `node join`.
diff --git a/embedded-cluster/embedded-cluster-node-upgrade.mdx b/embedded-cluster/embedded-cluster-node-upgrade.mdx new file mode 100644 index 0000000000..6d4458ac42 --- /dev/null +++ b/embedded-cluster/embedded-cluster-node-upgrade.mdx @@ -0,0 +1,26 @@ +# node upgrade + +This topic describes the options available with the Embedded Cluster `node upgrade` command. + +## Usage + +```bash +sudo ./ node upgrade [flags] +``` + +## Flags + +Run `sudo ./ node upgrade --help` on your installation host to list flags supported by your release. + + + + + + + + + + + + +
FlagTypeDescription
`-h`, `--help`Help for `node upgrade`.
diff --git a/embedded-cluster/embedded-cluster-remove-node.mdx b/embedded-cluster/embedded-cluster-remove-node.mdx new file mode 100644 index 0000000000..3d47f4e4f0 --- /dev/null +++ b/embedded-cluster/embedded-cluster-remove-node.mdx @@ -0,0 +1,36 @@ +# remove-node + +This topic describes the options available with the Embedded Cluster `remove-node` command. + +## Usage + +```bash +sudo ./ remove-node [flags] +``` + +Replace `node-name` with the Kubernetes node name to remove. + +## Flags + + + + + + + + + + + + + + + + + + + + + + +
FlagTypeDescription
`--force`Force removal without additional confirmation.
`--skip-drain`Skip draining workloads from the node before removal.
`-h`, `--help`Help for `remove-node`.
diff --git a/embedded-cluster/embedded-cluster-reset.mdx b/embedded-cluster/embedded-cluster-reset.mdx new file mode 100644 index 0000000000..994af82b6b --- /dev/null +++ b/embedded-cluster/embedded-cluster-reset.mdx @@ -0,0 +1,29 @@ +# reset + +This topic describes the options available with the Embedded Cluster `reset` command. + +## Usage + +```bash +sudo ./ reset [flags] +``` + +## Flags + + + + + + + + + + + + + + + + + +
FlagTypeDescription
`-f`, `--force`Ignore errors encountered when resetting the node.
`-h`, `--help`Help for `reset`.
diff --git a/embedded-cluster/embedded-cluster-shell.mdx b/embedded-cluster/embedded-cluster-shell.mdx new file mode 100644 index 0000000000..ef1d66ee9a --- /dev/null +++ b/embedded-cluster/embedded-cluster-shell.mdx @@ -0,0 +1,29 @@ +# shell + +This topic describes the options available with the Embedded Cluster `shell` command. + +## Usage + +```bash +sudo ./ shell [flags] +``` + +## Flags + + + + + + + + + + + + + + + + + +
FlagTypeDescription
`-c`, `--command`stringCommand to run instead of starting an interactive shell.
`-h`, `--help`Help for `shell`.
diff --git a/embedded-cluster/embedded-cluster-status.mdx b/embedded-cluster/embedded-cluster-status.mdx new file mode 100644 index 0000000000..4df608c027 --- /dev/null +++ b/embedded-cluster/embedded-cluster-status.mdx @@ -0,0 +1,29 @@ +# status + +This topic describes the options available with the Embedded Cluster `status` command. + +## Usage + +```bash +sudo ./ status [flags] +``` + +## Flags + + + + + + + + + + + + + + + + + +
FlagTypeDescription
`--json`Print status as JSON.
`-h`, `--help`Help for `status`.
diff --git a/embedded-cluster/embedded-cluster-support-bundle.mdx b/embedded-cluster/embedded-cluster-support-bundle.mdx new file mode 100644 index 0000000000..474dcd5902 --- /dev/null +++ b/embedded-cluster/embedded-cluster-support-bundle.mdx @@ -0,0 +1,29 @@ +# support-bundle + +This topic describes the options available with the Embedded Cluster `support-bundle` command. For more information about troubleshooting Embedded Cluster, see [Troubleshoot Embedded Cluster](embedded-troubleshooting). + +## Usage + +```bash +sudo ./ support-bundle [flags] +``` + +## Flags + + + + + + + + + + + + + + + + + +
FlagTypeDescription
`-o`, `--output`stringPath for the support bundle output file.
`-h`, `--help`Help for `support-bundle`.
diff --git a/embedded-cluster/embedded-cluster-upgrade.mdx b/embedded-cluster/embedded-cluster-upgrade.mdx new file mode 100644 index 0000000000..568124c784 --- /dev/null +++ b/embedded-cluster/embedded-cluster-upgrade.mdx @@ -0,0 +1,84 @@ +# upgrade + +This topic describes the options available with the Embedded Cluster `upgrade` command. For procedural steps, see [Perform updates in embedded clusters](updating-embedded). + +## Usage + +```bash +sudo ./ upgrade --license [flags] +``` + +## Flags + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FlagTypeDescription
`--config-values`stringPath to the [ConfigValues](/reference/custom-resource-configvalues) file for headless upgrades.
`--force-skip-ha-migration-check`Skip checks related to high availability (HA) migration. Use with caution.
`--headless`Run the upgrade without the interactive installer UI.
`--hostname`stringHostname to use for this node.
`--ignore-app-preflights`Skip application preflight checks.
`--ignore-host-preflights`Skip Embedded Cluster host preflight checks.
`--installer-password`stringPassword for the installer UI.
`--installer-port`intPort for the installer UI. **Default:** `30080`
`-l`, `--license`stringPath to the license file.
`--tls-cert`stringPath to a TLS certificate file for the installer.
`--tls-key`stringPath to a TLS private key file for the installer.
`-y`, `--yes`Assume yes to prompts.
`-h`, `--help`Help for `upgrade`.
diff --git a/embedded-cluster/embedded-cluster-version.mdx b/embedded-cluster/embedded-cluster-version.mdx new file mode 100644 index 0000000000..11d6a790f4 --- /dev/null +++ b/embedded-cluster/embedded-cluster-version.mdx @@ -0,0 +1,24 @@ +# version + +This topic describes the options available with the Embedded Cluster `version` command. + +## Usage + +```bash +sudo ./ version [flags] +``` + +## Flags + + + + + + + + + + + + +
FlagTypeDescription
`-h`, `--help`Help for `version`.
diff --git a/embedded-cluster/embedded-config.mdx b/embedded-cluster/embedded-config.mdx index 90ff89e52e..d88d59f7a9 100644 --- a/embedded-cluster/embedded-config.mdx +++ b/embedded-cluster/embedded-config.mdx @@ -2,7 +2,7 @@ import DoNotDowngrade from "../docs/partials/embedded-cluster/_warning-do-not-do # Embedded Cluster Config -This topic is a reference for the Replicated Embedded Cluster Config custom resource. For more information about Embedded Cluster, see [Use Embedded Cluster](/vendor/embedded-overview). +This topic is a reference for the Replicated Embedded Cluster Config custom resource. For more information about Embedded Cluster, see [Use Embedded Cluster](embedded-overview). ## Overview @@ -84,7 +84,7 @@ You can optionally customize node roles in the Embedded Cluster Config using the A common use case for customizing node roles is to assign workloads to specific nodes. For example, if your application has graphics processing unit (GPU) workloads, you could create a `custom` role that will add a `gpu=true` label to any node that is assigned the role. This allows you to then schedule GPU workloads on nodes labled `gpu=true`. -When the `roles` key is configured, users select one or more roles to assign to a node when it is joined to the cluster. For more information, see [Managing Multi-Node Clusters with Embedded Cluster](/enterprise/embedded-manage-nodes). +When the `roles` key is configured, users select one or more roles to assign to a node when it is joined to the cluster. For more information, see [Managing Multi-Node Clusters with Embedded Cluster](/embedded-cluster/v2/embedded-manage-nodes). If the `roles` key is _not_ configured, all nodes joined to the cluster are assigned the `controller` role. The `controller` role designates nodes that run the Kubernetes control plane. Controller nodes can also run other workloads, such as application or Replicated KOTS workloads. @@ -277,7 +277,7 @@ Each plugin that you add to the `extensions.velero.plugins` key must have a name #### Requirements * The image for the Velero plugin must be available publicly. Images behind authentication are not supported. -* The **Allow Disaster Recovery (Alpha)** option must be enabled in the license for Velero plugins to work. For more information about how to enable the Embedded Cluster disaster recovery feature, see [Disaster Recovery for Embedded Cluster (Alpha)](/vendor/embedded-disaster-recovery). +* The **Allow Disaster Recovery (Alpha)** option must be enabled in the license for Velero plugins to work. For more information about how to enable the Embedded Cluster disaster recovery feature, see [Disaster Recovery for Embedded Cluster (Alpha)](/embedded-cluster/v2/embedded-disaster-recovery). #### Example diff --git a/embedded-cluster/embedded-overview.mdx b/embedded-cluster/embedded-overview.mdx index 6bc0465543..229f99804c 100644 --- a/embedded-cluster/embedded-overview.mdx +++ b/embedded-cluster/embedded-overview.mdx @@ -11,23 +11,15 @@ This topic provides an introduction to Replicated Embedded Cluster. ## Comparison to Embedded Cluster v2 -### Breaking changes +### Removal of KOTS -Embedded Cluster v3 introduces the following breaking changes compared to Embedded Cluster v2: +Embedded Cluster 3.x removes KOTS from the architecture. That simplifies install and upgrade, but the KOTS CLI no longer works with Embedded Cluster, and there is no KOTS Admin Console in the previous form. The new installer provides the UI instead. Benefits include increased reliability, simpler feature work, and fewer dependencies running in the cluster. -* **Removal of KOTS:** Embedded Cluster 3.x removes KOTS from the architecture. That simplifies install and upgrade, but the KOTS CLI no longer works with Embedded Cluster, and there is no KOTS Admin Console in the previous form. The new installer provides the UI instead. Benefits include increased reliability, simpler feature work, and fewer dependencies running in the cluster. +Because KOTS is removed, you must include the [Replicated SDK](/vendor/replicated-sdk-overview) in your application to get reporting from application status informers (for example, for notifications and visibility in the Vendor Portal and Enterprise Portal). -* **Helm only with HelmChart v1beta2:** Embedded Cluster 3.x supports installing Helm charts only when each chart has a corresponding [HelmChart custom resource](/reference/custom-resource-helmchart-v2) that uses API version `helmchart/v1beta2`. Kustomize, plain Kubernetes manifests, and `HelmChart` `v1beta1` are not supported. +### Troubleshoot Preflight `v1beta3` -* **Replicated SDK required for status reporting:** Because KOTS is removed, you must include the [Replicated SDK](/vendor/replicated-sdk-overview) in your application to get reporting from application status informers (for example, for notifications and visibility in the Vendor Portal and Enterprise Portal). - -* **Some template functions not available:** Some Replicated template functions are not implemented in Embedded Cluster v3, either because they are discouraged in this model or because they are not yet ported. Contact Replicated if a missing template function blocks your release. - -* **Troubleshoot Preflight `v1beta3` required:** Preflight checks must use Troubleshoot `v1beta3`. `v1beta2` preflight specs are not supported. For more information, see [v1beta3 overview](https://troubleshoot.sh/docs/preflight/v1beta3-overview) in the Troubleshoot documentation. - -### Non-breaking change - -The default paths change from `/var/lib/embedded-cluster` and `/var/log/embedded-cluster` to `/var/lib/APP_SLUG` and `/var/log/APP_SLUG`, where `APP_SLUG` is your application slug. This better matches your brand and avoids Replicated-specific paths in the default layout. The change applies only to **new** installations. Upgrades from Embedded Cluster 2.x do not migrate or change existing data and log directories. +Preflight checks must use Troubleshoot `v1beta3`. `v1beta2` preflight specs are not supported. For more information, see [v1beta3 overview](https://troubleshoot.sh/docs/preflight/v1beta3-overview) in the Troubleshoot documentation. ## About installing with Embedded Cluster @@ -36,8 +28,8 @@ Embedded Cluster supports installations in online (internet-connected) environme The Embedded Cluster Config is included in the application release in the Replicated Vendor Portal and is used to generate the Embedded Cluster installation assets. Users can download these installation assets from the Replicated app service (`replicated.app`) on the command line, then run the Embedded Cluster installation command to install Kubernetes. Finally, users can install the application using the UI or CLI. During installation, users can optionally add nodes to the cluster and configure the application. For more information about how to install with Embedded Cluster, see: -* [Online Installation wtih Embedded Cluster](/enterprise/installing-embedded) -* [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap) +* [Online Installation wtih Embedded Cluster](installing-embedded) +* [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap) ### Embedded Cluster host preflight checks {#about-host-preflight-checks} @@ -59,13 +51,13 @@ Embedded Cluster host preflight checks have the following limitations: ### Multi-node installations -Embedded Cluster supports installations in mutli-node clusters. Your end customers can add nodes to a cluster during or after installation from the Admin Console. For more information, see [Manage Multi-Node Clusters with Embedded Cluster](/enterprise/embedded-manage-nodes). +Embedded Cluster supports installations in mutli-node clusters. Your end customers can add nodes to a cluster during or after installation from the Admin Console. For more information, see [Manage Multi-Node Clusters with Embedded Cluster](/embedded-cluster/v2/embedded-manage-nodes). #### High availability Multi-node clusters are not highly available by default. Enabling high availability (HA) requires that at least three controller nodes are present in the cluster. Users can enable HA when joining the third node. -For more information about creating HA multi-node clusters with Embedded Cluster, see [Enable High Availability](/enterprise/embedded-manage-nodes#ha) in _Managing Multi-Node Clusters with Embedded Cluster_. +For more information about creating HA multi-node clusters with Embedded Cluster, see [Enable High Availability](/embedded-cluster/v2/embedded-manage-nodes#ha) in _Managing Multi-Node Clusters with Embedded Cluster_. #### Node roles @@ -89,10 +81,10 @@ The built-in extensions installed by Embedded Cluster include: * **OpenEBS:** Embedded Cluster uses OpenEBS to provide local PersistentVolume (PV) storage, including the PV storage for rqlite used by KOTS. For more information, see the [OpenEBS](https://openebs.io/docs/) documentation. -* **(Air Gap Only) Image registry:** For air gap installations in environments with limited or no outbound internet access, Embedded Cluster installs an image registry where the images required to install and run the application are pushed. For more information about installing in air-gapped environments, see [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap). +* **(Air Gap Only) Image registry:** For air gap installations in environments with limited or no outbound internet access, Embedded Cluster installs an image registry where the images required to install and run the application are pushed. For more information about installing in air-gapped environments, see [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). -## Limtiations +## Limitations {#ec-limitations} * No disaster recovery support -* +* Some Replicated template functions are not implemented in Embedded Cluster v3, either because they are discouraged in this model or because they are not yet ported. Contact Replicated if a missing template function blocks your release. diff --git a/embedded-cluster/embedded-troubleshooting.mdx b/embedded-cluster/embedded-troubleshooting.mdx index dfbe838405..8d0d43f484 100644 --- a/embedded-cluster/embedded-troubleshooting.mdx +++ b/embedded-cluster/embedded-troubleshooting.mdx @@ -6,7 +6,7 @@ import TabItem from '@theme/TabItem'; # Troubleshoot Embedded Cluster -This topic provides information about troubleshooting Replicated Embedded Cluster installations. For more information about Embedded Cluster, including built-in extensions and architecture, see [Embedded Cluster Overview](/vendor/embedded-overview). +This topic provides information about troubleshooting Replicated Embedded Cluster installations. For more information about Embedded Cluster, including built-in extensions and architecture, see [Embedded Cluster Overview](embedded-overview). ## Troubleshoot with support bundles @@ -71,7 +71,7 @@ If there are any containerd services on the host, the NVIDIA GPU Operator will g This is the result of a known issue with v24.9.x of the NVIDIA GPU Operator. For more information about the known issue, see [container-toolkit does not modify the containerd config correctly when there are multiple instances of the containerd binary](https://github.com/NVIDIA/nvidia-container-toolkit/issues/982) in the nvidia-container-toolkit repository in GitHub. -For more information about including the GPU Operator as a Helm extension, see [NVIDIA GPU Operator](/vendor/embedded-using#nvidia-gpu-operator) in _Configure Embedded Cluster_. +For more information about including the GPU Operator as a Helm extension, see [NVIDIA GPU Operator](embedded-using#nvidia-gpu-operator) in _Configure Embedded Cluster_. #### Solution @@ -86,7 +86,7 @@ To troubleshoot: ``` Where `APP_SLUG` is the unique slug for the application. - For more information, see [Reset a Node](/enterprise/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. + For more information, see [Reset a Node](/embedded-cluster/v2/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. 1. Re-install with Embedded Cluster. @@ -152,7 +152,7 @@ Reasons can include: ``` Where `APP_SLUG` is the unique slug for the application. - For more information, see [Reset a Node](/enterprise/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. + For more information, see [Reset a Node](/embedded-cluster/v2/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. 1. Reinstall the application with different CIDRs using the `--cidr` flag: @@ -160,10 +160,10 @@ Reasons can include: sudo ./APP_SLUG install --license license.yaml --cidr 172.16.136.0/16 ``` - For more information, see [Embedded Cluster Install Options](/reference/embedded-cluster-install). + For more information, see [install](embedded-cluster-install). - Embedded Cluster 1.19.0 and later automatically sets the `net.ipv4.conf.default.arp_filter`, `net.ipv4.conf.default.arp_ignore`, and `net.ipv4.ip_forward` kernel parameters. Additionally, host preflight checks automatically run during installation to verify that the kernel parameters were set correctly. For more information about the Embedded Cluster preflight checks, see [About Host Preflight Checks](/vendor/embedded-overview#about-host-preflight-checks) in _Embedded Cluster Overview_. + Embedded Cluster 1.19.0 and later automatically sets the `net.ipv4.conf.default.arp_filter`, `net.ipv4.conf.default.arp_ignore`, and `net.ipv4.ip_forward` kernel parameters. Additionally, host preflight checks automatically run during installation to verify that the kernel parameters were set correctly. For more information about the Embedded Cluster preflight checks, see [About Host Preflight Checks](embedded-overview#about-host-preflight-checks) in _Embedded Cluster Overview_. If kernel parameters are not set correctly and these preflight checks fail, you might see a message such as `IP forwarding must be enabled.` or `ARP filtering must be disabled by default for newly created interfaces.`. @@ -185,7 +185,7 @@ Reasons can include: sudo ./APP_SLUG reset ``` Where `APP_SLUG` is the unique slug for the application. - For more information, see [Reset a Node](/enterprise/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. + For more information, see [Reset a Node](/embedded-cluster/v2/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. 1. Re-install with Embedded Cluster. diff --git a/embedded-cluster/installing-embedded-air-gap.mdx b/embedded-cluster/installing-embedded-air-gap.mdx index f03e6267b5..58d6e4e637 100644 --- a/embedded-cluster/installing-embedded-air-gap.mdx +++ b/embedded-cluster/installing-embedded-air-gap.mdx @@ -6,7 +6,7 @@ This topic describes how to install an application with Replicated Embedded Clus During installation, Embedded Cluster runs a default set of [host preflight checks](embedded-overview#about-host-preflight-checks) that verify the environment meets installer requirements. -For supported CLI flags, see [install](/reference/embedded-cluster-install). +For supported CLI flags, see [install](embedded-cluster-install). ## Overview @@ -16,10 +16,6 @@ The Embedded Cluster air gap bundle not only contains the assets normally contai During installation with Embedded Cluster in air gap environments, a Docker registry is deployed to the cluster to store application images. Infrastructure images (for Embedded Cluster and Helm extensions) and the Helm charts are preloaded on each node at installation time. -## Requirement - -Air gap installations are supported with Embedded Cluster version 1.3.0 or later. - ## Limitations and known issues Embedded Cluster installations in air gap environments have the following limitations and known issues: @@ -103,7 +99,7 @@ To install from the Vendor Portal: sudo ./APP_SLUG install --license license.yaml --airgap-bundle APP_SLUG.airgap ``` - Replace `APP_SLUG` with your application slug and use the correct paths for your license and bundle files. Add any other flags you need. For the full set of flags, see [install](/reference/embedded-cluster-install). + Replace `APP_SLUG` with your application slug and use the correct paths for your license and bundle files. Add any other flags you need. For the full set of flags, see [install](embedded-cluster-install). 1. Complete any prompts from the install command (for example, acceptance of a self-signed certificate and installer password). @@ -150,6 +146,6 @@ To install headlessly in an air gap environment, download and extract assets on sudo ./APP_SLUG install --license license.yaml --airgap-bundle APP_SLUG.airgap --headless --config-values PATH_TO_CONFIGVALUES --installer-password INSTALLER_PASSWORD ``` - Replace placeholders with values for your environment. Add any other flags you need. For the full set of flags, see [install](/reference/embedded-cluster-install). + Replace placeholders with values for your environment. Add any other flags you need. For the full set of flags, see [install](embedded-cluster-install). 1. Monitor the command output until the install completes, then access your application as you normally do. diff --git a/embedded-cluster/installing-embedded-automation.mdx b/embedded-cluster/installing-embedded-automation.mdx index 1afb377fd3..5027fc1c39 100644 --- a/embedded-cluster/installing-embedded-automation.mdx +++ b/embedded-cluster/installing-embedded-automation.mdx @@ -28,13 +28,13 @@ For more information, see [ConfigValues](/reference/custom-resource-configvalues ## Limitation -Automating deployment with Embedded Cluster is supported only for the initial installation. Performing automated (headless) updates of existing installations with Embedded Cluster is not supported. For information about how to update an existing installation through the Admin Console UI, see [Perform Updates in Embedded Clusters](/enterprise/updating-embedded). +Automating deployment with Embedded Cluster is supported only for the initial installation. Performing automated (headless) updates of existing installations with Embedded Cluster is not supported. For information about how to update an existing installation through the Admin Console UI, see [Perform Updates in Embedded Clusters](updating-embedded). ## Online (internet-connected) installation To install with Embedded Cluster in an online environment: -1. Follow the steps provided in the Vendor Portal to download and untar the Embedded Cluster installation assets. For more information, see [Online Installation with Embedded Cluster](/enterprise/installing-embedded). +1. Follow the steps provided in the Vendor Portal to download and untar the Embedded Cluster installation assets. For more information, see [Online Installation with Embedded Cluster](installing-embedded). 1. Run the following command to install: @@ -50,13 +50,13 @@ To install with Embedded Cluster in an online environment: * `ADMIN_CONSOLE_PASSWORD` is a password for accessing the Admin Console. * `PATH_TO_CONFIGVALUES` is the path to the ConfigValues file. - For more information about the `install` command options, see [install](/reference/embedded-cluster-install). + For more information about the `install` command options, see [install](embedded-cluster-install). ## Air gap installation To install with Embedded Cluster in an air-gapped environment: -1. Follow the steps provided in the Vendor Portal to download and untar the Embedded Cluster air gap installation assets. For more information, see [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap). +1. Follow the steps provided in the Vendor Portal to download and untar the Embedded Cluster air gap installation assets. For more information, see [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). 1. Ensure that the Embedded Cluster installation assets are available on the air-gapped machine, then run the following command to install: @@ -74,11 +74,11 @@ To install with Embedded Cluster in an air-gapped environment: * `ADMIN_CONSOLE_PASSWORD` with a password for accessing the Admin Console. * `PATH_TO_AIRGAP_BUNDLE` with the path to the Embedded Cluster `.airgap` bundle for the release. - For the complete list of `install` options, see [install](/reference/embedded-cluster-install). + For the complete list of `install` options, see [install](embedded-cluster-install). ## (Optional) Ignore preflight checks during installation -You can ignore both application-level preflight checks and Embedded Cluster host preflight checks during installation. When you ignore preflight checks, the installation proceeds despite any preflight failures. This is useful for automated installations in development environments. For more information about the `--ignore-host-preflights` and `--ignore-app-preflights` options, see [install](/reference/embedded-cluster-install). +You can ignore both application-level preflight checks and Embedded Cluster host preflight checks during installation. When you ignore preflight checks, the installation proceeds despite any preflight failures. This is useful for automated installations in development environments. For more information about the `--ignore-host-preflights` and `--ignore-app-preflights` options, see [install](embedded-cluster-install). Ignoring host preflight checks is _not_ recommended for production installations. diff --git a/embedded-cluster/installing-embedded.mdx b/embedded-cluster/installing-embedded.mdx index 23da11c6e4..f6869742ac 100644 --- a/embedded-cluster/installing-embedded.mdx +++ b/embedded-cluster/installing-embedded.mdx @@ -6,7 +6,7 @@ This topic describes how to install an application in an online (internet-connec During installation, Embedded Cluster runs a default set of [host preflight checks](embedded-overview#about-host-preflight-checks) that verify the environment meets installer requirements. -For supported CLI flags (proxy, network interface, and more), see [install](/reference/embedded-cluster-install). +For supported CLI flags (proxy, network interface, and more), see [install](embedded-cluster-install). ## Prerequisites @@ -92,6 +92,6 @@ Embedded Cluster 3.x supports headless installs. The way you start a headless in sudo ./APP_SLUG install --license LICENSE_FILE --headless --config-values PATH_TO_CONFIGVALUES --installer-password INSTALLER_PASSWORD ``` - Replace `APP_SLUG`, `LICENSE_FILE`, `PATH_TO_CONFIGVALUES`, and `INSTALLER_PASSWORD` with the values for your environment. Add any other flags you need. For the full set of flags, see [install](/reference/embedded-cluster-install). + Replace `APP_SLUG`, `LICENSE_FILE`, `PATH_TO_CONFIGVALUES`, and `INSTALLER_PASSWORD` with the values for your environment. Add any other flags you need. For the full set of flags, see [install](embedded-cluster-install). 1. Monitor the command output until the install completes, then access your application as you normally do. diff --git a/embedded-cluster/updating-embedded.mdx b/embedded-cluster/updating-embedded.mdx index 9d0d99fd95..662e9df39c 100644 --- a/embedded-cluster/updating-embedded.mdx +++ b/embedded-cluster/updating-embedded.mdx @@ -40,7 +40,7 @@ To upgrade more directly from the Vendor Portal: sudo ./APP_SLUG upgrade --license LICENSE_FILE ``` - Replace `APP_SLUG` with your application slug and `LICENSE_FILE` with the path to the license file. Add any other flags you use for this environment. For the full set of flags, see [install](/reference/embedded-cluster-install). + Replace `APP_SLUG` with your application slug and `LICENSE_FILE` with the path to the license file. Add any other flags you use for this environment. For the full set of flags, see [upgrade](embedded-cluster-upgrade). 1. When prompted, enter the password you set during installation to log in to the installer. To set a different password for the installer, use the `--installer-password` flag. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-install.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-install.mdx index 9a7e481900..99553d0227 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-install.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-install.mdx @@ -5,7 +5,7 @@ import DeprecatedPrivateCa from "../../docs/partials/embedded-cluster/_deprecate # install -This topic describes the options available with the Embedded Cluster install command. For more information about how to install with Embedded Cluster, see [Online Installation with Embedded Cluster](/enterprise/installing-embedded) or [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded). +This topic describes the options available with the Embedded Cluster install command. For more information about how to install with Embedded Cluster, see [Online Installation with Embedded Cluster](installing-embedded) or [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). ## Usage @@ -30,12 +30,12 @@ sudo ./ install --license [flags] `--admin-console-port`

Port on which to run the KOTS Admin Console. **Default**: By default, the Admin Console runs on port 30000.

-

**Limitation:** It is not possible to change the port for the Admin Console during a restore with Embedded Cluster. For more information, see [Disaster Recovery for Embedded Cluster (Alpha)](/vendor/embedded-disaster-recovery).

+

**Limitation:** It is not possible to change the port for the Admin Console during a restore with Embedded Cluster. For more information, see [Disaster Recovery for Embedded Cluster (Alpha)](embedded-disaster-recovery).

`--airgap-bundle` - The Embedded Cluster air gap bundle used for installations in air-gapped environments with no outbound internet access. For information about how to install in an air-gapped environment, see [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap). + The Embedded Cluster air gap bundle used for installations in air-gapped environments with no outbound internet access. For information about how to install in an air-gapped environment, see [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). `--cidr` @@ -47,7 +47,7 @@ sudo ./ install --license [flags] `--config-values` -

Path to the ConfigValues file for the application. The ConfigValues file can be used to pass the application configuration values from the command line during installation, such as when performing automated installations as part of CI/CD pipelines. For more information, see [Automate Installation with Embedded Cluster](/enterprise/installing-embedded-automation).

+

Path to the ConfigValues file for the application. The ConfigValues file can be used to pass the application configuration values from the command line during installation, such as when performing automated installations as part of CI/CD pipelines. For more information, see [Automate Installation with Embedded Cluster](installing-embedded-automation).

Requirement: Embedded Cluster 1.18.0 and later.

@@ -59,8 +59,8 @@ sudo ./ install --license [flags]

**Limitations:**

  • The data directory for Embedded Cluster cannot be changed after the cluster is installed.
  • -
  • For multi-node installations, the same data directory that is supplied at installation is used for all nodes joined to the cluster. You cannot choose a different data directory when joining nodes with the Embedded Cluster `join` command. For more information about joining nodes, see [Add Nodes to a Cluster](/enterprise/embedded-manage-nodes#add-nodes) in _Managing Multi-Node Clusters with Embedded Cluster_.
  • -
  • If you use the `--data-dir` flag to change the data directory during installation, then you must use the same location when restoring in a disaster recovery scenario. For more information about disaster recovery with Embedded Cluster, see [Disaster Recovery for Embedded Cluster](/vendor/embedded-disaster-recovery).
  • +
  • For multi-node installations, the same data directory that is supplied at installation is used for all nodes joined to the cluster. You cannot choose a different data directory when joining nodes with the Embedded Cluster `join` command. For more information about joining nodes, see [Add Nodes to a Cluster](embedded-manage-nodes#add-nodes) in _Managing Multi-Node Clusters with Embedded Cluster_.
  • +
  • If you use the `--data-dir` flag to change the data directory during installation, then you must use the same location when restoring in a disaster recovery scenario. For more information about disaster recovery with Embedded Cluster, see [Disaster Recovery for Embedded Cluster](embedded-disaster-recovery).
  • Replicated does not support using symlinks for the Embedded Cluster data directory. Use the `--data-dir` flag instead of symlinking `/var/lib/embedded-cluster`.
@@ -93,7 +93,7 @@ sudo ./ install --license [flags] `--ignore-host-preflights` -

When `--ignore-host-preflights` is passed, the host preflight checks are still run, but the user is prompted and can choose to continue with the installation if preflight failures occur. Additionally, the Admin Console still runs any application-specific preflight checks before the application is deployed. For more information about the Embedded Cluster host preflight checks, see [About Host Preflight Checks](/vendor/embedded-overview#about-host-preflight-checks) in _Using Embedded Cluster_.

+

When `--ignore-host-preflights` is passed, the host preflight checks are still run, but the user is prompted and can choose to continue with the installation if preflight failures occur. Additionally, the Admin Console still runs any application-specific preflight checks before the application is deployed. For more information about the Embedded Cluster host preflight checks, see [About Host Preflight Checks](embedded-overview#about-host-preflight-checks) in _Using Embedded Cluster_.

Ignoring host preflight checks is _not_ recommended for production installations.

diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-join-print-command.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-join-print-command.mdx index fbf003489b..1ebeaaf4db 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-join-print-command.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-join-print-command.mdx @@ -1,6 +1,6 @@ # join print-command -This topic describes the options available with the Embedded Cluster `join print-command` command. For more information about joining nodes, see [Manage Multi-Node Clusters with Embedded Cluster](/enterprise/embedded-manage-nodes). +This topic describes the options available with the Embedded Cluster `join print-command` command. For more information about joining nodes, see [Manage Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). ## Usage diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-join.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-join.mdx index 354a5c9826..364d13c178 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-join.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-join.mdx @@ -1,6 +1,6 @@ # join -This topic describes the options available with the Embedded Cluster `join` command. For more information about joining nodes, see [Manage Multi-Node Clusters with Embedded Cluster](/enterprise/embedded-manage-nodes). +This topic describes the options available with the Embedded Cluster `join` command. For more information about joining nodes, see [Manage Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). ## Usage diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-support-bundle.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-support-bundle.mdx index 5eba094dc4..ef4f9331d7 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-support-bundle.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-support-bundle.mdx @@ -1,6 +1,6 @@ # support-bundle -This topic describes the options available with the Embedded Cluster `support-bundle` command. For more information about generating support bundles for Embedded Cluster installations, see [Troubleshoot Embedded Cluster](/vendor/embedded-troubleshooting). +This topic describes the options available with the Embedded Cluster `support-bundle` command. For more information about generating support bundles for Embedded Cluster installations, see [Troubleshoot Embedded Cluster](embedded-troubleshooting). ## Usage diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-update.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-update.mdx index 6fc8474972..dab5e88aa8 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-update.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-cluster-update.mdx @@ -1,6 +1,6 @@ # update -This topic describes the options available with the Embedded Cluster `update` command. The `update` command allows you to update an instance with a new air gap bundle. This is part of the process for performing updates in air-gapped environments. For more information, see [Update in Air Gap Clusters](/enterprise/updating-embedded#update-in-air-gap-clusters) in _Perform Updates in Embedded Clusters_. +This topic describes the options available with the Embedded Cluster `update` command. The `update` command allows you to update an instance with a new air gap bundle. This is part of the process for performing updates in air-gapped environments. For more information, see [Update in Air Gap Clusters](updating-embedded#update-in-air-gap-clusters) in _Perform Updates in Embedded Clusters_. ## Usage diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-config.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-config.mdx index 15ac79ea76..b76beaf880 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-config.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-config.mdx @@ -2,7 +2,7 @@ import DoNotDowngrade from "../../docs/partials/embedded-cluster/_warning-do-not # Embedded Cluster Config -This topic is a reference for the Replicated Embedded Cluster Config custom resource. For more information about Embedded Cluster, see [Use Embedded Cluster](/vendor/embedded-overview). +This topic is a reference for the Replicated Embedded Cluster Config custom resource. For more information about Embedded Cluster, see [Use Embedded Cluster](embedded-overview). ## Overview @@ -84,7 +84,7 @@ You can optionally customize node roles in the Embedded Cluster Config using the A common use case for customizing node roles is to assign workloads to specific nodes. For example, if your application has graphics processing unit (GPU) workloads, you could create a `custom` role that will add a `gpu=true` label to any node that is assigned the role. This allows you to then schedule GPU workloads on nodes labled `gpu=true`. -When the `roles` key is configured, users select one or more roles to assign to a node when it is joined to the cluster. For more information, see [Managing Multi-Node Clusters with Embedded Cluster](/enterprise/embedded-manage-nodes). +When the `roles` key is configured, users select one or more roles to assign to a node when it is joined to the cluster. For more information, see [Managing Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). If the `roles` key is _not_ configured, all nodes joined to the cluster are assigned the `controller` role. The `controller` role designates nodes that run the Kubernetes control plane. Controller nodes can also run other workloads, such as application or Replicated KOTS workloads. @@ -277,7 +277,7 @@ Each plugin that you add to the `extensions.velero.plugins` key must have a name #### Requirements * The image for the Velero plugin must be available publicly. Images behind authentication are not supported. -* The **Allow Disaster Recovery (Alpha)** option must be enabled in the license for Velero plugins to work. For more information about how to enable the Embedded Cluster disaster recovery feature, see [Disaster Recovery for Embedded Cluster (Alpha)](/vendor/embedded-disaster-recovery). +* The **Allow Disaster Recovery (Alpha)** option must be enabled in the license for Velero plugins to work. For more information about how to enable the Embedded Cluster disaster recovery feature, see [Disaster Recovery for Embedded Cluster (Alpha)](embedded-disaster-recovery). #### Example diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx index aecf12ae69..5f4fe6571e 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-disaster-recovery.mdx @@ -44,7 +44,7 @@ Embedded Cluster disaster recovery has the following limitations and known issue * Velero is installed only during the initial installation process. Enabling the disaster recovery license field for customers after they have already installed will not do anything. -* If the `--admin-console-port` flag was used during install to change the port for the Admin Console, note that during a restore the Admin Console port will be used from the backup and cannot be changed. For more information, see [install](/reference/embedded-cluster-install). +* If the `--admin-console-port` flag was used during install to change the port for the Admin Console, note that during a restore the Admin Console port will be used from the backup and cannot be changed. For more information, see [install](embedded-cluster-install). ## Configure disaster recovery @@ -216,7 +216,7 @@ To restore from a backup: 1. SSH onto a new machine where you want to restore from a backup. -1. Download the Embedded Cluster installation assets for the version of the application that was included in the backup. You can find the command for downloading Embedded Cluster installation assets in the **Embedded Cluster install instructions dialog** for the customer. For more information, [Online Installation with Embedded Cluster](/enterprise/installing-embedded). +1. Download the Embedded Cluster installation assets for the version of the application that was included in the backup. You can find the command for downloading Embedded Cluster installation assets in the **Embedded Cluster install instructions dialog** for the customer. For more information, [Online Installation with Embedded Cluster](installing-embedded). :::note The version of the Embedded Cluster installation assets must match the version that is in the backup. For more information, see [Limitations and Known Issues](#limitations-and-known-issues). @@ -231,11 +231,11 @@ To restore from a backup: Note the following requirements and guidance for the `restore` command: - * If the installation is behind a proxy, the same proxy settings provided during install must be provided to the restore command using `--http-proxy`, `--https-proxy`, and `--no-proxy`. For more information, see [install](/reference/embedded-cluster-install). + * If the installation is behind a proxy, the same proxy settings provided during install must be provided to the restore command using `--http-proxy`, `--https-proxy`, and `--no-proxy`. For more information, see [install](embedded-cluster-install). - * If the `--cidr` flag was used during install to the set IP address ranges for Pods and Services, this flag must be provided with the same CIDR during the restore. If this flag is not provided or is provided with a different CIDR, the restore will fail with an error message telling you to rerun with the appropriate value. However, it will take some time before that error occurs. For more information, see [install](/reference/embedded-cluster-install). + * If the `--cidr` flag was used during install to the set IP address ranges for Pods and Services, this flag must be provided with the same CIDR during the restore. If this flag is not provided or is provided with a different CIDR, the restore will fail with an error message telling you to rerun with the appropriate value. However, it will take some time before that error occurs. For more information, see [install](embedded-cluster-install). - * If the `--local-artifact-mirror-port` flag was used during install to change the port for the Local Artifact Mirror (LAM), you can optionally use the `--local-artifact-mirror-port` flag to choose a different LAM port during restore. For example, `restore --local-artifact-mirror-port=50000`. If no LAM port is provided during restore, the LAM port that was supplied during installation will be used. For more information, see [install](/reference/embedded-cluster-install). + * If the `--local-artifact-mirror-port` flag was used during install to change the port for the Local Artifact Mirror (LAM), you can optionally use the `--local-artifact-mirror-port` flag to choose a different LAM port during restore. For example, `restore --local-artifact-mirror-port=50000`. If no LAM port is provided during restore, the LAM port that was supplied during installation will be used. For more information, see [install](embedded-cluster-install). You will be guided through the process of restoring from a backup. @@ -254,7 +254,7 @@ To restore from a backup: ![Restore from detected backup prompt on the command line](/images/dr-restore-admin-console-url.png) [View a larger version of this image](/images/dr-restore-admin-console-url.png) -1. (Optional) If the cluster should have multiple nodes, go to the Admin Console to get a join command and join additional nodes to the cluster. For more information, see [Manage Multi-Node Clusters with Embedded Cluster](/enterprise/embedded-manage-nodes). +1. (Optional) If the cluster should have multiple nodes, go to the Admin Console to get a join command and join additional nodes to the cluster. For more information, see [Manage Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). 1. Type `continue` when you are ready to proceed with the restore process. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx index 1768d6022e..2f8a698955 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx @@ -19,11 +19,11 @@ This section describes how to join nodes to a cluster with Embedded Cluster. Multi-node clusters with Embedded Cluster have the following limitations: -* Setting node roles with the Embedded Cluster Config [roles](embedded-config#roles-beta) key is Beta. +* Setting node roles with the Embedded Cluster Config [roles](embedded-config#roles) key is Beta. -* The first node added to the cluster is always a controller and cannot be assigned any custom roles. For more information about configuring node roles, see [roles](embedded-config#roles-beta) in _Embedded Cluster Config_. +* The first node added to the cluster is always a controller and cannot be assigned any custom roles. For more information about configuring node roles, see [roles](embedded-config#roles) in _Embedded Cluster Config_. -* The same Embedded Cluster data directory used at installation is used for all nodes joined to the cluster. This is either the default `/var/lib/embedded-cluster` directory or the directory set with the [`--data-dir`](/reference/embedded-cluster-install#flags) flag. You cannot choose a different data directory for Embedded Cluster when joining nodes. +* The same Embedded Cluster data directory used at installation is used for all nodes joined to the cluster. This is either the default `/var/lib/embedded-cluster` directory or the directory set with the [`--data-dir`](embedded-cluster-install#flags) flag. You cannot choose a different data directory for Embedded Cluster when joining nodes. * More than one controller node should not be joined at the same time. When joining a controller node, a warning is printed that explains that the user should not attempt to join another node until the controller node joins successfully. @@ -39,17 +39,17 @@ This section describes how to add nodes to a cluster with Embedded Cluster. To add a node to a cluster with Embedded Cluster: -1. (Optional) In the Embedded Cluster Config, configure the `roles` key to customize node roles. For more information, see [roles](embedded-config#roles-beta) in _Embedded Cluster Config_. When you are done, create and promote a new release with the updated Config. +1. (Optional) In the Embedded Cluster Config, configure the `roles` key to customize node roles. For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. When you are done, create and promote a new release with the updated Config. 1. Do one of the following: - 1. Follow the steps in [Online Installation with Embedded Cluster](/enterprise/installing-embedded) or [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap)to install. When you see the **Nodes** screen as part of the installation flow in the Admin Console, continue to the next step. + 1. Follow the steps in [Online Installation with Embedded Cluster](installing-embedded) or [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap) to install. When you see the **Nodes** screen as part of the installation flow in the Admin Console, continue to the next step. 1. Otherwise, to add a node to an existing cluster: 1. Log in to the Admin Console. - 1. If you promoted a new release that configures the `roles` key in the Embedded Cluster Config, update the instance to the new version. See [Perform Updates in Embedded Clusters](/enterprise/updating-embedded). + 1. If you promoted a new release that configures the `roles` key in the Embedded Cluster Config, update the instance to the new version. See [Perform Updates in Embedded Clusters](updating-embedded). 1. Go to **Cluster Management > Add node** at the top of the page. @@ -110,7 +110,7 @@ Users are automatically prompted to enable HA when joining the third controller -For more information about the Embedded Cluster built-in extensions, see [Built-In Extensions](/vendor/embedded-overview#built-in-extensions) in _Embedded Cluster Overview_. +For more information about the Embedded Cluster built-in extensions, see [Built-In Extensions](embedded-overview#built-in-extensions) in _Embedded Cluster Overview_. ### Requirements @@ -126,7 +126,7 @@ Enabling high availability has the following requirements: Consider the following best practices and recommendations for creating HA clusters: -* At least three _controller_ nodes that run the Kubernetes control plane are required for HA. This is because clusters use a quorum system, in which more than half the nodes must be up and reachable. In clusters with three controller nodes, the Kubernetes control plane can continue to operate if one node fails because a quorum can still be reached by the remaining two nodes. By default, with Embedded Cluster, all new nodes added to a cluster are controller nodes. For information about customizing the controller node role, see [roles](embedded-config#roles-beta) in _Embedded Cluster Config_. +* At least three _controller_ nodes that run the Kubernetes control plane are required for HA. This is because clusters use a quorum system, in which more than half the nodes must be up and reachable. In clusters with three controller nodes, the Kubernetes control plane can continue to operate if one node fails because a quorum can still be reached by the remaining two nodes. By default, with Embedded Cluster, all new nodes added to a cluster are controller nodes. For information about customizing the controller node role, see [roles](embedded-config#roles) in _Embedded Cluster Config_. * Always use an odd number of controller nodes in HA clusters. Using an odd number of controller nodes ensures that the cluster can make decisions efficiently with quorum calculations. Clusters with an odd number of controller nodes also avoid split-brain scenarios where the cluster runs as two, independent groups of nodes, resulting in inconsistencies and conflicts. @@ -138,7 +138,7 @@ You can enable high availability for a multi-node cluster when joining the third To create a multi-node HA cluster: -1. Set up a cluster with at least two controller nodes. You can do an online (internet-connected) or air gap installation. For more information, see [Online Installation with Embedded Cluster](/enterprise/installing-embedded) or [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap). +1. Set up a cluster with at least two controller nodes. You can do an online (internet-connected) or air gap installation. For more information, see [Online Installation with Embedded Cluster](installing-embedded) or [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). 1. Get the commands for downloading the Embedded Cluster binary, extracting the binary, and joining the third controller node either in the Admin Console **Cluster Management** tab or by running the following command on an existing node: @@ -171,7 +171,7 @@ Where `APP_SLUG` is the unique slug for the application. ## Reset nodes and remove clusters -This section describes how to reset individual nodes and how to delete an entire multi-node cluster using the Embedded Cluster [reset](/reference/embedded-cluster-reset) command. +This section describes how to reset individual nodes and how to delete an entire multi-node cluster using the Embedded Cluster [reset](embedded-cluster-reset) command. ### About the `reset` command @@ -186,7 +186,7 @@ The `reset` command performs the following steps: 1. Remove all Embedded Cluster files 1. Reboot the node -For more information about the command, see [reset](/reference/embedded-cluster-reset). +For more information about the command, see [reset](embedded-cluster-reset). ### Limitations and best practices diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx index 0cbff2bfba..6d14afd528 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx @@ -32,8 +32,8 @@ The following diagram demonstrates how Kubernetes and an application are install As shown in the diagram above, the Embedded Cluster Config is included in the application release in the Replicated Vendor Portal and is used to generate the Embedded Cluster installation assets. Users can download these installation assets from the Replicated app service (`replicated.app`) on the command line, then run the Embedded Cluster installation command to install Kubernetes and the KOTS Admin Console. Finally, users access the Admin Console to optionally add nodes to the cluster and to configure and install the application. For more information about how to install with Embedded Cluster, see: -* [Online Installation wtih Embedded Cluster](/enterprise/installing-embedded) -* [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap) +* [Online Installation wtih Embedded Cluster](installing-embedded) +* [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap) ### Embedded Cluster host preflight checks {#about-host-preflight-checks} @@ -55,13 +55,13 @@ Embedded Cluster host preflight checks have the following limitations: ### Multi-node installations -Embedded Cluster supports installations in mutli-node clusters. Your end customers can add nodes to a cluster during or after installation from the Admin Console. For more information, see [Manage Multi-Node Clusters with Embedded Cluster](/enterprise/embedded-manage-nodes). +Embedded Cluster supports installations in mutli-node clusters. Your end customers can add nodes to a cluster during or after installation from the Admin Console. For more information, see [Manage Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). #### High availability Multi-node clusters are not highly available by default. Enabling high availability (HA) requires that at least three controller nodes are present in the cluster. Users can enable HA when joining the third node. -For more information about creating HA multi-node clusters with Embedded Cluster, see [Enable High Availability](/enterprise/embedded-manage-nodes#ha) in _Managing Multi-Node Clusters with Embedded Cluster_. +For more information about creating HA multi-node clusters with Embedded Cluster, see [Enable High Availability](embedded-manage-nodes#ha) in _Managing Multi-Node Clusters with Embedded Cluster_. #### Node roles @@ -127,9 +127,9 @@ The built-in extensions installed by Embedded Cluster include: * **OpenEBS:** Embedded Cluster uses OpenEBS to provide local PersistentVolume (PV) storage, including the PV storage for rqlite used by KOTS. For more information, see the [OpenEBS](https://openebs.io/docs/) documentation. -* **(Disaster Recovery Only) Velero:** If the installation uses the Embedded Cluster disaster recovery feature, Embedded Cluster installs Velero, which is an open-source tool that provides backup and restore functionality. For more information about Velero, see the [Velero](https://velero.io/docs/latest/) documentation. For more information about the disaster recovery feature, see [Disaster Recovery for Embedded Cluster (Alpha)](/vendor/embedded-disaster-recovery). +* **(Disaster Recovery Only) Velero:** If the installation uses the Embedded Cluster disaster recovery feature, Embedded Cluster installs Velero, which is an open-source tool that provides backup and restore functionality. For more information about Velero, see the [Velero](https://velero.io/docs/latest/) documentation. For more information about the disaster recovery feature, see [Disaster Recovery for Embedded Cluster (Alpha)](embedded-disaster-recovery). -* **(Air Gap Only) Image registry:** For air gap installations in environments with limited or no outbound internet access, Embedded Cluster installs an image registry where the images required to install and run the application are pushed. For more information about installing in air-gapped environments, see [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap). +* **(Air Gap Only) Image registry:** For air gap installations in environments with limited or no outbound internet access, Embedded Cluster installs an image registry where the images required to install and run the application are pushed. For more information about installing in air-gapped environments, see [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). ## Limitations {#ec-limitations} @@ -137,11 +137,11 @@ Embedded Cluster has the following limitations: * **Migration from kURL**: We are helping several customers migrate from kURL to Embedded Cluster. For more information about migrating from kURL to Embedded Cluster, including key considerations before migrating and an example step-by-step migration process, see [Replicated kURL to Embedded Cluster Migration](https://docs.google.com/document/d/1Qw9owCK4xNXHRRmxDgAq_NJdxQ4O-6w2rWk_luzBD7A/edit?tab=t.0). For additional questions and to begin the migration process for your application, reach out to Alex Parker at alexp@replicated.com. -* **Disaster recovery is in alpha**: Disaster Recovery for Embedded Cluster installations is in alpha. For more information, see [Disaster Recovery for Embedded Cluster (Alpha)](/vendor/embedded-disaster-recovery). +* **Disaster recovery is in alpha**: Disaster Recovery for Embedded Cluster installations is in alpha. For more information, see [Disaster Recovery for Embedded Cluster (Alpha)](embedded-disaster-recovery). * **Partial rollback support**: In Embedded Cluster 1.17.0 and later, rollbacks are supported only when rolling back to a version where there is no change to the [Embedded Cluster Config](embedded-config) compared to the currently-installed version. For example, users can roll back to release version 1.0.0 after upgrading to 1.1.0 only if both 1.0.0 and 1.1.0 use the same Embedded Cluster Config. For more information about how to enable rollbacks for your application in the KOTS Application custom resource, see [allowRollback](/reference/custom-resource-application#allowrollback) in _Application_. -* **Changing node hostnames is not supported**: After a host is added to a cluster, Kubernetes assumes that the hostname and IP address of the host will not change. If you need to change the hostname or IP address of a node, you must first remove the node from the cluster, reset it, and then rejoin it. For information about how to reset nodes with Embedded Cluster, see [Reset a Node](/enterprise/embedded-manage-nodes#reset-a-node). For information about the requirements for naming nodes, see [Node name uniqueness](https://kubernetes.io/docs/concepts/architecture/nodes/#node-name-uniqueness) in the Kubernetes documentation. +* **Changing node hostnames is not supported**: After a host is added to a cluster, Kubernetes assumes that the hostname and IP address of the host will not change. If you need to change the hostname or IP address of a node, you must first remove the node from the cluster, reset it, and then rejoin it. For information about how to reset nodes with Embedded Cluster, see [Reset a Node](embedded-manage-nodes#reset-a-node). For information about the requirements for naming nodes, see [Node name uniqueness](https://kubernetes.io/docs/concepts/architecture/nodes/#node-name-uniqueness) in the Kubernetes documentation. :::note If you need to change the hostname or IP address of a controller node in a three-node cluster, Replicated recommends that you join a fourth controller node to the cluster before removing the target node. This ensures that you maintain a minimum of three nodes for the Kubernetes control plane. You can add and remove worker nodes as needed because they do not have any control plane components. For information about how to remove controller nodes, see [Remove or Replace a Controller](https://docs.k0sproject.io/stable/remove_controller/) in the k0s documentation. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx index fda8dbb6ba..d3873a2c15 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx @@ -6,7 +6,7 @@ import TabItem from '@theme/TabItem'; # Troubleshoot Embedded Cluster -This topic provides information about troubleshooting Replicated Embedded Cluster installations. For more information about Embedded Cluster, including built-in extensions and architecture, see [Embedded Cluster Overview](/vendor/embedded-overview). +This topic provides information about troubleshooting Replicated Embedded Cluster installations. For more information about Embedded Cluster, including built-in extensions and architecture, see [Embedded Cluster Overview](embedded-overview). ## Troubleshoot with support bundles @@ -71,7 +71,7 @@ If there are any containerd services on the host, the NVIDIA GPU Operator will g This is the result of a known issue with v24.9.x of the NVIDIA GPU Operator. For more information about the known issue, see [container-toolkit does not modify the containerd config correctly when there are multiple instances of the containerd binary](https://github.com/NVIDIA/nvidia-container-toolkit/issues/982) in the nvidia-container-toolkit repository in GitHub. -For more information about including the GPU Operator as a Helm extension, see [NVIDIA GPU Operator](/vendor/embedded-using#nvidia-gpu-operator) in _Configure Embedded Cluster_. +For more information about including the GPU Operator as a Helm extension, see [NVIDIA GPU Operator](embedded-using#nvidia-gpu-operator) in _Configure Embedded Cluster_. #### Solution @@ -86,7 +86,7 @@ To troubleshoot: ``` Where `APP_SLUG` is the unique slug for the application. - For more information, see [Reset a Node](/enterprise/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. + For more information, see [Reset a Node](embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. 1. Re-install with Embedded Cluster. @@ -152,7 +152,7 @@ Reasons can include: ``` Where `APP_SLUG` is the unique slug for the application. - For more information, see [Reset a Node](/enterprise/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. + For more information, see [Reset a Node](embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. 1. Reinstall the application with different CIDRs using the `--cidr` flag: @@ -160,10 +160,10 @@ Reasons can include: sudo ./APP_SLUG install --license license.yaml --cidr 172.16.136.0/16 ``` - For more information, see [Embedded Cluster Install Options](/reference/embedded-cluster-install). + For more information, see [Embedded Cluster Install Options](embedded-cluster-install). - Embedded Cluster 1.19.0 and later automatically sets the `net.ipv4.conf.default.arp_filter`, `net.ipv4.conf.default.arp_ignore`, and `net.ipv4.ip_forward` kernel parameters. Additionally, host preflight checks automatically run during installation to verify that the kernel parameters were set correctly. For more information about the Embedded Cluster preflight checks, see [About Host Preflight Checks](/vendor/embedded-overview#about-host-preflight-checks) in _Embedded Cluster Overview_. + Embedded Cluster 1.19.0 and later automatically sets the `net.ipv4.conf.default.arp_filter`, `net.ipv4.conf.default.arp_ignore`, and `net.ipv4.ip_forward` kernel parameters. Additionally, host preflight checks automatically run during installation to verify that the kernel parameters were set correctly. For more information about the Embedded Cluster preflight checks, see [About Host Preflight Checks](embedded-overview#about-host-preflight-checks) in _Embedded Cluster Overview_. If kernel parameters are not set correctly and these preflight checks fail, you might see a message such as `IP forwarding must be enabled.` or `ARP filtering must be disabled by default for newly created interfaces.`. @@ -185,7 +185,7 @@ Reasons can include: sudo ./APP_SLUG reset ``` Where `APP_SLUG` is the unique slug for the application. - For more information, see [Reset a Node](/enterprise/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. + For more information, see [Reset a Node](embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. 1. Re-install with Embedded Cluster. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx index 5bd6af5901..8528269d83 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx @@ -12,10 +12,6 @@ The Embedded Cluster air gap bundle not only contains the assets normally contai During installation with Embedded Cluster in air gap environments, a Docker registry is deployed to the cluster to store application images. Infrastructure images (for Embedded Cluster and Helm extensions) and the Helm charts are preloaded on each node at installation time. -## Requirement - -Air gap installations are supported with Embedded Cluster version 1.3.0 or later. - ## Limitations and known issues Embedded Cluster installations in air gap environments have the following limitations and known issues: @@ -82,11 +78,11 @@ To install with Embedded Cluster in an air gap environment: ``` Where `APP_SLUG` is the unique application slug. - For the list of flags supported with the Embedded Cluster `install` command, see [install](/reference/embedded-cluster-install). + For the list of flags supported with the Embedded Cluster `install` command, see [install](embedded-cluster-install). 1. When prompted, enter a password for accessing the KOTS Admin Console. - The installation command takes a few minutes to complete. During installation, Embedded Cluster completes tasks to prepare the cluster and install KOTS in the cluster. Embedded Cluster also automatically runs a default set of [_host preflight checks_](/vendor/embedded-overview#about-host-preflight-checks) which verify that the environment meets the requirements for the installer. + The installation command takes a few minutes to complete. During installation, Embedded Cluster completes tasks to prepare the cluster and install KOTS in the cluster. Embedded Cluster also automatically runs a default set of [_host preflight checks_](embedded-overview#about-host-preflight-checks) which verify that the environment meets the requirements for the installer. **Example output:** @@ -119,7 +115,7 @@ To install with Embedded Cluster in an air gap environment: 1. On the **Nodes** page, you can view details about the machine where you installed, including its node role, status, CPU, and memory. - Optionally, add nodes to the cluster before deploying the application. For more information about joining nodes, see [Manage Multi-Node Clusters with Embedded Cluster](/enterprise/embedded-manage-nodes). Click **Continue**. + Optionally, add nodes to the cluster before deploying the application. For more information about joining nodes, see [Manage Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). Click **Continue**. 1. On the **Configure [App Name]** screen, complete the fields for the application configuration options. Click **Continue**. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-automation.mdx b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-automation.mdx index 7aff906b8c..da933db8a0 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-automation.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-automation.mdx @@ -28,13 +28,13 @@ For more information, see [ConfigValues](/reference/custom-resource-configvalues ## Limitation -Automating deployment with Embedded Cluster is supported only for the initial installation. Performing automated (headless) updates of existing installations with Embedded Cluster is not supported. For information about how to update an existing installation through the Admin Console UI, see [Perform Updates in Embedded Clusters](/enterprise/updating-embedded). +Automating deployment with Embedded Cluster is supported only for the initial installation. Performing automated (headless) updates of existing installations with Embedded Cluster is not supported. For information about how to update an existing installation through the Admin Console UI, see [Perform Updates in Embedded Clusters](updating-embedded). ## Online (internet-connected) installation To install with Embedded Cluster in an online environment: -1. Follow the steps provided in the Vendor Portal to download and untar the Embedded Cluster installation assets. For more information, see [Online Installation with Embedded Cluster](/enterprise/installing-embedded). +1. Follow the steps provided in the Vendor Portal to download and untar the Embedded Cluster installation assets. For more information, see [Online Installation with Embedded Cluster](installing-embedded). 1. Run the following command to install: @@ -50,13 +50,13 @@ To install with Embedded Cluster in an online environment: * `ADMIN_CONSOLE_PASSWORD` is a password for accessing the Admin Console. * `PATH_TO_CONFIGVALUES` is the path to the ConfigValues file. - For more information about the `install` command options, see [install](/reference/embedded-cluster-install). + For more information about the `install` command options, see [install](embedded-cluster-install). ## Air gap installation To install with Embedded Cluster in an air-gapped environment: -1. Follow the steps provided in the Vendor Portal to download and untar the Embedded Cluster air gap installation assets. For more information, see [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap). +1. Follow the steps provided in the Vendor Portal to download and untar the Embedded Cluster air gap installation assets. For more information, see [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). 1. Ensure that the Embedded Cluster installation assets are available on the air-gapped machine, then run the following command to install: @@ -74,11 +74,11 @@ To install with Embedded Cluster in an air-gapped environment: * `ADMIN_CONSOLE_PASSWORD` with a password for accessing the Admin Console. * `PATH_TO_AIRGAP_BUNDLE` with the path to the Embedded Cluster `.airgap` bundle for the release. - For the complete list of `install` options, see [install](/reference/embedded-cluster-install). + For the complete list of `install` options, see [install](embedded-cluster-install). ## (Optional) Ignore preflight checks during installation -You can ignore both application-level preflight checks and Embedded Cluster host preflight checks during installation. When you ignore preflight checks, the installation proceeds despite any preflight failures. This is useful for automated installations in development environments. For more information about the `--ignore-host-preflights` and `--ignore-app-preflights` options, see [install](/reference/embedded-cluster-install). +You can ignore both application-level preflight checks and Embedded Cluster host preflight checks during installation. When you ignore preflight checks, the installation proceeds despite any preflight failures. This is useful for automated installations in development environments. For more information about the `--ignore-host-preflights` and `--ignore-app-preflights` options, see [install](embedded-cluster-install). Ignoring host preflight checks is _not_ recommended for production installations. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded.mdx b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded.mdx index 10f19171de..c8a5b04a60 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded.mdx @@ -2,9 +2,9 @@ import Prerequisites from "../../docs/partials/install/_ec-prereqs.mdx" # Online installation with Embedded Cluster -This topic describes how to install an application in an online (internet-connected) environment with the Replicated Embedded Cluster installer. For information about air gap installations with Embedded Cluster, see [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap). +This topic describes how to install an application in an online (internet-connected) environment with the Replicated Embedded Cluster installer. For information about air gap installations with Embedded Cluster, see [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). -For the list of all Embedded Cluster installation options, including how to install behind a proxy, how to use a specific network interface, and more, see [install](/reference/embedded-cluster-install). +For the list of all Embedded Cluster installation options, including how to install behind a proxy, how to use a specific network interface, and more, see [install](embedded-cluster-install). ## Prerequisites @@ -12,7 +12,7 @@ Before you install, complete the following prerequisites: -* Ensure that the required domains are accessible from servers performing the installation. See [Firewall Openings for Online Installations](/enterprise/installing-embedded-requirements#firewall). +* Ensure that the required domains are accessible from servers performing the installation. See [Firewall Openings for Online Installations](installing-embedded-requirements#firewall). ## Install @@ -50,11 +50,11 @@ To install an application with Embedded Cluster: * `APP_SLUG` is the unique slug for the application. * `LICENSE_FILE` is the customer license. - For the list of all Embedded Cluster installation options, including how to install behind a proxy, how to use a specific network interface, and more, see [install](/reference/embedded-cluster-install). + For the list of all Embedded Cluster installation options, including how to install behind a proxy, how to use a specific network interface, and more, see [install](embedded-cluster-install). 1. When prompted, enter a password for accessing the KOTS Admin Console. - The installation command takes a few minutes to complete. During installation, Embedded Cluster completes tasks to prepare the cluster and install KOTS in the cluster. Embedded Cluster also automatically runs a default set of [_host preflight checks_](/vendor/embedded-overview#about-host-preflight-checks) which verify that the environment meets the requirements for the installer. + The installation command takes a few minutes to complete. During installation, Embedded Cluster completes tasks to prepare the cluster and install KOTS in the cluster. Embedded Cluster also automatically runs a default set of [_host preflight checks_](embedded-overview#about-host-preflight-checks) which verify that the environment meets the requirements for the installer. **Example output:** @@ -87,7 +87,7 @@ To install an application with Embedded Cluster: 1. On the **Nodes** page, you can view details about the machine where you installed, including its node role, status, CPU, and memory. - Optionally, add nodes to the cluster before deploying the application. For more information about joining nodes, see [Manage Multi-Node Clusters with Embedded Cluster](/enterprise/embedded-manage-nodes). Click **Continue**. + Optionally, add nodes to the cluster before deploying the application. For more information about joining nodes, see [Manage Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). Click **Continue**. 1. On the **Configure [App Name]** screen, complete the fields for the application configuration options. Click **Continue**. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx b/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx index 6374b5769a..5ab2803a6c 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx @@ -6,7 +6,7 @@ import Overview from "../../docs/partials/embedded-cluster/_update-overview.mdx" # Perform updates in embedded clusters -This topic describes how to perform updates for [Replicated Embedded Cluster](/vendor/embedded-overview) installations. +This topic describes how to perform updates for [Replicated Embedded Cluster](embedded-overview) installations. ## Overview diff --git a/sidebarEmbeddedCluster.js b/sidebarEmbeddedCluster.js index fb0ebd19d0..2b7af8127c 100644 --- a/sidebarEmbeddedCluster.js +++ b/sidebarEmbeddedCluster.js @@ -9,5 +9,25 @@ module.exports = { "installing-embedded-automation", "updating-embedded", "embedded-troubleshooting", + { + type: "category", + label: "Embedded Cluster Commands", + items: [ + "embedded-cluster-completion", + "embedded-cluster-create-join-bundle", + "embedded-cluster-create-upgrade-bundle", + "embedded-cluster-enable-ha", + "embedded-cluster-install", + "embedded-cluster-node-join", + "embedded-cluster-node-upgrade", + "embedded-cluster-remove-node", + "embedded-cluster-reset", + "embedded-cluster-shell", + "embedded-cluster-status", + "embedded-cluster-support-bundle", + "embedded-cluster-upgrade", + "embedded-cluster-version", + ], + }, ], }; From a3a3ca5642c465790e97f388a96ac5462f743e0f Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Thu, 2 Apr 2026 12:50:57 -0600 Subject: [PATCH 11/31] fix links in partials --- .../embedded-cluster/{ => v2}/_definition.mdx | 2 +- .../embedded-cluster/{ => v2}/_ec-config.mdx | 2 +- .../v2}/_ec-prereqs.mdx | 6 +-- .../{ => v2}/_multi-node-ha-arch.mdx | 2 +- .../embedded-cluster/{ => v2}/_port-reqs.mdx | 4 +- .../embedded-cluster/v2/_requirements.mdx | 40 +++++++++++++++++ .../_update-air-gap-admin-console.mdx | 2 +- .../{ => v2}/_update-air-gap-cli.mdx | 2 +- .../{ => v2}/_update-air-gap-overview.mdx | 2 +- .../{ => v2}/_update-overview.mdx | 2 +- .../embedded-cluster/v3/_definition.mdx | 3 ++ .../{_ec-config-v3.mdx => v3/_ec-config.mdx} | 0 .../embedded-cluster/v3/_ec-prereqs.mdx | 5 +++ .../v3/_multi-node-ha-arch.mdx | 14 ++++++ .../embedded-cluster/v3/_port-reqs.mdx | 43 +++++++++++++++++++ .../{ => v3}/_requirements.mdx | 0 .../embedded-cluster/v3/_update-overview.mdx | 7 +++ docs/vendor/environment-setup.mdx | 2 +- docs/vendor/quick-start.mdx | 2 +- docs/vendor/replicated-onboarding.mdx | 4 +- docs/vendor/tutorial-cmx-airgap.mdx | 2 +- .../tutorial-embedded-cluster-automation.mdx | 2 +- docs/vendor/tutorial-helm-cli.mdx | 2 +- embedded-cluster/embedded-overview.mdx | 4 +- embedded-cluster/embedded-using.mdx | 6 +-- .../installing-embedded-air-gap.mdx | 2 +- .../installing-embedded-requirements.mdx | 4 +- embedded-cluster/installing-embedded.mdx | 2 +- .../version-2.0.0/embedded-manage-nodes.mdx | 2 +- .../version-2.0.0/embedded-overview.mdx | 4 +- .../version-2.0.0/embedded-using.mdx | 4 +- .../installing-embedded-air-gap.mdx | 2 +- .../installing-embedded-requirements.mdx | 4 +- .../version-2.0.0/installing-embedded.mdx | 2 +- .../version-2.0.0/updating-embedded.mdx | 8 ++-- 35 files changed, 153 insertions(+), 41 deletions(-) rename docs/partials/embedded-cluster/{ => v2}/_definition.mdx (95%) rename docs/partials/embedded-cluster/{ => v2}/_ec-config.mdx (96%) rename docs/partials/{install => embedded-cluster/v2}/_ec-prereqs.mdx (53%) rename docs/partials/embedded-cluster/{ => v2}/_multi-node-ha-arch.mdx (97%) rename docs/partials/embedded-cluster/{ => v2}/_port-reqs.mdx (93%) create mode 100644 docs/partials/embedded-cluster/v2/_requirements.mdx rename docs/partials/embedded-cluster/{ => v2}/_update-air-gap-admin-console.mdx (99%) rename docs/partials/embedded-cluster/{ => v2}/_update-air-gap-cli.mdx (99%) rename docs/partials/embedded-cluster/{ => v2}/_update-air-gap-overview.mdx (96%) rename docs/partials/embedded-cluster/{ => v2}/_update-overview.mdx (95%) create mode 100644 docs/partials/embedded-cluster/v3/_definition.mdx rename docs/partials/embedded-cluster/{_ec-config-v3.mdx => v3/_ec-config.mdx} (100%) create mode 100644 docs/partials/embedded-cluster/v3/_ec-prereqs.mdx create mode 100644 docs/partials/embedded-cluster/v3/_multi-node-ha-arch.mdx create mode 100644 docs/partials/embedded-cluster/v3/_port-reqs.mdx rename docs/partials/embedded-cluster/{ => v3}/_requirements.mdx (100%) create mode 100644 docs/partials/embedded-cluster/v3/_update-overview.mdx diff --git a/docs/partials/embedded-cluster/_definition.mdx b/docs/partials/embedded-cluster/v2/_definition.mdx similarity index 95% rename from docs/partials/embedded-cluster/_definition.mdx rename to docs/partials/embedded-cluster/v2/_definition.mdx index 884b34edff..a67269e60f 100644 --- a/docs/partials/embedded-cluster/_definition.mdx +++ b/docs/partials/embedded-cluster/v2/_definition.mdx @@ -1,3 +1,3 @@ Replicated Embedded Cluster allows you to distribute a Kubernetes cluster and your application together as a single appliance, making it easy for enterprise users to install, update, and manage the application and the cluster in tandem. Embedded Cluster is based on the open source Kubernetes distribution k0s. For more information, see the [k0s documentation](https://docs.k0sproject.io/stable/). -For software vendors, Embedded Cluster provides a Config for defining characteristics of the cluster that will be created in the customer environment. Additionally, each version of Embedded Cluster includes a specific version of Replicated KOTS, ensuring compatibility between KOTS and the cluster. For enterprise users, cluster updates are done automatically at the same time as application updates, allowing users to more easily keep the cluster up-to-date without needing to use kubectl. \ No newline at end of file +For software vendors, Embedded Cluster provides a Config for defining characteristics of the cluster that will be created in the customer environment. Additionally, each version of Embedded Cluster includes a specific version of Replicated KOTS, ensuring compatibility between KOTS and the cluster. For enterprise users, cluster updates are done automatically at the same time as application updates, allowing users to more easily keep the cluster up-to-date without needing to use kubectl. diff --git a/docs/partials/embedded-cluster/_ec-config.mdx b/docs/partials/embedded-cluster/v2/_ec-config.mdx similarity index 96% rename from docs/partials/embedded-cluster/_ec-config.mdx rename to docs/partials/embedded-cluster/v2/_ec-config.mdx index f5d5300d14..4d75b2b4e2 100644 --- a/docs/partials/embedded-cluster/_ec-config.mdx +++ b/docs/partials/embedded-cluster/v2/_ec-config.mdx @@ -3,4 +3,4 @@ apiVersion: embeddedcluster.replicated.com/v1beta1 kind: Config spec: version: 2.13.5+k8s-1.33 -``` \ No newline at end of file +``` diff --git a/docs/partials/install/_ec-prereqs.mdx b/docs/partials/embedded-cluster/v2/_ec-prereqs.mdx similarity index 53% rename from docs/partials/install/_ec-prereqs.mdx rename to docs/partials/embedded-cluster/v2/_ec-prereqs.mdx index e7de78b75b..30f34231ea 100644 --- a/docs/partials/install/_ec-prereqs.mdx +++ b/docs/partials/embedded-cluster/v2/_ec-prereqs.mdx @@ -1,5 +1,5 @@ -* Ensure that your installation environment meets the Embedded Cluster requirements. See [Embedded Cluster Requirements](installing-embedded-requirements). +* Ensure that your installation environment meets the Embedded Cluster requirements. See [Embedded Cluster Requirements](/embedded-cluster/v2/installing-embedded-requirements). -* The application release that you want to install must include an [Embedded Cluster Config](embedded-config). +* The application release that you want to install must include an [Embedded Cluster Config](/embedded-cluster/v2/embedded-config). -* The license used to install must have the **Embedded Cluster Enabled** license field enabled. See [Create and Manage Customers](/vendor/releases-creating-customer). \ No newline at end of file +* The license used to install must have the **Embedded Cluster Enabled** license field enabled. See [Create and Manage Customers](/vendor/releases-creating-customer). diff --git a/docs/partials/embedded-cluster/_multi-node-ha-arch.mdx b/docs/partials/embedded-cluster/v2/_multi-node-ha-arch.mdx similarity index 97% rename from docs/partials/embedded-cluster/_multi-node-ha-arch.mdx rename to docs/partials/embedded-cluster/v2/_multi-node-ha-arch.mdx index cfca0aff3e..b180fb8892 100644 --- a/docs/partials/embedded-cluster/_multi-node-ha-arch.mdx +++ b/docs/partials/embedded-cluster/v2/_multi-node-ha-arch.mdx @@ -11,4 +11,4 @@ As shown in the diagram above, in HA installations with Embedded Cluster: * For installations that include disaster recovery, the Velero pod is deployed on one node. The Velero Node Agent runs on each node in the cluster. The Node Agent is a Kubernetes DaemonSet that performs backup and restore tasks such as creating snapshots and transferring data during restores. * For air gap installations, two replicas of the air gap image registry are deployed. -Any Helm [`extensions`](embedded-config#extensions) that you include in the Embedded Cluster Config are installed in the cluster depending on the given chart and whether or not it is configured to be deployed with high availability. \ No newline at end of file +Any Helm [`extensions`](embedded-config#extensions) that you include in the Embedded Cluster Config are installed in the cluster depending on the given chart and whether or not it is configured to be deployed with high availability. diff --git a/docs/partials/embedded-cluster/_port-reqs.mdx b/docs/partials/embedded-cluster/v2/_port-reqs.mdx similarity index 93% rename from docs/partials/embedded-cluster/_port-reqs.mdx rename to docs/partials/embedded-cluster/v2/_port-reqs.mdx index 4113c8ac9e..2f007519f9 100644 --- a/docs/partials/embedded-cluster/_port-reqs.mdx +++ b/docs/partials/embedded-cluster/v2/_port-reqs.mdx @@ -34,10 +34,10 @@ The KOTS Admin Console requires that port 30000/TCP is open and available. Creat Additionally, port 30000 must be accessible by nodes joining the cluster. -If port 30000 is occupied, you can select a different port for the Admin Console during installation. For more information, see [install](/embedded-cluster/v3/embedded-cluster-install). +If port 30000 is occupied, you can select a different port for the Admin Console during installation. For more information, see [install](/embedded-cluster/v2/embedded-cluster-install). #### LAM port The Local Artifact Mirror (LAM) requires that port 50000/TCP is open and available. -If port 50000 is occupied, you can select a different port for the LAM during installation. For more information, see [install](/embedded-cluster/v3/embedded-cluster-install). +If port 50000 is occupied, you can select a different port for the LAM during installation. For more information, see [install](/embedded-cluster/v2/embedded-cluster-install). diff --git a/docs/partials/embedded-cluster/v2/_requirements.mdx b/docs/partials/embedded-cluster/v2/_requirements.mdx new file mode 100644 index 0000000000..57e642eecd --- /dev/null +++ b/docs/partials/embedded-cluster/v2/_requirements.mdx @@ -0,0 +1,40 @@ +* Linux operating system + +* x86-64 architecture + +* systemd + +* At least 2GB of memory and 2 CPU cores + +* The disk on the host must have a maximum P99 write latency of 10 ms. This supports etcd performance and stability. For more information about the disk write latency requirements for etcd, see [Disks](https://etcd.io/docs/latest/op-guide/hardware/#disks) in _Hardware recommendations_ and [What does the etcd warning “failed to send out heartbeat on time” mean?](https://etcd.io/docs/latest/faq/) in the etcd documentation. + +* The user performing the installation must have root access to the machine, such as with `sudo`. + +* The data directory used by Embedded Cluster must have 40Gi or more of total space and be less than 80% full. By default, the data directory is `/var/lib/embedded-cluster`. The directory can be changed by passing the `--data-dir` flag with the Embedded Cluster `install` command. For more information, see [install](/embedded-cluster/v2/embedded-cluster-install). + + Note that in addition to the primary data directory, Embedded Cluster creates directories and files in the following locations: + + - `/etc/cni` + - `/etc/k0s` + - `/opt/cni` + - `/opt/containerd` + - `/run/calico` + - `/run/containerd` + - `/run/k0s` + - `/sys/fs/cgroup/kubepods` + - `/sys/fs/cgroup/system.slice/containerd.service` + - `/sys/fs/cgroup/system.slice/k0scontroller.service` + - `/usr/libexec/k0s` + - `/var/lib/calico` + - `/var/lib/cni` + - `/var/lib/containers` + - `/var/lib/kubelet` + - `/var/log/calico` + - `/var/log/containers` + - `/var/log/embedded-cluster` + - `/var/log/pods` + - `/usr/local/bin/k0s` + +* (Online installations only) Access to replicated.app and proxy.replicated.com or your custom domain for each + +* Embedded Cluster is based on k0s, so all k0s system requirements and external runtime dependencies apply. See [System requirements](https://docs.k0sproject.io/stable/system-requirements/) and [External runtime dependencies](https://docs.k0sproject.io/stable/external-runtime-deps/) in the k0s documentation. diff --git a/docs/partials/embedded-cluster/_update-air-gap-admin-console.mdx b/docs/partials/embedded-cluster/v2/_update-air-gap-admin-console.mdx similarity index 99% rename from docs/partials/embedded-cluster/_update-air-gap-admin-console.mdx rename to docs/partials/embedded-cluster/v2/_update-air-gap-admin-console.mdx index 0159a8951f..2430166aa2 100644 --- a/docs/partials/embedded-cluster/_update-air-gap-admin-console.mdx +++ b/docs/partials/embedded-cluster/v2/_update-air-gap-admin-console.mdx @@ -38,4 +38,4 @@ ![Confirmation screen in the upgrade wizard](/images/ec-upgrade-wizard-confirm.png) - [View a larger version of this image](/images/ec-upgrade-wizard-confirm.png) \ No newline at end of file + [View a larger version of this image](/images/ec-upgrade-wizard-confirm.png) diff --git a/docs/partials/embedded-cluster/_update-air-gap-cli.mdx b/docs/partials/embedded-cluster/v2/_update-air-gap-cli.mdx similarity index 99% rename from docs/partials/embedded-cluster/_update-air-gap-cli.mdx rename to docs/partials/embedded-cluster/v2/_update-air-gap-cli.mdx index 2a0b707ba9..e762a485ee 100644 --- a/docs/partials/embedded-cluster/_update-air-gap-cli.mdx +++ b/docs/partials/embedded-cluster/v2/_update-air-gap-cli.mdx @@ -47,4 +47,4 @@ ![Confirmation screen in the upgrade wizard](/images/ec-upgrade-wizard-confirm.png) - [View a larger version of this image](/images/ec-upgrade-wizard-confirm.png) \ No newline at end of file + [View a larger version of this image](/images/ec-upgrade-wizard-confirm.png) diff --git a/docs/partials/embedded-cluster/_update-air-gap-overview.mdx b/docs/partials/embedded-cluster/v2/_update-air-gap-overview.mdx similarity index 96% rename from docs/partials/embedded-cluster/_update-air-gap-overview.mdx rename to docs/partials/embedded-cluster/v2/_update-air-gap-overview.mdx index 99517a853c..a872997ccd 100644 --- a/docs/partials/embedded-cluster/_update-air-gap-overview.mdx +++ b/docs/partials/embedded-cluster/v2/_update-air-gap-overview.mdx @@ -1,3 +1,3 @@ To upgrade an installation, new air gap bundles can be uploaded to the Admin Console from the browser or with the Embedded Cluster binary from the command line. -Using the binary is faster and allows the user to download the air gap bundle directly to the machine where the Embedded Cluster is running. Using the browser is slower because the user must download the air gap bundle to a machine with a browser, then upload that bundle to the Admin Console, and then the Admin Console can process it. \ No newline at end of file +Using the binary is faster and allows the user to download the air gap bundle directly to the machine where the Embedded Cluster is running. Using the browser is slower because the user must download the air gap bundle to a machine with a browser, then upload that bundle to the Admin Console, and then the Admin Console can process it. diff --git a/docs/partials/embedded-cluster/_update-overview.mdx b/docs/partials/embedded-cluster/v2/_update-overview.mdx similarity index 95% rename from docs/partials/embedded-cluster/_update-overview.mdx rename to docs/partials/embedded-cluster/v2/_update-overview.mdx index 53918c6113..e58dad3468 100644 --- a/docs/partials/embedded-cluster/_update-overview.mdx +++ b/docs/partials/embedded-cluster/v2/_update-overview.mdx @@ -4,4 +4,4 @@ When you deploy a new version, any changes to the cluster are deployed first. Th Any changes made to the Embedded Cluster Config, including changes to the Embedded Cluster version, Helm extensions, and unsupported overrides, trigger a cluster update. -When performing an upgrade with Embedded Cluster, the user is able to change the application config before deploying the new version. Additionally, the user's license is synced automatically. Users can also make config changes and sync their license outside of performing an update. This requires deploying a new version to apply the config change or license sync. \ No newline at end of file +When performing an upgrade with Embedded Cluster, the user is able to change the application config before deploying the new version. Additionally, the user's license is synced automatically. Users can also make config changes and sync their license outside of performing an update. This requires deploying a new version to apply the config change or license sync. diff --git a/docs/partials/embedded-cluster/v3/_definition.mdx b/docs/partials/embedded-cluster/v3/_definition.mdx new file mode 100644 index 0000000000..97c367563d --- /dev/null +++ b/docs/partials/embedded-cluster/v3/_definition.mdx @@ -0,0 +1,3 @@ +Replicated Embedded Cluster allows you to distribute a Kubernetes cluster and your application together as a single appliance, making it easy for enterprise users to install, update, and manage the application and the cluster in tandem. Embedded Cluster is based on the open source Kubernetes distribution k0s. For more information, see the [k0s documentation](https://docs.k0sproject.io/stable/). + +For software vendors, Embedded Cluster provides a Config for defining characteristics of the cluster that will be created in the customer environment. For enterprise users, cluster updates are done automatically at the same time as application updates, allowing users to more easily keep the cluster up-to-date without needing to use kubectl. diff --git a/docs/partials/embedded-cluster/_ec-config-v3.mdx b/docs/partials/embedded-cluster/v3/_ec-config.mdx similarity index 100% rename from docs/partials/embedded-cluster/_ec-config-v3.mdx rename to docs/partials/embedded-cluster/v3/_ec-config.mdx diff --git a/docs/partials/embedded-cluster/v3/_ec-prereqs.mdx b/docs/partials/embedded-cluster/v3/_ec-prereqs.mdx new file mode 100644 index 0000000000..8492f2e9d0 --- /dev/null +++ b/docs/partials/embedded-cluster/v3/_ec-prereqs.mdx @@ -0,0 +1,5 @@ +* Ensure that your installation environment meets the Embedded Cluster requirements. See [Embedded Cluster Requirements](/embedded-cluster/v3/installing-embedded-requirements). + +* The application release that you want to install must include an [Embedded Cluster Config](/embedded-cluster/v3/embedded-config). + +* The license used to install must have the **Embedded Cluster Enabled** license field enabled. See [Create and Manage Customers](/vendor/releases-creating-customer). diff --git a/docs/partials/embedded-cluster/v3/_multi-node-ha-arch.mdx b/docs/partials/embedded-cluster/v3/_multi-node-ha-arch.mdx new file mode 100644 index 0000000000..b180fb8892 --- /dev/null +++ b/docs/partials/embedded-cluster/v3/_multi-node-ha-arch.mdx @@ -0,0 +1,14 @@ +The following diagram shows the architecture of an HA multi-node Embedded Cluster installation: + +![Embedded Cluster multi-node architecture with high availability](/images/embedded-architecture-multi-node-ha.png) + +[View a larger version of this image](/images/embedded-architecture-multi-node-ha.png) + +As shown in the diagram above, in HA installations with Embedded Cluster: +* A single replica of the Embedded Cluster Operator is deployed and runs on a controller node. +* A single replica of the KOTS Admin Console is deployed and runs on a controller node. +* Three replicas of rqlite are deployed in the kotsadm namespace. Rqlite is used by KOTS to store information such as support bundles, version history, application metadata, and other small amounts of data needed to manage the application. +* For installations that include disaster recovery, the Velero pod is deployed on one node. The Velero Node Agent runs on each node in the cluster. The Node Agent is a Kubernetes DaemonSet that performs backup and restore tasks such as creating snapshots and transferring data during restores. +* For air gap installations, two replicas of the air gap image registry are deployed. + +Any Helm [`extensions`](embedded-config#extensions) that you include in the Embedded Cluster Config are installed in the cluster depending on the given chart and whether or not it is configured to be deployed with high availability. diff --git a/docs/partials/embedded-cluster/v3/_port-reqs.mdx b/docs/partials/embedded-cluster/v3/_port-reqs.mdx new file mode 100644 index 0000000000..61fe73756e --- /dev/null +++ b/docs/partials/embedded-cluster/v3/_port-reqs.mdx @@ -0,0 +1,43 @@ +This section lists the ports used by Embedded Cluster. These ports must be open and available for both single- and multi-node installations. + +#### Ports used by local processes + +The following ports must be open and available for use by local processes running on the same node. It is not necessary to create firewall openings for these ports. + +* 2379/TCP +* 7443/TCP +* 9099/TCP +* 10248/TCP +* 10257/TCP +* 10259/TCP + +#### Ports required for bidirectional communication between nodes + +The following ports are used for bidirectional communication between nodes. + +For multi-node installations, create firewall openings between nodes for these ports. + +For single-node installations, ensure that there are no other processes using these ports. Although there is no communication between nodes in single-node installations, these ports are still required. + +* 2380/TCP +* 4789/UDP +* 6443/TCP +* 9091/TCP +* 9443/TCP +* 10249/TCP +* 10250/TCP +* 10256/TCP + +#### Embedded Cluster UI port + +The Embedded Cluster UI requires that port 30000/TCP is open and available. Create a firewall opening for port 30000/TCP so that the end user can access the UI. + +Additionally, port 30000 must be accessible by nodes joining the cluster. + +If port 30000 is occupied, you can select a different port for the Admin Console during installation. For more information, see [install](/embedded-cluster/v3/embedded-cluster-install). + +#### LAM port + +The Local Artifact Mirror (LAM) requires that port 50000/TCP is open and available. + +If port 50000 is occupied, you can select a different port for the LAM during installation. For more information, see [install](/embedded-cluster/v3/embedded-cluster-install). diff --git a/docs/partials/embedded-cluster/_requirements.mdx b/docs/partials/embedded-cluster/v3/_requirements.mdx similarity index 100% rename from docs/partials/embedded-cluster/_requirements.mdx rename to docs/partials/embedded-cluster/v3/_requirements.mdx diff --git a/docs/partials/embedded-cluster/v3/_update-overview.mdx b/docs/partials/embedded-cluster/v3/_update-overview.mdx new file mode 100644 index 0000000000..b4dbb21827 --- /dev/null +++ b/docs/partials/embedded-cluster/v3/_update-overview.mdx @@ -0,0 +1,7 @@ +When you update an application installed with Embedded Cluster, you update both the application and the cluster infrastructure together, including Kubernetes and other components running in the cluster. There is no need or mechanism to update the infrastructure on its own. + +When you deploy a new version, any changes to the cluster are deployed first. Embedded Cluster waits until the cluster is ready before updatng the application. + +Any changes made to the Embedded Cluster Config, including changes to the Embedded Cluster version, Helm extensions, and unsupported overrides, trigger a cluster update. + +When performing an upgrade with Embedded Cluster, the user is able to change the application config before deploying the new version. Additionally, the user's license is synced automatically. Users can also make config changes and sync their license outside of performing an update. This requires deploying a new version to apply the config change or license sync. diff --git a/docs/vendor/environment-setup.mdx b/docs/vendor/environment-setup.mdx index ee0972eb3f..11a7f48bdc 100644 --- a/docs/vendor/environment-setup.mdx +++ b/docs/vendor/environment-setup.mdx @@ -1,4 +1,4 @@ -import Requirements from "../partials/embedded-cluster/_requirements.mdx" +import Requirements from "../partials/embedded-cluster/v3/_requirements.mdx" import Verify from "../partials/replicated-cli/_verify-install.mdx" import InstallMac from "../partials/replicated-cli/_install-mac.mdx" import InstallLinux from "../partials/replicated-cli/_install-linux.mdx" diff --git a/docs/vendor/quick-start.mdx b/docs/vendor/quick-start.mdx index 8acf54813f..fe4744e35b 100644 --- a/docs/vendor/quick-start.mdx +++ b/docs/vendor/quick-start.mdx @@ -7,7 +7,7 @@ import KotsCr from "../partials/getting-started/_slackernews-repl-app.mdx" import K8sCr from "../partials/getting-started/_slackernews-k8s-app.mdx" import EcCr from "../partials/getting-started/_slackernews-embedded-cluster.mdx" import ConfigCr from "../partials/getting-started/_slackernews-config.mdx" -import Requirements from "../partials/embedded-cluster/_requirements.mdx" +import Requirements from "../partials/embedded-cluster/v3/_requirements.mdx" # Replicated quick start diff --git a/docs/vendor/replicated-onboarding.mdx b/docs/vendor/replicated-onboarding.mdx index 5072b87722..13d06927f2 100644 --- a/docs/vendor/replicated-onboarding.mdx +++ b/docs/vendor/replicated-onboarding.mdx @@ -2,9 +2,9 @@ import CommunityHelp from "../partials/getting-started/_community-help.mdx" import CreateApp from "../partials/getting-started/_create-app.mdx" import CreateRelease from "../partials/getting-started/_create-promote-release.mdx" import DependencyYaml from "../partials/replicated-sdk/_dependency-yaml.mdx" -import EcCr from "../partials/embedded-cluster/_ec-config.mdx" +import EcCr from "../partials/embedded-cluster/v3/_ec-config.mdx" import HelmPackage from "../partials/helm/_helm-package.mdx" -import Requirements from "../partials/embedded-cluster/_requirements.mdx" +import Requirements from "../partials/embedded-cluster/v3/_requirements.mdx" import TestYourChanges from "../partials/getting-started/_test-your-changes.mdx" import UnauthorizedError from "../partials/replicated-sdk/_401-unauthorized.mdx" import StepCreds from "../partials/proxy-service/_step-creds.mdx" diff --git a/docs/vendor/tutorial-cmx-airgap.mdx b/docs/vendor/tutorial-cmx-airgap.mdx index 2f7bd767d4..ec237c9beb 100644 --- a/docs/vendor/tutorial-cmx-airgap.mdx +++ b/docs/vendor/tutorial-cmx-airgap.mdx @@ -1,6 +1,6 @@ import DependencyYaml from "../partials/replicated-sdk/_dependency-yaml.mdx" import HelmPackage from "../partials/helm/_helm-package.mdx" -import Requirements from "../partials/embedded-cluster/_requirements.mdx" +import Requirements from "../partials/embedded-cluster/v3/_requirements.mdx" # Test an air gap installation with compatibility matrix diff --git a/docs/vendor/tutorial-embedded-cluster-automation.mdx b/docs/vendor/tutorial-embedded-cluster-automation.mdx index 0455622d48..515923271a 100644 --- a/docs/vendor/tutorial-embedded-cluster-automation.mdx +++ b/docs/vendor/tutorial-embedded-cluster-automation.mdx @@ -1,6 +1,6 @@ import DependencyYaml from "../partials/replicated-sdk/_dependency-yaml.mdx" import HelmPackage from "../partials/helm/_helm-package.mdx" -import Requirements from "../partials/embedded-cluster/_requirements.mdx" +import Requirements from "../partials/embedded-cluster/v3/_requirements.mdx" # Install SlackerNews with Embedded Cluster from the command line diff --git a/docs/vendor/tutorial-helm-cli.mdx b/docs/vendor/tutorial-helm-cli.mdx index 8349b29de3..bbf446b5d2 100644 --- a/docs/vendor/tutorial-helm-cli.mdx +++ b/docs/vendor/tutorial-helm-cli.mdx @@ -1,6 +1,6 @@ import DependencyYaml from "../partials/replicated-sdk/_dependency-yaml.mdx" import HelmPackage from "../partials/helm/_helm-package.mdx" -import Requirements from "../partials/embedded-cluster/_requirements.mdx" +import Requirements from "../partials/embedded-cluster/v3/_requirements.mdx" # Install SlackerNews with the Helm CLI diff --git a/embedded-cluster/embedded-overview.mdx b/embedded-cluster/embedded-overview.mdx index 229f99804c..816ecd4aba 100644 --- a/embedded-cluster/embedded-overview.mdx +++ b/embedded-cluster/embedded-overview.mdx @@ -1,5 +1,5 @@ -import EmbeddedCluster from "../docs/partials/embedded-cluster/_definition.mdx" -import HaArchitecture from "../docs/partials/embedded-cluster/_multi-node-ha-arch.mdx" +import EmbeddedCluster from "../docs/partials/embedded-cluster/v3/_definition.mdx" +import HaArchitecture from "../docs/partials/embedded-cluster/v3/_multi-node-ha-arch.mdx" # Embedded Cluster overview diff --git a/embedded-cluster/embedded-using.mdx b/embedded-cluster/embedded-using.mdx index cfac836ced..cbcccb1045 100644 --- a/embedded-cluster/embedded-using.mdx +++ b/embedded-cluster/embedded-using.mdx @@ -1,5 +1,5 @@ -import UpdateOverview from "../docs/partials/embedded-cluster/_update-overview.mdx" -import EcConfigV3 from "../docs/partials/embedded-cluster/_ec-config-v3.mdx" +import UpdateOverview from "../docs/partials/embedded-cluster/v3/_update-overview.mdx" +import EcConfig from "../docs/partials/embedded-cluster/v3/_ec-config.mdx" import ShellCommand from "../docs/partials/embedded-cluster/_shell-command.mdx" # Configure Embedded Cluster @@ -18,7 +18,7 @@ To add the Embedded Cluster Config: 1. In the release, add an [Embedded Cluster Config](embedded-config) manifest that specifies the Embedded Cluster version to use: - + 1. If your application requires that certain components are deployed before the application and as part of the Embedded Cluster itself, update the Embedded Cluster Config to add [extensions](embedded-config#extensions). diff --git a/embedded-cluster/installing-embedded-air-gap.mdx b/embedded-cluster/installing-embedded-air-gap.mdx index 58d6e4e637..4da823f9da 100644 --- a/embedded-cluster/installing-embedded-air-gap.mdx +++ b/embedded-cluster/installing-embedded-air-gap.mdx @@ -1,4 +1,4 @@ -import Prerequisites from "../docs/partials/install/_ec-prereqs.mdx" +import Prerequisites from "../docs/partials/embedded-cluster/v3/_ec-prereqs.mdx" # Air gap installation with Embedded Cluster diff --git a/embedded-cluster/installing-embedded-requirements.mdx b/embedded-cluster/installing-embedded-requirements.mdx index 77f1f9d200..cd81ba9ce7 100644 --- a/embedded-cluster/installing-embedded-requirements.mdx +++ b/embedded-cluster/installing-embedded-requirements.mdx @@ -1,5 +1,5 @@ -import EmbeddedClusterRequirements from "../docs/partials/embedded-cluster/_requirements.mdx" -import EmbeddedClusterPortRequirements from "../docs/partials/embedded-cluster/_port-reqs.mdx" +import EmbeddedClusterRequirements from "../docs/partials/embedded-cluster/v3/_requirements.mdx" +import EmbeddedClusterPortRequirements from "../docs/partials/embedded-cluster/v3/_port-reqs.mdx" import FirewallOpeningsIntro from "../docs/partials/install/_firewall-openings-intro.mdx" import FirewallOpeningsEc from "../docs/partials/install/_firewall-openings-embedded-cluster.mdx" diff --git a/embedded-cluster/installing-embedded.mdx b/embedded-cluster/installing-embedded.mdx index f6869742ac..80528d3b88 100644 --- a/embedded-cluster/installing-embedded.mdx +++ b/embedded-cluster/installing-embedded.mdx @@ -1,4 +1,4 @@ -import Prerequisites from "../docs/partials/install/_ec-prereqs.mdx" +import Prerequisites from "../docs/partials/embedded-cluster/v3/_ec-prereqs.mdx" # Online installation with Embedded Cluster diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx index 2f8a698955..2d674822cd 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx @@ -1,4 +1,4 @@ -import HaArchitecture from "../../docs/partials/embedded-cluster/_multi-node-ha-arch.mdx" +import HaArchitecture from "../../docs/partials/embedded-cluster/v2/_multi-node-ha-arch.mdx" import ShellCommand from "../../docs/partials/embedded-cluster/_shell-command.mdx" # Access and manage embedded clusters diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx index 6d14afd528..c415739bf2 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx @@ -1,5 +1,5 @@ -import EmbeddedCluster from "../../docs/partials/embedded-cluster/_definition.mdx" -import HaArchitecture from "../../docs/partials/embedded-cluster/_multi-node-ha-arch.mdx" +import EmbeddedCluster from "../../docs/partials/embedded-cluster/v2/_definition.mdx" +import HaArchitecture from "../../docs/partials/embedded-cluster/v2/_multi-node-ha-arch.mdx" # Embedded Cluster overview diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx index 0c1a8e2749..330f57acc5 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx @@ -1,5 +1,5 @@ -import UpdateOverview from "../../docs/partials/embedded-cluster/_update-overview.mdx" -import EcConfig from "../../docs/partials/embedded-cluster/_ec-config.mdx" +import UpdateOverview from "../../docs/partials/embedded-cluster/v2/_update-overview.mdx" +import EcConfig from "../../docs/partials/embedded-cluster/v2/_ec-config.mdx" import ShellCommand from "../../docs/partials/embedded-cluster/_shell-command.mdx" # Configure Embedded Cluster diff --git a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx index 8528269d83..e037312b66 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-air-gap.mdx @@ -1,4 +1,4 @@ -import Prerequisites from "../../docs/partials/install/_ec-prereqs.mdx" +import Prerequisites from "../../docs/partials/embedded-cluster/v2/_ec-prereqs.mdx" # Air gap installation with Embedded Cluster diff --git a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-requirements.mdx b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-requirements.mdx index 6db6c11aec..3098137ccd 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-requirements.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded-requirements.mdx @@ -1,5 +1,5 @@ -import EmbeddedClusterRequirements from "../../docs/partials/embedded-cluster/_requirements.mdx" -import EmbeddedClusterPortRequirements from "../../docs/partials/embedded-cluster/_port-reqs.mdx" +import EmbeddedClusterRequirements from "../../docs/partials/embedded-cluster/v2/_requirements.mdx" +import EmbeddedClusterPortRequirements from "../../docs/partials/embedded-cluster/v2/_port-reqs.mdx" import FirewallOpeningsIntro from "../../docs/partials/install/_firewall-openings-intro.mdx" import FirewallOpeningsEc from "../../docs/partials/install/_firewall-openings-embedded-cluster.mdx" diff --git a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded.mdx b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded.mdx index c8a5b04a60..088fddd7d8 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/installing-embedded.mdx @@ -1,4 +1,4 @@ -import Prerequisites from "../../docs/partials/install/_ec-prereqs.mdx" +import Prerequisites from "../../docs/partials/embedded-cluster/v2/_ec-prereqs.mdx" # Online installation with Embedded Cluster diff --git a/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx b/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx index 5ab2803a6c..67880ad17b 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/updating-embedded.mdx @@ -1,8 +1,8 @@ -import UpdateAirGapAdm from "../../docs/partials/embedded-cluster/_update-air-gap-admin-console.mdx" -import UpdateAirGapCli from "../../docs/partials/embedded-cluster/_update-air-gap-cli.mdx" -import UpdateAirGapOverview from "../../docs/partials/embedded-cluster/_update-air-gap-overview.mdx" +import UpdateAirGapAdm from "../../docs/partials/embedded-cluster/v2/_update-air-gap-admin-console.mdx" +import UpdateAirGapCli from "../../docs/partials/embedded-cluster/v2/_update-air-gap-cli.mdx" +import UpdateAirGapOverview from "../../docs/partials/embedded-cluster/v2/_update-air-gap-overview.mdx" import DoNotDowngrade from "../../docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx" -import Overview from "../../docs/partials/embedded-cluster/_update-overview.mdx" +import Overview from "../../docs/partials/embedded-cluster/v2/_update-overview.mdx" # Perform updates in embedded clusters From bdad2deab8d842b44a237500296bbeaaf53c1481 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Thu, 2 Apr 2026 13:15:52 -0600 Subject: [PATCH 12/31] add more v3 content --- .../embedded-cluster/v3/_ec-config.mdx | 2 +- embedded-cluster/embedded-config.mdx | 291 ++++++++++-------- embedded-cluster/embedded-manage-nodes.mdx | 228 ++++++++++++++ embedded-cluster/embedded-overview.mdx | 4 +- embedded-cluster/embedded-troubleshooting.mdx | 6 +- .../version-2.0.0/embedded-manage-nodes.mdx | 2 +- sidebarEmbeddedCluster.js | 1 + 7 files changed, 391 insertions(+), 143 deletions(-) create mode 100644 embedded-cluster/embedded-manage-nodes.mdx diff --git a/docs/partials/embedded-cluster/v3/_ec-config.mdx b/docs/partials/embedded-cluster/v3/_ec-config.mdx index 34c38132f7..173181f5d7 100644 --- a/docs/partials/embedded-cluster/v3/_ec-config.mdx +++ b/docs/partials/embedded-cluster/v3/_ec-config.mdx @@ -2,5 +2,5 @@ apiVersion: embeddedcluster.replicated.com/v1beta1 kind: Config spec: - version: 3.0.0-alpha-27+k8s-1.34 + version: 3.0.0-alpha-26+k8s-1.34 ``` diff --git a/embedded-cluster/embedded-config.mdx b/embedded-cluster/embedded-config.mdx index d88d59f7a9..a8937a2da8 100644 --- a/embedded-cluster/embedded-config.mdx +++ b/embedded-cluster/embedded-config.mdx @@ -12,7 +12,7 @@ The Embedded Cluster Config lets you define several aspects of the Kubernetes cl ### Limitations -* The Embedded Cluster Config does not support the use of Go template functions, including [Replicated template functions](/reference/template-functions-about). +* Top-level fields and most of the Config spec are plain YAML and do not support Go template functions, including Replicated template functions. The `values` field for each entry under `extensions.helmCharts` does support [Replicated template functions](/reference/template-functions-about). * There are additional, property-specific limitations. For more information, see the sections below. @@ -21,55 +21,93 @@ The Embedded Cluster Config lets you define several aspects of the Kubernetes cl ```yaml apiVersion: embeddedcluster.replicated.com/v1beta1 kind: Config +metadata: + name: my-embedded-cluster-config spec: - version: 3.0.0-alpha-27+k8s-1.34 + version: "3.0.0-alpha-26+k8s-1.34" + binaryOverrideUrl: "" + metadataOverrideUrl: "" + domains: + proxyRegistryDomain: proxy.example.com + replicatedAppDomain: updates.example.com roles: - controller: - name: app - labels: - app: "true" - custom: - - name: gpu - labels: - gpu: "true" - - name: database + controller: + name: controller-custom labels: - database: "true" - domains: - proxyRegistryDomain: proxy.yourcompany.com - replicatedAppDomain: updates.yourcompany.com + controller-label: controller-label-value + custom: + - name: abc + labels: + abc-test-label: abc-test-label-value + - name: xyz + labels: + xyz-test-label: xyz-value + unsupportedOverrides: + builtInExtensions: + - name: admin-console + values: | + labels: + release-custom-label: release-custom-value + - name: embedded-cluster-operator + values: | + global: + labels: + release-custom-label: release-custom-value + k0s: | + config: + metadata: + name: foo + spec: + telemetry: + enabled: false + workerProfiles: + - name: ip-forward + values: + allowedUnsafeSysctls: + - net.ipv4.ip_forward extensions: - helm: - repositories: - - name: ingress-nginx - url: https://kubernetes.github.io/ingress-nginx - charts: - - name: ingress-nginx - chartname: ingress-nginx/ingress-nginx - namespace: ingress-nginx - version: "4.8.3" - values: | - controller: - service: - type: NodePort - nodePorts: - http: "80" - https: "443" - # Known issue: Only use image tags for multi-architecture images. - # Set digest to empty string to ensure the air gap builder uses - # single-architecture images. - image: - digest: "" - digestChroot: "" - admissionWebhooks: - patch: - image: - digest: "" + helmCharts: + - chart: + name: ingress-nginx + chartVersion: "4.11.3" + releaseName: ingress-nginx + namespace: ingress-nginx + values: | + controller: + service: + type: NodePort + nodePorts: + http: "80" + https: "443" + image: + repository: 'repl{{ ReplicatedImageName "registry.k8s.io/ingress-nginx/controller" }}' + tag: 'repl{{ HelmValue ".Values.controller.image.tag" }}' + digest: "" + digestChroot: "" + admissionWebhooks: + patch: + image: + repository: 'repl{{ ReplicatedImageName "registry.k8s.io/ingress-nginx/kube-webhook-certgen" }}' + tag: 'repl{{ HelmValue ".Values.controller.admissionWebhooks.patch.image.tag" }}' + digest: "" + - chart: + name: goldpinger + chartVersion: "6.1.2" + releaseName: goldpinger + namespace: goldpinger + weight: 11 + values: | + image: + repository: 'repl{{ ReplicatedImageName "docker.io/bloomberg/goldpinger" }}' ``` +## metadata + +The Config is a Kubernetes custom resource. Set `metadata.name` to a name for this object in the cluster (for example, `my-embedded-cluster-config`). + ## version -Specify the versions of Embedded Cluster and Kubernetes to install. The version of Kubernetes is appended to the Embedded Cluster version in the format `+k8s-1.34`. For example, Embedded Cluster 3.0.0-alpha-27+k8s-1.34 uses Embedded Cluster 3.0.0-alpha-27 and Kubernetes 1.34. +Specify the versions of Embedded Cluster and Kubernetes to install. The version of Kubernetes is appended to the Embedded Cluster version in the format `+k8s-1.34`. For example, Embedded Cluster `3.0.0-alpha-26+k8s-1.34` uses Embedded Cluster `3.0.0-alpha-26` and Kubernetes 1.34. Each version of Embedded Cluster includes specific versions of components like KOTS (Admin Console) and OpenEBS. For more information, see the [Embedded Cluster Release Notes](/release-notes/rn-embedded-cluster). @@ -78,13 +116,17 @@ Replicated recommends that you update the version frequently to ensure that you +## binaryOverrideUrl and metadataOverrideUrl + +Optional. Use `spec.binaryOverrideUrl` and `spec.metadataOverrideUrl` to override the default locations of Embedded Cluster binary and metadata artifacts when you need a non-default artifact source. Leave them as empty strings when you are using the defaults from the release. + ## roles (Beta) {#roles} You can optionally customize node roles in the Embedded Cluster Config using the `roles` key. -A common use case for customizing node roles is to assign workloads to specific nodes. For example, if your application has graphics processing unit (GPU) workloads, you could create a `custom` role that will add a `gpu=true` label to any node that is assigned the role. This allows you to then schedule GPU workloads on nodes labled `gpu=true`. +A common use case for customizing node roles is to assign workloads to specific nodes. For example, if your application has graphics processing unit (GPU) workloads, you could create a `custom` role that will add a `gpu=true` label to any node that is assigned the role. This allows you to then schedule GPU workloads on nodes labeled `gpu=true`. -When the `roles` key is configured, users select one or more roles to assign to a node when it is joined to the cluster. For more information, see [Managing Multi-Node Clusters with Embedded Cluster](/embedded-cluster/v2/embedded-manage-nodes). +When the `roles` key is configured, users select one or more roles to assign to a node when it is joined to the cluster. For more information, see [Managing Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). If the `roles` key is _not_ configured, all nodes joined to the cluster are assigned the `controller` role. The `controller` role designates nodes that run the Kubernetes control plane. Controller nodes can also run other workloads, such as application or Replicated KOTS workloads. @@ -96,18 +138,16 @@ kind: Config spec: roles: controller: - # Optionally change the name for the default controller role name: app labels: - app: "true" # Label applied to "app" nodes - # Custom roles + app: "true" custom: - name: db labels: - db: "true" # Label applied to "db" nodes + db: "true" - name: gpu labels: - gpu: "true" # Label applied to "gpu" nodes + gpu: "true" ``` ### Limitations @@ -119,16 +159,17 @@ spec: ### roles.controller In the `roles.controller` key, you can set the following fields to customize the default controller role: + * `name`: Set the name that is assigned to controller nodes. By default, controller nodes are named “controller”. :::note - If you plan to create any custom roles, Replicated recommends that you change the default name for the controller role to a term that is easy to understand, such as "app". This is because, when you add custom roles, both the name of the controller role and the names of any custom roles are displayed to the user when they join a node. + If you plan to create any custom roles, Replicated recommends that you change the default name for the controller role to a term that is easy to understand, such as "app". This is because, when you add custom roles, both the name of the controller role and the names of any custom roles are displayed to the user when they join a node. ::: * `labels`: Kubernetes labels that Embedded Cluster will apply to any node in the cluster that is assigned the given role. - ### roles.custom In the `roles.custom` key, you can add custom roles. Each custom role includes the following fields: + * `name`: (Required) A name for the custom role. * `labels`: Kubernetes labels that Embedded Cluster will apply to any node in the cluster that is assigned the given role. @@ -149,19 +190,33 @@ apiVersion: embeddedcluster.replicated.com/v1beta1 kind: Config spec: domains: - # Your proxy registry custom domain proxyRegistryDomain: proxy.yourcompany.com - # Your app service custom domain - replicatedAppDomain: updates.yourcompany.com + replicatedAppDomain: updates.yourcompany.com ``` ## extensions -If you need to install Helm charts before your application and as part of the Embedded Cluster itself, you can do this with Helm extensions. One situation where this is useful is if you want to ship an ingress controller, because Embedded Cluster does not yet include one. +Helm charts that must be installed before your application—and as part of Embedded Cluster itself—are listed under `spec.extensions.helmCharts`. Each item describes one chart release. + +### helmCharts -Helm extensions are updated when new versions of your application are deployed from the Admin Console. So, for example, you can change the values for a Helm extension from one release to another, and those changes will be applied to the cluster when the new release is deployed. +Each object in `helmCharts` can include the following fields: -The format for specifying Helm extensions uses the same k0s Helm extensions format from the k0s configuration. For more information about these fields, see the [k0s documentation](https://docs.k0sproject.io/stable/helm-charts/#example). +* `chart`: (Required) Identifies the chart. + * `name`: Chart name. + * `chartVersion`: Chart version string to install. +* `releaseName`: (Required) Helm release name. +* `namespace`: (Required) Namespace for the release. +* `weight`: Optional. Controls ordering relative to other `helmCharts` entries. **Lower** `weight` values install **earlier**. If omitted, a default is used. +* `values`: Optional multi-line string of Helm values. This field supports [Replicated template functions](/reference/template-functions-about) (for example, `ReplicatedImageName`, `HelmValue`, `ReplicatedImageRegistry`, and `ReplicatedImageRepository`) so you can align images and values with your release. + +Helm extensions are updated when new versions of your application are deployed from the Admin Console. For example, you can change `values` from one release to another, and those changes apply when the new version is deployed. + +#### Requirements + +* `chart.chartVersion` is required. Omitting it can cause upgrade issues. + +* For air gap bundles, follow the same image and digest guidance as in prior Embedded Cluster releases: avoid multi-architecture image digests in extension values where only single-arch images are bundled; use tags and empty digests where appropriate so the air gap builder can resolve images. #### Example @@ -170,47 +225,31 @@ apiVersion: embeddedcluster.replicated.com/v1beta1 kind: Config spec: extensions: - helm: - repositories: - - name: ingress-nginx - url: https://kubernetes.github.io/ingress-nginx - charts: - - name: ingress-nginx - chartname: ingress-nginx/ingress-nginx - namespace: ingress-nginx - version: "4.8.3" - values: | - controller: - service: - type: NodePort - nodePorts: - http: "80" - https: "443" - # Known issue: Only use image tags for multi-architecture images. - # Set digest to empty string to ensure the air gap builder uses - # single-architecture images. - image: - digest: "" - digestChroot: "" - admissionWebhooks: - patch: - image: - digest: "" + helmCharts: + - chart: + name: ingress-nginx + chartVersion: "4.11.3" + releaseName: ingress-nginx + namespace: ingress-nginx + values: | + controller: + service: + type: NodePort + nodePorts: + http: "80" + https: "443" + image: + digest: "" + digestChroot: "" ``` -### Requirements - -* The `version` field is required. Failing to specify a chart version will cause problems for upgrades. - -* If you need to install multiple charts in a particular order, set the `order` field to a value greater than or equal to 10. Numbers below 10 are reserved for use by Embedded Cluster to deploy things like a storage provider and the Admin Console. If an `order` is not provided, Helm extensions are installed with order 10. - ## unsupportedOverrides :::important This feature should be used with caution by advanced users who understand the risks and ramifications of changing the default configuration. ::: -Unsupported overrides allow you to override Embedded Cluster's default configuration, including the k0s config and the Helm values for extensions like KOTS and OpenEBS. This should be used with caution because changes here are untested and can disrupt or break Embedded Clusters. Any issues that are caused by unsupported overrides are not supported. +Unsupported overrides allow you to override Embedded Cluster's default configuration, including the k0s config and the Helm values for built-in extensions like KOTS and the Embedded Cluster Operator. Use overrides carefully: they are untested combinations and can disrupt clusters. Issues caused by unsupported overrides are not supported. While they should be used with caution, unsupported overrides are useful if you need to make changes that are not otherwise exposed by Embedded Cluster. @@ -220,7 +259,10 @@ By default, Embedded Cluster uses a k0s config that is tested and known to work For more information on the k0s config, see [Configuration options](https://docs.k0sproject.io/stable/configuration/#configuration-file-reference) in the k0s documentation. -For example, you can do the following to enable WireGuard-based encryption. Note that other configuration might be necessary. See [`spec.network.calico`](https://docs.k0sproject.io/stable/configuration/#specnetworkcalico) in the k0s documentation for more details. +The value of `unsupportedOverrides.k0s` is a string containing YAML that becomes (or patches) the k0s configuration Embedded Cluster uses. How deeply that YAML is merged with Embedded Cluster defaults can depend on the field; treat overrides as high risk and validate in a non-production cluster. + +For example, you can enable WireGuard-based encryption (other configuration may be required; see [`spec.network.calico`](https://docs.k0sproject.io/stable/configuration/#specnetworkcalico) in the k0s documentation): + ```yaml apiVersion: embeddedcluster.replicated.com/v1beta1 kind: Config @@ -238,20 +280,18 @@ spec: * The `spec.api` and `spec.storage` keys in the k0s config cannot be changed after installation. Whereas most keys in the k0s config apply to the whole cluster, these two keys are set for each node. Embedded Cluster cannot update these keys on each individual node during updates, so they cannot be changed after installation. -* Overrides overwrite the corresponding fields in the k0s configuration. They are not merged into Embedded Cluster’s default configuration. When using overrides to override a list, for example, ensure that you include other elements in the list that Embedded Cluster includes by default. +* Overrides can replace whole sections of the k0s configuration rather than deep-merge with every default. When overriding a list (for example, `workerProfiles`), you may need to include entries that Embedded Cluster relies on by default, or behavior can change in ways that are hard to predict. Confirm the effective k0s config for your release if you rely on defaults plus overrides. ### Override the Helm Values for Built-In Extensions -Embedded Cluster deploys built-in extensions like KOTS and OpenEBS to provide capabilities like storage and application management. These extensions are deployed with Helm, and the Helm values for each can be modified if necessary. - -To modify these values, you can use the `unsupportedOverrides.builtInExtensions` key of the Embedded Cluster Config. Each chart you want to modify is an item in the array. The `name` key identifies the Helm chart that you want to modify, and the `values` key is a string where you specify your modified Helm values. Your modified values are merged into the values used by Embedded Cluster. +Embedded Cluster deploys built-in extensions with Helm. You can patch their values with `unsupportedOverrides.builtInExtensions`. Each item sets `name` (the chart to patch) and `values` (a multi-line YAML string). Your values are merged into the defaults Embedded Cluster uses. -The following are the built-in extensions available for modification: +Common `name` values include: -- `openebs` - `admin-console` -- `velero` - `embedded-cluster-operator` +- `openebs` +- `velero` #### Example @@ -261,55 +301,36 @@ kind: Config spec: unsupportedOverrides: builtInExtensions: - - name: openebs + - name: admin-console values: | - key: value + labels: + release-custom-label: release-custom-value + - name: embedded-cluster-operator + values: | + global: + labels: + release-custom-label: release-custom-value ``` -### Configure Velero Plugins - -> Introduced in Embedded Cluster v2.13.0 - -If the customer license has the **Allow Disaster Recovery (Alpha)** option enabled, you can add custom Velero plugins in the `extensions.velero.plugins` key to extend Velero's backup and restore capabilities. For example, you can add support for backing up databases like PostgreSQL, MySQL, or other stateful applications that require advanced disaster recovery capabilities. - -Each plugin that you add to the `extensions.velero.plugins` key must have a name and a publicly accessible container image. For more information about the Velero plugin system, including how to create custom plugins, see [Velero plugin system](https://velero.io/docs/v1.17/overview-plugins/) in the Velero documentation. - -#### Requirements - -* The image for the Velero plugin must be available publicly. Images behind authentication are not supported. -* The **Allow Disaster Recovery (Alpha)** option must be enabled in the license for Velero plugins to work. For more information about how to enable the Embedded Cluster disaster recovery feature, see [Disaster Recovery for Embedded Cluster (Alpha)](/embedded-cluster/v2/embedded-disaster-recovery). - -#### Example +### Configure the Kubelet -```yaml -apiVersion: embeddedcluster.replicated.com/v1beta1 -kind: Config -spec: - extensions: - velero: - # Each plugin requires a name and publicly accessible container image - plugins: - - name: velero-plugin-postgresql - image: myvendor/velero-postgresql:v1.0.0 - imagePullPolicy: Always -``` +You can configure the Kubelet to customize worker nodes with Embedded Cluster. One common use case is raising the per-node pod limit (`maxPods`). Another is tuning parallel image pulls (`maxParallelImagePulls`). -### Configure the Kubelet +Add a _worker profile_ under `unsupportedOverrides.k0s` at `config.spec.workerProfiles[]`. When a worker profile is defined, Embedded Cluster uses it for every node during initial installation and when joining nodes. -You can configure the Kubelet to customize your worker nodes with Embedded Cluster. One common use case for configuring the Kubelet is that you need more pods on a single node than the default limit of 100. In this case, you could set the `maxPods` Kubelet configuration option to 150. Another common example is reducing startup time by setting `maxParallelImagePulls` to increase the maximum number of image pulls that can be done in parallel. +Each profile requires: -You can customize the Kubelet configuration settings by adding a _worker profile_ in the Embedded Cluster Config under `unsupportedOverrides.k0s.config.spec.workerProfiles[]`. When a worker profile is defined, Embedded Cluster uses the profile for every node in the cluster during initial installation and when joining nodes to the cluster. +* `name`: Profile name. Do not use `default`; it is reserved by k0s. +* `values`: Kubelet settings. See [KubeletConfiguration](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/#kubelet-config-k8s-io-v1beta1-KubeletConfiguration) in the Kubernetes documentation. -The worker profile has the following required fields: -* `name`: The name of the worker profile. Do not use the name `default` for your custom worker profile. `default` is reserved by k0s. -* `values`: The Kubelet configuration settings for the profile. For a complete list of the available Kubelet configuration options that you can set in a worker profile, see [KubeletConfiguration](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/#kubelet-config-k8s-io-v1beta1-KubeletConfiguration) in the Kubernetes documentation. +For more information, see [spec.workerProfiles](https://docs.k0sproject.io/stable/configuration/#specworkerprofiles) in the k0s documentation. -For more information about how to define worker profiles, see [spec.workerProfiles](https://docs.k0sproject.io/stable/configuration/#specworkerprofiles) in the k0s documentation. +You can combine worker profiles with other k0s settings in the same `k0s` string (for example, `metadata`, `telemetry`, or `network`). #### Limitations * The worker profile is set during initial installation. Worker profiles cannot be changed or added on upgrade. -* Embedded Cluster supports only one worker profile that is used for all nodes. If you add more than one worker profile in the `workerProfiles[]` array in the Embedded Cluster Config, only the first profile is used. +* Embedded Cluster supports only one worker profile that is used for all nodes. If you add more than one profile in `workerProfiles[]`, only the first profile is used. #### Example @@ -321,9 +342,7 @@ spec: k0s: | config: spec: - # Define a profile that sets maxPods to 150 workerProfiles: - # Note: Do not use the name "default" - name: custom-maxpods values: maxPods: 150 diff --git a/embedded-cluster/embedded-manage-nodes.mdx b/embedded-cluster/embedded-manage-nodes.mdx new file mode 100644 index 0000000000..39e46ee9ea --- /dev/null +++ b/embedded-cluster/embedded-manage-nodes.mdx @@ -0,0 +1,228 @@ +import ShellCommand from "../docs/partials/embedded-cluster/_shell-command.mdx" + +# Access and manage embedded clusters + +This topic describes managing nodes in clusters created with Replicated Embedded Cluster, including how to add nodes and enable high-availability for multi-node clusters. + +## Access the cluster + +You can use the CLI to access the cluster. This is useful for development or troubleshooting. + + + +## Configure multi-node clusters + +This section describes how to join nodes to a cluster with Embedded Cluster. + +### Limitations + +Multi-node clusters with Embedded Cluster have the following limitations: + +* Setting node roles with the Embedded Cluster Config [roles](embedded-config#roles) key is Beta. + +* The first node added to the cluster is always a controller and cannot be assigned any custom roles. For more information about configuring node roles, see [roles](embedded-config#roles) in _Embedded Cluster Config_. + +* The same Embedded Cluster data directory used at installation is used for all nodes joined to the cluster. This is either the default `/var/lib/embedded-cluster` directory or the directory set with the [`--data-dir`](embedded-cluster-install#flags) flag. You cannot choose a different data directory for Embedded Cluster when joining nodes. + +* More than one controller node should not be joined at the same time. When joining a controller node, a warning is printed that explains that the user should not attempt to join another node until the controller node joins successfully. + +* The `join print-command` command always returns the commands for joining a node with the controller role. It does not support printing the join command for any custom node roles defined in the Embedded Cluster Config `roles` key. See [Automate Controller Node Joins](#automate-node-joins) below. + +### Requirement + +To deploy multi-node clusters with Embedded Cluster, the **Multi-node Cluster (Embedded Cluster only)** license field must be enabled for the customer. For more information about managing customer licenses, see [Create and Manage Customers](/vendor/releases-creating-customer). + +### Add nodes to a cluster {#add-nodes} + +This section describes how to add nodes to a cluster with Embedded Cluster. + +To add a node to a cluster with Embedded Cluster: + +1. (Optional) In the Embedded Cluster Config, configure the `roles` key to customize node roles. For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. When you are done, create and promote a new release with the updated Config. + +1. Do one of the following: + + 1. Follow the steps in [Online Installation with Embedded Cluster](installing-embedded) or [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap) to install. When you see the **Nodes** screen as part of the installation flow in the Admin Console, continue to the next step. + + 1. Otherwise, to add a node to an existing cluster: + + 1. Log in to the Admin Console. + + 1. If you promoted a new release that configures the `roles` key in the Embedded Cluster Config, update the instance to the new version. See [Perform Updates in Embedded Clusters](updating-embedded). + + 1. Go to **Cluster Management > Add node** at the top of the page. + +1. If you configured the `roles` key to customize node roles, select one or more roles for the node. + + The Admin Console page is updated to display the commands for downloading the Embedded Cluster binary, extracting the binary, and joining the node to the cluster based on the roles you selected. Keep this Admin Console page open for the next steps. + + :::note + The role cannot be changed after a node is added. If you need to change a node’s role, reset the node and add it again with the new role. + ::: + +1. SSH onto the node that you want to join. + +1. Copy the curl command provided in the Admin Console to download the Embedded Cluster binary and then run it on the node you want to join. + +1. Copy and run the tar command to extract the Embedded Cluster binary. + +1. Copy and run the join command to add the node to the cluster. + +1. In the Admin Console, either on the installation **Nodes** screen or on the **Cluster Management** page, verify that the node appears. Wait for the node's status to change to Ready. + +1. Repeat these steps for each node you want to add. + +### Automate controller node joins {#automate-node-joins} + +With Embedded Cluster, you can use the command line to get the commands for joining controller nodes, rather than having to log into the Admin Console UI to get the commands. This is especially useful when testing multi-node Embedded Cluster installations where you need to automate the process of joining controller nodes to a cluster. + +To automate controller node joins with Embedded Cluster: + +1. SSH onto a controller node that is already joined to the cluster. On the controller node, run: + + ```bash + sudo ./APP_SLUG join print-command + ``` + Where `APP_SLUG` is the unique application slug. + + The output lists the commands for downloading the Embedded Cluster binary, extracting the binary, and joining a new controller node to the cluster. + + **Example:** + + ``` + sudo ./your-app-slug join print-command + + curl -k https://172.17.0.2:30000/api/v1/embedded-cluster/binary -o your-app-slug.tar.gz && \ + tar -xvf your-app-slug.tar.gz && \ + sudo ./your-app-slug join 172.17.0.2:30000 1234aBcD + ``` + +1. On the node that you want to join as a controller, run each of the commands provided in the `join print-command` output to download the Embedded Cluster binary, extract the binary, and join the node to the cluster. + +## Configure high availability for multi-node clusters {#ha} + +Multi-node clusters are not highly available by default. The first node of the cluster holds important data for Kubernetes and KOTS, such that the loss of this node would be catastrophic for the cluster. Enabling high availability requires that at least three controller nodes are present in the cluster. + +Users are automatically prompted to enable HA when joining the third controller node to a cluster. Alternatively, users can enable HA with the `enable-ha` command after adding three or more controller nodes. + +### Requirements + +Enabling high availability has the following requirements: + +* High availability is supported with Embedded Cluster 1.4.1 and later. + +* The [`enable-ha`](#enable-ha-existing) command is available with Embedded Cluster 2.3.0 and later. + +* High availability is supported only for clusters where at least three nodes with the controller role are present. + +### Best practices for high availability + +Consider the following best practices and recommendations for creating HA clusters: + +* At least three _controller_ nodes that run the Kubernetes control plane are required for HA. This is because clusters use a quorum system, in which more than half the nodes must be up and reachable. In clusters with three controller nodes, the Kubernetes control plane can continue to operate if one node fails because a quorum can still be reached by the remaining two nodes. By default, with Embedded Cluster, all new nodes added to a cluster are controller nodes. For information about customizing the controller node role, see [roles](embedded-config#roles) in _Embedded Cluster Config_. + +* Always use an odd number of controller nodes in HA clusters. Using an odd number of controller nodes ensures that the cluster can make decisions efficiently with quorum calculations. Clusters with an odd number of controller nodes also avoid split-brain scenarios where the cluster runs as two, independent groups of nodes, resulting in inconsistencies and conflicts. + +* You can have any number of _worker_ nodes in HA clusters. Worker nodes do not run the Kubernetes control plane, but can run workloads such as application or Replicated KOTS workloads. + +### Create a multi-node cluster with high availability {#create-ha} + +You can enable high availability for a multi-node cluster when joining the third controller node. Alternatively, you can enable HA for an existing cluster with three or more controller nodes. For more information, see [Enable High Availability For an Existing Cluster](#enable-ha-existing) below. + +To create a multi-node HA cluster: + +1. Set up a cluster with at least two controller nodes. You can do an online (internet-connected) or air gap installation. For more information, see [Online Installation with Embedded Cluster](installing-embedded) or [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). + +1. Get the commands for downloading the Embedded Cluster binary, extracting the binary, and joining the third controller node either in the Admin Console **Cluster Management** tab or by running the following command on an existing node: + + ```bash + sudo ./APP_SLUG join print-command + ``` + Where `APP_SLUG` is the unique application slug. + +1. SSH onto the node that you want to add as a third controller. + +1. On the node that you want to add as a third controller, run each of the commands that you copied. + + :::note + For Embedded Cluster versions earlier than 2.3.0, pass the `--enable-ha` flag with the `join` command. + ::: + +1. In response to the prompt asking if you want to enable high availability, type `y` or `yes`. + +1. Wait for the migration to HA to complete. + +### Enable high availability for an existing cluster {#enable-ha-existing} + +To enable high availability for an existing Embedded Cluster installation with three or more controller nodes, run the following command: + +```bash +sudo ./APP_SLUG enable-ha +``` + +Where `APP_SLUG` is the unique slug for the application. + +## Reset nodes and remove clusters + +This section describes how to reset individual nodes and how to delete an entire multi-node cluster using the Embedded Cluster [reset](embedded-cluster-reset) command. + +### About the `reset` command + +Resetting a node with Embedded Cluster removes the cluster and your application from that node. This is useful for iteration, development, and when mistakes are made because you can reuse the machine instead of having to procure a new one. + +The `reset` command performs the following steps: + +1. Run safety checks. For example, `reset` does not remove a controller node when there are workers nodes available. And, it does not remove a node when the etcd cluster is unhealthy. +1. Drain the node and evict all the Pods gracefully +1. Delete the node from the cluster +1. Stop and reset k0s +1. Remove all Embedded Cluster files +1. Reboot the node + +For more information about the command, see [reset](embedded-cluster-reset). + +### Limitations and best practices + +Before you reset a node or remove a cluster, consider the following limitations and best practices: + +* When you reset a node, OpenEBS PVCs on the node are deleted. Only PVCs created as part of a StatefulSet are recreated automatically on another node in the cluster. To recreate other PVCs, redeploy the application in the cluster. + +* If you need to reset one controller node in a three-node cluster, first join a fourth controller node to the cluster before removing the target node. This ensures that you maintain a minimum of three nodes for the Kubernetes control plane. You can add and remove worker nodes as needed because they do not have any control plane components. + +* When resetting a single node or deleting a test environment, you can include the `--force` flag with the `reset` command to ignore any errors. + +* When removing a multi-node cluster, run `reset` on each of the worker nodes first. Then, run `reset` on controller nodes. Controller nodes also remove themselves from etcd membership. + +### Reset a node {#reset-a-node} + +To reset a node: + +1. SSH onto the node. Ensure that the Embedded Cluster binary is still available on the machine. + +1. Run the following command to remove the node and reboot the machine: + + ```bash + sudo ./APP_SLUG reset + ``` + Where `APP_SLUG` is the unique slug for the application. + +### Remove a multi-node cluster + +To remove a multi-node cluster: + +1. SSH onto a worker node. + + :::note + The safety checks for the `reset` command prevent you from removing a controller node when there are still worker nodes available in the cluster. + ::: + +1. Remove the node and reboot the machine: + + ```bash + sudo ./APP_SLUG reset + ``` + Where `APP_SLUG` is the unique slug for the application. + +1. After removing all the worker nodes in the cluster, SSH onto a controller node and run the `reset` command to remove the node. + +1. Repeat the previous step on the remaining controller nodes in the cluster. diff --git a/embedded-cluster/embedded-overview.mdx b/embedded-cluster/embedded-overview.mdx index 816ecd4aba..e59cc8d876 100644 --- a/embedded-cluster/embedded-overview.mdx +++ b/embedded-cluster/embedded-overview.mdx @@ -51,13 +51,13 @@ Embedded Cluster host preflight checks have the following limitations: ### Multi-node installations -Embedded Cluster supports installations in mutli-node clusters. Your end customers can add nodes to a cluster during or after installation from the Admin Console. For more information, see [Manage Multi-Node Clusters with Embedded Cluster](/embedded-cluster/v2/embedded-manage-nodes). +Embedded Cluster supports installations in mutli-node clusters. Your end customers can add nodes to a cluster during or after installation from the Admin Console. For more information, see [Manage Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). #### High availability Multi-node clusters are not highly available by default. Enabling high availability (HA) requires that at least three controller nodes are present in the cluster. Users can enable HA when joining the third node. -For more information about creating HA multi-node clusters with Embedded Cluster, see [Enable High Availability](/embedded-cluster/v2/embedded-manage-nodes#ha) in _Managing Multi-Node Clusters with Embedded Cluster_. +For more information about creating HA multi-node clusters with Embedded Cluster, see [Enable High Availability](embedded-manage-nodes#ha) in _Managing Multi-Node Clusters with Embedded Cluster_. #### Node roles diff --git a/embedded-cluster/embedded-troubleshooting.mdx b/embedded-cluster/embedded-troubleshooting.mdx index 8d0d43f484..a099537382 100644 --- a/embedded-cluster/embedded-troubleshooting.mdx +++ b/embedded-cluster/embedded-troubleshooting.mdx @@ -86,7 +86,7 @@ To troubleshoot: ``` Where `APP_SLUG` is the unique slug for the application. - For more information, see [Reset a Node](/embedded-cluster/v2/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. + For more information, see [Reset a Node](embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. 1. Re-install with Embedded Cluster. @@ -152,7 +152,7 @@ Reasons can include: ``` Where `APP_SLUG` is the unique slug for the application. - For more information, see [Reset a Node](/embedded-cluster/v2/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. + For more information, see [Reset a Node](embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. 1. Reinstall the application with different CIDRs using the `--cidr` flag: @@ -185,7 +185,7 @@ Reasons can include: sudo ./APP_SLUG reset ``` Where `APP_SLUG` is the unique slug for the application. - For more information, see [Reset a Node](/embedded-cluster/v2/embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. + For more information, see [Reset a Node](embedded-manage-nodes#reset-a-node) in _Access and Manage Embedded Clusters_. 1. Re-install with Embedded Cluster. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx index 2d674822cd..57f782b814 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx @@ -200,7 +200,7 @@ Before you reset a node or remove a cluster, consider the following limitations * When removing a multi-node cluster, run `reset` on each of the worker nodes first. Then, run `reset` on controller nodes. Controller nodes also remove themselves from etcd membership. -### Reset a node +### Reset a node {#reset-a-node} To reset a node: diff --git a/sidebarEmbeddedCluster.js b/sidebarEmbeddedCluster.js index 2b7af8127c..fa64016a84 100644 --- a/sidebarEmbeddedCluster.js +++ b/sidebarEmbeddedCluster.js @@ -7,6 +7,7 @@ module.exports = { "installing-embedded", "installing-embedded-air-gap", "installing-embedded-automation", + "embedded-manage-nodes", "updating-embedded", "embedded-troubleshooting", { From d6b4b95736ae1aff8451350e4c647a703c1c4fa0 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Thu, 2 Apr 2026 13:52:06 -0600 Subject: [PATCH 13/31] install docs edits --- .../installing-embedded-air-gap.mdx | 21 ++++- .../installing-embedded-automation.mdx | 92 ------------------- embedded-cluster/installing-embedded.mdx | 24 ++++- sidebarEmbeddedCluster.js | 1 - 4 files changed, 40 insertions(+), 98 deletions(-) delete mode 100644 embedded-cluster/installing-embedded-automation.mdx diff --git a/embedded-cluster/installing-embedded-air-gap.mdx b/embedded-cluster/installing-embedded-air-gap.mdx index 4da823f9da..d4193b0499 100644 --- a/embedded-cluster/installing-embedded-air-gap.mdx +++ b/embedded-cluster/installing-embedded-air-gap.mdx @@ -46,7 +46,7 @@ To use the guided install experience in the Enterprise Portal: 1. Follow the Linux install instructions for Embedded Cluster in an air gap environment. -### Install using the Replicated Vendor Portal +### Install using instructions from the Vendor Portal To install from the Vendor Portal: @@ -121,7 +121,9 @@ To install from the Vendor Portal: ## Install using the CLI (headless) -To install headlessly in an air gap environment, download and extract assets on a machine with internet access, transfer them to the air-gapped host, then run `install` there with air gap and headless flags. +With headless installation, you provide all the necessary installation assets, such as the license file and the application config values, with the installation command rather than through the UI. Any preflight checks defined for the application run automatically during headless installations from the command line rather than being displayed in the UI. You can also ignore preflight checks during headless installations when testing in development environments. See [Ignore preflight checks during installation](#ignore-preflights) on this page. + +To install headlessly in an air gap environment: 1. Complete the Vendor Portal steps to build the air gap bundle, enable **Airgap Download Enabled** for the customer, and open **Install instructions** with **Install in an air gap environment** selected. For more detail, see steps 1 through 6 in [Install using the Replicated Vendor Portal](#install-using-the-replicated-vendor-portal). @@ -149,3 +151,18 @@ To install headlessly in an air gap environment, download and extract assets on Replace placeholders with values for your environment. Add any other flags you need. For the full set of flags, see [install](embedded-cluster-install). 1. Monitor the command output until the install completes, then access your application as you normally do. + +## (Optional) Ignore preflight checks during installation {#ignore-preflights} + +You can ignore both application-level preflight checks and Embedded Cluster host preflight checks during installation. When you ignore preflight checks, the installation proceeds despite any preflight failures. This is useful for automated installations in development environments. For more information about the `--ignore-host-preflights` and `--ignore-app-preflights` options, see [install](embedded-cluster-install). + +Ignoring host preflight checks is _not_ recommended for production installations. + +* To ignore preflight checks: + + ```bash + sudo ./APP_SLUG install --license license.yaml --ignore-host-preflights --ignore-app-preflights --yes + ``` + Where: + * `APP_SLUG` is the unique slug for the application + * The `--yes` flag addresses the prompt for `--ignore-host-preflights` to continue with installation diff --git a/embedded-cluster/installing-embedded-automation.mdx b/embedded-cluster/installing-embedded-automation.mdx deleted file mode 100644 index 5027fc1c39..0000000000 --- a/embedded-cluster/installing-embedded-automation.mdx +++ /dev/null @@ -1,92 +0,0 @@ -import ConfigValuesExample from "../docs/partials/configValues/_configValuesExample.mdx" -import ConfigValuesProcedure from "../docs/partials/configValues/_config-values-procedure.mdx" -import ConfigValuesRequirements from "../docs/partials/configValues/_requirements.mdx" - -# Automate installation with Embedded Cluster - -This topic describes how to install an application with Replicated Embedded Cluster from the command line, without needing to access the Replicated KOTS Admin Console. - -## Overview - -A common use case for installing with Embedded Cluster from the command line is to automate installation, such as performing headless installations as part of CI/CD pipelines. - -With headless installation, you provide all the necessary installation assets, such as the license file and the application config values, with the installation command rather than through the Admin Console UI. Any preflight checks defined for the application run automatically during headless installations from the command line rather than being displayed in the Admin Console. - -## Prerequisite - -Create a ConfigValues resource to define the configuration values for the application. The ConfigValues resource allows you to pass the configuration values for an application from the command line with the install command, rather than through the Admin Console UI. For air-gapped environments, ensure that the ConfigValues file can be accessed from the installation environment. - -The ConfigValues resource includes the fields that are defined in the Replicated KOTS Config custom resource for the release, along with the user-supplied and default values for each field, as shown in the example below: - - - -#### ConfigValues requirements - - - -For more information, see [ConfigValues](/reference/custom-resource-configvalues). - -## Limitation - -Automating deployment with Embedded Cluster is supported only for the initial installation. Performing automated (headless) updates of existing installations with Embedded Cluster is not supported. For information about how to update an existing installation through the Admin Console UI, see [Perform Updates in Embedded Clusters](updating-embedded). - -## Online (internet-connected) installation - -To install with Embedded Cluster in an online environment: - -1. Follow the steps provided in the Vendor Portal to download and untar the Embedded Cluster installation assets. For more information, see [Online Installation with Embedded Cluster](installing-embedded). - -1. Run the following command to install: - - ```bash - sudo ./APP_SLUG install --license PATH_TO_LICENSE \ - --config-values PATH_TO_CONFIGVALUES \ - --admin-console-password ADMIN_CONSOLE_PASSWORD - ``` - - Where: - * `APP_SLUG` is the unique slug for the application. - * `PATH_TO_LICENSE` is the path to the customer license. - * `ADMIN_CONSOLE_PASSWORD` is a password for accessing the Admin Console. - * `PATH_TO_CONFIGVALUES` is the path to the ConfigValues file. - - For more information about the `install` command options, see [install](embedded-cluster-install). - -## Air gap installation - -To install with Embedded Cluster in an air-gapped environment: - -1. Follow the steps provided in the Vendor Portal to download and untar the Embedded Cluster air gap installation assets. For more information, see [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). - -1. Ensure that the Embedded Cluster installation assets are available on the air-gapped machine, then run the following command to install: - - ```bash - sudo ./APP_SLUG install --license PATH_TO_LICENSE \ - --config-values PATH_TO_CONFIGVALUES \ - --admin-console-password ADMIN_CONSOLE_PASSWORD \ - --airgap-bundle PATH_TO_AIRGAP_BUNDLE - ``` - - Replace: - * `APP_SLUG` with the unique slug for the application. - * `PATH_TO_LICENSE` with the path to the customer license. - * `PATH_TO_CONFIGVALUES` with the path to the ConfigValues file. - * `ADMIN_CONSOLE_PASSWORD` with a password for accessing the Admin Console. - * `PATH_TO_AIRGAP_BUNDLE` with the path to the Embedded Cluster `.airgap` bundle for the release. - - For the complete list of `install` options, see [install](embedded-cluster-install). - -## (Optional) Ignore preflight checks during installation - -You can ignore both application-level preflight checks and Embedded Cluster host preflight checks during installation. When you ignore preflight checks, the installation proceeds despite any preflight failures. This is useful for automated installations in development environments. For more information about the `--ignore-host-preflights` and `--ignore-app-preflights` options, see [install](embedded-cluster-install). - -Ignoring host preflight checks is _not_ recommended for production installations. - -* To ignore preflight checks: - - ```bash - sudo ./APP_SLUG install --license license.yaml --ignore-host-preflights --ignore-app-preflights --yes - ``` - Where: - * `APP_SLUG` is the unique slug for the application - * The `--yes` flag addresses the prompt for `--ignore-host-preflights` to continue with installation diff --git a/embedded-cluster/installing-embedded.mdx b/embedded-cluster/installing-embedded.mdx index 80528d3b88..7f55925b8e 100644 --- a/embedded-cluster/installing-embedded.mdx +++ b/embedded-cluster/installing-embedded.mdx @@ -26,7 +26,7 @@ To use the guided install experience in the Enterprise Portal: 1. Follow the Linux install instructions for Embedded Cluster. -### Install using the Replicated Vendor Portal +### Install using instructions from the Vendor Portal To install from the Vendor Portal: @@ -62,9 +62,11 @@ To install from the Vendor Portal: Links to port-forwarded services are not available on this page. ::: -## Install using the CLI (headless) +## Install using the CLI (Headless) -Embedded Cluster 3.x supports headless installs. The way you start a headless install is slightly different from Embedded Cluster 2.x. +With headless installation, you provide all the necessary installation assets, such as the license file and the application config values, with the installation command rather than through the UI. Any preflight checks defined for the application run automatically during headless installations from the command line rather than being displayed in the UI. You can also ignore preflight checks during headless installations when testing in development environments. See [Ignore preflight checks during installation](#ignore-preflights) on this page. + +To install using the CLI: 1. In the Vendor Portal, open the **Customers** page and select a customer that is assigned to the channel you use for testing. @@ -95,3 +97,19 @@ Embedded Cluster 3.x supports headless installs. The way you start a headless in Replace `APP_SLUG`, `LICENSE_FILE`, `PATH_TO_CONFIGVALUES`, and `INSTALLER_PASSWORD` with the values for your environment. Add any other flags you need. For the full set of flags, see [install](embedded-cluster-install). 1. Monitor the command output until the install completes, then access your application as you normally do. + + +## (Optional) Ignore preflight checks during installation {#ignore-preflights} + +You can ignore both application-level preflight checks and Embedded Cluster host preflight checks during installation. When you ignore preflight checks, the installation proceeds despite any preflight failures. This is useful for automated installations in development environments. For more information about the `--ignore-host-preflights` and `--ignore-app-preflights` options, see [install](embedded-cluster-install). + +Ignoring host preflight checks is _not_ recommended for production installations. + +* To ignore preflight checks: + + ```bash + sudo ./APP_SLUG install --license license.yaml --ignore-host-preflights --ignore-app-preflights --yes + ``` + Where: + * `APP_SLUG` is the unique slug for the application + * The `--yes` flag addresses the prompt for `--ignore-host-preflights` to continue with installation diff --git a/sidebarEmbeddedCluster.js b/sidebarEmbeddedCluster.js index fa64016a84..8c2c834d8d 100644 --- a/sidebarEmbeddedCluster.js +++ b/sidebarEmbeddedCluster.js @@ -6,7 +6,6 @@ module.exports = { "installing-embedded-requirements", "installing-embedded", "installing-embedded-air-gap", - "installing-embedded-automation", "embedded-manage-nodes", "updating-embedded", "embedded-troubleshooting", From f9baf82d51dffcc08f73a95d7da54438a907700b Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Thu, 2 Apr 2026 14:28:11 -0600 Subject: [PATCH 14/31] edits to upgrade and install steps --- embedded-cluster/embedded-overview.mdx | 14 +++-- embedded-cluster/embedded-using.mdx | 24 +-------- .../installing-embedded-air-gap.mdx | 16 +++--- embedded-cluster/installing-embedded.mdx | 12 ++--- embedded-cluster/updating-embedded.mdx | 51 ++++++++++++------- sidebarEmbeddedCluster.js | 13 +++-- 6 files changed, 67 insertions(+), 63 deletions(-) diff --git a/embedded-cluster/embedded-overview.mdx b/embedded-cluster/embedded-overview.mdx index e59cc8d876..9d318e581e 100644 --- a/embedded-cluster/embedded-overview.mdx +++ b/embedded-cluster/embedded-overview.mdx @@ -1,7 +1,7 @@ import EmbeddedCluster from "../docs/partials/embedded-cluster/v3/_definition.mdx" import HaArchitecture from "../docs/partials/embedded-cluster/v3/_multi-node-ha-arch.mdx" -# Embedded Cluster overview +# Embedded Cluster overview (Beta) This topic provides an introduction to Replicated Embedded Cluster. @@ -13,9 +13,11 @@ This topic provides an introduction to Replicated Embedded Cluster. ### Removal of KOTS -Embedded Cluster 3.x removes KOTS from the architecture. That simplifies install and upgrade, but the KOTS CLI no longer works with Embedded Cluster, and there is no KOTS Admin Console in the previous form. The new installer provides the UI instead. Benefits include increased reliability, simpler feature work, and fewer dependencies running in the cluster. +Embedded Cluster 3.x removes KOTS from the architecture. The new installer provides the UI instead. Benefits include increased reliability, simpler feature work, and fewer dependencies running in the cluster. -Because KOTS is removed, you must include the [Replicated SDK](/vendor/replicated-sdk-overview) in your application to get reporting from application status informers (for example, for notifications and visibility in the Vendor Portal and Enterprise Portal). +The KOTS CLI no longer works with Embedded Cluster, and there is no KOTS Admin Console. + +Also, because KOTS is removed, you must include the [Replicated SDK](/vendor/replicated-sdk-overview) in your application to get reporting from application status informers (for example, for notifications and visibility in the Vendor Portal and Enterprise Portal). ### Troubleshoot Preflight `v1beta3` @@ -25,6 +27,8 @@ Preflight checks must use Troubleshoot `v1beta3`. `v1beta2` preflight specs are Embedded Cluster supports installations in online (internet-connected) environments and air gap environments with no outbound internet access. +Embedded Cluster also supports installing using the built-in interactive UI or performing headless installs from the CLI. + The Embedded Cluster Config is included in the application release in the Replicated Vendor Portal and is used to generate the Embedded Cluster installation assets. Users can download these installation assets from the Replicated app service (`replicated.app`) on the command line, then run the Embedded Cluster installation command to install Kubernetes. Finally, users can install the application using the UI or CLI. During installation, users can optionally add nodes to the cluster and configure the application. For more information about how to install with Embedded Cluster, see: @@ -85,6 +89,6 @@ The built-in extensions installed by Embedded Cluster include: ## Limitations {#ec-limitations} -* No disaster recovery support +* Embedded Cluster v3 does not support disaster recovery. -* Some Replicated template functions are not implemented in Embedded Cluster v3, either because they are discouraged in this model or because they are not yet ported. Contact Replicated if a missing template function blocks your release. +* Some Replicated template functions are not implemented in Embedded Cluster v3, either because they are discouraged or because they are not yet ported. Contact Replicated if a missing template function blocks your release. diff --git a/embedded-cluster/embedded-using.mdx b/embedded-cluster/embedded-using.mdx index cbcccb1045..521abb60cb 100644 --- a/embedded-cluster/embedded-using.mdx +++ b/embedded-cluster/embedded-using.mdx @@ -24,27 +24,7 @@ To add the Embedded Cluster Config: 1. Save the release and promote it to the channel that you use for testing internally. -1. Install with Embedded Cluster in a development environment to test: - - 1. Go to the **Manage customer** page for a new or existing Development customer. - - 1. Under **Install types**, enable the **Embedded Cluster (current generation product)** option. Click **Save**. - - 1. At the top right of the customer page, click **Install instructions** and choose **Embedded Cluster**. A dialog appears with instructions on how to download the Embedded Cluster installation assets and install your application. - - ![Customer install instructions drop down button](/images/customer-install-instructions-dropdown.png) - - [View a larger version of this image](/images/customer-install-instructions-dropdown.png) - - 1. On your VM, run the commands in the **Embedded Cluster install instructions** dialog. - - Embedded cluster install instruction dialog - - [View a larger version of this image](/images/embedded-cluster-install-dialog-latest.png) - - 1. Enter an Admin Console password when prompted. - - The Admin Console URL is printed when the installation finishes. Access the Admin Console and follow the instructions in the wizard to install your application. +1. Install with Embedded Cluster in a development environment to test. See [Online installation with Embedded Cluster](installing-embedded) or [Air gap installation with Embedded Cluster](installing-embedded-air-gap). 1. After successfully installing your application with Embedded Cluster, customize the [Embedded Cluster Config](embedded-config) as desired: * Add your custom domain for the Replicated proxy registry and Replicated app service. See [domains](embedded-config#domains). @@ -53,7 +33,7 @@ To add the Embedded Cluster Config: Replicated recommends that you work in small iterations and test your changes frequently in your development environment. -## (Optional) Serve installation assets using the vendor API +## (Optional) Serve installation assets using the Vendor API To install with Embedded Cluster, your end customers need to download the Embedded Cluster installer binary and their license. Air gap installations also require an air gap bundle. End customers can download all these installation assets using a curl command by following the installation steps available in the [Replicated Enterprise Portal](/vendor/enterprise-portal-about). diff --git a/embedded-cluster/installing-embedded-air-gap.mdx b/embedded-cluster/installing-embedded-air-gap.mdx index d4193b0499..dbd0a229e1 100644 --- a/embedded-cluster/installing-embedded-air-gap.mdx +++ b/embedded-cluster/installing-embedded-air-gap.mdx @@ -2,11 +2,7 @@ import Prerequisites from "../docs/partials/embedded-cluster/v3/_ec-prereqs.mdx" # Air gap installation with Embedded Cluster -This topic describes how to install an application with Replicated Embedded Cluster 3.x on a virtual machine (VM) or bare metal server with no outbound internet access. For online installations, see [Online installation with Embedded Cluster](installing-embedded). For an introduction to Embedded Cluster, see [Embedded Cluster overview](embedded-overview). - -During installation, Embedded Cluster runs a default set of [host preflight checks](embedded-overview#about-host-preflight-checks) that verify the environment meets installer requirements. - -For supported CLI flags, see [install](embedded-cluster-install). +This topic describes how to install an application with Replicated Embedded Cluster on a virtual machine (VM) or bare metal server with no outbound internet access. For online installations, see [Online installation with Embedded Cluster](installing-embedded). For an introduction to Embedded Cluster, see [Embedded Cluster overview](embedded-overview). ## Overview @@ -34,9 +30,13 @@ Before you install, complete the following prerequisites: -## Install using the UI +## Install using the Embedded Cluster UI + +This section describes how to install using the interative Embedded Cluster installer UI. +:::note These steps assume you download installation assets on a host that has internet access, then copy them into the air-gapped environment where Embedded Cluster will run. +::: ### Use the Enterprise Portal for a guided install @@ -107,7 +107,7 @@ To install from the Vendor Portal: 1. Log in to the installer with the password you set when you ran the install command. -1. On the **Configure** page, enter the configuration values for your application. This page serves the same role as the config screen in KOTS Admin Console, with an updated design. +1. On the **Configure** page, enter the configuration values for your application. 1. On the **Set Up** page, provide any information required for the cluster installation. This corresponds to values you previously passed with install flags in Embedded Cluster 2.x (for example, proxy settings), where those options apply in your air gap environment. @@ -121,7 +121,7 @@ To install from the Vendor Portal: ## Install using the CLI (headless) -With headless installation, you provide all the necessary installation assets, such as the license file and the application config values, with the installation command rather than through the UI. Any preflight checks defined for the application run automatically during headless installations from the command line rather than being displayed in the UI. You can also ignore preflight checks during headless installations when testing in development environments. See [Ignore preflight checks during installation](#ignore-preflights) on this page. +With headless installations, you provide all the necessary installation assets, such as the license file and the application config values, with the installation command rather than through the UI. Any preflight checks defined for the application run automatically during headless installations from the command line rather than being displayed in the UI. You can also ignore preflight checks during headless installations when testing in development environments. See [Ignore preflight checks during installation](#ignore-preflights) on this page. To install headlessly in an air gap environment: diff --git a/embedded-cluster/installing-embedded.mdx b/embedded-cluster/installing-embedded.mdx index 7f55925b8e..c8894185a5 100644 --- a/embedded-cluster/installing-embedded.mdx +++ b/embedded-cluster/installing-embedded.mdx @@ -2,11 +2,7 @@ import Prerequisites from "../docs/partials/embedded-cluster/v3/_ec-prereqs.mdx" # Online installation with Embedded Cluster -This topic describes how to install an application in an online (internet-connected) environment with Replicated Embedded Cluster 3.x. For air gap installations, see [Air gap installation with Embedded Cluster](installing-embedded-air-gap). For an introduction to Embedded Cluster, see [Embedded Cluster overview](embedded-overview). - -During installation, Embedded Cluster runs a default set of [host preflight checks](embedded-overview#about-host-preflight-checks) that verify the environment meets installer requirements. - -For supported CLI flags (proxy, network interface, and more), see [install](embedded-cluster-install). +This topic describes how to install an application in an online (internet-connected) environment with Replicated Embedded Cluster. For air gap installations, see [Air gap installation with Embedded Cluster](installing-embedded-air-gap). For an introduction to Embedded Cluster, see [Embedded Cluster overview](embedded-overview). ## Prerequisites @@ -16,7 +12,9 @@ Before you install, complete the following prerequisites: * Ensure that the required domains are reachable from the installation host. See [Firewall openings for online installations](installing-embedded-requirements#firewall). -## Install using the UI +## Install using the Embedded Cluster UI + +This section describes how to install using the interative Embedded Cluster installer UI. ### Use the Enterprise Portal for a guided install @@ -50,7 +48,7 @@ To install from the Vendor Portal: 1. Log in to the installer with the password you set when you ran the install command. -1. On the **Configure** page, enter the configuration values for your application. This page serves the same role as the config screen in KOTS Admin Console, with an updated design. +1. On the **Configure** page, enter the configuration values for your application. 1. On the **Set Up** page, provide any information required for the cluster installation. This corresponds to values you previously passed with install flags in Embedded Cluster 2.x (for example, proxy settings). diff --git a/embedded-cluster/updating-embedded.mdx b/embedded-cluster/updating-embedded.mdx index 662e9df39c..625a9b5254 100644 --- a/embedded-cluster/updating-embedded.mdx +++ b/embedded-cluster/updating-embedded.mdx @@ -8,7 +8,7 @@ Each Embedded Cluster binary that you download is built for a particular applica You can upgrade interactively in the browser or headlessly from the command line. To change configuration or redeploy without moving to a newer application version, run `upgrade` using the binary for the version that is already installed. -## Upgrade using the UI +## Upgrade using the Embedded Cluster UI ### Use the Enterprise Portal for a guided upgrade @@ -18,7 +18,7 @@ To use the guided upgrade experience in the Enterprise Portal: 1. Open the **Update** tab and follow the instructions to upgrade the instance. -### Upgrade using the Replicated Vendor Portal +### Upgrade using the instructions in the Vendor Portal To upgrade more directly from the Vendor Portal: @@ -52,19 +52,15 @@ To upgrade more directly from the Vendor Portal: ## Upgrade using the CLI (headless) -Embedded Cluster 3.x supports headless upgrades. +To perform a headless upgrade from the CLI: -1. In the Vendor Portal, open the **Customers** page and select a customer that is assigned to the channel you use for testing. +1. In the Vendor Portal, open the **Customers** page and select the target customer. -1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The control may appear as **Embedded Cluster install instructions**.) - - :::note - You can also open the Enterprise Portal to get install and upgrade instructions. - ::: +1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The label might also appear as **Embedded Cluster install instructions**). -1. Under **Select a version** (or equivalent), choose the application version to upgrade to. +1. Under **Select a version**, choose the application version to upgrade to. -1. On a Linux machine, run the first two commands from the dialog (download the archive, then extract it). +1. On a Linux machine, run the first two commands from the dialog to download the archive and extract it. 1. For the third command, do the following: @@ -79,16 +75,35 @@ Embedded Cluster 3.x supports headless upgrades. sudo ./APP_SLUG upgrade --license LICENSE_FILE --headless ``` -1. Monitor the command output until the upgrade completes, then access your application as you normally do. +1. Monitor the command output until the upgrade completes. + +## Reconfigure an application without upgrading the application version + +If you need to redeploy or reconfigure an instance without upgrading to a later application version, you can do so by including the installation assets for the application versions that is currently installed when you perform the upgrade. + +### UI-based upgrade + +To change an application's configuration without upgrading the application version: + +* In the Embedded Cluster UI, change the target values on the **Configure** page. Then, follow the interactive upgrade process in the UI. + +### Headless upgrade + +To change an application's configuration without upgrading the application version: + +1. Update the ConfigValues to make the application configuration changes. +1. Run the `upgrade` command using the binary for the application version that is already installed. For example, if version 1.2.3 is installed, download and run `upgrade` with the assets for version 1.2.3. Pass the updated configuration values with `--config-values`. + +## Upgrade in air-gapped environments -## Redeploy or reconfigure without changing the application version +To perform an upgrade with Embedded Cluster in air-gapped environments: -Installing or upgrading with a given binary always targets the application version that binary was built for. +1. In the Vendor Portal, open the **Customers** page and select the target customer. -To redeploy or reconfigure without upgrading to a newer application version, run the `upgrade` command using the binary for the version that is **already** installed. For example, if version 1.2.3 is installed, download and run `upgrade` with the 1.2.3 assets. That redeploys the release. +1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The label might also appear as **Embedded Cluster install instructions**). -To change configuration without a version change, pass updated values with `--config-values` (headless) or change values on the **Configure** page (interactive upgrade). +1. In the **Install instructions** dialog, enable the air gap option. -## Upgrade in air gap clusters +1. Download the installations assets to a machine with internet access and transfer them to the air-gapped host. -For air gap environments, enable air gap in the **Install instructions** dialog, download the assets to a machine with internet access, transfer them to the air-gapped host, then run `upgrade` with the same air gap flags you use for `install` (for example, `--airgap-bundle`). For more information about air gap assets, see [Air gap installation with Embedded Cluster](installing-embedded-air-gap). +1. Run `upgrade` with the same air gap flags you use for `install` (for example, `--airgap-bundle`). For more information, see [Air gap installation with Embedded Cluster](installing-embedded-air-gap). diff --git a/sidebarEmbeddedCluster.js b/sidebarEmbeddedCluster.js index 8c2c834d8d..6acdd4315a 100644 --- a/sidebarEmbeddedCluster.js +++ b/sidebarEmbeddedCluster.js @@ -3,9 +3,16 @@ module.exports = { "embedded-overview", "embedded-using", "embedded-config", - "installing-embedded-requirements", - "installing-embedded", - "installing-embedded-air-gap", + { + + type: "category", + label: "Install with Embedded Cluster", + items: [ + "installing-embedded-requirements", + "installing-embedded", + "installing-embedded-air-gap", + ] + }, "embedded-manage-nodes", "updating-embedded", "embedded-troubleshooting", From f09d5b448ab84adca978cfed2140c16475d8bbef Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Thu, 2 Apr 2026 14:31:20 -0600 Subject: [PATCH 15/31] add beta labels --- embedded-cluster/embedded-cluster-completion.mdx | 2 +- embedded-cluster/embedded-cluster-create-join-bundle.mdx | 2 +- embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx | 2 +- embedded-cluster/embedded-cluster-enable-ha.mdx | 2 +- embedded-cluster/embedded-cluster-install.mdx | 2 +- embedded-cluster/embedded-cluster-node-join.mdx | 2 +- embedded-cluster/embedded-cluster-node-upgrade.mdx | 2 +- embedded-cluster/embedded-cluster-remove-node.mdx | 2 +- embedded-cluster/embedded-cluster-reset.mdx | 2 +- embedded-cluster/embedded-cluster-shell.mdx | 2 +- embedded-cluster/embedded-cluster-status.mdx | 2 +- embedded-cluster/embedded-cluster-support-bundle.mdx | 2 +- embedded-cluster/embedded-cluster-upgrade.mdx | 2 +- embedded-cluster/embedded-cluster-version.mdx | 2 +- embedded-cluster/embedded-config.mdx | 2 +- embedded-cluster/embedded-manage-nodes.mdx | 2 +- embedded-cluster/embedded-troubleshooting.mdx | 2 +- embedded-cluster/embedded-using.mdx | 2 +- embedded-cluster/installing-embedded-air-gap.mdx | 2 +- embedded-cluster/installing-embedded-requirements.mdx | 2 +- embedded-cluster/installing-embedded.mdx | 2 +- embedded-cluster/updating-embedded.mdx | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/embedded-cluster/embedded-cluster-completion.mdx b/embedded-cluster/embedded-cluster-completion.mdx index 5639a8d1ae..20305ea657 100644 --- a/embedded-cluster/embedded-cluster-completion.mdx +++ b/embedded-cluster/embedded-cluster-completion.mdx @@ -1,4 +1,4 @@ -# completion +# completion (Beta) This topic describes the options available with the Embedded Cluster `completion` command. diff --git a/embedded-cluster/embedded-cluster-create-join-bundle.mdx b/embedded-cluster/embedded-cluster-create-join-bundle.mdx index 365243a760..03da988f4d 100644 --- a/embedded-cluster/embedded-cluster-create-join-bundle.mdx +++ b/embedded-cluster/embedded-cluster-create-join-bundle.mdx @@ -1,4 +1,4 @@ -# create-join-bundle +# create-join-bundle (Beta) This topic describes the options available with the Embedded Cluster `create-join-bundle` command. Use this command to produce a bundle that nodes can use to join the cluster with a given role. diff --git a/embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx b/embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx index 2deb1b9c15..d89154fddf 100644 --- a/embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx +++ b/embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx @@ -1,4 +1,4 @@ -# create-upgrade-bundle +# create-upgrade-bundle (Beta) This topic describes the options available with the Embedded Cluster `create-upgrade-bundle` command. Use this command to produce a bundle used for offline or constrained-path upgrades. diff --git a/embedded-cluster/embedded-cluster-enable-ha.mdx b/embedded-cluster/embedded-cluster-enable-ha.mdx index ddb6fe958f..31d0432602 100644 --- a/embedded-cluster/embedded-cluster-enable-ha.mdx +++ b/embedded-cluster/embedded-cluster-enable-ha.mdx @@ -1,4 +1,4 @@ -# enable-ha +# enable-ha (Beta) This topic describes the options available with the Embedded Cluster `enable-ha` command. diff --git a/embedded-cluster/embedded-cluster-install.mdx b/embedded-cluster/embedded-cluster-install.mdx index d8d58cac8d..9cf3e22dee 100644 --- a/embedded-cluster/embedded-cluster-install.mdx +++ b/embedded-cluster/embedded-cluster-install.mdx @@ -1,4 +1,4 @@ -# install +# install (Beta) This topic describes the options available with the Embedded Cluster `install` command. For procedural steps, see [Online installation with Embedded Cluster](installing-embedded), [Air gap installation with Embedded Cluster](installing-embedded-air-gap), and [Automate installation with Embedded Cluster](installing-embedded-automation). diff --git a/embedded-cluster/embedded-cluster-node-join.mdx b/embedded-cluster/embedded-cluster-node-join.mdx index 3b0ca7b23c..ce91dbcc12 100644 --- a/embedded-cluster/embedded-cluster-node-join.mdx +++ b/embedded-cluster/embedded-cluster-node-join.mdx @@ -1,4 +1,4 @@ -# node join +# node join (Beta) This topic describes the options available with the Embedded Cluster `node join` command. diff --git a/embedded-cluster/embedded-cluster-node-upgrade.mdx b/embedded-cluster/embedded-cluster-node-upgrade.mdx index 6d4458ac42..df79ed6644 100644 --- a/embedded-cluster/embedded-cluster-node-upgrade.mdx +++ b/embedded-cluster/embedded-cluster-node-upgrade.mdx @@ -1,4 +1,4 @@ -# node upgrade +# node upgrade (Beta) This topic describes the options available with the Embedded Cluster `node upgrade` command. diff --git a/embedded-cluster/embedded-cluster-remove-node.mdx b/embedded-cluster/embedded-cluster-remove-node.mdx index 3d47f4e4f0..3f25b220bd 100644 --- a/embedded-cluster/embedded-cluster-remove-node.mdx +++ b/embedded-cluster/embedded-cluster-remove-node.mdx @@ -1,4 +1,4 @@ -# remove-node +# remove-node (Beta) This topic describes the options available with the Embedded Cluster `remove-node` command. diff --git a/embedded-cluster/embedded-cluster-reset.mdx b/embedded-cluster/embedded-cluster-reset.mdx index 994af82b6b..4fa7bfe186 100644 --- a/embedded-cluster/embedded-cluster-reset.mdx +++ b/embedded-cluster/embedded-cluster-reset.mdx @@ -1,4 +1,4 @@ -# reset +# reset (Beta) This topic describes the options available with the Embedded Cluster `reset` command. diff --git a/embedded-cluster/embedded-cluster-shell.mdx b/embedded-cluster/embedded-cluster-shell.mdx index ef1d66ee9a..6e8d673559 100644 --- a/embedded-cluster/embedded-cluster-shell.mdx +++ b/embedded-cluster/embedded-cluster-shell.mdx @@ -1,4 +1,4 @@ -# shell +# shell (Beta) This topic describes the options available with the Embedded Cluster `shell` command. diff --git a/embedded-cluster/embedded-cluster-status.mdx b/embedded-cluster/embedded-cluster-status.mdx index 4df608c027..d46192b251 100644 --- a/embedded-cluster/embedded-cluster-status.mdx +++ b/embedded-cluster/embedded-cluster-status.mdx @@ -1,4 +1,4 @@ -# status +# status (Beta) This topic describes the options available with the Embedded Cluster `status` command. diff --git a/embedded-cluster/embedded-cluster-support-bundle.mdx b/embedded-cluster/embedded-cluster-support-bundle.mdx index 474dcd5902..78d43d1bc0 100644 --- a/embedded-cluster/embedded-cluster-support-bundle.mdx +++ b/embedded-cluster/embedded-cluster-support-bundle.mdx @@ -1,4 +1,4 @@ -# support-bundle +# support-bundle (Beta) This topic describes the options available with the Embedded Cluster `support-bundle` command. For more information about troubleshooting Embedded Cluster, see [Troubleshoot Embedded Cluster](embedded-troubleshooting). diff --git a/embedded-cluster/embedded-cluster-upgrade.mdx b/embedded-cluster/embedded-cluster-upgrade.mdx index 568124c784..d72620ba15 100644 --- a/embedded-cluster/embedded-cluster-upgrade.mdx +++ b/embedded-cluster/embedded-cluster-upgrade.mdx @@ -1,4 +1,4 @@ -# upgrade +# upgrade (Beta) This topic describes the options available with the Embedded Cluster `upgrade` command. For procedural steps, see [Perform updates in embedded clusters](updating-embedded). diff --git a/embedded-cluster/embedded-cluster-version.mdx b/embedded-cluster/embedded-cluster-version.mdx index 11d6a790f4..40d9104ea4 100644 --- a/embedded-cluster/embedded-cluster-version.mdx +++ b/embedded-cluster/embedded-cluster-version.mdx @@ -1,4 +1,4 @@ -# version +# version (Beta) This topic describes the options available with the Embedded Cluster `version` command. diff --git a/embedded-cluster/embedded-config.mdx b/embedded-cluster/embedded-config.mdx index a8937a2da8..6f253c0ca3 100644 --- a/embedded-cluster/embedded-config.mdx +++ b/embedded-cluster/embedded-config.mdx @@ -1,6 +1,6 @@ import DoNotDowngrade from "../docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx" -# Embedded Cluster Config +# Embedded Cluster Config (Beta) This topic is a reference for the Replicated Embedded Cluster Config custom resource. For more information about Embedded Cluster, see [Use Embedded Cluster](embedded-overview). diff --git a/embedded-cluster/embedded-manage-nodes.mdx b/embedded-cluster/embedded-manage-nodes.mdx index 39e46ee9ea..1409617043 100644 --- a/embedded-cluster/embedded-manage-nodes.mdx +++ b/embedded-cluster/embedded-manage-nodes.mdx @@ -1,6 +1,6 @@ import ShellCommand from "../docs/partials/embedded-cluster/_shell-command.mdx" -# Access and manage embedded clusters +# Access and manage embedded clusters (Beta) This topic describes managing nodes in clusters created with Replicated Embedded Cluster, including how to add nodes and enable high-availability for multi-node clusters. diff --git a/embedded-cluster/embedded-troubleshooting.mdx b/embedded-cluster/embedded-troubleshooting.mdx index a099537382..2646d7b9fc 100644 --- a/embedded-cluster/embedded-troubleshooting.mdx +++ b/embedded-cluster/embedded-troubleshooting.mdx @@ -4,7 +4,7 @@ import ShellCommand from "../docs/partials/embedded-cluster/_shell-command.mdx" import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -# Troubleshoot Embedded Cluster +# Troubleshoot Embedded Cluster (Beta) This topic provides information about troubleshooting Replicated Embedded Cluster installations. For more information about Embedded Cluster, including built-in extensions and architecture, see [Embedded Cluster Overview](embedded-overview). diff --git a/embedded-cluster/embedded-using.mdx b/embedded-cluster/embedded-using.mdx index 521abb60cb..525a0503fd 100644 --- a/embedded-cluster/embedded-using.mdx +++ b/embedded-cluster/embedded-using.mdx @@ -2,7 +2,7 @@ import UpdateOverview from "../docs/partials/embedded-cluster/v3/_update-overvie import EcConfig from "../docs/partials/embedded-cluster/v3/_ec-config.mdx" import ShellCommand from "../docs/partials/embedded-cluster/_shell-command.mdx" -# Configure Embedded Cluster +# Configure Embedded Cluster (Beta) This topic provides information about how to configure your application releases to support installations with Replicated Embedded Cluster. For an introduction to Embedded Cluster, see [Embedded Cluster Overview](embedded-overview). diff --git a/embedded-cluster/installing-embedded-air-gap.mdx b/embedded-cluster/installing-embedded-air-gap.mdx index dbd0a229e1..0818ae12ff 100644 --- a/embedded-cluster/installing-embedded-air-gap.mdx +++ b/embedded-cluster/installing-embedded-air-gap.mdx @@ -1,6 +1,6 @@ import Prerequisites from "../docs/partials/embedded-cluster/v3/_ec-prereqs.mdx" -# Air gap installation with Embedded Cluster +# Air gap installation with Embedded Cluster (Beta) This topic describes how to install an application with Replicated Embedded Cluster on a virtual machine (VM) or bare metal server with no outbound internet access. For online installations, see [Online installation with Embedded Cluster](installing-embedded). For an introduction to Embedded Cluster, see [Embedded Cluster overview](embedded-overview). diff --git a/embedded-cluster/installing-embedded-requirements.mdx b/embedded-cluster/installing-embedded-requirements.mdx index cd81ba9ce7..a9096bf6a9 100644 --- a/embedded-cluster/installing-embedded-requirements.mdx +++ b/embedded-cluster/installing-embedded-requirements.mdx @@ -3,7 +3,7 @@ import EmbeddedClusterPortRequirements from "../docs/partials/embedded-cluster/v import FirewallOpeningsIntro from "../docs/partials/install/_firewall-openings-intro.mdx" import FirewallOpeningsEc from "../docs/partials/install/_firewall-openings-embedded-cluster.mdx" -# Embedded Cluster installation requirements +# Embedded Cluster installation requirements (Beta) This topic lists the installation requirements for Replicated Embedded Cluster. Ensure that the installation environment meets these requirements before attempting to install. diff --git a/embedded-cluster/installing-embedded.mdx b/embedded-cluster/installing-embedded.mdx index c8894185a5..004fed520a 100644 --- a/embedded-cluster/installing-embedded.mdx +++ b/embedded-cluster/installing-embedded.mdx @@ -1,6 +1,6 @@ import Prerequisites from "../docs/partials/embedded-cluster/v3/_ec-prereqs.mdx" -# Online installation with Embedded Cluster +# Online installation with Embedded Cluster (Beta) This topic describes how to install an application in an online (internet-connected) environment with Replicated Embedded Cluster. For air gap installations, see [Air gap installation with Embedded Cluster](installing-embedded-air-gap). For an introduction to Embedded Cluster, see [Embedded Cluster overview](embedded-overview). diff --git a/embedded-cluster/updating-embedded.mdx b/embedded-cluster/updating-embedded.mdx index 625a9b5254..8e4e9316ff 100644 --- a/embedded-cluster/updating-embedded.mdx +++ b/embedded-cluster/updating-embedded.mdx @@ -1,4 +1,4 @@ -# Perform updates in embedded clusters +# Perform updates in embedded clusters (Beta) This topic describes how to upgrade, redeploy, or reconfigure an application installed with Replicated Embedded Cluster 3.x. For an introduction to Embedded Cluster, see [Embedded Cluster overview](embedded-overview). From 3a27e5a09a634e66e76a1410abe32b972e7a70cb Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Thu, 2 Apr 2026 16:47:58 -0600 Subject: [PATCH 16/31] run vale linter agent and improve it --- .claude/skills/vale-prose-review/SKILL.md | 2 +- .../references/vale-rules.md | 28 +++++++- .../embedded-cluster-create-join-bundle.mdx | 2 +- ...embedded-cluster-create-upgrade-bundle.mdx | 2 +- embedded-cluster/embedded-cluster-install.mdx | 2 +- embedded-cluster/embedded-config.mdx | 68 +++++++++---------- embedded-cluster/embedded-manage-nodes.mdx | 30 ++++---- embedded-cluster/embedded-overview.mdx | 28 ++++---- embedded-cluster/embedded-troubleshooting.mdx | 14 ++-- embedded-cluster/embedded-using.mdx | 16 ++--- .../installing-embedded-air-gap.mdx | 28 ++++---- .../installing-embedded-requirements.mdx | 14 ++-- embedded-cluster/installing-embedded.mdx | 14 ++-- embedded-cluster/updating-embedded.mdx | 12 ++-- .../config/vocabularies/TechJargon/accept.txt | 16 +++++ 15 files changed, 159 insertions(+), 117 deletions(-) diff --git a/.claude/skills/vale-prose-review/SKILL.md b/.claude/skills/vale-prose-review/SKILL.md index 94f44e852c..efa7a7a279 100644 --- a/.claude/skills/vale-prose-review/SKILL.md +++ b/.claude/skills/vale-prose-review/SKILL.md @@ -85,7 +85,7 @@ See `references/vale-rules.md` for full fix patterns, before/after examples, and **`Replicated.PositionalLanguage`** — Replace "above/below" with "the following" or a section link; replace directional "right/left" with "the following" or a UI element name. -**`Replicated.Headings`** — Apply sentence case: lowercase all words except the first word and proper nouns (product names, trademarks). +**`Replicated.Headings`** — Apply sentence case, with two exceptions: (1) **Skip entirely** when the heading IS a CLI command name or YAML field name (e.g., `# install (Beta)`, `## helmCharts`) — those follow the thing's own casing conventions. (2) **Parentheticals reset sentence case** — `(Beta)` is correct, not `(beta)`. See `references/vale-rules.md` for full patterns. **`Replicated.WordsToAvoid`** — Remove "easy/easily", "simple/simply", "just" (when minimizing). Rephrase or omit. diff --git a/.claude/skills/vale-prose-review/references/vale-rules.md b/.claude/skills/vale-prose-review/references/vale-rules.md index 47975dfdbb..f51f98ede3 100644 --- a/.claude/skills/vale-prose-review/references/vale-rules.md +++ b/.claude/skills/vale-prose-review/references/vale-rules.md @@ -101,6 +101,26 @@ Avoid directional and spatial language that assumes a page layout. Users may be Headings should use sentence case: capitalize only the first word and proper nouns. +### Skip this rule entirely for reference page headings + +Do NOT apply sentence case to headings that are the exact name of a CLI command, YAML field, or other code identifier. These headings document the thing itself, so their capitalization is determined by the thing's own conventions, not sentence case. + +**Skip examples (leave unchanged):** +- `# install (Beta)` — CLI command name; do not capitalize "install" +- `# create-join-bundle (Beta)` — CLI command name +- `### helmCharts` — YAML field name; do not change to `### HelmCharts` +- `#### roles.controller` — dotted YAML field path +- `## metadata` — YAML field name +- `## unsupportedOverrides` — YAML field name + +### Parentheticals reset sentence case + +A parenthetical like `(Beta)` or `(Preview)` opens a new "sentence" within the heading. Capitalize the first word inside the parenthetical. + +- `(Beta)` is correct — **not** `(beta)` +- `(Preview)` is correct — **not** `(preview)` +- `(Deprecated)` is correct — **not** `(deprecated)` + ### What to capitalize (proper nouns and trademarks) - Replicated product names: Embedded Cluster, KOTS, Vendor Portal, Enterprise Portal, Compatibility Matrix, Replicated SDK, Admin Console, Replicated CLI @@ -109,17 +129,19 @@ Headings should use sentence case: capitalize only the first word and proper nou ### What to lowercase -- Descriptive words that aren't proper names: "matrix" (when not a product name), "lifecycle", "overview", "portal" (when standalone), "guide", "about" -- Status/qualifier words in parentheses: "(beta)", "(preview)", "(deprecated)" +- Descriptive words that aren't proper names: "config", "overview", "lifecycle", "portal" (when standalone), "guide", "about" +- Capitalized common words mid-heading: "Matrix" → "matrix" (when not a product name), "Values" → "values", "Built-In" → "built-in" ### Examples | Before | After | |---|---| | `### Compatibility Matrix` | `### Compatibility matrix` | -| `### Enterprise Portal (Beta)` | `### Enterprise Portal (beta)` | +| `### Enterprise Portal (Beta)` | `### Enterprise Portal (Beta)` ← keep capital B | | `## Commercial Software Distribution Lifecycle` | `## Commercial software distribution lifecycle` | | `### Vendor Portal Overview` | `### Vendor Portal overview` | +| `# install (Beta)` | `# install (Beta)` ← CLI command, do not change | +| `### helmCharts` | `### helmCharts` ← YAML field, do not change | **Note:** Only headings are subject to this rule. Body text references to product names keep their standard capitalization. diff --git a/embedded-cluster/embedded-cluster-create-join-bundle.mdx b/embedded-cluster/embedded-cluster-create-join-bundle.mdx index 03da988f4d..074f788a21 100644 --- a/embedded-cluster/embedded-cluster-create-join-bundle.mdx +++ b/embedded-cluster/embedded-cluster-create-join-bundle.mdx @@ -19,7 +19,7 @@ sudo ./ create-join-bundle [flags] `--output` string - Output path for the bundle. **Default:** A path of the form `./cli-join-ROLE-TIMESTAMP.tar.gz` (role and timestamp are filled in by the CLI). + Output path for the bundle. **Default:** A path of the form `./cli-join-ROLE-TIMESTAMP.tar.gz` (the CLI fills in the role and timestamp). `--role` diff --git a/embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx b/embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx index d89154fddf..f407dbda9f 100644 --- a/embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx +++ b/embedded-cluster/embedded-cluster-create-upgrade-bundle.mdx @@ -19,7 +19,7 @@ sudo ./ create-upgrade-bundle [flags] `--output` string - Output path for the bundle. **Default:** A path of the form `./cli-upgrade-TIMESTAMP.tar.gz` (timestamp is filled in by the CLI). + Output path for the bundle. **Default:** A path of the form `./cli-upgrade-TIMESTAMP.tar.gz` (the CLI fills in the timestamp). `-h`, `--help` diff --git a/embedded-cluster/embedded-cluster-install.mdx b/embedded-cluster/embedded-cluster-install.mdx index 9cf3e22dee..b5e06779e2 100644 --- a/embedded-cluster/embedded-cluster-install.mdx +++ b/embedded-cluster/embedded-cluster-install.mdx @@ -19,7 +19,7 @@ sudo ./ install --license [flags] `--airgap` - Perform an air gap installation. For more information, see [Air gap installation with Embedded Cluster](installing-embedded-air-gap). + Perform an air-gapped installation. For more information, see [Air gap installation with Embedded Cluster](installing-embedded-air-gap). `--cidr` diff --git a/embedded-cluster/embedded-config.mdx b/embedded-cluster/embedded-config.mdx index 6f253c0ca3..fb13e1c1cc 100644 --- a/embedded-cluster/embedded-config.mdx +++ b/embedded-cluster/embedded-config.mdx @@ -1,20 +1,20 @@ import DoNotDowngrade from "../docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx" -# Embedded Cluster Config (Beta) +# Embedded Cluster config (Beta) This topic is a reference for the Replicated Embedded Cluster Config custom resource. For more information about Embedded Cluster, see [Use Embedded Cluster](embedded-overview). ## Overview -To install your application with Embedded Cluster, an Embedded Cluster Config must be included in the release. Embedded Cluster installation artifacts are available only for releases that include an Embedded Cluster Config. +To install your application with Embedded Cluster, you must include an Embedded Cluster Config in the release. Embedded Cluster installation artifacts are available only for releases that include an Embedded Cluster Config. -The Embedded Cluster Config lets you define several aspects of the Kubernetes cluster that will be created. +The Embedded Cluster Config lets you define several aspects of the Kubernetes cluster that Embedded Cluster creates. ### Limitations -* Top-level fields and most of the Config spec are plain YAML and do not support Go template functions, including Replicated template functions. The `values` field for each entry under `extensions.helmCharts` does support [Replicated template functions](/reference/template-functions-about). +* Top-level fields and most of the Config spec are plain YAML and do not support Go template functions, including Replicated template functions. The `values` field for each entry in `extensions.helmCharts` does support [Replicated template functions](/reference/template-functions-about). -* There are additional, property-specific limitations. For more information, see the sections below. +* There are additional, property-specific limitations. For more information, see the following sections. ### Example @@ -107,7 +107,7 @@ The Config is a Kubernetes custom resource. Set `metadata.name` to a name for th ## version -Specify the versions of Embedded Cluster and Kubernetes to install. The version of Kubernetes is appended to the Embedded Cluster version in the format `+k8s-1.34`. For example, Embedded Cluster `3.0.0-alpha-26+k8s-1.34` uses Embedded Cluster `3.0.0-alpha-26` and Kubernetes 1.34. +Specify the versions of Embedded Cluster and Kubernetes to install. Embedded Cluster appends the version of Kubernetes to the Embedded Cluster version in the format `+k8s-1.34`. For example, Embedded Cluster `3.0.0-alpha-26+k8s-1.34` uses Embedded Cluster `3.0.0-alpha-26` and Kubernetes 1.34. Each version of Embedded Cluster includes specific versions of components like KOTS (Admin Console) and OpenEBS. For more information, see the [Embedded Cluster Release Notes](/release-notes/rn-embedded-cluster). @@ -124,11 +124,11 @@ Optional. Use `spec.binaryOverrideUrl` and `spec.metadataOverrideUrl` to overrid You can optionally customize node roles in the Embedded Cluster Config using the `roles` key. -A common use case for customizing node roles is to assign workloads to specific nodes. For example, if your application has graphics processing unit (GPU) workloads, you could create a `custom` role that will add a `gpu=true` label to any node that is assigned the role. This allows you to then schedule GPU workloads on nodes labeled `gpu=true`. +A common use case for customizing node roles is to assign workloads to specific nodes. For example, if your application has graphics processing unit (GPU) workloads, you could create a `custom` role that adds a `gpu=true` label to any node that takes on the role. You can then schedule GPU workloads on nodes labeled `gpu=true`. -When the `roles` key is configured, users select one or more roles to assign to a node when it is joined to the cluster. For more information, see [Managing Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). +When you configure the `roles` key, users select one or more roles to assign to a node when they join it to the cluster. For more information, see [Managing Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). -If the `roles` key is _not_ configured, all nodes joined to the cluster are assigned the `controller` role. The `controller` role designates nodes that run the Kubernetes control plane. Controller nodes can also run other workloads, such as application or Replicated KOTS workloads. +If the `roles` key is _not_ configured, Embedded Cluster assigns all nodes that join the cluster the `controller` role. The `controller` role designates nodes that run the Kubernetes control plane. Controller nodes can also run other workloads, such as application or Replicated KOTS workloads. #### Example @@ -154,32 +154,32 @@ spec: * Defining node roles with the `roles` key is Beta. -* The first node added to the cluster is always a controller and cannot be assigned any custom roles. You can add custom labels to the first node by setting the `labels` field in the `roles.controller` key. +* The first node added to the cluster is always a controller and cannot receive any custom roles. You can add custom labels to the first node by setting the `labels` field in the `roles.controller` key. ### roles.controller In the `roles.controller` key, you can set the following fields to customize the default controller role: -* `name`: Set the name that is assigned to controller nodes. By default, controller nodes are named “controller”. +* `name`: Set the name for controller nodes. By default, controller nodes have the name “controller”. :::note - If you plan to create any custom roles, Replicated recommends that you change the default name for the controller role to a term that is easy to understand, such as "app". This is because, when you add custom roles, both the name of the controller role and the names of any custom roles are displayed to the user when they join a node. + If you plan to create any custom roles, Replicated recommends that you change the default name for the controller role to a clear, descriptive term, such as “app”. When you add custom roles, the user sees both the name of the controller role and the names of any custom roles when they join a node. ::: -* `labels`: Kubernetes labels that Embedded Cluster will apply to any node in the cluster that is assigned the given role. +* `labels`: Kubernetes labels that Embedded Cluster applies to any node in the cluster that takes on the given role. ### roles.custom In the `roles.custom` key, you can add custom roles. Each custom role includes the following fields: * `name`: (Required) A name for the custom role. -* `labels`: Kubernetes labels that Embedded Cluster will apply to any node in the cluster that is assigned the given role. +* `labels`: Kubernetes labels that Embedded Cluster applies to any node in the cluster that takes on the given role. ## domains Configure the `domains` key so that Embedded Cluster uses your custom domains for the Replicated proxy registry and Replicated app service. -When `domains.proxyRegistryDomain` and `domains.replicatedAppDomain` are set, Embedded Cluster uses the custom domains specified when making requests to the given service. Embedded Cluster also passes the values to KOTS to ensure that KOTS uses the same domains for these services. +When you set `domains.proxyRegistryDomain` and `domains.replicatedAppDomain`, Embedded Cluster uses the custom domains specified when making requests to the given service. Embedded Cluster also passes the values to KOTS to ensure that KOTS uses the same domains for these services. -The custom domains that you specify in the `domains.proxyRegistryDomain` and `domains.replicatedAppDomain` fields must be added to the Vendor Portal before they can be used by Embedded Cluster. For more information, see [Add a Custom Domain in the Vendor Portal](/vendor/custom-domains-using#add-domain) in _Using Custom Domains_. +You must add the custom domains that you specify in the `domains.proxyRegistryDomain` and `domains.replicatedAppDomain` fields to the Vendor Portal before Embedded Cluster can use them. For more information, see [Add a Custom Domain in the Vendor Portal](/vendor/custom-domains-using#add-domain) in _Using Custom Domains_. If `domains.proxyRegistryDomain` and `domains.replicatedAppDomain` are not set, Embedded Cluster uses the default Replicated domains. For more information about aliasing Replicated endpoints with custom domains, see [About Custom Domains](/vendor/custom-domains). @@ -196,7 +196,7 @@ spec: ## extensions -Helm charts that must be installed before your application—and as part of Embedded Cluster itself—are listed under `spec.extensions.helmCharts`. Each item describes one chart release. +Embedded Cluster installs Helm charts before your application as part of Embedded Cluster itself. Specify these charts in `spec.extensions.helmCharts`. Each item describes one chart release. ### helmCharts @@ -207,16 +207,16 @@ Each object in `helmCharts` can include the following fields: * `chartVersion`: Chart version string to install. * `releaseName`: (Required) Helm release name. * `namespace`: (Required) Namespace for the release. -* `weight`: Optional. Controls ordering relative to other `helmCharts` entries. **Lower** `weight` values install **earlier**. If omitted, a default is used. +* `weight`: Optional. Controls ordering relative to other `helmCharts` entries. **Lower** `weight` values install **earlier**. If omitted, Embedded Cluster applies a default value. * `values`: Optional multi-line string of Helm values. This field supports [Replicated template functions](/reference/template-functions-about) (for example, `ReplicatedImageName`, `HelmValue`, `ReplicatedImageRegistry`, and `ReplicatedImageRepository`) so you can align images and values with your release. -Helm extensions are updated when new versions of your application are deployed from the Admin Console. For example, you can change `values` from one release to another, and those changes apply when the new version is deployed. +Embedded Cluster updates Helm extensions when you deploy new versions of your application from the Admin Console. For example, you can change `values` from one release to another, and those changes apply when you deploy the new version. #### Requirements -* `chart.chartVersion` is required. Omitting it can cause upgrade issues. +* You must provide `chart.chartVersion`. Omitting it can cause upgrade issues. -* For air gap bundles, follow the same image and digest guidance as in prior Embedded Cluster releases: avoid multi-architecture image digests in extension values where only single-arch images are bundled; use tags and empty digests where appropriate so the air gap builder can resolve images. +* For air gap bundles, follow the same image and digest guidance as in prior Embedded Cluster releases: avoid multi-architecture image digests in extension values where the air gap bundle includes only single-arch images. Use tags and empty digests where appropriate so the air gap builder can resolve images. #### Example @@ -246,22 +246,22 @@ spec: ## unsupportedOverrides :::important -This feature should be used with caution by advanced users who understand the risks and ramifications of changing the default configuration. +Advanced users who understand the risks and ramifications of changing the default configuration should use this feature with caution. ::: -Unsupported overrides allow you to override Embedded Cluster's default configuration, including the k0s config and the Helm values for built-in extensions like KOTS and the Embedded Cluster Operator. Use overrides carefully: they are untested combinations and can disrupt clusters. Issues caused by unsupported overrides are not supported. +Unsupported overrides allow you to override Embedded Cluster's default configuration, including the k0s config and the Helm values for built-in extensions like KOTS and the Embedded Cluster Operator. Use overrides carefully. These combinations have not been tested and can disrupt clusters. Replicated does not support issues caused by unsupported overrides. -While they should be used with caution, unsupported overrides are useful if you need to make changes that are not otherwise exposed by Embedded Cluster. +While you should use them with caution, unsupported overrides are useful if you need to make changes that Embedded Cluster does not otherwise expose. ### Override the k0s Config -By default, Embedded Cluster uses a k0s config that is tested and known to work for Embedded Clusters. In some circumstances, you might want to change the k0s config. +By default, Embedded Cluster uses a k0s config that Replicated has tested and confirmed works for Embedded Clusters. In some circumstances, you might want to change the k0s config. For more information on the k0s config, see [Configuration options](https://docs.k0sproject.io/stable/configuration/#configuration-file-reference) in the k0s documentation. -The value of `unsupportedOverrides.k0s` is a string containing YAML that becomes (or patches) the k0s configuration Embedded Cluster uses. How deeply that YAML is merged with Embedded Cluster defaults can depend on the field; treat overrides as high risk and validate in a non-production cluster. +The value of `unsupportedOverrides.k0s` is a string containing YAML that becomes (or patches) the k0s configuration Embedded Cluster uses. How deeply Embedded Cluster merges that YAML with its defaults depends on the field. Treat overrides as high risk and validate in a non-production cluster. -For example, you can enable WireGuard-based encryption (other configuration may be required; see [`spec.network.calico`](https://docs.k0sproject.io/stable/configuration/#specnetworkcalico) in the k0s documentation): +For example, you can enable WireGuard-based encryption. Other configuration may be required. See [`spec.network.calico`](https://docs.k0sproject.io/stable/configuration/#specnetworkcalico) in the k0s documentation: ```yaml apiVersion: embeddedcluster.replicated.com/v1beta1 @@ -278,13 +278,13 @@ spec: #### Limitations -* The `spec.api` and `spec.storage` keys in the k0s config cannot be changed after installation. Whereas most keys in the k0s config apply to the whole cluster, these two keys are set for each node. Embedded Cluster cannot update these keys on each individual node during updates, so they cannot be changed after installation. +* You cannot change the `spec.api` and `spec.storage` keys in the k0s config after installation. Whereas most keys in the k0s config apply to the whole cluster, k0s sets these two keys for each node individually. Embedded Cluster cannot update these keys on each individual node during updates, so you cannot change them after installation. * Overrides can replace whole sections of the k0s configuration rather than deep-merge with every default. When overriding a list (for example, `workerProfiles`), you may need to include entries that Embedded Cluster relies on by default, or behavior can change in ways that are hard to predict. Confirm the effective k0s config for your release if you rely on defaults plus overrides. -### Override the Helm Values for Built-In Extensions +### Override the Helm values for built-in extensions -Embedded Cluster deploys built-in extensions with Helm. You can patch their values with `unsupportedOverrides.builtInExtensions`. Each item sets `name` (the chart to patch) and `values` (a multi-line YAML string). Your values are merged into the defaults Embedded Cluster uses. +Embedded Cluster deploys built-in extensions with Helm. You can patch their values with `unsupportedOverrides.builtInExtensions`. Each item sets `name` (the chart to patch) and `values` (a multi-line YAML string). Embedded Cluster merges your values into the defaults it uses. Common `name` values include: @@ -316,11 +316,11 @@ spec: You can configure the Kubelet to customize worker nodes with Embedded Cluster. One common use case is raising the per-node pod limit (`maxPods`). Another is tuning parallel image pulls (`maxParallelImagePulls`). -Add a _worker profile_ under `unsupportedOverrides.k0s` at `config.spec.workerProfiles[]`. When a worker profile is defined, Embedded Cluster uses it for every node during initial installation and when joining nodes. +Add a _worker profile_ in `unsupportedOverrides.k0s` at `config.spec.workerProfiles[]`. When you define a worker profile, Embedded Cluster uses it for every node during initial installation and when joining nodes. Each profile requires: -* `name`: Profile name. Do not use `default`; it is reserved by k0s. +* `name`: Profile name. Do not use `default` because k0s reserves that name. * `values`: Kubelet settings. See [KubeletConfiguration](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/#kubelet-config-k8s-io-v1beta1-KubeletConfiguration) in the Kubernetes documentation. For more information, see [spec.workerProfiles](https://docs.k0sproject.io/stable/configuration/#specworkerprofiles) in the k0s documentation. @@ -329,8 +329,8 @@ You can combine worker profiles with other k0s settings in the same `k0s` string #### Limitations -* The worker profile is set during initial installation. Worker profiles cannot be changed or added on upgrade. -* Embedded Cluster supports only one worker profile that is used for all nodes. If you add more than one profile in `workerProfiles[]`, only the first profile is used. +* Embedded Cluster sets the worker profile during initial installation. You cannot change or add worker profiles on upgrade. +* Embedded Cluster supports only one worker profile and applies it to all nodes. If you add more than one profile in `workerProfiles[]`, Embedded Cluster applies only the first profile. #### Example diff --git a/embedded-cluster/embedded-manage-nodes.mdx b/embedded-cluster/embedded-manage-nodes.mdx index 1409617043..27ce6a7a96 100644 --- a/embedded-cluster/embedded-manage-nodes.mdx +++ b/embedded-cluster/embedded-manage-nodes.mdx @@ -20,17 +20,17 @@ Multi-node clusters with Embedded Cluster have the following limitations: * Setting node roles with the Embedded Cluster Config [roles](embedded-config#roles) key is Beta. -* The first node added to the cluster is always a controller and cannot be assigned any custom roles. For more information about configuring node roles, see [roles](embedded-config#roles) in _Embedded Cluster Config_. +* The first node added to the cluster is always a controller and cannot receive any custom roles. For more information about configuring node roles, see [roles](embedded-config#roles) in _Embedded Cluster Config_. -* The same Embedded Cluster data directory used at installation is used for all nodes joined to the cluster. This is either the default `/var/lib/embedded-cluster` directory or the directory set with the [`--data-dir`](embedded-cluster-install#flags) flag. You cannot choose a different data directory for Embedded Cluster when joining nodes. +* All nodes joined to the cluster use the same Embedded Cluster data directory as the installation node. This is either the default `/var/lib/embedded-cluster` directory or the directory set with the [`--data-dir`](embedded-cluster-install#flags) flag. You cannot choose a different data directory for Embedded Cluster when joining nodes. -* More than one controller node should not be joined at the same time. When joining a controller node, a warning is printed that explains that the user should not attempt to join another node until the controller node joins successfully. +* You should not join more than one controller node at the same time. When joining a controller node, Embedded Cluster prints a warning explaining that you should not attempt to join another node until the controller node joins successfully. -* The `join print-command` command always returns the commands for joining a node with the controller role. It does not support printing the join command for any custom node roles defined in the Embedded Cluster Config `roles` key. See [Automate Controller Node Joins](#automate-node-joins) below. +* The `join print-command` command always returns the commands for joining a node with the controller role. It does not support printing the join command for any custom node roles defined in the Embedded Cluster Config `roles` key. See [Automate Controller Node Joins](#automate-node-joins). ### Requirement -To deploy multi-node clusters with Embedded Cluster, the **Multi-node Cluster (Embedded Cluster only)** license field must be enabled for the customer. For more information about managing customer licenses, see [Create and Manage Customers](/vendor/releases-creating-customer). +To deploy multi-node clusters with Embedded Cluster, you must enable the **Multi-node Cluster (Embedded Cluster only)** license field for the customer. For more information about managing customer licenses, see [Create and Manage Customers](/vendor/releases-creating-customer). ### Add nodes to a cluster {#add-nodes} @@ -38,7 +38,7 @@ This section describes how to add nodes to a cluster with Embedded Cluster. To add a node to a cluster with Embedded Cluster: -1. (Optional) In the Embedded Cluster Config, configure the `roles` key to customize node roles. For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. When you are done, create and promote a new release with the updated Config. +1. (Optional) In the Embedded Cluster Config, configure the `roles` key to customize node roles. For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. After you finish, create and promote a new release with the updated Config. 1. Do one of the following: @@ -54,10 +54,10 @@ To add a node to a cluster with Embedded Cluster: 1. If you configured the `roles` key to customize node roles, select one or more roles for the node. - The Admin Console page is updated to display the commands for downloading the Embedded Cluster binary, extracting the binary, and joining the node to the cluster based on the roles you selected. Keep this Admin Console page open for the next steps. + The Admin Console page refreshes to display the commands for downloading the Embedded Cluster binary, extracting the binary, and joining the node based on the roles you selected. Keep this Admin Console page open for the next steps. :::note - The role cannot be changed after a node is added. If you need to change a node’s role, reset the node and add it again with the new role. + You cannot change the role after you add a node. If you need to change a node’s role, reset the node and add it again with the new role. ::: 1. SSH onto the node that you want to join. @@ -74,7 +74,7 @@ To add a node to a cluster with Embedded Cluster: ### Automate controller node joins {#automate-node-joins} -With Embedded Cluster, you can use the command line to get the commands for joining controller nodes, rather than having to log into the Admin Console UI to get the commands. This is especially useful when testing multi-node Embedded Cluster installations where you need to automate the process of joining controller nodes to a cluster. +With Embedded Cluster, you can use the command line to get the commands for joining controller nodes, rather than logging into the Admin Console UI. This is especially useful when testing multi-node Embedded Cluster installations where you need to automate joining controller nodes to a cluster. To automate controller node joins with Embedded Cluster: @@ -109,17 +109,17 @@ Users are automatically prompted to enable HA when joining the third controller Enabling high availability has the following requirements: -* High availability is supported with Embedded Cluster 1.4.1 and later. +* Embedded Cluster 1.4.1 and later supports high availability. * The [`enable-ha`](#enable-ha-existing) command is available with Embedded Cluster 2.3.0 and later. -* High availability is supported only for clusters where at least three nodes with the controller role are present. +* Embedded Cluster supports high availability only for clusters where at least three nodes with the controller role are present. ### Best practices for high availability Consider the following best practices and recommendations for creating HA clusters: -* At least three _controller_ nodes that run the Kubernetes control plane are required for HA. This is because clusters use a quorum system, in which more than half the nodes must be up and reachable. In clusters with three controller nodes, the Kubernetes control plane can continue to operate if one node fails because a quorum can still be reached by the remaining two nodes. By default, with Embedded Cluster, all new nodes added to a cluster are controller nodes. For information about customizing the controller node role, see [roles](embedded-config#roles) in _Embedded Cluster Config_. +* HA requires at least three _controller_ nodes that run the Kubernetes control plane. This is because clusters use a quorum system, in which more than half the nodes must be up and reachable. In clusters with three controller nodes, the Kubernetes control plane can continue to operate if one node fails because the remaining two nodes can still form a quorum. By default, with Embedded Cluster, all new nodes added to a cluster are controller nodes. For information about customizing the controller node role, see [roles](embedded-config#roles) in _Embedded Cluster Config_. * Always use an odd number of controller nodes in HA clusters. Using an odd number of controller nodes ensures that the cluster can make decisions efficiently with quorum calculations. Clusters with an odd number of controller nodes also avoid split-brain scenarios where the cluster runs as two, independent groups of nodes, resulting in inconsistencies and conflicts. @@ -127,7 +127,7 @@ Consider the following best practices and recommendations for creating HA cluste ### Create a multi-node cluster with high availability {#create-ha} -You can enable high availability for a multi-node cluster when joining the third controller node. Alternatively, you can enable HA for an existing cluster with three or more controller nodes. For more information, see [Enable High Availability For an Existing Cluster](#enable-ha-existing) below. +You can enable high availability for a multi-node cluster when joining the third controller node. Alternatively, you can enable HA for an existing cluster with three or more controller nodes. For more information, see [Enable High Availability For an Existing Cluster](#enable-ha-existing). To create a multi-node HA cluster: @@ -168,7 +168,7 @@ This section describes how to reset individual nodes and how to delete an entire ### About the `reset` command -Resetting a node with Embedded Cluster removes the cluster and your application from that node. This is useful for iteration, development, and when mistakes are made because you can reuse the machine instead of having to procure a new one. +Resetting a node with Embedded Cluster removes the cluster and your application from that node. This is useful for iteration, development, and when you make mistakes because you can reuse the machine instead of having to procure a new one. The `reset` command performs the following steps: @@ -185,7 +185,7 @@ For more information about the command, see [reset](embedded-cluster-reset). Before you reset a node or remove a cluster, consider the following limitations and best practices: -* When you reset a node, OpenEBS PVCs on the node are deleted. Only PVCs created as part of a StatefulSet are recreated automatically on another node in the cluster. To recreate other PVCs, redeploy the application in the cluster. +* When you reset a node, Embedded Cluster deletes OpenEBS PVCs on that node. Kubernetes automatically recreates only PVCs created as part of a StatefulSet on another node in the cluster. To recreate other PVCs, redeploy the application in the cluster. * If you need to reset one controller node in a three-node cluster, first join a fourth controller node to the cluster before removing the target node. This ensures that you maintain a minimum of three nodes for the Kubernetes control plane. You can add and remove worker nodes as needed because they do not have any control plane components. diff --git a/embedded-cluster/embedded-overview.mdx b/embedded-cluster/embedded-overview.mdx index 9d318e581e..d40fd7a698 100644 --- a/embedded-cluster/embedded-overview.mdx +++ b/embedded-cluster/embedded-overview.mdx @@ -17,9 +17,9 @@ Embedded Cluster 3.x removes KOTS from the architecture. The new installer provi The KOTS CLI no longer works with Embedded Cluster, and there is no KOTS Admin Console. -Also, because KOTS is removed, you must include the [Replicated SDK](/vendor/replicated-sdk-overview) in your application to get reporting from application status informers (for example, for notifications and visibility in the Vendor Portal and Enterprise Portal). +Also, because Embedded Cluster removes KOTS, you must include the [Replicated SDK](/vendor/replicated-sdk-overview) in your application. The SDK provides reporting from application status informers, such as notifications and visibility in the Vendor Portal and Enterprise Portal. -### Troubleshoot Preflight `v1beta3` +### Troubleshoot preflight `v1beta3` Preflight checks must use Troubleshoot `v1beta3`. `v1beta2` preflight specs are not supported. For more information, see [v1beta3 overview](https://troubleshoot.sh/docs/preflight/v1beta3-overview) in the Troubleshoot documentation. @@ -29,7 +29,7 @@ Embedded Cluster supports installations in online (internet-connected) environme Embedded Cluster also supports installing using the built-in interactive UI or performing headless installs from the CLI. -The Embedded Cluster Config is included in the application release in the Replicated Vendor Portal and is used to generate the Embedded Cluster installation assets. Users can download these installation assets from the Replicated app service (`replicated.app`) on the command line, then run the Embedded Cluster installation command to install Kubernetes. Finally, users can install the application using the UI or CLI. During installation, users can optionally add nodes to the cluster and configure the application. +You include the Embedded Cluster Config in the application release in the Replicated Vendor Portal, and Replicated uses it to generate the Embedded Cluster installation assets. Users can download these installation assets from the Replicated app service (`replicated.app`) on the command line, then run the Embedded Cluster installation command to install Kubernetes. Finally, users can install the application using the UI or CLI. During installation, users can optionally add nodes to the cluster and configure the application. For more information about how to install with Embedded Cluster, see: * [Online Installation wtih Embedded Cluster](installing-embedded) @@ -37,12 +37,12 @@ For more information about how to install with Embedded Cluster, see: ### Embedded Cluster host preflight checks {#about-host-preflight-checks} -During installation, Embedded Cluster automatically runs a default set of _host preflight checks_. The default host preflight checks are designed to verify that the installation environment meets the requirements for Embedded Cluster, such as: +During installation, Embedded Cluster automatically runs a default set of _host preflight checks_. The default host preflight checks verify that the installation environment meets the requirements for Embedded Cluster, such as: * The system has sufficient disk space * The system has at least 2G of memory and 2 CPU cores -* The system clock is synchronized +* The system clock syncs -If any of the Embedded Cluster host preflight checks fail, installation is blocked and a message describing the failure is displayed. +If any of the Embedded Cluster host preflight checks fail, Embedded Cluster blocks installation and displays a message describing the failure. For the full default host preflight spec for Embedded Cluster, see [`host-preflight.yaml`](https://github.com/replicatedhq/embedded-cluster/blob/main/pkg/preflights/host-preflight.yaml) in the `embedded-cluster` repository in GitHub. @@ -50,8 +50,8 @@ For the full default host preflight spec for Embedded Cluster, see [`host-prefli Embedded Cluster host preflight checks have the following limitations: -* The default host preflight checks for Embedded Cluster cannot be modified, and vendors cannot provide their own custom host preflight spec for Embedded Cluster. -* Host preflight checks do not check that any application-specific requirements are met. For more information about defining preflight checks for your application, see [Define Preflight Checks](/vendor/preflight-defining). +* Vendors cannot modify the default host preflight checks for Embedded Cluster or provide their own custom host preflight spec for Embedded Cluster. +* Host preflight checks do not verify that the application meets any application-specific requirements. For more information about defining preflight checks for your application, see [Define Preflight Checks](/vendor/preflight-defining). ### Multi-node installations @@ -65,30 +65,30 @@ For more information about creating HA multi-node clusters with Embedded Cluster #### Node roles -You can optionally define node roles in the Embedded Cluster Config. For multi-node clusters, roles can be useful for the purpose of assigning specific application workloads to nodes. If nodes roles are defined, users assign one or more roles to a node when it is joined to the cluster. +You can optionally define node roles in the Embedded Cluster Config. For multi-node clusters, roles can be useful for assigning specific application workloads to nodes. If node roles are defined, users assign one or more roles to a node when it joins the cluster. For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. ## About configuring Embedded Cluster -To support installations with Embedded Cluster, an Embedded Cluster Config must be present in the application release. The Embedded Cluster Config lets you define several characteristics about the cluster that will be created. +To support installations with Embedded Cluster, an Embedded Cluster Config must be present in the application release. The Embedded Cluster Config lets you define several characteristics about the cluster that Embedded Cluster creates. For more information, see [Embedded Cluster Config](embedded-config). ## Built-in extensions {#built-in-extensions} -Embedded Cluster includes several built-in extensions. The built-in extensions provide capabilities such as application management and storage. Each built-in extension is installed in its own namespace. +Embedded Cluster includes several built-in extensions. The built-in extensions provide capabilities such as application management and storage. Embedded Cluster installs each built-in extension in its own namespace. The built-in extensions installed by Embedded Cluster include: -* **Embedded Cluster Operator**: The Operator is used for reporting purposes as well as some clean up operations. +* **Embedded Cluster Operator**: The Operator handles reporting and some clean up operations. * **OpenEBS:** Embedded Cluster uses OpenEBS to provide local PersistentVolume (PV) storage, including the PV storage for rqlite used by KOTS. For more information, see the [OpenEBS](https://openebs.io/docs/) documentation. -* **(Air Gap Only) Image registry:** For air gap installations in environments with limited or no outbound internet access, Embedded Cluster installs an image registry where the images required to install and run the application are pushed. For more information about installing in air-gapped environments, see [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). +* **(Air Gap Only) Image registry:** For air gap installations in environments with limited or no outbound internet access, Embedded Cluster installs an image registry where it pushes the images required to install and run the application. For more information about installing in air-gapped environments, see [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). ## Limitations {#ec-limitations} * Embedded Cluster v3 does not support disaster recovery. -* Some Replicated template functions are not implemented in Embedded Cluster v3, either because they are discouraged or because they are not yet ported. Contact Replicated if a missing template function blocks your release. +* Some Replicated template functions are not implemented in Embedded Cluster v3, either because Replicated discourages their use or because they are not yet ported. Contact Replicated if a missing template function blocks your release. diff --git a/embedded-cluster/embedded-troubleshooting.mdx b/embedded-cluster/embedded-troubleshooting.mdx index 2646d7b9fc..bfb41b6e03 100644 --- a/embedded-cluster/embedded-troubleshooting.mdx +++ b/embedded-cluster/embedded-troubleshooting.mdx @@ -6,7 +6,9 @@ import TabItem from '@theme/TabItem'; # Troubleshoot Embedded Cluster (Beta) -This topic provides information about troubleshooting Replicated Embedded Cluster installations. For more information about Embedded Cluster, including built-in extensions and architecture, see [Embedded Cluster Overview](embedded-overview). +This topic provides information about troubleshooting Replicated Embedded Cluster installations. + +For more information about Embedded Cluster, including built-in extensions and architecture, see [Embedded Cluster Overview](embedded-overview). ## Troubleshoot with support bundles @@ -38,7 +40,7 @@ To use journalctl to view k0s logs: 1. SSH onto a controller node or a worker node. -1. Use journalctl to view logs for the k0s systemd service that was deployed by Embedded Cluster. +1. Use journalctl to view logs for the k0s systemd service that Embedded Cluster deployed. **Examples:** @@ -59,7 +61,7 @@ When troubleshooting, it can be useful to list the cluster and view logs using t This section provides troubleshooting advice for common errors. -### Installation failure when NVIDIA gpu operator is included as Helm extension {#nvidia} +### Installation failure when a release includes the NVIDIA gpu operator as a Helm extension {#nvidia} #### Symptom @@ -96,7 +98,7 @@ To troubleshoot: Symptoms of Calico networking issues can include: -* The pod is stuck in a CrashLoopBackOff state with failed health checks: +* The pod enters a CrashLoopBackOff state with failed health checks: ``` Warning Unhealthy 6h51m (x3 over 6h52m) kubelet Liveness probe failed: Get "http:///readyz": dial tcp : connect: no route to host @@ -163,7 +165,9 @@ Reasons can include: For more information, see [install](embedded-cluster-install). - Embedded Cluster 1.19.0 and later automatically sets the `net.ipv4.conf.default.arp_filter`, `net.ipv4.conf.default.arp_ignore`, and `net.ipv4.ip_forward` kernel parameters. Additionally, host preflight checks automatically run during installation to verify that the kernel parameters were set correctly. For more information about the Embedded Cluster preflight checks, see [About Host Preflight Checks](embedded-overview#about-host-preflight-checks) in _Embedded Cluster Overview_. + Embedded Cluster 1.19.0 and later automatically sets the `net.ipv4.conf.default.arp_filter`, `net.ipv4.conf.default.arp_ignore`, and `net.ipv4.ip_forward` kernel parameters. Additionally, host preflight checks automatically run during installation to verify that Embedded Cluster set the kernel parameters correctly. + + For more information about the Embedded Cluster preflight checks, see [About Host Preflight Checks](embedded-overview#about-host-preflight-checks) in _Embedded Cluster Overview_. If kernel parameters are not set correctly and these preflight checks fail, you might see a message such as `IP forwarding must be enabled.` or `ARP filtering must be disabled by default for newly created interfaces.`. diff --git a/embedded-cluster/embedded-using.mdx b/embedded-cluster/embedded-using.mdx index 525a0503fd..8c3309104e 100644 --- a/embedded-cluster/embedded-using.mdx +++ b/embedded-cluster/embedded-using.mdx @@ -4,7 +4,7 @@ import ShellCommand from "../docs/partials/embedded-cluster/_shell-command.mdx" # Configure Embedded Cluster (Beta) -This topic provides information about how to configure your application releases to support installations with Replicated Embedded Cluster. For an introduction to Embedded Cluster, see [Embedded Cluster Overview](embedded-overview). +This topic describes how to configure your application releases to support installations with Replicated Embedded Cluster. For an introduction, see [Embedded Cluster Overview](embedded-overview). ## Add the Embedded Cluster Config resource @@ -14,13 +14,13 @@ To add the Embedded Cluster Config: 1. Create a new release that includes your application and a unique [HelmChart v2](/reference/custom-resource-helmchart-v2) custom resource for each Helm chart in the release. - If you have not yet configured the HelmChart custom resource for your application, see [Onboard to the Replicated Platform](/vendor/replicated-onboarding) for more detailed instructions on how to configure releases that support installation with a Replicated installer. + If you have not yet configured the HelmChart custom resource for your application, see [Onboard to the Replicated Platform](/vendor/replicated-onboarding). That guide provides detailed instructions for configuring releases that support installation with a Replicated installer. 1. In the release, add an [Embedded Cluster Config](embedded-config) manifest that specifies the Embedded Cluster version to use: -1. If your application requires that certain components are deployed before the application and as part of the Embedded Cluster itself, update the Embedded Cluster Config to add [extensions](embedded-config#extensions). +1. If your application requires that Embedded Cluster deploy certain components before the application and as part of the cluster itself, update the Embedded Cluster Config to add [extensions](embedded-config#extensions). 1. Save the release and promote it to the channel that you use for testing internally. @@ -28,7 +28,7 @@ To add the Embedded Cluster Config: 1. After successfully installing your application with Embedded Cluster, customize the [Embedded Cluster Config](embedded-config) as desired: * Add your custom domain for the Replicated proxy registry and Replicated app service. See [domains](embedded-config#domains). - * Add custom Helm extensions. Extensions allow you to provide Helm charts that are deployed before your application. For example, you can add a Helm extension to ship an ingress controller. See [extensions](embedded-config#extensions). + * Add custom Helm extensions. Extensions allow you to provide Helm charts that Embedded Cluster deploys before your application. For example, you can add a Helm extension to ship an ingress controller. See [extensions](embedded-config#extensions). * Define roles to assign workloads to specific nodes in multi-node installations. See [roles](embedded-config#roles). Replicated recommends that you work in small iterations and test your changes frequently in your development environment. @@ -37,7 +37,7 @@ To add the Embedded Cluster Config: To install with Embedded Cluster, your end customers need to download the Embedded Cluster installer binary and their license. Air gap installations also require an air gap bundle. End customers can download all these installation assets using a curl command by following the installation steps available in the [Replicated Enterprise Portal](/vendor/enterprise-portal-about). -However, some vendors already have a portal where their customers can log in to access documentation or download artifacts. In cases like this, you can serve the Embedded Cluster installation assets yourself using the Replicated Vendor API, rather than having customers download the assets from the Replicated app service using a curl command during installation. +However, some vendors already have a portal where their customers can log in to access documentation or download artifacts. In cases like this, you can serve the Embedded Cluster installation assets yourself using the Replicated Vendor API. This removes the need for customers to download assets from the Replicated app service using a curl command during installation. To serve Embedded Cluster installation assets with the Vendor API: @@ -47,7 +47,7 @@ To serve Embedded Cluster installation assets with the Vendor API: Note the following: - * (Recommended) Provide the `customerId` query parameter so that the customer’s license is included in the downloaded tarball. This mirrors what is returned when a customer downloads the binary directly using the Replicated app service and is the most useful option. Excluding the `customerId` is useful if you plan to distribute the license separately. + * (Recommended) Provide the `customerId` query parameter so that the downloaded tarball includes the customer’s license. This mirrors what the Replicated app service returns when a customer downloads the binary directly and is the most useful option. Excluding the `customerId` is useful if you plan to distribute the license separately. * If you do not provide any query parameters, this endpoint downloads the Embedded Cluster binary for the latest release on the specified channel. You can provide the `channelSequence` query parameter to download the binary for a particular release. @@ -90,8 +90,8 @@ Using the NVIDIA GPU Operator with Embedded Cluster requires configuring the con ### containerd known issue -When the containerd options are configured as shown above, the NVIDIA GPU Operator automatically creates the required configurations in the `/etc/k0s/containerd.d/nvidia.toml` file. It is not necessary to create this file manually, or modify any other configuration on the hosts. +When you configure the containerd options as shown earlier on this page, the NVIDIA GPU Operator automatically creates the required configurations in the `/etc/k0s/containerd.d/nvidia.toml` file. It is not necessary to create this file manually, or modify any other configuration on the hosts. -If you include the NVIDIA GPU Operator as a Helm extension, remove any existing containerd services that are running on the host (such as those deployed by Docker) before attempting to install the release with Embedded Cluster. If there are any containerd services on the host, the NVIDIA GPU Operator will generate an invalid containerd config, causing the installation to fail. For more information, see [Installation failure when NVIDIA GPU Operator is included as Helm extension](#nvidia-gpu-operator) in _Troubleshooting Embedded Cluster_. +If you include the NVIDIA GPU Operator as a Helm extension, remove any existing containerd services running on the host (such as those deployed by Docker) before installing the release with Embedded Cluster. If any containerd services are present on the host, the NVIDIA GPU Operator will generate an invalid containerd config, causing the installation to fail. For more information, see [Installation failure when NVIDIA GPU Operator is included as Helm extension](#nvidia-gpu-operator) in _Troubleshooting Embedded Cluster_. This is the result of a known issue with v24.9.x of the NVIDIA GPU Operator. For more information about the known issue, see [container-toolkit does not modify the containerd config correctly when there are multiple instances of the containerd binary](https://github.com/NVIDIA/nvidia-container-toolkit/issues/982) in the nvidia-container-toolkit repository in GitHub. diff --git a/embedded-cluster/installing-embedded-air-gap.mdx b/embedded-cluster/installing-embedded-air-gap.mdx index 0818ae12ff..160a827cc4 100644 --- a/embedded-cluster/installing-embedded-air-gap.mdx +++ b/embedded-cluster/installing-embedded-air-gap.mdx @@ -6,11 +6,11 @@ This topic describes how to install an application with Replicated Embedded Clus ## Overview -When an air gap bundle is built for a release containing an Embedded Cluster Config, both an application air gap bundle and an Embedded Cluster air gap bundle are built. The application air gap bundle can be used for air gap installations with Replicated kURL or with Replicated KOTS in an existing cluster. The Embedded Cluster air gap bundle is used for air gap installations with Embedded Cluster. +When you build an air gap bundle for a release containing an Embedded Cluster Config, Replicated produces both an application air gap bundle and an Embedded Cluster air gap bundle. You can use the application air gap bundle for air gap installations with Replicated kURL or with Replicated KOTS in an existing cluster. Use the Embedded Cluster air gap bundle for air gap installations with Embedded Cluster. -The Embedded Cluster air gap bundle not only contains the assets normally contained in an application air gap bundle (`airgap.yaml`, `app.tar.gz`, and an images directory), but it also contains an `embedded-cluster` directory with the assets needed to install the infrastructure (Embedded Cluster/k0s and [extensions](embedded-config#extensions)). +The Embedded Cluster air gap bundle contains the assets normally found in an application air gap bundle (`airgap.yaml`, `app.tar.gz`, and an images directory). It also includes an `embedded-cluster` directory with the assets needed to install the infrastructure (Embedded Cluster/k0s and [extensions](embedded-config#extensions)). -During installation with Embedded Cluster in air gap environments, a Docker registry is deployed to the cluster to store application images. Infrastructure images (for Embedded Cluster and Helm extensions) and the Helm charts are preloaded on each node at installation time. +During installation with Embedded Cluster in air gap environments, Embedded Cluster deploys a Docker registry to the cluster to store application images. The installer preloads infrastructure images (for Embedded Cluster and Helm extensions) and the Helm charts on each node at installation time. ## Limitations and known issues @@ -18,9 +18,9 @@ Embedded Cluster installations in air gap environments have the following limita * If you pass `?airgap=true` to the `replicated.app` endpoint but an air gap bundle is not built for the latest release, the API will not return a 404. Instead it will return the tarball without the air gap bundle (as in, with the installer and the license in it, like for online installations). -* Images used by Helm extensions must not refer to a multi-architecture image by digest. Only x64 images are included in air gap bundles, and the digest for the x64 image will be different from the digest for the multi-architecture image, preventing the image from being discovered in the bundle. An example of a chart that does this is ingress-nginx/ingress-nginx chart. For an example of how the digests should be set to empty string to pull by tag only, see [extensions](embedded-config#extensions) in _Embedded Cluster Config_. +* Images used by Helm extensions must not refer to a multi-architecture image by digest. Air gap bundles include only x64 images, and the digest for the x64 image will be different from the digest for the multi-architecture image, preventing Kubernetes from locating the image in the bundle. An example of a chart that does this is ingress-nginx/ingress-nginx chart. For an example of how the digests should be set to empty string to pull by tag only, see [extensions](embedded-config#extensions) in _Embedded Cluster Config_. -* Images for Helm extensions are loaded directly into containerd so that they are available without internet access. But if an image used by a Helm extension has **Always** set as the image pull policy, Kubernetes will try to pull the image from the internet. If necessary, use the Helm values to set `IfNotPresent` as the image pull policy to ensure the extension works in air gap environments. +* Embedded Cluster loads images for Helm extensions directly into containerd so that they are available without internet access. But if an image used by a Helm extension has **Always** set as the image pull policy, Kubernetes will try to pull the image from the internet. If necessary, use the Helm values to configure `IfNotPresent` as the image pull policy to ensure the extension works in air gap environments. * On the channel release history page, the links for **Download air gap bundle**, **Copy download URL**, and **View bundle contents** pertain to the application air gap bundle only, not the Embedded Cluster bundle. @@ -32,10 +32,10 @@ Before you install, complete the following prerequisites: ## Install using the Embedded Cluster UI -This section describes how to install using the interative Embedded Cluster installer UI. +This section describes how to install using the interactive Embedded Cluster installer UI. :::note -These steps assume you download installation assets on a host that has internet access, then copy them into the air-gapped environment where Embedded Cluster will run. +These steps assume you download installation assets on a host that has internet access. Then copy them into the air-gapped environment where Embedded Cluster will run. ::: ### Use the Enterprise Portal for a guided install @@ -50,9 +50,9 @@ To use the guided install experience in the Enterprise Portal: To install from the Vendor Portal: -1. In the [Vendor Portal](https://vendor.replicated.com), open the channel where the target release was promoted so the air gap bundle can be built. Do one of the following: +1. In the [Vendor Portal](https://vendor.replicated.com), open the channel where you promoted the target release so Replicated can build the air gap bundle. Do one of the following: - * If **Automatically create airgap builds for newly promoted releases in this channel** is enabled on the channel, wait until the build completes. + * If you have **Automatically create airgap builds for newly promoted releases in this channel** enabled on the channel, wait until the build completes. * If automatic air gap builds are not enabled, open the **Release history** page for the channel and build the air gap bundle manually. :::note @@ -61,7 +61,7 @@ To install from the Vendor Portal: 1. Open **Customers** and select the target customer. -1. On the **Manage customer** tab, under **License options**, enable **Airgap Download Enabled**. +1. On the **Manage customer** tab, in **License options**, enable **Airgap Download Enabled**. 1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The control may appear as **Embedded Cluster install instructions**.) @@ -79,7 +79,7 @@ To install from the Vendor Portal: [View a larger version of this image](/images/embedded-cluster-install-dialog-airgap.png) -1. Under **Select a version** (or equivalent), choose the application version you promoted to that channel for testing, or leave the latest version selected if that is what you want to install. +1. In the **Select a version** field (or equivalent), choose the application version you promoted to that channel for testing, or leave the latest version selected if that is what you want to install. 1. On a machine **with internet access**, run the download command from the dialog to save the air gap installation assets as a `.tgz` archive. @@ -113,7 +113,7 @@ To install from the Vendor Portal: 1. On the **Run** page, start the installation and wait for it to complete. -1. On the **Finish** page, confirm completion. If your KOTS Application custom resource defines links, they appear here. +1. On the **Finish** page, confirm completion. If your KOTS Application custom resource defines links, they appear on this page. :::note Links to port-forwarded services are not available on this page. @@ -121,13 +121,13 @@ To install from the Vendor Portal: ## Install using the CLI (headless) -With headless installations, you provide all the necessary installation assets, such as the license file and the application config values, with the installation command rather than through the UI. Any preflight checks defined for the application run automatically during headless installations from the command line rather than being displayed in the UI. You can also ignore preflight checks during headless installations when testing in development environments. See [Ignore preflight checks during installation](#ignore-preflights) on this page. +With headless installations, you provide all the necessary installation assets with the installation command rather than through the UI. These assets include the license file and the application config values. Any preflight checks defined for the application run automatically from the command line rather than displaying in the UI. You can also ignore preflight checks during headless installations when testing in development environments. See [Ignore preflight checks during installation](#ignore-preflights) on this page. To install headlessly in an air gap environment: 1. Complete the Vendor Portal steps to build the air gap bundle, enable **Airgap Download Enabled** for the customer, and open **Install instructions** with **Install in an air gap environment** selected. For more detail, see steps 1 through 6 in [Install using the Replicated Vendor Portal](#install-using-the-replicated-vendor-portal). -1. Under **Select a version** (or equivalent), choose the application version to install. +1. In the **Select a version** field (or equivalent), choose the application version to install. 1. On a machine **with internet access**, run the first two commands from the dialog (download the archive, then extract it). diff --git a/embedded-cluster/installing-embedded-requirements.mdx b/embedded-cluster/installing-embedded-requirements.mdx index a9096bf6a9..0f52f1c2af 100644 --- a/embedded-cluster/installing-embedded-requirements.mdx +++ b/embedded-cluster/installing-embedded-requirements.mdx @@ -5,7 +5,7 @@ import FirewallOpeningsEc from "../docs/partials/install/_firewall-openings-embe # Embedded Cluster installation requirements (Beta) -This topic lists the installation requirements for Replicated Embedded Cluster. Ensure that the installation environment meets these requirements before attempting to install. +This topic lists the installation requirements for Replicated Embedded Cluster. Ensure that the installation environment meets these requirements before you attempt to install. ## System requirements @@ -17,14 +17,14 @@ This topic lists the installation requirements for Replicated Embedded Cluster. ## Unix accounts for Kubernetes components -During installation, Embedded Cluster automatically creates the following Unix accounts that are required by internal Kubernetes components: +During installation, Embedded Cluster automatically creates the following Unix accounts, which internal Kubernetes components require: * **etcd**: Used by the Kubernetes etcd database, which stores cluster state. * **konnectivity-server**: Used by the Konnectivity service, which facilitates secure communication between internal components. * **kube-apiserver**: Used by the Kubernetes API server. * **kube-scheduler**: Used by the Kubernetes scheduler to schedule workloads such as pods. -No action is required to create these roles. Removing them will make the cluster non-functional. +You do not need to take any action to create these roles. Removing them will make the cluster non-functional. For more information about the internal Kubernetes components, see [Kubernetes Components](https://kubernetes.io/docs/concepts/overview/components/) in the Kubernetes documentation. @@ -37,14 +37,14 @@ For more information about the Konnectivity service, see [Set up Konnectivity se :::note -If you monitor the outbound traffic attempts made by Embedded Cluster, you might see an attempted call to `updates.k0sproject.io` approximately every 30 minutes. These calls are made by a feature of the upstream k0s project called `update-prober`, which checks for k0s updates. Embedded Cluster does not use the `update-prober` feature and blocking it in your firewall rules will not affect Replicated product functionality. +If you monitor the outbound traffic attempts made by Embedded Cluster, you might see an attempted call to `updates.k0sproject.io` approximately every 30 minutes. A feature of the upstream k0s project called `update-prober` makes these calls to check for k0s updates. Embedded Cluster does not use the `update-prober` feature and blocking it in your firewall rules will not affect Replicated product functionality. ::: ## About firewalld configuration -When Firewalld is enabled in the installation environment, Embedded Cluster modifies the Firewalld config to allow traffic over the pod and service networks and to open the required ports on the host. No additional configuration is required. +When Firewalld runs in the installation environment, Embedded Cluster modifies the Firewalld config to allow traffic over the pod and service networks and to open the required ports on the host. No additional configuration is necessary. -The following rule is added to Firewalld: +Embedded Cluster adds the following rule to Firewalld: ```xml @@ -60,7 +60,7 @@ The following rule is added to Firewalld: ``` -The following ports are opened in the default zone: +Embedded Cluster opens the following ports in the default zone: diff --git a/embedded-cluster/installing-embedded.mdx b/embedded-cluster/installing-embedded.mdx index 004fed520a..0c0da74865 100644 --- a/embedded-cluster/installing-embedded.mdx +++ b/embedded-cluster/installing-embedded.mdx @@ -14,7 +14,7 @@ Before you install, complete the following prerequisites: ## Install using the Embedded Cluster UI -This section describes how to install using the interative Embedded Cluster installer UI. +This section describes how to install using the interactive Embedded Cluster installer UI. ### Use the Enterprise Portal for a guided install @@ -28,7 +28,7 @@ To use the guided install experience in the Enterprise Portal: To install from the Vendor Portal: -1. In the [Vendor Portal](https://vendor.replicated.com), open the **Customers** page and select a customer that is assigned to the channel you use for testing. +1. In the [Vendor Portal](https://vendor.replicated.com), open the **Customers** page and select a customer that belongs to the channel you use for testing. 1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The control may appear as **Embedded Cluster install instructions**.) @@ -36,7 +36,7 @@ To install from the Vendor Portal: You can also open the Enterprise Portal to get install and upgrade instructions. ::: -1. Under **Select a version** (or equivalent), choose the application version you promoted to that channel for testing, or leave the latest version selected if that is what you want to install. +1. In the **Select a version** field (or equivalent), choose the application version you promoted to that channel for testing, or leave the latest version selected if that is what you want to install. 1. On a Linux machine, run the three commands from the dialog in order: download the archive, extract it, then run the install command. @@ -54,7 +54,7 @@ To install from the Vendor Portal: 1. On the **Run** page, start the installation and wait for it to complete. -1. On the **Finish** page, confirm completion. If your KOTS Application custom resource defines links, they appear here. +1. On the **Finish** page, confirm completion. If your KOTS Application custom resource defines links, they appear on this page. :::note Links to port-forwarded services are not available on this page. @@ -62,11 +62,11 @@ To install from the Vendor Portal: ## Install using the CLI (Headless) -With headless installation, you provide all the necessary installation assets, such as the license file and the application config values, with the installation command rather than through the UI. Any preflight checks defined for the application run automatically during headless installations from the command line rather than being displayed in the UI. You can also ignore preflight checks during headless installations when testing in development environments. See [Ignore preflight checks during installation](#ignore-preflights) on this page. +With headless installation, you provide all the necessary installation assets, such as the license file and the application config values, with the installation command rather than through the UI. During headless installations, any preflight checks defined for the application run automatically from the command line rather than appearing in the UI. You can also ignore preflight checks during headless installations when testing in development environments. See [Ignore preflight checks during installation](#ignore-preflights) on this page. To install using the CLI: -1. In the Vendor Portal, open the **Customers** page and select a customer that is assigned to the channel you use for testing. +1. In the Vendor Portal, open the **Customers** page and select a customer that belongs to the channel you use for testing. 1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The control may appear as **Embedded Cluster install instructions**.) @@ -74,7 +74,7 @@ To install using the CLI: You can also open the Enterprise Portal to get install and upgrade instructions. ::: -1. Under **Select a version** (or equivalent), choose the application version you promoted to that channel for testing, or leave the latest version selected if that is what you want to install. +1. In the **Select a version** field (or equivalent), choose the application version you promoted to that channel for testing, or leave the latest version selected if that is what you want to install. 1. On a Linux machine, run the first two commands from the dialog (download the archive, then extract it). diff --git a/embedded-cluster/updating-embedded.mdx b/embedded-cluster/updating-embedded.mdx index 8e4e9316ff..bd845194ab 100644 --- a/embedded-cluster/updating-embedded.mdx +++ b/embedded-cluster/updating-embedded.mdx @@ -4,7 +4,7 @@ This topic describes how to upgrade, redeploy, or reconfigure an application ins ## Overview -Each Embedded Cluster binary that you download is built for a particular application version. Running `install` or `upgrade` with that binary installs or upgrades to that version. Upgrades can update both your application and cluster infrastructure (including Kubernetes and Embedded Cluster components), depending on what changed in the release. +Each Embedded Cluster binary that you download targets a particular application version. Running `install` or `upgrade` with that binary installs or upgrades to that version. Upgrades can update both your application and cluster infrastructure (including Kubernetes and Embedded Cluster components), depending on what changed in the release. You can upgrade interactively in the browser or headlessly from the command line. To change configuration or redeploy without moving to a newer application version, run `upgrade` using the binary for the version that is already installed. @@ -22,7 +22,7 @@ To use the guided upgrade experience in the Enterprise Portal: To upgrade more directly from the Vendor Portal: -1. In the [Vendor Portal](https://vendor.replicated.com), open the **Customers** page and select a customer that is assigned to the channel you use for testing. +1. In the [Vendor Portal](https://vendor.replicated.com), open the **Customers** page and select a customer that you assigned to the channel you use for testing. 1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The control may appear as **Embedded Cluster install instructions**.) @@ -30,7 +30,7 @@ To upgrade more directly from the Vendor Portal: You can also open the Enterprise Portal to get install and upgrade instructions. ::: -1. Under **Select a version** (or equivalent), choose the application version to upgrade to. +1. In the **Select a version** section (or equivalent), choose the application version to upgrade to. 1. On a Linux machine, run the first two commands from the dialog (download the archive, then extract it). @@ -58,7 +58,7 @@ To perform a headless upgrade from the CLI: 1. At the top of the customer page, click **Install instructions** and select **Embedded Cluster**. (The label might also appear as **Embedded Cluster install instructions**). -1. Under **Select a version**, choose the application version to upgrade to. +1. In the **Select a version** section, choose the application version to upgrade to. 1. On a Linux machine, run the first two commands from the dialog to download the archive and extract it. @@ -79,7 +79,7 @@ To perform a headless upgrade from the CLI: ## Reconfigure an application without upgrading the application version -If you need to redeploy or reconfigure an instance without upgrading to a later application version, you can do so by including the installation assets for the application versions that is currently installed when you perform the upgrade. +If you need to redeploy or reconfigure an instance without upgrading to a later application version, include the installation assets for the application version that is already installed when you perform the upgrade. ### UI-based upgrade @@ -92,7 +92,7 @@ To change an application's configuration without upgrading the application versi To change an application's configuration without upgrading the application version: 1. Update the ConfigValues to make the application configuration changes. -1. Run the `upgrade` command using the binary for the application version that is already installed. For example, if version 1.2.3 is installed, download and run `upgrade` with the assets for version 1.2.3. Pass the updated configuration values with `--config-values`. +1. Run the `upgrade` command using the binary for the application version that you already have installed. For example, if you installed version 1.2.3, download and run `upgrade` with the assets for version 1.2.3. Pass the updated configuration values with `--config-values`. ## Upgrade in air-gapped environments diff --git a/styles/config/vocabularies/TechJargon/accept.txt b/styles/config/vocabularies/TechJargon/accept.txt index 4ba373e195..4e9e6312fe 100644 --- a/styles/config/vocabularies/TechJargon/accept.txt +++ b/styles/config/vocabularies/TechJargon/accept.txt @@ -59,6 +59,22 @@ YAML addon addons deprovision +etcd +firewalld +Firewalld +GPUs +headlessly +helmCharts +Konnectivity +Kubelet +PVC +PVCs +preflights +preloaded +rqlite +Subcommands +unsupportedOverrides +zsh deprovisioning IdP IDP From d5d0d501b1f531fe7ff825c099f9778280978641 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Fri, 3 Apr 2026 08:48:02 -0600 Subject: [PATCH 17/31] more edits from style linter --- embedded-cluster/embedded-config.mdx | 6 +++--- embedded-cluster/embedded-manage-nodes.mdx | 2 +- embedded-cluster/embedded-overview.mdx | 2 +- embedded-cluster/installing-embedded-air-gap.mdx | 4 ++-- embedded-cluster/installing-embedded-requirements.mdx | 2 +- embedded-cluster/installing-embedded.mdx | 2 +- embedded-cluster/updating-embedded.mdx | 2 +- styles/config/vocabularies/TechJargon/accept.txt | 1 + 8 files changed, 11 insertions(+), 10 deletions(-) diff --git a/embedded-cluster/embedded-config.mdx b/embedded-cluster/embedded-config.mdx index fb13e1c1cc..28145f503e 100644 --- a/embedded-cluster/embedded-config.mdx +++ b/embedded-cluster/embedded-config.mdx @@ -124,7 +124,7 @@ Optional. Use `spec.binaryOverrideUrl` and `spec.metadataOverrideUrl` to overrid You can optionally customize node roles in the Embedded Cluster Config using the `roles` key. -A common use case for customizing node roles is to assign workloads to specific nodes. For example, if your application has graphics processing unit (GPU) workloads, you could create a `custom` role that adds a `gpu=true` label to any node that takes on the role. You can then schedule GPU workloads on nodes labeled `gpu=true`. +A common use case for customizing node roles is to assign workloads to specific nodes. For example, if your application has graphics processing unit (GPU) workloads, you could create a `custom` role. This role adds a `gpu=true` label to any node that takes it on. You can then schedule GPU workloads on nodes labeled `gpu=true`. When you configure the `roles` key, users select one or more roles to assign to a node when they join it to the cluster. For more information, see [Managing Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). @@ -249,7 +249,7 @@ spec: Advanced users who understand the risks and ramifications of changing the default configuration should use this feature with caution. ::: -Unsupported overrides allow you to override Embedded Cluster's default configuration, including the k0s config and the Helm values for built-in extensions like KOTS and the Embedded Cluster Operator. Use overrides carefully. These combinations have not been tested and can disrupt clusters. Replicated does not support issues caused by unsupported overrides. +Use unsupported overrides to change Embedded Cluster's default configuration, including the k0s config and Helm values for built-in extensions like KOTS and the Embedded Cluster Operator. Use overrides carefully. Replicated has not tested these combinations and they can disrupt clusters. Replicated does not support issues caused by unsupported overrides. While you should use them with caution, unsupported overrides are useful if you need to make changes that Embedded Cluster does not otherwise expose. @@ -261,7 +261,7 @@ For more information on the k0s config, see [Configuration options](https://docs The value of `unsupportedOverrides.k0s` is a string containing YAML that becomes (or patches) the k0s configuration Embedded Cluster uses. How deeply Embedded Cluster merges that YAML with its defaults depends on the field. Treat overrides as high risk and validate in a non-production cluster. -For example, you can enable WireGuard-based encryption. Other configuration may be required. See [`spec.network.calico`](https://docs.k0sproject.io/stable/configuration/#specnetworkcalico) in the k0s documentation: +For example, you can enable WireGuard-based encryption. You might need to add other configuration. See [`spec.network.calico`](https://docs.k0sproject.io/stable/configuration/#specnetworkcalico) in the k0s documentation: ```yaml apiVersion: embeddedcluster.replicated.com/v1beta1 diff --git a/embedded-cluster/embedded-manage-nodes.mdx b/embedded-cluster/embedded-manage-nodes.mdx index 27ce6a7a96..0409c0624e 100644 --- a/embedded-cluster/embedded-manage-nodes.mdx +++ b/embedded-cluster/embedded-manage-nodes.mdx @@ -54,7 +54,7 @@ To add a node to a cluster with Embedded Cluster: 1. If you configured the `roles` key to customize node roles, select one or more roles for the node. - The Admin Console page refreshes to display the commands for downloading the Embedded Cluster binary, extracting the binary, and joining the node based on the roles you selected. Keep this Admin Console page open for the next steps. + The Admin Console page refreshes and shows the commands to download the Embedded Cluster binary, extract the binary, and join the node. These commands are based on the roles you selected. Keep this Admin Console page open for the next steps. :::note You cannot change the role after you add a node. If you need to change a node’s role, reset the node and add it again with the new role. diff --git a/embedded-cluster/embedded-overview.mdx b/embedded-cluster/embedded-overview.mdx index d40fd7a698..653c76afdb 100644 --- a/embedded-cluster/embedded-overview.mdx +++ b/embedded-cluster/embedded-overview.mdx @@ -65,7 +65,7 @@ For more information about creating HA multi-node clusters with Embedded Cluster #### Node roles -You can optionally define node roles in the Embedded Cluster Config. For multi-node clusters, roles can be useful for assigning specific application workloads to nodes. If node roles are defined, users assign one or more roles to a node when it joins the cluster. +You can optionally define node roles in the Embedded Cluster Config. For multi-node clusters, roles can be useful for assigning specific application workloads to nodes. If you define node roles, users assign one or more roles to a node when it joins the cluster. For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. diff --git a/embedded-cluster/installing-embedded-air-gap.mdx b/embedded-cluster/installing-embedded-air-gap.mdx index 160a827cc4..e9728ba131 100644 --- a/embedded-cluster/installing-embedded-air-gap.mdx +++ b/embedded-cluster/installing-embedded-air-gap.mdx @@ -6,7 +6,7 @@ This topic describes how to install an application with Replicated Embedded Clus ## Overview -When you build an air gap bundle for a release containing an Embedded Cluster Config, Replicated produces both an application air gap bundle and an Embedded Cluster air gap bundle. You can use the application air gap bundle for air gap installations with Replicated kURL or with Replicated KOTS in an existing cluster. Use the Embedded Cluster air gap bundle for air gap installations with Embedded Cluster. +Building an air gap bundle for a release with an Embedded Cluster Config produces both an application air gap bundle and an Embedded Cluster air gap bundle. You can use the application air gap bundle for air gap installations with Replicated kURL or with Replicated KOTS in an existing cluster. Use the Embedded Cluster air gap bundle for air gap installations with Embedded Cluster. The Embedded Cluster air gap bundle contains the assets normally found in an application air gap bundle (`airgap.yaml`, `app.tar.gz`, and an images directory). It also includes an `embedded-cluster` directory with the assets needed to install the infrastructure (Embedded Cluster/k0s and [extensions](embedded-config#extensions)). @@ -18,7 +18,7 @@ Embedded Cluster installations in air gap environments have the following limita * If you pass `?airgap=true` to the `replicated.app` endpoint but an air gap bundle is not built for the latest release, the API will not return a 404. Instead it will return the tarball without the air gap bundle (as in, with the installer and the license in it, like for online installations). -* Images used by Helm extensions must not refer to a multi-architecture image by digest. Air gap bundles include only x64 images, and the digest for the x64 image will be different from the digest for the multi-architecture image, preventing Kubernetes from locating the image in the bundle. An example of a chart that does this is ingress-nginx/ingress-nginx chart. For an example of how the digests should be set to empty string to pull by tag only, see [extensions](embedded-config#extensions) in _Embedded Cluster Config_. +* Images used by Helm extensions must not refer to a multi-architecture image by digest. Air gap bundles include only x64 images, and the digest for the x64 image will be different from the digest for the multi-architecture image, preventing Kubernetes from locating the image in the bundle. An example of a chart that does this is ingress-nginx/ingress-nginx chart. For an example of how to set digests to empty strings and pull by tag only, see [extensions](embedded-config#extensions) in _Embedded Cluster Config_. * Embedded Cluster loads images for Helm extensions directly into containerd so that they are available without internet access. But if an image used by a Helm extension has **Always** set as the image pull policy, Kubernetes will try to pull the image from the internet. If necessary, use the Helm values to configure `IfNotPresent` as the image pull policy to ensure the extension works in air gap environments. diff --git a/embedded-cluster/installing-embedded-requirements.mdx b/embedded-cluster/installing-embedded-requirements.mdx index 0f52f1c2af..7604e76230 100644 --- a/embedded-cluster/installing-embedded-requirements.mdx +++ b/embedded-cluster/installing-embedded-requirements.mdx @@ -42,7 +42,7 @@ If you monitor the outbound traffic attempts made by Embedded Cluster, you might ## About firewalld configuration -When Firewalld runs in the installation environment, Embedded Cluster modifies the Firewalld config to allow traffic over the pod and service networks and to open the required ports on the host. No additional configuration is necessary. +When Firewalld runs in the installation environment, Embedded Cluster modifies the Firewalld config to allow traffic over the pod and service networks. It also opens the required ports on the host. No additional configuration is necessary. Embedded Cluster adds the following rule to Firewalld: diff --git a/embedded-cluster/installing-embedded.mdx b/embedded-cluster/installing-embedded.mdx index 0c0da74865..58a4bcf5b0 100644 --- a/embedded-cluster/installing-embedded.mdx +++ b/embedded-cluster/installing-embedded.mdx @@ -62,7 +62,7 @@ To install from the Vendor Portal: ## Install using the CLI (Headless) -With headless installation, you provide all the necessary installation assets, such as the license file and the application config values, with the installation command rather than through the UI. During headless installations, any preflight checks defined for the application run automatically from the command line rather than appearing in the UI. You can also ignore preflight checks during headless installations when testing in development environments. See [Ignore preflight checks during installation](#ignore-preflights) on this page. +With headless installation, you provide all necessary installation assets with the installation command rather than through the UI. Assets include the license file and the application config values. During headless installations, any preflight checks defined for the application run automatically from the command line rather than appearing in the UI. You can also ignore preflight checks during headless installations when testing in development environments. See [Ignore preflight checks during installation](#ignore-preflights) on this page. To install using the CLI: diff --git a/embedded-cluster/updating-embedded.mdx b/embedded-cluster/updating-embedded.mdx index bd845194ab..6c2c8f9930 100644 --- a/embedded-cluster/updating-embedded.mdx +++ b/embedded-cluster/updating-embedded.mdx @@ -79,7 +79,7 @@ To perform a headless upgrade from the CLI: ## Reconfigure an application without upgrading the application version -If you need to redeploy or reconfigure an instance without upgrading to a later application version, include the installation assets for the application version that is already installed when you perform the upgrade. +To redeploy or reconfigure an instance without upgrading, include the installation assets for the currently installed version when you perform the upgrade. ### UI-based upgrade diff --git a/styles/config/vocabularies/TechJargon/accept.txt b/styles/config/vocabularies/TechJargon/accept.txt index 4e9e6312fe..6489e0d9e4 100644 --- a/styles/config/vocabularies/TechJargon/accept.txt +++ b/styles/config/vocabularies/TechJargon/accept.txt @@ -71,6 +71,7 @@ PVC PVCs preflights preloaded +preloads rqlite Subcommands unsupportedOverrides From 9773b6296d1dacf7e0b79f53be8fcac03c82d050 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Fri, 3 Apr 2026 10:15:22 -0600 Subject: [PATCH 18/31] vale prose linting --- .claude/skills/vale-prose-review/SKILL.md | 2 +- .../references/vale-rules.md | 17 +++++++++++++++++ .../v2}/_generate-bundle-ec.mdx | 0 .../v3/_generate-bundle-ec.mdx | 19 +++++++++++++++++++ docs/vendor/support-bundle-embedded.mdx | 2 +- embedded-cluster/embedded-troubleshooting.mdx | 2 +- .../embedded-troubleshooting.mdx | 2 +- 7 files changed, 40 insertions(+), 4 deletions(-) rename docs/partials/{support-bundles => embedded-cluster/v2}/_generate-bundle-ec.mdx (100%) create mode 100644 docs/partials/embedded-cluster/v3/_generate-bundle-ec.mdx diff --git a/.claude/skills/vale-prose-review/SKILL.md b/.claude/skills/vale-prose-review/SKILL.md index efa7a7a279..a66f02518b 100644 --- a/.claude/skills/vale-prose-review/SKILL.md +++ b/.claude/skills/vale-prose-review/SKILL.md @@ -85,7 +85,7 @@ See `references/vale-rules.md` for full fix patterns, before/after examples, and **`Replicated.PositionalLanguage`** — Replace "above/below" with "the following" or a section link; replace directional "right/left" with "the following" or a UI element name. -**`Replicated.Headings`** — Apply sentence case, with two exceptions: (1) **Skip entirely** when the heading IS a CLI command name or YAML field name (e.g., `# install (Beta)`, `## helmCharts`) — those follow the thing's own casing conventions. (2) **Parentheticals reset sentence case** — `(Beta)` is correct, not `(beta)`. See `references/vale-rules.md` for full patterns. +**`Replicated.Headings`** — Apply sentence case, with three exceptions: (1) **Skip entirely** when the heading IS a CLI command name or YAML field name (e.g., `# install (Beta)`, `## helmCharts`) — those follow the thing's own casing conventions. (2) **Parentheticals reset sentence case** — `(Beta)` is correct, not `(beta)`. (3) **Kubernetes custom resource kind names stay capitalized** — `Preflight`, `SupportBundle`, `Config`, `HelmChart` are proper names; check context to confirm the word refers to a `kind:` value before lowercasing. See `references/vale-rules.md` for full patterns. **`Replicated.WordsToAvoid`** — Remove "easy/easily", "simple/simply", "just" (when minimizing). Rephrase or omit. diff --git a/.claude/skills/vale-prose-review/references/vale-rules.md b/.claude/skills/vale-prose-review/references/vale-rules.md index f51f98ede3..e5ed27aecf 100644 --- a/.claude/skills/vale-prose-review/references/vale-rules.md +++ b/.claude/skills/vale-prose-review/references/vale-rules.md @@ -121,6 +121,23 @@ A parenthetical like `(Beta)` or `(Preview)` opens a new "sentence" within the h - `(Preview)` is correct — **not** `(preview)` - `(Deprecated)` is correct — **not** `(deprecated)` +### Kubernetes custom resource kinds — always capitalize + +Custom resource kind names are proper names and must remain capitalized wherever they appear in headings, even mid-sentence. The key examples in Replicated docs: + +- `Preflight` +- `SupportBundle` +- `Config` +- `HelmChart` + +**How to decide:** Look at the surrounding context. If the page or section is about a Kubernetes custom resource and the word refers to its `kind:` value, keep it capitalized. If the word is used in a different sense (for example, `config` as a generic noun, or `install` as a CLI command), lowercase it per the normal rules. + +**Examples:** +- `## About the Preflight custom resource` — `Preflight` is the kind name, keep capital P +- `## Configure your HelmChart` — `HelmChart` is the kind name, keep capital H +- `## Embedded Cluster Config` — `Config` is the kind name (`kind: Config`), keep capital C +- `## Override the k0s config` — `config` here is a generic noun referring to a k0s configuration file, lowercase is correct + ### What to capitalize (proper nouns and trademarks) - Replicated product names: Embedded Cluster, KOTS, Vendor Portal, Enterprise Portal, Compatibility Matrix, Replicated SDK, Admin Console, Replicated CLI diff --git a/docs/partials/support-bundles/_generate-bundle-ec.mdx b/docs/partials/embedded-cluster/v2/_generate-bundle-ec.mdx similarity index 100% rename from docs/partials/support-bundles/_generate-bundle-ec.mdx rename to docs/partials/embedded-cluster/v2/_generate-bundle-ec.mdx diff --git a/docs/partials/embedded-cluster/v3/_generate-bundle-ec.mdx b/docs/partials/embedded-cluster/v3/_generate-bundle-ec.mdx new file mode 100644 index 0000000000..2def864b17 --- /dev/null +++ b/docs/partials/embedded-cluster/v3/_generate-bundle-ec.mdx @@ -0,0 +1,19 @@ +### Generate a support bundle + +The `support-bundle` command uses the default Embedded Cluster support bundle spec to collect both cluster- and host-level information. It also automatically includes any application-specific support bundle specs in the generated bundle. + +To generate a support bundle: + +1. SSH onto a controller node. + + :::note + You can SSH onto a worker node to generate a support bundle that contains information specific to that node. However, when run on a worker node, the `support-bundle` command does not capture cluster-wide information. + ::: + +1. Run the following command: + + ```bash + sudo ./APP_SLUG support-bundle + ``` + + Where `APP_SLUG` is the unique slug for the application. diff --git a/docs/vendor/support-bundle-embedded.mdx b/docs/vendor/support-bundle-embedded.mdx index f6f624244a..db4f019a9a 100644 --- a/docs/vendor/support-bundle-embedded.mdx +++ b/docs/vendor/support-bundle-embedded.mdx @@ -1,4 +1,4 @@ -import EmbeddedClusterSupportBundle from "../partials/support-bundles/_generate-bundle-ec.mdx" +import EmbeddedClusterSupportBundle from "../partials/embedded-cluster/v3/_generate-bundle-ec.mdx" import SupportBundleIntro from "../partials/support-bundles/_ec-support-bundle-intro.mdx" # Generate support bundles for Embedded Cluster diff --git a/embedded-cluster/embedded-troubleshooting.mdx b/embedded-cluster/embedded-troubleshooting.mdx index bfb41b6e03..96ae2dde9e 100644 --- a/embedded-cluster/embedded-troubleshooting.mdx +++ b/embedded-cluster/embedded-troubleshooting.mdx @@ -1,5 +1,5 @@ import SupportBundleIntro from "../docs/partials/support-bundles/_ec-support-bundle-intro.mdx" -import EmbeddedClusterSupportBundle from "../docs/partials/support-bundles/_generate-bundle-ec.mdx" +import EmbeddedClusterSupportBundle from "../docs/partials/embedded-cluster/v3/_generate-bundle-ec.mdx" import ShellCommand from "../docs/partials/embedded-cluster/_shell-command.mdx" import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx index d3873a2c15..1973f6f399 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-troubleshooting.mdx @@ -1,5 +1,5 @@ import SupportBundleIntro from "../../docs/partials/support-bundles/_ec-support-bundle-intro.mdx" -import EmbeddedClusterSupportBundle from "../../docs/partials/support-bundles/_generate-bundle-ec.mdx" +import EmbeddedClusterSupportBundle from "../../docs/partials/embedded-cluster/v2/_generate-bundle-ec.mdx" import ShellCommand from "../../docs/partials/embedded-cluster/_shell-command.mdx" import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; From 56dd51affb99904cc4f231163b64efb3226d5f61 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Fri, 3 Apr 2026 13:21:48 -0600 Subject: [PATCH 19/31] adding migration doc --- .../embedded-cluster/v3/_definition.mdx | 4 +- docs/vendor/quick-start.mdx | 2 +- embedded-cluster/embedded-config.mdx | 69 +++++++------------ embedded-cluster/embedded-overview.mdx | 54 ++++++--------- embedded-cluster/embedded-v3-migrate.md | 49 +++++++++++++ 5 files changed, 99 insertions(+), 79 deletions(-) create mode 100644 embedded-cluster/embedded-v3-migrate.md diff --git a/docs/partials/embedded-cluster/v3/_definition.mdx b/docs/partials/embedded-cluster/v3/_definition.mdx index 97c367563d..4c16a244ab 100644 --- a/docs/partials/embedded-cluster/v3/_definition.mdx +++ b/docs/partials/embedded-cluster/v3/_definition.mdx @@ -1,3 +1,5 @@ Replicated Embedded Cluster allows you to distribute a Kubernetes cluster and your application together as a single appliance, making it easy for enterprise users to install, update, and manage the application and the cluster in tandem. Embedded Cluster is based on the open source Kubernetes distribution k0s. For more information, see the [k0s documentation](https://docs.k0sproject.io/stable/). -For software vendors, Embedded Cluster provides a Config for defining characteristics of the cluster that will be created in the customer environment. For enterprise users, cluster updates are done automatically at the same time as application updates, allowing users to more easily keep the cluster up-to-date without needing to use kubectl. +Software vendors can configure the Embedded Cluster Config manifest to define characteristics of the cluster and the installation. For example, you can define custom node roles to assign workloads to specific nodes. Or, you can add optional Helm extensions to deploy components in the cluster before Embedded Cluster installs your application. + +For enterprise users, Embedded Cluster provides a built-in UI that guides users through installation and upgrades. Additionally, Embedded Cluster automatically updates the cluster infrastructure at the same time as application updates, allowing users to more easily keep the cluster up-to-date without needing to use kubectl. diff --git a/docs/vendor/quick-start.mdx b/docs/vendor/quick-start.mdx index fe4744e35b..a4267173bc 100644 --- a/docs/vendor/quick-start.mdx +++ b/docs/vendor/quick-start.mdx @@ -7,7 +7,7 @@ import KotsCr from "../partials/getting-started/_slackernews-repl-app.mdx" import K8sCr from "../partials/getting-started/_slackernews-k8s-app.mdx" import EcCr from "../partials/getting-started/_slackernews-embedded-cluster.mdx" import ConfigCr from "../partials/getting-started/_slackernews-config.mdx" -import Requirements from "../partials/embedded-cluster/v3/_requirements.mdx" +import Requirements from "../partials/embedded-cluster/v2/_requirements.mdx" # Replicated quick start diff --git a/embedded-cluster/embedded-config.mdx b/embedded-cluster/embedded-config.mdx index 28145f503e..eefd3e09f2 100644 --- a/embedded-cluster/embedded-config.mdx +++ b/embedded-cluster/embedded-config.mdx @@ -1,22 +1,16 @@ import DoNotDowngrade from "../docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx" -# Embedded Cluster config (Beta) +# Embedded Cluster Config (Beta) This topic is a reference for the Replicated Embedded Cluster Config custom resource. For more information about Embedded Cluster, see [Use Embedded Cluster](embedded-overview). -## Overview +## Limitations -To install your application with Embedded Cluster, you must include an Embedded Cluster Config in the release. Embedded Cluster installation artifacts are available only for releases that include an Embedded Cluster Config. - -The Embedded Cluster Config lets you define several aspects of the Kubernetes cluster that Embedded Cluster creates. - -### Limitations - -* Top-level fields and most of the Config spec are plain YAML and do not support Go template functions, including Replicated template functions. The `values` field for each entry in `extensions.helmCharts` does support [Replicated template functions](/reference/template-functions-about). +* Most of the fields in the Config spec are plain YAML and do not support Go template functions, including [Replicated template functions](/reference/template-functions-about). The `values` field for each entry in `extensions.helmCharts` does support the use of template functions. * There are additional, property-specific limitations. For more information, see the following sections. -### Example +## Example ```yaml apiVersion: embeddedcluster.replicated.com/v1beta1 @@ -24,7 +18,7 @@ kind: Config metadata: name: my-embedded-cluster-config spec: - version: "3.0.0-alpha-26+k8s-1.34" + version: "3.0.0-alpha-27+k8s-1.34" binaryOverrideUrl: "" metadataOverrideUrl: "" domains: @@ -101,15 +95,13 @@ spec: repository: 'repl{{ ReplicatedImageName "docker.io/bloomberg/goldpinger" }}' ``` -## metadata +## version (Required) -The Config is a Kubernetes custom resource. Set `metadata.name` to a name for this object in the cluster (for example, `my-embedded-cluster-config`). +Specify the versions of Embedded Cluster and Kubernetes to install. -## version +Embedded Cluster appends the version of Kubernetes to the version label in the format `+k8s-1.34`. For example, Embedded Cluster `3.0.0-alpha-26+k8s-1.34` uses Embedded Cluster `3.0.0-alpha-26` and Kubernetes 1.34. -Specify the versions of Embedded Cluster and Kubernetes to install. Embedded Cluster appends the version of Kubernetes to the Embedded Cluster version in the format `+k8s-1.34`. For example, Embedded Cluster `3.0.0-alpha-26+k8s-1.34` uses Embedded Cluster `3.0.0-alpha-26` and Kubernetes 1.34. - -Each version of Embedded Cluster includes specific versions of components like KOTS (Admin Console) and OpenEBS. +Each version of Embedded Cluster includes specific versions of components like OpenEBS. For more information, see the [Embedded Cluster Release Notes](/release-notes/rn-embedded-cluster). Replicated recommends that you update the version frequently to ensure that you are using the latest version of Embedded Cluster. @@ -118,17 +110,17 @@ Replicated recommends that you update the version frequently to ensure that you ## binaryOverrideUrl and metadataOverrideUrl -Optional. Use `spec.binaryOverrideUrl` and `spec.metadataOverrideUrl` to override the default locations of Embedded Cluster binary and metadata artifacts when you need a non-default artifact source. Leave them as empty strings when you are using the defaults from the release. +Use `spec.binaryOverrideUrl` and `spec.metadataOverrideUrl` to override the default locations of Embedded Cluster binary and metadata artifacts. -## roles (Beta) {#roles} +## roles {#roles} -You can optionally customize node roles in the Embedded Cluster Config using the `roles` key. +Use the `roles` key to customize node roles. -A common use case for customizing node roles is to assign workloads to specific nodes. For example, if your application has graphics processing unit (GPU) workloads, you could create a `custom` role. This role adds a `gpu=true` label to any node that takes it on. You can then schedule GPU workloads on nodes labeled `gpu=true`. +A common use case for customizing node roles is to assign workloads to specific nodes. For example, if your application has graphics processing unit (GPU) workloads, you could create a `custom` role that adds a `gpu=true` label to the node. You could then schedule GPU workloads on nodes labeled `gpu=true`. When you configure the `roles` key, users select one or more roles to assign to a node when they join it to the cluster. For more information, see [Managing Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). -If the `roles` key is _not_ configured, Embedded Cluster assigns all nodes that join the cluster the `controller` role. The `controller` role designates nodes that run the Kubernetes control plane. Controller nodes can also run other workloads, such as application or Replicated KOTS workloads. +If the `roles` key is _not_ configured, Embedded Cluster assigns all nodes that join the cluster the `controller` role. The `controller` role designates nodes that run the Kubernetes control plane. Controller nodes can also run other workloads in addition to the control plane. #### Example @@ -150,11 +142,9 @@ spec: gpu: "true" ``` -### Limitations - -* Defining node roles with the `roles` key is Beta. +### Limitation -* The first node added to the cluster is always a controller and cannot receive any custom roles. You can add custom labels to the first node by setting the `labels` field in the `roles.controller` key. +The first node added to the cluster is always a controller. You cannot assign custom roles to the first node. To add labels to the first node, set the `labels` field in the `roles.controller` key. ### roles.controller @@ -164,20 +154,20 @@ In the `roles.controller` key, you can set the following fields to customize the :::note If you plan to create any custom roles, Replicated recommends that you change the default name for the controller role to a clear, descriptive term, such as “app”. When you add custom roles, the user sees both the name of the controller role and the names of any custom roles when they join a node. ::: -* `labels`: Kubernetes labels that Embedded Cluster applies to any node in the cluster that takes on the given role. +* `labels`: Kubernetes labels applied to any node in the cluster with the given role. ### roles.custom In the `roles.custom` key, you can add custom roles. Each custom role includes the following fields: * `name`: (Required) A name for the custom role. -* `labels`: Kubernetes labels that Embedded Cluster applies to any node in the cluster that takes on the given role. +* `labels`: Kubernetes labels applied to any node in the cluster with the given role. ## domains Configure the `domains` key so that Embedded Cluster uses your custom domains for the Replicated proxy registry and Replicated app service. -When you set `domains.proxyRegistryDomain` and `domains.replicatedAppDomain`, Embedded Cluster uses the custom domains specified when making requests to the given service. Embedded Cluster also passes the values to KOTS to ensure that KOTS uses the same domains for these services. +Embedded Cluster uses the custom domains specified in `domains.proxyRegistryDomain` and `domains.replicatedAppDomain` when making requests to the given service. You must add the custom domains that you specify in the `domains.proxyRegistryDomain` and `domains.replicatedAppDomain` fields to the Vendor Portal before Embedded Cluster can use them. For more information, see [Add a Custom Domain in the Vendor Portal](/vendor/custom-domains-using#add-domain) in _Using Custom Domains_. @@ -190,8 +180,8 @@ apiVersion: embeddedcluster.replicated.com/v1beta1 kind: Config spec: domains: - proxyRegistryDomain: proxy.yourcompany.com - replicatedAppDomain: updates.yourcompany.com + proxyRegistryDomain: proxy.mycompany.com + replicatedAppDomain: updates.mycompany.com ``` ## extensions @@ -207,18 +197,16 @@ Each object in `helmCharts` can include the following fields: * `chartVersion`: Chart version string to install. * `releaseName`: (Required) Helm release name. * `namespace`: (Required) Namespace for the release. -* `weight`: Optional. Controls ordering relative to other `helmCharts` entries. **Lower** `weight` values install **earlier**. If omitted, Embedded Cluster applies a default value. -* `values`: Optional multi-line string of Helm values. This field supports [Replicated template functions](/reference/template-functions-about) (for example, `ReplicatedImageName`, `HelmValue`, `ReplicatedImageRegistry`, and `ReplicatedImageRepository`) so you can align images and values with your release. - -Embedded Cluster updates Helm extensions when you deploy new versions of your application from the Admin Console. For example, you can change `values` from one release to another, and those changes apply when you deploy the new version. +* `weight`: Controls installation order relative to other Helm chart extensions. Lower weights install before higher weights. +* `values`: Multi-line string of Helm values. This field supports [Replicated template functions](/reference/template-functions-about). Embedded Cluster updates Helm extensions when users deploy new versions of your application. For example, you can change `values` from one release to another, and those changes apply when the user deploys the new version. #### Requirements * You must provide `chart.chartVersion`. Omitting it can cause upgrade issues. -* For air gap bundles, follow the same image and digest guidance as in prior Embedded Cluster releases: avoid multi-architecture image digests in extension values where the air gap bundle includes only single-arch images. Use tags and empty digests where appropriate so the air gap builder can resolve images. +* For air gap bundles, images used by Helm extensions must not refer to a multi-architecture image by digest. Air gap bundles include only x64 images, and the digest for the x64 image will be different from the digest for the multi-architecture image, preventing Kubernetes from locating the image in the bundle. For an example of how to set digests to empty strings and pull by tag only, see the `ingress-nginx` [Example](embedded-config#extension-example). -#### Example +#### Example {#extension-example} ```yaml apiVersion: embeddedcluster.replicated.com/v1beta1 @@ -286,13 +274,6 @@ spec: Embedded Cluster deploys built-in extensions with Helm. You can patch their values with `unsupportedOverrides.builtInExtensions`. Each item sets `name` (the chart to patch) and `values` (a multi-line YAML string). Embedded Cluster merges your values into the defaults it uses. -Common `name` values include: - -- `admin-console` -- `embedded-cluster-operator` -- `openebs` -- `velero` - #### Example ```yaml diff --git a/embedded-cluster/embedded-overview.mdx b/embedded-cluster/embedded-overview.mdx index 653c76afdb..ce8ba31eca 100644 --- a/embedded-cluster/embedded-overview.mdx +++ b/embedded-cluster/embedded-overview.mdx @@ -9,33 +9,39 @@ This topic provides an introduction to Replicated Embedded Cluster. -## Comparison to Embedded Cluster v2 +## Limitations {#ec-limitations} + +* Embedded Cluster v3 is Beta. The limitations and features are subject to change. -### Removal of KOTS +* Embedded Cluster v3 (Beta) does not support disaster recovery. + +* Some Replicated template functions are not implemented in Embedded Cluster v3, either because Replicated discourages their use or because they are not yet ported. Contact Replicated if a missing template function blocks your release. -Embedded Cluster 3.x removes KOTS from the architecture. The new installer provides the UI instead. Benefits include increased reliability, simpler feature work, and fewer dependencies running in the cluster. +## Built-in extensions {#built-in-extensions} + +Embedded Cluster includes several built-in extensions. The built-in extensions provide capabilities such as application management and storage. Embedded Cluster installs each built-in extension in its own namespace. -The KOTS CLI no longer works with Embedded Cluster, and there is no KOTS Admin Console. +The built-in extensions installed by Embedded Cluster include: -Also, because Embedded Cluster removes KOTS, you must include the [Replicated SDK](/vendor/replicated-sdk-overview) in your application. The SDK provides reporting from application status informers, such as notifications and visibility in the Vendor Portal and Enterprise Portal. +* **Embedded Cluster Operator**: The Operator handles reporting and some clean up operations. -### Troubleshoot preflight `v1beta3` +* **OpenEBS:** Embedded Cluster uses OpenEBS to provide local PersistentVolume (PV) storage, including the PV storage for rqlite used by KOTS. For more information, see the [OpenEBS](https://openebs.io/docs/) documentation. -Preflight checks must use Troubleshoot `v1beta3`. `v1beta2` preflight specs are not supported. For more information, see [v1beta3 overview](https://troubleshoot.sh/docs/preflight/v1beta3-overview) in the Troubleshoot documentation. +* **(Air Gap Only) Image registry:** For air gap installations in environments with limited or no outbound internet access, Embedded Cluster installs an image registry where it pushes the images required to install and run the application. For more information about installing in air-gapped environments, see [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). ## About installing with Embedded Cluster Embedded Cluster supports installations in online (internet-connected) environments and air gap environments with no outbound internet access. -Embedded Cluster also supports installing using the built-in interactive UI or performing headless installs from the CLI. +To install, users first download and extract the Embedded Cluster installation assets. Then, users can choose to follow a guided installation with the UI or a headless install with the CLI. -You include the Embedded Cluster Config in the application release in the Replicated Vendor Portal, and Replicated uses it to generate the Embedded Cluster installation assets. Users can download these installation assets from the Replicated app service (`replicated.app`) on the command line, then run the Embedded Cluster installation command to install Kubernetes. Finally, users can install the application using the UI or CLI. During installation, users can optionally add nodes to the cluster and configure the application. +During installation, Embedded Cluster automatically runs preflight checks to verify that the installation environment meets the requirements. Users then configure the application and can optionally add nodes to the cluster before deploying. For more information about how to install with Embedded Cluster, see: * [Online Installation wtih Embedded Cluster](installing-embedded) * [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap) -### Embedded Cluster host preflight checks {#about-host-preflight-checks} +## Embedded Cluster host preflight checks {#about-host-preflight-checks} During installation, Embedded Cluster automatically runs a default set of _host preflight checks_. The default host preflight checks verify that the installation environment meets the requirements for Embedded Cluster, such as: * The system has sufficient disk space @@ -46,24 +52,24 @@ If any of the Embedded Cluster host preflight checks fail, Embedded Cluster bloc For the full default host preflight spec for Embedded Cluster, see [`host-preflight.yaml`](https://github.com/replicatedhq/embedded-cluster/blob/main/pkg/preflights/host-preflight.yaml) in the `embedded-cluster` repository in GitHub. -#### Limitations +### Limitations Embedded Cluster host preflight checks have the following limitations: * Vendors cannot modify the default host preflight checks for Embedded Cluster or provide their own custom host preflight spec for Embedded Cluster. * Host preflight checks do not verify that the application meets any application-specific requirements. For more information about defining preflight checks for your application, see [Define Preflight Checks](/vendor/preflight-defining). -### Multi-node installations +## Multi-node installations -Embedded Cluster supports installations in mutli-node clusters. Your end customers can add nodes to a cluster during or after installation from the Admin Console. For more information, see [Manage Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). +Embedded Cluster supports installations in mutli-node clusters. Your end customers can add nodes to a cluster during or after installation from the UI. For more information, see [Manage Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). -#### High availability +### High availability Multi-node clusters are not highly available by default. Enabling high availability (HA) requires that at least three controller nodes are present in the cluster. Users can enable HA when joining the third node. For more information about creating HA multi-node clusters with Embedded Cluster, see [Enable High Availability](embedded-manage-nodes#ha) in _Managing Multi-Node Clusters with Embedded Cluster_. -#### Node roles +### Node roles You can optionally define node roles in the Embedded Cluster Config. For multi-node clusters, roles can be useful for assigning specific application workloads to nodes. If you define node roles, users assign one or more roles to a node when it joins the cluster. @@ -74,21 +80,3 @@ For more information, see [roles](embedded-config#roles) in _Embedded Cluster Co To support installations with Embedded Cluster, an Embedded Cluster Config must be present in the application release. The Embedded Cluster Config lets you define several characteristics about the cluster that Embedded Cluster creates. For more information, see [Embedded Cluster Config](embedded-config). - -## Built-in extensions {#built-in-extensions} - -Embedded Cluster includes several built-in extensions. The built-in extensions provide capabilities such as application management and storage. Embedded Cluster installs each built-in extension in its own namespace. - -The built-in extensions installed by Embedded Cluster include: - -* **Embedded Cluster Operator**: The Operator handles reporting and some clean up operations. - -* **OpenEBS:** Embedded Cluster uses OpenEBS to provide local PersistentVolume (PV) storage, including the PV storage for rqlite used by KOTS. For more information, see the [OpenEBS](https://openebs.io/docs/) documentation. - -* **(Air Gap Only) Image registry:** For air gap installations in environments with limited or no outbound internet access, Embedded Cluster installs an image registry where it pushes the images required to install and run the application. For more information about installing in air-gapped environments, see [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). - -## Limitations {#ec-limitations} - -* Embedded Cluster v3 does not support disaster recovery. - -* Some Replicated template functions are not implemented in Embedded Cluster v3, either because Replicated discourages their use or because they are not yet ported. Contact Replicated if a missing template function blocks your release. diff --git a/embedded-cluster/embedded-v3-migrate.md b/embedded-cluster/embedded-v3-migrate.md new file mode 100644 index 0000000000..f0ec79cd2a --- /dev/null +++ b/embedded-cluster/embedded-v3-migrate.md @@ -0,0 +1,49 @@ +# Migrate from Embedded Cluster v2 + +This page describes how to migrate from Embedded Cluster v2 to Embedded Cluster v3. + +It includes information about how to update your application release to support Embedded Cluster v3. It also describes how to upgrade existing installations from Embedded Cluster v2 to v3. + +## Comparison to Embedded Cluster v2 + +This section describes the key differences between Embedded Cluster v2 and v3. + +### Removal of KOTS + +Embedded Cluster v3 removes Replicated KOTS from the architecture. This reduces the number of dependencies that are running in the cluster, which improves reliability. + +The KOTS CLI does not work with Embedded Cluster v3, and there is no KOTS Admin Console. + +Embedded Cluster v3 still requires the KOTS HelmChart v2 custom resource to process and deploy Helm charts. Embedded Cluster v3 also still uses KOTS custom resources like the KOTS Application and KOTS Config resources to define aspects of the installation experience. + +### Replicated SDK required for application status informers + +Because Embedded Cluster v3 removes KOTS, you must include the [Replicated SDK](/vendor/replicated-sdk-overview) in your application to get instance reporting in the Vendor Portal from application status informers. + +### Troubleshoot Preflight `v1beta3` required + +Application preflight checks must use Troubleshoot `v1beta3`. `v1beta2` preflight specs are not supported. + +For more information, see [v1beta3 overview](https://troubleshoot.sh/docs/preflight/v1beta3-overview) in the Troubleshoot documentation. + +### HelmChart v2 required + +Embedded Cluster v3 supports installing Helm charts with a corresponding HelmChart v2 custom resource (API version `v1beta2`). + +Embedded Cluster v3 does not support Kustomize, Kubernetes manifests, or HelmChart v1. + +### Unsupported Replicated template functions + +Some Replicated template functions are unsupported with Embedded Cluster v3. + +## Update your release to Embedded Cluster v3 + +To update your release to support installation with Embedded Cluster v3: + +1. Remove any standalone Kubernetes manifests or `kustomization.yaml` files from your release. Embedded Cluster v3 only deploys resources that are managed by Helm charts. If you need to deploy any components before your application is deployed, use Helm chart `extensions`. + +1. Ensure that you include a corresponding HelmChart v2 custom resource for each of your Helm charts. For information about how to configure the HelmChart v2 custom resource, see [Support installations with HelmChart v2](/vendor/helm-native-v2-using). + +## Migrate an installation from Embedded Cluster v2 to Embedded Cluster v3 + + From ca4e6087ae44e2cdf7241f36a3dab6802fd0ba52 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Fri, 3 Apr 2026 14:34:55 -0600 Subject: [PATCH 20/31] edits to migration topic --- embedded-cluster/embedded-v3-migrate.md | 49 ------ embedded-cluster/embedded-v3-migrate.mdx | 163 ++++++++++++++++++ sidebarEmbeddedCluster.js | 1 + ...luster-v3-slackernews-upgrade-progress.png | Bin 0 -> 267011 bytes ...-cluster-v3-slackernews-upgrade-wizard.png | Bin 0 -> 204706 bytes 5 files changed, 164 insertions(+), 49 deletions(-) delete mode 100644 embedded-cluster/embedded-v3-migrate.md create mode 100644 embedded-cluster/embedded-v3-migrate.mdx create mode 100644 static/images/embedded-cluster-v3-slackernews-upgrade-progress.png create mode 100644 static/images/embedded-cluster-v3-slackernews-upgrade-wizard.png diff --git a/embedded-cluster/embedded-v3-migrate.md b/embedded-cluster/embedded-v3-migrate.md deleted file mode 100644 index f0ec79cd2a..0000000000 --- a/embedded-cluster/embedded-v3-migrate.md +++ /dev/null @@ -1,49 +0,0 @@ -# Migrate from Embedded Cluster v2 - -This page describes how to migrate from Embedded Cluster v2 to Embedded Cluster v3. - -It includes information about how to update your application release to support Embedded Cluster v3. It also describes how to upgrade existing installations from Embedded Cluster v2 to v3. - -## Comparison to Embedded Cluster v2 - -This section describes the key differences between Embedded Cluster v2 and v3. - -### Removal of KOTS - -Embedded Cluster v3 removes Replicated KOTS from the architecture. This reduces the number of dependencies that are running in the cluster, which improves reliability. - -The KOTS CLI does not work with Embedded Cluster v3, and there is no KOTS Admin Console. - -Embedded Cluster v3 still requires the KOTS HelmChart v2 custom resource to process and deploy Helm charts. Embedded Cluster v3 also still uses KOTS custom resources like the KOTS Application and KOTS Config resources to define aspects of the installation experience. - -### Replicated SDK required for application status informers - -Because Embedded Cluster v3 removes KOTS, you must include the [Replicated SDK](/vendor/replicated-sdk-overview) in your application to get instance reporting in the Vendor Portal from application status informers. - -### Troubleshoot Preflight `v1beta3` required - -Application preflight checks must use Troubleshoot `v1beta3`. `v1beta2` preflight specs are not supported. - -For more information, see [v1beta3 overview](https://troubleshoot.sh/docs/preflight/v1beta3-overview) in the Troubleshoot documentation. - -### HelmChart v2 required - -Embedded Cluster v3 supports installing Helm charts with a corresponding HelmChart v2 custom resource (API version `v1beta2`). - -Embedded Cluster v3 does not support Kustomize, Kubernetes manifests, or HelmChart v1. - -### Unsupported Replicated template functions - -Some Replicated template functions are unsupported with Embedded Cluster v3. - -## Update your release to Embedded Cluster v3 - -To update your release to support installation with Embedded Cluster v3: - -1. Remove any standalone Kubernetes manifests or `kustomization.yaml` files from your release. Embedded Cluster v3 only deploys resources that are managed by Helm charts. If you need to deploy any components before your application is deployed, use Helm chart `extensions`. - -1. Ensure that you include a corresponding HelmChart v2 custom resource for each of your Helm charts. For information about how to configure the HelmChart v2 custom resource, see [Support installations with HelmChart v2](/vendor/helm-native-v2-using). - -## Migrate an installation from Embedded Cluster v2 to Embedded Cluster v3 - - diff --git a/embedded-cluster/embedded-v3-migrate.mdx b/embedded-cluster/embedded-v3-migrate.mdx new file mode 100644 index 0000000000..7ee5b3da10 --- /dev/null +++ b/embedded-cluster/embedded-v3-migrate.mdx @@ -0,0 +1,163 @@ +import DependencyYaml from "../docs//partials/replicated-sdk/_dependency-yaml.mdx" + +# Migrate from Embedded Cluster v2 + +This page describes how to migrate from Embedded Cluster v2 to Embedded Cluster v3. + +It includes information about how to update your application release to support Embedded Cluster v3. It also describes how to upgrade existing installations from Embedded Cluster v2 to v3. + +## Comparison to Embedded Cluster v2 + +This section describes the key differences between Embedded Cluster v2 and v3. + +### Removal of KOTS + +Embedded Cluster v3 removes Replicated KOTS from the architecture. This reduces the number of dependencies that are running in the cluster, which improves reliability. + +The KOTS CLI does not work with Embedded Cluster v3, and there is no KOTS Admin Console. + +Embedded Cluster v3 still requires the KOTS HelmChart v2 custom resource to process and deploy Helm charts. Embedded Cluster v3 also still uses KOTS custom resources like the KOTS Application and KOTS Config resources to define aspects of the installation experience. + +### Replicated SDK required for application status informers + +Because Embedded Cluster v3 removes KOTS, you must include the [Replicated SDK](/vendor/replicated-sdk-overview) in your application to get instance reporting in the Vendor Portal from application status informers. + +### Troubleshoot Preflight `v1beta3` required + +Application preflight checks must use Troubleshoot `v1beta3`. `v1beta2` preflight specs are not supported. + +For more information, see [v1beta3 overview](https://troubleshoot.sh/docs/preflight/v1beta3-overview) in the Troubleshoot documentation. + +### HelmChart v2 required + +Embedded Cluster v3 supports installing Helm charts with a corresponding HelmChart v2 custom resource (API version `v1beta2`). + +Embedded Cluster v3 does not support Kustomize, Kubernetes manifests, or HelmChart v1. + +## Update your release to Embedded Cluster v3 + +To update your release to support installation with Embedded Cluster v3: + +1. Remove any standalone Kubernetes manifests or `kustomization.yaml` files from your release. Embedded Cluster v3 only deploys resources that are managed by Helm charts. If you need to deploy any resources before Embedded Cluster deploys your application, you can use Helm chart [`extensions`](embedded-config#extensions) in the Embedded Cluster Config. + +1. In your application Helm chart `Chart.yaml` file, add the SDK as a dependency. With Embedded Cluster v3, the SDK is required to get instance insights from status informers. + + If your application is installed as multiple charts, declare the SDK as a dependency of the chart that customers install first. Do not declare the SDK in more than one chart. + + + +1. Update your application Preflight specs to API version `troubleshoot.sh/v1beta3`. For more information, see [Migrate from v1beta2 to v1beta3](https://troubleshoot.sh/docs/preflight/v1beta3-migration) in the Troubleshoot documentation. + +1. Ensure that your release has a corresponding HelmChart v2 custom resource for each of your Helm charts. For information about how to configure the HelmChart v2 custom resource, see [Support installations with HelmChart v2](/vendor/helm-native-v2-using). For information about how to migrate from HelmChart v1 or Kubernetes manifests to HelmChart v2, see [Migrate existing installations to HelmChart v2](/vendor/helm-v2-migrate). + +1. In your Embedded Cluster Config, update `version` to **EMBEDDED_CLUSTER_V3_VERSION**. You can also optionally increment the Kubernetes version by one minor version. + + ```yaml + apiVersion: embeddedcluster.replicated.com/v1beta1 + kind: Config + metadata: + name: my-embedded-cluster-config + spec: + version: "" + ``` + +1. Update any existing Helm extensions to use the `extensions.helmChart` format. See [`extensions`](embedded-config#extensions). + + **Example:** + + ```yaml + apiVersion: embeddedcluster.replicated.com/v1beta1 + kind: Config + spec: + extensions: + helmCharts: + - chart: + name: ingress-nginx + chartVersion: "4.11.3" + releaseName: ingress-nginx + namespace: ingress-nginx + values: | + controller: + service: + type: NodePort + nodePorts: + http: "80" + https: "443" + image: + digest: "" + digestChroot: "" + ``` + +1. Promote the release to a development channel that you use for testing. + +1. Test the installation using a development customer. + +## Migrate an installation from Embedded Cluster v2 to Embedded Cluster v3 + +Embedded Cluster supports upgrading existing installations from v2 to v3 without having to reinstall the application. + +To migrate an existing installation to Embedded Cluster v3: + +1. Get the customer's Embedded Cluster install instructions from the Vendor Portal or from the Enterprise Portal. + +1. For application version, select the release that enables Embedded Cluster v3. + +1. SSH into the VM where the Embedded Cluster v2 installation is running. + +1. On the VM, run the commands to download and extract the installation assets for the target release. + + **Example:** + + ```bash + $ tar -xvzf slackernews-unstable.tgz + slackernews-service + slackernews + slackernews-web + license.yaml + release.tgz + ec-3.0.0-beta-1+k8s-1.34.online + ``` + +1. Run the following command to upgrade using the Embedded Cluster v3 upgrade wizard: + + ```bash + sudo ./APP_SLUG upgrade --license license.yaml + ``` + Where `APP_SLUG` in the unique application slug. + +1. When prompted, type `yes` to confirm that you want to migrate to v3. + + ```bash + Detected EC v2 installation. This upgrade will migrate the cluster from v2 to v3. + This is a one-way migration and cannot be undone. + Do you want to proceed with the migration? (yes/NO): yes + ``` + +1. When the upgrade command completes, go to the URL provided to access the upgrade wizard. + + ```bash + Installation started. Connect to the web interface to continue the installation. + + Open the following URL in your browser: + + https://kotsadm.default.svc.cluster.local:30080 + + Note: You may see a browser warning for the self-signed certificate. + Click "Advanced" > "Proceed" to continue. + + Press Ctrl+C when the installation is complete to stop the web interface. + ``` + +1. Log in to the upgrade wizard using the existing password for the Admin Console. + + ![upgrade wizard log in screen](/images/embedded-cluster-v3-slackernews-upgrade-wizard.png) + + [View a larger version of this image](/images/embedded-cluster-v3-slackernews-upgrade-wizard.png) + +1. Follow the steps in the wizard to configure the application and then complete the upgrade process. + + ![upgrade wizard app upgrade screen](/images/embedded-cluster-v3-slackernews-upgrade-progress.png) + + [View a larger version of this image](/images/embedded-cluster-v3-slackernews-upgrade-progress.png) + +1. Press Ctrl+C when the upgrade is complete to close the wizard. diff --git a/sidebarEmbeddedCluster.js b/sidebarEmbeddedCluster.js index 6acdd4315a..11bea866dc 100644 --- a/sidebarEmbeddedCluster.js +++ b/sidebarEmbeddedCluster.js @@ -1,6 +1,7 @@ module.exports = { embeddedClusterSidebar: [ "embedded-overview", + "embedded-v3-migrate", "embedded-using", "embedded-config", { diff --git a/static/images/embedded-cluster-v3-slackernews-upgrade-progress.png b/static/images/embedded-cluster-v3-slackernews-upgrade-progress.png new file mode 100644 index 0000000000000000000000000000000000000000..4fc8b7a442c89fe87bf7511697ab59a7c1a6e6cc GIT binary patch literal 267011 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 W*zcM==|nK7HOGuCj^rJ7y7nL3a31Oa literal 0 HcmV?d00001 diff --git a/static/images/embedded-cluster-v3-slackernews-upgrade-wizard.png b/static/images/embedded-cluster-v3-slackernews-upgrade-wizard.png new file mode 100644 index 0000000000000000000000000000000000000000..99f963362fd7b4ff53f698547b009a0258c14cb1 GIT binary patch literal 204706 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 z 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 Date: Fri, 3 Apr 2026 15:00:28 -0600 Subject: [PATCH 21/31] edit steps on adding nodes --- embedded-cluster/embedded-manage-nodes.mdx | 90 +++++----------------- embedded-cluster/embedded-v3-migrate.mdx | 2 +- 2 files changed, 21 insertions(+), 71 deletions(-) diff --git a/embedded-cluster/embedded-manage-nodes.mdx b/embedded-cluster/embedded-manage-nodes.mdx index 0409c0624e..a5312ed2eb 100644 --- a/embedded-cluster/embedded-manage-nodes.mdx +++ b/embedded-cluster/embedded-manage-nodes.mdx @@ -20,88 +20,51 @@ Multi-node clusters with Embedded Cluster have the following limitations: * Setting node roles with the Embedded Cluster Config [roles](embedded-config#roles) key is Beta. -* The first node added to the cluster is always a controller and cannot receive any custom roles. For more information about configuring node roles, see [roles](embedded-config#roles) in _Embedded Cluster Config_. +* The first node added to the cluster is always a controller and cannot have any custom roles. For more information about configuring node roles, see [roles](embedded-config#roles) in _Embedded Cluster Config_. -* All nodes joined to the cluster use the same Embedded Cluster data directory as the installation node. This is either the default `/var/lib/embedded-cluster` directory or the directory set with the [`--data-dir`](embedded-cluster-install#flags) flag. You cannot choose a different data directory for Embedded Cluster when joining nodes. +* All nodes joined to the cluster use the same Embedded Cluster data directory as the installation node. You cannot choose a different data directory for Embedded Cluster when joining nodes. * You should not join more than one controller node at the same time. When joining a controller node, Embedded Cluster prints a warning explaining that you should not attempt to join another node until the controller node joins successfully. -* The `join print-command` command always returns the commands for joining a node with the controller role. It does not support printing the join command for any custom node roles defined in the Embedded Cluster Config `roles` key. See [Automate Controller Node Joins](#automate-node-joins). - ### Requirement To deploy multi-node clusters with Embedded Cluster, you must enable the **Multi-node Cluster (Embedded Cluster only)** license field for the customer. For more information about managing customer licenses, see [Create and Manage Customers](/vendor/releases-creating-customer). ### Add nodes to a cluster {#add-nodes} -This section describes how to add nodes to a cluster with Embedded Cluster. - -To add a node to a cluster with Embedded Cluster: - -1. (Optional) In the Embedded Cluster Config, configure the `roles` key to customize node roles. For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. After you finish, create and promote a new release with the updated Config. - -1. Do one of the following: +To join a node: - 1. Follow the steps in [Online Installation with Embedded Cluster](installing-embedded) or [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap) to install. When you see the **Nodes** screen as part of the installation flow in the Admin Console, continue to the next step. +1. SSH into a controller node. - 1. Otherwise, to add a node to an existing cluster: - - 1. Log in to the Admin Console. - - 1. If you promoted a new release that configures the `roles` key in the Embedded Cluster Config, update the instance to the new version. See [Perform Updates in Embedded Clusters](updating-embedded). - - 1. Go to **Cluster Management > Add node** at the top of the page. - -1. If you configured the `roles` key to customize node roles, select one or more roles for the node. - - The Admin Console page refreshes and shows the commands to download the Embedded Cluster binary, extract the binary, and join the node. These commands are based on the roles you selected. Keep this Admin Console page open for the next steps. +1. Run the following command to generate the `.tar.gz` bundle for joining a node: + ```bash + sudo ./APP_SLUG create-join-bundle [--role] + ``` + Where: + * `APP_SLUG` is the unique slug for the application. + * `--role` is an optional flag to set the role for the new node. is the See [roles](embedded-config#roles) in _Embedded Cluster Config_. :::note You cannot change the role after you add a node. If you need to change a node’s role, reset the node and add it again with the new role. ::: -1. SSH onto the node that you want to join. - -1. Copy the curl command provided in the Admin Console to download the Embedded Cluster binary and then run it on the node you want to join. - -1. Copy and run the tar command to extract the Embedded Cluster binary. - -1. Copy and run the join command to add the node to the cluster. - -1. In the Admin Console, either on the installation **Nodes** screen or on the **Cluster Management** page, verify that the node appears. Wait for the node's status to change to Ready. - -1. Repeat these steps for each node you want to add. - -### Automate controller node joins {#automate-node-joins} +1. SSH into the node that you want to join. -With Embedded Cluster, you can use the command line to get the commands for joining controller nodes, rather than logging into the Admin Console UI. This is especially useful when testing multi-node Embedded Cluster installations where you need to automate joining controller nodes to a cluster. +1. Copy the `.tar.gz` to the node. -To automate controller node joins with Embedded Cluster: +1. Extract the `.tar.gz`. -1. SSH onto a controller node that is already joined to the cluster. On the controller node, run: +1. Run the join command to add the node to the cluster: ```bash - sudo ./APP_SLUG join print-command + sudo ./APP_SLUG node join ``` - Where `APP_SLUG` is the unique application slug. - The output lists the commands for downloading the Embedded Cluster binary, extracting the binary, and joining a new controller node to the cluster. - - **Example:** - - ``` - sudo ./your-app-slug join print-command - - curl -k https://172.17.0.2:30000/api/v1/embedded-cluster/binary -o your-app-slug.tar.gz && \ - tar -xvf your-app-slug.tar.gz && \ - sudo ./your-app-slug join 172.17.0.2:30000 1234aBcD - ``` - -1. On the node that you want to join as a controller, run each of the commands provided in the `join print-command` output to download the Embedded Cluster binary, extract the binary, and join the node to the cluster. +1. Repeat these steps for each node you want to add. ## Configure high availability for multi-node clusters {#ha} -Multi-node clusters are not highly available by default. The first node of the cluster holds important data for Kubernetes and KOTS, such that the loss of this node would be catastrophic for the cluster. Enabling high availability requires that at least three controller nodes are present in the cluster. +Multi-node clusters are not highly available by default. The first node of the cluster holds important data for Kubernetes, such that the loss of this node would be catastrophic for the cluster. Enabling high availability requires that at least three controller nodes are present in the cluster. Users are automatically prompted to enable HA when joining the third controller node to a cluster. Alternatively, users can enable HA with the `enable-ha` command after adding three or more controller nodes. @@ -123,7 +86,7 @@ Consider the following best practices and recommendations for creating HA cluste * Always use an odd number of controller nodes in HA clusters. Using an odd number of controller nodes ensures that the cluster can make decisions efficiently with quorum calculations. Clusters with an odd number of controller nodes also avoid split-brain scenarios where the cluster runs as two, independent groups of nodes, resulting in inconsistencies and conflicts. -* You can have any number of _worker_ nodes in HA clusters. Worker nodes do not run the Kubernetes control plane, but can run workloads such as application or Replicated KOTS workloads. +* You can have any number of _worker_ nodes in HA clusters. Worker nodes do not run the Kubernetes control plane, but can run workloads such as application workloads. ### Create a multi-node cluster with high availability {#create-ha} @@ -133,20 +96,7 @@ To create a multi-node HA cluster: 1. Set up a cluster with at least two controller nodes. You can do an online (internet-connected) or air gap installation. For more information, see [Online Installation with Embedded Cluster](installing-embedded) or [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). -1. Get the commands for downloading the Embedded Cluster binary, extracting the binary, and joining the third controller node either in the Admin Console **Cluster Management** tab or by running the following command on an existing node: - - ```bash - sudo ./APP_SLUG join print-command - ``` - Where `APP_SLUG` is the unique application slug. - -1. SSH onto the node that you want to add as a third controller. - -1. On the node that you want to add as a third controller, run each of the commands that you copied. - - :::note - For Embedded Cluster versions earlier than 2.3.0, pass the `--enable-ha` flag with the `join` command. - ::: +1. Follow the steps in [Add nodes to a cluster](#add-nodes) on this page to join a third controller node. Pass `--role controller` with the `create-join-bundle` command. 1. In response to the prompt asking if you want to enable high availability, type `y` or `yes`. diff --git a/embedded-cluster/embedded-v3-migrate.mdx b/embedded-cluster/embedded-v3-migrate.mdx index 7ee5b3da10..1b7b3c0715 100644 --- a/embedded-cluster/embedded-v3-migrate.mdx +++ b/embedded-cluster/embedded-v3-migrate.mdx @@ -154,7 +154,7 @@ To migrate an existing installation to Embedded Cluster v3: [View a larger version of this image](/images/embedded-cluster-v3-slackernews-upgrade-wizard.png) -1. Follow the steps in the wizard to configure the application and then complete the upgrade process. +1. Follow the steps in the wizard to upgrade any other nodes in the cluster, configure the application, and then deploy the application. ![upgrade wizard app upgrade screen](/images/embedded-cluster-v3-slackernews-upgrade-progress.png) From dd5cd42cfffc6aad2ba81dcf8068fb7ab321752c Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Fri, 3 Apr 2026 15:06:00 -0600 Subject: [PATCH 22/31] copy edits and corrections --- embedded-cluster/embedded-manage-nodes.mdx | 12 ------------ embedded-cluster/embedded-overview.mdx | 6 ------ 2 files changed, 18 deletions(-) diff --git a/embedded-cluster/embedded-manage-nodes.mdx b/embedded-cluster/embedded-manage-nodes.mdx index a5312ed2eb..b8cbb3a8cf 100644 --- a/embedded-cluster/embedded-manage-nodes.mdx +++ b/embedded-cluster/embedded-manage-nodes.mdx @@ -18,8 +18,6 @@ This section describes how to join nodes to a cluster with Embedded Cluster. Multi-node clusters with Embedded Cluster have the following limitations: -* Setting node roles with the Embedded Cluster Config [roles](embedded-config#roles) key is Beta. - * The first node added to the cluster is always a controller and cannot have any custom roles. For more information about configuring node roles, see [roles](embedded-config#roles) in _Embedded Cluster Config_. * All nodes joined to the cluster use the same Embedded Cluster data directory as the installation node. You cannot choose a different data directory for Embedded Cluster when joining nodes. @@ -68,16 +66,6 @@ Multi-node clusters are not highly available by default. The first node of the c Users are automatically prompted to enable HA when joining the third controller node to a cluster. Alternatively, users can enable HA with the `enable-ha` command after adding three or more controller nodes. -### Requirements - -Enabling high availability has the following requirements: - -* Embedded Cluster 1.4.1 and later supports high availability. - -* The [`enable-ha`](#enable-ha-existing) command is available with Embedded Cluster 2.3.0 and later. - -* Embedded Cluster supports high availability only for clusters where at least three nodes with the controller role are present. - ### Best practices for high availability Consider the following best practices and recommendations for creating HA clusters: diff --git a/embedded-cluster/embedded-overview.mdx b/embedded-cluster/embedded-overview.mdx index ce8ba31eca..39689a5390 100644 --- a/embedded-cluster/embedded-overview.mdx +++ b/embedded-cluster/embedded-overview.mdx @@ -74,9 +74,3 @@ For more information about creating HA multi-node clusters with Embedded Cluster You can optionally define node roles in the Embedded Cluster Config. For multi-node clusters, roles can be useful for assigning specific application workloads to nodes. If you define node roles, users assign one or more roles to a node when it joins the cluster. For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. - -## About configuring Embedded Cluster - -To support installations with Embedded Cluster, an Embedded Cluster Config must be present in the application release. The Embedded Cluster Config lets you define several characteristics about the cluster that Embedded Cluster creates. - -For more information, see [Embedded Cluster Config](embedded-config). From 4882993ca7d65da7bf3b2074235b757fb4055c31 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Fri, 3 Apr 2026 15:22:05 -0600 Subject: [PATCH 23/31] add redirects --- netlify.toml | 145 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 139 insertions(+), 6 deletions(-) diff --git a/netlify.toml b/netlify.toml index 20b689f1b8..62ca108129 100644 --- a/netlify.toml +++ b/netlify.toml @@ -43,6 +43,139 @@ to = "https://docs.replicated.com/release-notes/rn-whats-new" +################################################### +# Embedded Cluster docs (moved to /embedded-cluster plugin) +# +# Default version is v3. Pages that exist only in v2 use /embedded-cluster/v2/... +# Note: URL fragments (#anchors) are not sent to the server; old deep links may +# land on the new page without the intended heading anchor. +################################################### + +# bare plugin path → current Embedded Cluster docs (v3 landing page) + +[[redirects]] + from = "https://docs.replicated.com/embedded-cluster" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-overview" + +[[redirects]] + from = "https://docs.replicated.com/embedded-cluster/" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-overview" + +[[redirects]] + from = "https://docs.replicated.com/embedded-cluster/v3" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-overview" + +[[redirects]] + from = "https://docs.replicated.com/embedded-cluster/v3/" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-overview" + +# Vendor (→ v3) +[[redirects]] + from = "https://docs.replicated.com/vendor/embedded-overview" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-overview" + +[[redirects]] + from = "https://docs.replicated.com/vendor/embedded-using" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-using" + +[[redirects]] + from = "https://docs.replicated.com/vendor/embedded-troubleshooting" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-troubleshooting" + +# Vendor (→ v2 only) +[[redirects]] + from = "https://docs.replicated.com/vendor/embedded-disaster-recovery" + to = "https://docs.replicated.com/embedded-cluster/v2/embedded-disaster-recovery" + +[[redirects]] + from = "https://docs.replicated.com/vendor/embedded-tls-certs" + to = "https://docs.replicated.com/embedded-cluster/v2/embedded-tls-certs" + +# Enterprise install / manage / update (→ v3) +[[redirects]] + from = "https://docs.replicated.com/enterprise/installing-embedded" + to = "https://docs.replicated.com/embedded-cluster/v3/installing-embedded" + +[[redirects]] + from = "https://docs.replicated.com/enterprise/installing-embedded-air-gap" + to = "https://docs.replicated.com/embedded-cluster/v3/installing-embedded-air-gap" + +[[redirects]] + from = "https://docs.replicated.com/enterprise/installing-embedded-requirements" + to = "https://docs.replicated.com/embedded-cluster/v3/installing-embedded-requirements" + +[[redirects]] + from = "https://docs.replicated.com/enterprise/embedded-manage-nodes" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-manage-nodes" + +[[redirects]] + from = "https://docs.replicated.com/enterprise/updating-embedded" + to = "https://docs.replicated.com/embedded-cluster/v3/updating-embedded" + +# Enterprise (→ v2 only) +[[redirects]] + from = "https://docs.replicated.com/enterprise/installing-embedded-automation" + to = "https://docs.replicated.com/embedded-cluster/v2/installing-embedded-automation" + +[[redirects]] + from = "https://docs.replicated.com/enterprise/embedded-tls-certs" + to = "https://docs.replicated.com/embedded-cluster/v2/embedded-tls-certs" + +# Reference (→ v3) +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-config" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-config" + +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-cluster-install" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-install" + +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-cluster-reset" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-reset" + +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-cluster-shell" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-shell" + +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-cluster-version" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-version" + +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-cluster-support-bundle" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-support-bundle" + +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-cluster-enable-ha" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-enable-ha" + +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-cluster-completion" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-completion" + +# Reference: v3 renamed CLI topics (old slug → new doc) +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-cluster-update" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-upgrade" + +# Reference (→ v2 only) +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-cluster-join" + to = "https://docs.replicated.com/embedded-cluster/v2/embedded-cluster-join" + +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-cluster-join-print-command" + to = "https://docs.replicated.com/embedded-cluster/v2/embedded-cluster-join-print-command" + +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-cluster-restore" + to = "https://docs.replicated.com/embedded-cluster/v2/embedded-cluster-restore" + +[[redirects]] + from = "https://docs.replicated.com/reference/embedded-cluster-admin-console" + to = "https://docs.replicated.com/embedded-cluster/v2/embedded-cluster-admin-console" + ################################################### # Redirects To the Getting Started Section @@ -85,7 +218,7 @@ [[redirects]] from="https://docs.replicated.com/vendor/tutorial-ha-cluster-deploying" - to="https://docs.replicated.com/enterprise/installing-embedded-cluster#install-with-ha-in-online-environments" + to="https://docs.replicated.com/embedded-cluster/v3/embedded-manage-nodes#create-ha" [[redirects]] from="https://docs.replicated.com/vendor/tutorial-installing-air-gap-existing-cluster-gcp" @@ -212,7 +345,7 @@ [[redirects]] from = "https://docs.replicated.com/vendor/embedded-kubernetes-overview" - to = "https://docs.replicated.com/vendor/embedded-overview" + to = "https://docs.replicated.com/embedded-cluster/v3/embedded-overview" ################################################### # Redirects To the Enterprise Section @@ -244,15 +377,15 @@ [[redirects]] from="https://docs.replicated.com/enterprise/installing-embedded-airgapped" - to="https://docs.replicated.com/enterprise/installing-kurl-airgap" + to="https://docs.replicated.com/embedded-cluster/v3/installing-embedded-air-gap" [[redirects]] from="https://docs.replicated.com/enterprise/installing-embedded-cluster" - to="https://docs.replicated.com/enterprise/installing-kurl" + to="https://docs.replicated.com/embedded-cluster/v3/installing-embedded" [[redirects]] from="https://docs.replicated.com/enterprise/updating-embedded-cluster" - to="https://docs.replicated.com/enterprise/updating-kurl" + to="https://docs.replicated.com/embedded-cluster/v3/updating-embedded" [[redirects]] from="https://docs.replicated.com/enterprise/image-registry-embedded-cluster" @@ -260,7 +393,7 @@ [[redirects]] from="https://docs.replicated.com/vendor/releases-configvalues" - to="https://docs.replicated.com/enterprise/installing-embedded-automation" + to="https://docs.replicated.com/embedded-cluster/v2/installing-embedded-automation" [[redirects]] From 3e523b55ecb255cb096f67c0d9d584a6010cac17 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Fri, 3 Apr 2026 15:27:16 -0600 Subject: [PATCH 24/31] make sure v2 partials are used in vendor docs --- docs/vendor/environment-setup.mdx | 2 +- docs/vendor/replicated-onboarding.mdx | 4 ++-- docs/vendor/support-bundle-embedded.mdx | 2 +- docs/vendor/tutorial-cmx-airgap.mdx | 2 +- docs/vendor/tutorial-embedded-cluster-automation.mdx | 2 +- docs/vendor/tutorial-helm-cli.mdx | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/vendor/environment-setup.mdx b/docs/vendor/environment-setup.mdx index 11a7f48bdc..a6cf215f56 100644 --- a/docs/vendor/environment-setup.mdx +++ b/docs/vendor/environment-setup.mdx @@ -1,4 +1,4 @@ -import Requirements from "../partials/embedded-cluster/v3/_requirements.mdx" +import Requirements from "../partials/embedded-cluster/v2/_requirements.mdx" import Verify from "../partials/replicated-cli/_verify-install.mdx" import InstallMac from "../partials/replicated-cli/_install-mac.mdx" import InstallLinux from "../partials/replicated-cli/_install-linux.mdx" diff --git a/docs/vendor/replicated-onboarding.mdx b/docs/vendor/replicated-onboarding.mdx index 13d06927f2..184b441327 100644 --- a/docs/vendor/replicated-onboarding.mdx +++ b/docs/vendor/replicated-onboarding.mdx @@ -2,9 +2,9 @@ import CommunityHelp from "../partials/getting-started/_community-help.mdx" import CreateApp from "../partials/getting-started/_create-app.mdx" import CreateRelease from "../partials/getting-started/_create-promote-release.mdx" import DependencyYaml from "../partials/replicated-sdk/_dependency-yaml.mdx" -import EcCr from "../partials/embedded-cluster/v3/_ec-config.mdx" +import EcCr from "../partials/embedded-cluster/v2/_ec-config.mdx" import HelmPackage from "../partials/helm/_helm-package.mdx" -import Requirements from "../partials/embedded-cluster/v3/_requirements.mdx" +import Requirements from "../partials/embedded-cluster/v2/_requirements.mdx" import TestYourChanges from "../partials/getting-started/_test-your-changes.mdx" import UnauthorizedError from "../partials/replicated-sdk/_401-unauthorized.mdx" import StepCreds from "../partials/proxy-service/_step-creds.mdx" diff --git a/docs/vendor/support-bundle-embedded.mdx b/docs/vendor/support-bundle-embedded.mdx index db4f019a9a..6180c2025e 100644 --- a/docs/vendor/support-bundle-embedded.mdx +++ b/docs/vendor/support-bundle-embedded.mdx @@ -1,4 +1,4 @@ -import EmbeddedClusterSupportBundle from "../partials/embedded-cluster/v3/_generate-bundle-ec.mdx" +import EmbeddedClusterSupportBundle from "../partials/embedded-cluster/v2/_generate-bundle-ec.mdx" import SupportBundleIntro from "../partials/support-bundles/_ec-support-bundle-intro.mdx" # Generate support bundles for Embedded Cluster diff --git a/docs/vendor/tutorial-cmx-airgap.mdx b/docs/vendor/tutorial-cmx-airgap.mdx index ec237c9beb..86018ddd79 100644 --- a/docs/vendor/tutorial-cmx-airgap.mdx +++ b/docs/vendor/tutorial-cmx-airgap.mdx @@ -1,6 +1,6 @@ import DependencyYaml from "../partials/replicated-sdk/_dependency-yaml.mdx" import HelmPackage from "../partials/helm/_helm-package.mdx" -import Requirements from "../partials/embedded-cluster/v3/_requirements.mdx" +import Requirements from "../partials/embedded-cluster/v2/_requirements.mdx" # Test an air gap installation with compatibility matrix diff --git a/docs/vendor/tutorial-embedded-cluster-automation.mdx b/docs/vendor/tutorial-embedded-cluster-automation.mdx index 515923271a..c2c263e2d5 100644 --- a/docs/vendor/tutorial-embedded-cluster-automation.mdx +++ b/docs/vendor/tutorial-embedded-cluster-automation.mdx @@ -1,6 +1,6 @@ import DependencyYaml from "../partials/replicated-sdk/_dependency-yaml.mdx" import HelmPackage from "../partials/helm/_helm-package.mdx" -import Requirements from "../partials/embedded-cluster/v3/_requirements.mdx" +import Requirements from "../partials/embedded-cluster/v2/_requirements.mdx" # Install SlackerNews with Embedded Cluster from the command line diff --git a/docs/vendor/tutorial-helm-cli.mdx b/docs/vendor/tutorial-helm-cli.mdx index bbf446b5d2..edea07de07 100644 --- a/docs/vendor/tutorial-helm-cli.mdx +++ b/docs/vendor/tutorial-helm-cli.mdx @@ -1,6 +1,6 @@ import DependencyYaml from "../partials/replicated-sdk/_dependency-yaml.mdx" import HelmPackage from "../partials/helm/_helm-package.mdx" -import Requirements from "../partials/embedded-cluster/v3/_requirements.mdx" +import Requirements from "../partials/embedded-cluster/v2/_requirements.mdx" # Install SlackerNews with the Helm CLI From dafc483620cb7555fdb4b4d553e5e5e327171d15 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Fri, 3 Apr 2026 15:51:02 -0600 Subject: [PATCH 25/31] update the vale linter config and skill --- .claude/skills/vale-prose-review/SKILL.md | 3 +++ .../vale-prose-review/references/vale-rules.md | 13 +++++++++++++ .vale.ini | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/.claude/skills/vale-prose-review/SKILL.md b/.claude/skills/vale-prose-review/SKILL.md index a66f02518b..ac840c9e90 100644 --- a/.claude/skills/vale-prose-review/SKILL.md +++ b/.claude/skills/vale-prose-review/SKILL.md @@ -56,6 +56,8 @@ Do not apply prose fixes to: Vale sometimes flags these; ignore those warnings. +**Exception — markdown inside HTML tables:** When `Vale.Spelling` flags a word like `_Using` inside an HTML `
- +
` or `

` element, the cause is markdown italic syntax (`_text_`) used inside raw HTML. Do NOT add `_Using` to an accept list. Instead, convert the markdown formatting to HTML (`_foo_` → `foo`). See `references/vale-rules.md` for details. + ### Step 5: Verify After making all changes, do a quick pass to confirm: @@ -94,3 +96,4 @@ See `references/vale-rules.md` for full fix patterns, before/after examples, and ## Additional Resources - **`references/vale-rules.md`** — Detailed fix patterns, edge cases, and examples for every common Replicated vale rule +- **`README.md` (repo root)** — The Replicated Docs style guide lives in the "Style Guide" section of this file. Read it when deciding how to rewrite a flagged sentence, choose word alternatives, or apply formatting conventions. This is the authoritative source — do not rely on cached knowledge of its contents. diff --git a/.claude/skills/vale-prose-review/references/vale-rules.md b/.claude/skills/vale-prose-review/references/vale-rules.md index e5ed27aecf..89f7bb2167 100644 --- a/.claude/skills/vale-prose-review/references/vale-rules.md +++ b/.claude/skills/vale-prose-review/references/vale-rules.md @@ -28,6 +28,19 @@ Fix if the flagged word is a genuine misspelling. Vale flags these as errors, so - Flagged words inside inline code or code blocks - Acronyms in YAML frontmatter keys +### Markdown formatting inside HTML tables + +When a file uses HTML ``/` - + diff --git a/docs/reference/custom-resource-application.mdx b/docs/reference/custom-resource-application.mdx index da58b5340d..bd6cca61f7 100644 --- a/docs/reference/custom-resource-application.mdx +++ b/docs/reference/custom-resource-application.mdx @@ -78,7 +78,7 @@ spec: - +
`/`

` tags and the cell content contains markdown italic syntax (e.g., `_Using Embedded Cluster_`), vale treats the leading underscore as part of a word and flags `_Using` as a misspelling. + +**Do NOT add these to an accept list.** The fix is to convert the markdown formatting inside the HTML element to its HTML equivalent: + +| Before (markdown inside HTML) | After (HTML formatting) | +|---|---| +| `_Using Embedded Cluster_` | `Using Embedded Cluster` | +| `**important**` | `important` | + +Apply this fix to the specific cell content where the flag appears. Other cells in the same table that use plain text are fine as-is. + --- ## Replicated.Passive (suggestion) diff --git a/.vale.ini b/.vale.ini index 51ff9b2bd6..9a5c6fefad 100644 --- a/.vale.ini +++ b/.vale.ini @@ -19,6 +19,10 @@ BasedOnStyles = Vale, Replicated Vale.Terms = NO +# Don't lint .claude skill/memory files +[.claude/**] +BasedOnStyles = + # Don't lint CLI docs [docs/reference/kots-cli-*] BasedOnStyles = From afc22e434d05f00f4ece894870ad67acd61bba5a Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Fri, 3 Apr 2026 16:04:02 -0600 Subject: [PATCH 26/31] convert to path-only redirects --- netlify.toml | 473 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 291 insertions(+), 182 deletions(-) diff --git a/netlify.toml b/netlify.toml index 62ca108129..0d1e059c5e 100644 --- a/netlify.toml +++ b/netlify.toml @@ -15,6 +15,11 @@ #to = "TO_URL" # For more information, see https://docs.netlify.com/configure-builds/file-based-configuration/#redirects +# +# Use path-only `from` and `to` values (starting with `/`, not +# `https://docs.replicated.com/...`) so redirects run on production, branch +# deploys, and Deploy Previews. Host-specific `from` URLs only match that exact +# hostname. ################################################### # High-Level Redirects @@ -27,20 +32,20 @@ #to = "/blog/:splat" # See https://docs.netlify.com/configure-builds/file-based-configuration/#redirects - from = "https://docs.replicated.com/vendor" - to = "https://docs.replicated.com/" + from = "/vendor" + to = "/" [[redirects]] - from = "https://docs.replicated.com/enterprise" - to = "https://docs.replicated.com/enterprise/installing-overview" + from = "/enterprise" + to = "/enterprise/installing-overview" [[redirects]] - from = "https://docs.replicated.com/reference" - to = "https://docs.replicated.com/reference/kots-cli-getting-started" + from = "/reference" + to = "/reference/kots-cli-getting-started" [[redirects]] - from = "https://docs.replicated.com/release-notes" - to = "https://docs.replicated.com/release-notes/rn-whats-new" + from = "/release-notes" + to = "/release-notes/rn-whats-new" ################################################### @@ -54,351 +59,455 @@ # bare plugin path → current Embedded Cluster docs (v3 landing page) [[redirects]] - from = "https://docs.replicated.com/embedded-cluster" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-overview" + from = "/embedded-cluster" + to = "/embedded-cluster/v3/embedded-overview" + +[[redirects]] + from = "/embedded-cluster/" + to = "/embedded-cluster/v3/embedded-overview" + +[[redirects]] + from = "/embedded-cluster/v3" + to = "/embedded-cluster/v3/embedded-overview" + +[[redirects]] + from = "/embedded-cluster/v3/" + to = "/embedded-cluster/v3/embedded-overview" + +# Unversioned /embedded-cluster/ → default Embedded Cluster version (v3). +# Use these stable URLs in cross-docs links; when "latest" changes, update the +# `to` paths below (or switch v3 → v4 in bulk). Keep this list in sync with +# sidebarEmbeddedCluster.js doc IDs. +# +# Does not use a single /embedded-cluster/* wildcard so /embedded-cluster/v2/... +# and /embedded-cluster/v3/... are never rewritten incorrectly. + +[[redirects]] + from = "/embedded-cluster/embedded-overview" + to = "/embedded-cluster/v3/embedded-overview" + +[[redirects]] + from = "/embedded-cluster/embedded-v3-migrate" + to = "/embedded-cluster/v3/embedded-v3-migrate" + +[[redirects]] + from = "/embedded-cluster/embedded-using" + to = "/embedded-cluster/v3/embedded-using" + +[[redirects]] + from = "/embedded-cluster/embedded-config" + to = "/embedded-cluster/v3/embedded-config" + +[[redirects]] + from = "/embedded-cluster/installing-embedded-requirements" + to = "/embedded-cluster/v3/installing-embedded-requirements" + +[[redirects]] + from = "/embedded-cluster/installing-embedded" + to = "/embedded-cluster/v3/installing-embedded" + +[[redirects]] + from = "/embedded-cluster/installing-embedded-air-gap" + to = "/embedded-cluster/v3/installing-embedded-air-gap" + +[[redirects]] + from = "/embedded-cluster/embedded-manage-nodes" + to = "/embedded-cluster/v3/embedded-manage-nodes" + +[[redirects]] + from = "/embedded-cluster/updating-embedded" + to = "/embedded-cluster/v3/updating-embedded" + +[[redirects]] + from = "/embedded-cluster/embedded-troubleshooting" + to = "/embedded-cluster/v3/embedded-troubleshooting" + +[[redirects]] + from = "/embedded-cluster/embedded-cluster-completion" + to = "/embedded-cluster/v3/embedded-cluster-completion" + +[[redirects]] + from = "/embedded-cluster/embedded-cluster-create-join-bundle" + to = "/embedded-cluster/v3/embedded-cluster-create-join-bundle" + +[[redirects]] + from = "/embedded-cluster/embedded-cluster-create-upgrade-bundle" + to = "/embedded-cluster/v3/embedded-cluster-create-upgrade-bundle" + +[[redirects]] + from = "/embedded-cluster/embedded-cluster-enable-ha" + to = "/embedded-cluster/v3/embedded-cluster-enable-ha" + +[[redirects]] + from = "/embedded-cluster/embedded-cluster-install" + to = "/embedded-cluster/v3/embedded-cluster-install" + +[[redirects]] + from = "/embedded-cluster/embedded-cluster-node-join" + to = "/embedded-cluster/v3/embedded-cluster-node-join" + +[[redirects]] + from = "/embedded-cluster/embedded-cluster-node-upgrade" + to = "/embedded-cluster/v3/embedded-cluster-node-upgrade" + +[[redirects]] + from = "/embedded-cluster/embedded-cluster-remove-node" + to = "/embedded-cluster/v3/embedded-cluster-remove-node" + +[[redirects]] + from = "/embedded-cluster/embedded-cluster-reset" + to = "/embedded-cluster/v3/embedded-cluster-reset" + +[[redirects]] + from = "/embedded-cluster/embedded-cluster-shell" + to = "/embedded-cluster/v3/embedded-cluster-shell" + +[[redirects]] + from = "/embedded-cluster/embedded-cluster-status" + to = "/embedded-cluster/v3/embedded-cluster-status" [[redirects]] - from = "https://docs.replicated.com/embedded-cluster/" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-overview" + from = "/embedded-cluster/embedded-cluster-support-bundle" + to = "/embedded-cluster/v3/embedded-cluster-support-bundle" [[redirects]] - from = "https://docs.replicated.com/embedded-cluster/v3" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-overview" + from = "/embedded-cluster/embedded-cluster-upgrade" + to = "/embedded-cluster/v3/embedded-cluster-upgrade" [[redirects]] - from = "https://docs.replicated.com/embedded-cluster/v3/" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-overview" + from = "/embedded-cluster/embedded-cluster-version" + to = "/embedded-cluster/v3/embedded-cluster-version" # Vendor (→ v3) [[redirects]] - from = "https://docs.replicated.com/vendor/embedded-overview" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-overview" + from = "/vendor/embedded-overview" + to = "/embedded-cluster/v3/embedded-overview" [[redirects]] - from = "https://docs.replicated.com/vendor/embedded-using" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-using" + from = "/vendor/embedded-using" + to = "/embedded-cluster/v3/embedded-using" [[redirects]] - from = "https://docs.replicated.com/vendor/embedded-troubleshooting" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-troubleshooting" + from = "/vendor/embedded-troubleshooting" + to = "/embedded-cluster/v3/embedded-troubleshooting" # Vendor (→ v2 only) [[redirects]] - from = "https://docs.replicated.com/vendor/embedded-disaster-recovery" - to = "https://docs.replicated.com/embedded-cluster/v2/embedded-disaster-recovery" + from = "/vendor/embedded-disaster-recovery" + to = "/embedded-cluster/v2/embedded-disaster-recovery" [[redirects]] - from = "https://docs.replicated.com/vendor/embedded-tls-certs" - to = "https://docs.replicated.com/embedded-cluster/v2/embedded-tls-certs" + from = "/vendor/embedded-tls-certs" + to = "/embedded-cluster/v2/embedded-tls-certs" # Enterprise install / manage / update (→ v3) [[redirects]] - from = "https://docs.replicated.com/enterprise/installing-embedded" - to = "https://docs.replicated.com/embedded-cluster/v3/installing-embedded" + from = "/enterprise/installing-embedded" + to = "/embedded-cluster/v3/installing-embedded" [[redirects]] - from = "https://docs.replicated.com/enterprise/installing-embedded-air-gap" - to = "https://docs.replicated.com/embedded-cluster/v3/installing-embedded-air-gap" + from = "/enterprise/installing-embedded-air-gap" + to = "/embedded-cluster/v3/installing-embedded-air-gap" [[redirects]] - from = "https://docs.replicated.com/enterprise/installing-embedded-requirements" - to = "https://docs.replicated.com/embedded-cluster/v3/installing-embedded-requirements" + from = "/enterprise/installing-embedded-requirements" + to = "/embedded-cluster/v3/installing-embedded-requirements" [[redirects]] - from = "https://docs.replicated.com/enterprise/embedded-manage-nodes" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-manage-nodes" + from = "/enterprise/embedded-manage-nodes" + to = "/embedded-cluster/v3/embedded-manage-nodes" [[redirects]] - from = "https://docs.replicated.com/enterprise/updating-embedded" - to = "https://docs.replicated.com/embedded-cluster/v3/updating-embedded" + from = "/enterprise/updating-embedded" + to = "/embedded-cluster/v3/updating-embedded" # Enterprise (→ v2 only) [[redirects]] - from = "https://docs.replicated.com/enterprise/installing-embedded-automation" - to = "https://docs.replicated.com/embedded-cluster/v2/installing-embedded-automation" + from = "/enterprise/installing-embedded-automation" + to = "/embedded-cluster/v2/installing-embedded-automation" [[redirects]] - from = "https://docs.replicated.com/enterprise/embedded-tls-certs" - to = "https://docs.replicated.com/embedded-cluster/v2/embedded-tls-certs" + from = "/enterprise/embedded-tls-certs" + to = "/embedded-cluster/v2/embedded-tls-certs" # Reference (→ v3) [[redirects]] - from = "https://docs.replicated.com/reference/embedded-config" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-config" + from = "/reference/embedded-config" + to = "/embedded-cluster/v3/embedded-config" [[redirects]] - from = "https://docs.replicated.com/reference/embedded-cluster-install" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-install" + from = "/reference/embedded-cluster-install" + to = "/embedded-cluster/v3/embedded-cluster-install" [[redirects]] - from = "https://docs.replicated.com/reference/embedded-cluster-reset" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-reset" + from = "/reference/embedded-cluster-reset" + to = "/embedded-cluster/v3/embedded-cluster-reset" [[redirects]] - from = "https://docs.replicated.com/reference/embedded-cluster-shell" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-shell" + from = "/reference/embedded-cluster-shell" + to = "/embedded-cluster/v3/embedded-cluster-shell" [[redirects]] - from = "https://docs.replicated.com/reference/embedded-cluster-version" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-version" + from = "/reference/embedded-cluster-version" + to = "/embedded-cluster/v3/embedded-cluster-version" [[redirects]] - from = "https://docs.replicated.com/reference/embedded-cluster-support-bundle" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-support-bundle" + from = "/reference/embedded-cluster-support-bundle" + to = "/embedded-cluster/v3/embedded-cluster-support-bundle" [[redirects]] - from = "https://docs.replicated.com/reference/embedded-cluster-enable-ha" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-enable-ha" + from = "/reference/embedded-cluster-enable-ha" + to = "/embedded-cluster/v3/embedded-cluster-enable-ha" [[redirects]] - from = "https://docs.replicated.com/reference/embedded-cluster-completion" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-completion" + from = "/reference/embedded-cluster-completion" + to = "/embedded-cluster/v3/embedded-cluster-completion" # Reference: v3 renamed CLI topics (old slug → new doc) [[redirects]] - from = "https://docs.replicated.com/reference/embedded-cluster-update" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-cluster-upgrade" + from = "/reference/embedded-cluster-update" + to = "/embedded-cluster/v3/embedded-cluster-upgrade" # Reference (→ v2 only) [[redirects]] - from = "https://docs.replicated.com/reference/embedded-cluster-join" - to = "https://docs.replicated.com/embedded-cluster/v2/embedded-cluster-join" + from = "/reference/embedded-cluster-join" + to = "/embedded-cluster/v2/embedded-cluster-join" [[redirects]] - from = "https://docs.replicated.com/reference/embedded-cluster-join-print-command" - to = "https://docs.replicated.com/embedded-cluster/v2/embedded-cluster-join-print-command" + from = "/reference/embedded-cluster-join-print-command" + to = "/embedded-cluster/v2/embedded-cluster-join-print-command" [[redirects]] - from = "https://docs.replicated.com/reference/embedded-cluster-restore" - to = "https://docs.replicated.com/embedded-cluster/v2/embedded-cluster-restore" + from = "/reference/embedded-cluster-restore" + to = "/embedded-cluster/v2/embedded-cluster-restore" [[redirects]] - from = "https://docs.replicated.com/reference/embedded-cluster-admin-console" - to = "https://docs.replicated.com/embedded-cluster/v2/embedded-cluster-admin-console" + from = "/reference/embedded-cluster-admin-console" + to = "/embedded-cluster/v2/embedded-cluster-admin-console" ################################################### # Redirects To the Getting Started Section ################################################### [[redirects]] - from = "https://docs.replicated.com/vendor/tutorial-installing-with-existing-cluster" - to = "https://docs.replicated.com/vendor/quick-start" + from = "/vendor/tutorial-installing-with-existing-cluster" + to = "/vendor/quick-start" [[redirects]] - from = "https://docs.replicated.com/vendor/tutorial-installing-with-cli" - to = "https://docs.replicated.com/vendor/quick-start" + from = "/vendor/tutorial-installing-with-cli" + to = "/vendor/quick-start" [[redirects]] - from = "https://docs.replicated.com/vendor/tutorial-installing-without-existing-cluster" - to = "https://docs.replicated.com/vendor/quick-start" + from = "/vendor/tutorial-installing-without-existing-cluster" + to = "/vendor/quick-start" [[redirects]] - from = "https://docs.replicated.com/vendor/helm-mapping-example" - to = "https://docs.replicated.com/vendor/quick-start" + from = "/vendor/helm-mapping-example" + to = "/vendor/quick-start" [[redirects]] - from = "https://docs.replicated.com/vendor/releases-download-airgap-bundles" - to = "https://docs.replicated.com/vendor/releases-share-download-portal" + from = "/vendor/releases-download-airgap-bundles" + to = "/vendor/releases-share-download-portal" ################################################### # Redirects To the Vendor Section ################################################### [[redirects]] - from = "https://docs.replicated.com/vendor/helm-chart-components" - to = "https://docs.replicated.com/vendor/packaging-include-resources" + from = "/vendor/helm-chart-components" + to = "/vendor/packaging-include-resources" [[redirects]] - from = "https://docs.replicated.com/vendor/helm-optional-charts" - to = "https://docs.replicated.com/vendor/packaging-include-resources" + from = "/vendor/helm-optional-charts" + to = "/vendor/packaging-include-resources" [[redirects]] - from = "https://docs.replicated.com/vendor/packaging-custom-resources" - to = "https://docs.replicated.com/vendor/releases-creating-releases" + from = "/vendor/packaging-custom-resources" + to = "/vendor/releases-creating-releases" [[redirects]] - from="https://docs.replicated.com/vendor/tutorial-ha-cluster-deploying" - to="https://docs.replicated.com/embedded-cluster/v3/embedded-manage-nodes#create-ha" + from="/vendor/tutorial-ha-cluster-deploying" + to="/embedded-cluster/v3/embedded-manage-nodes#create-ha" [[redirects]] - from="https://docs.replicated.com/vendor/tutorial-installing-air-gap-existing-cluster-gcp" - to="https://docs.replicated.com/enterprise/installing-existing-cluster-airgapped" + from="/vendor/tutorial-installing-air-gap-existing-cluster-gcp" + to="/enterprise/installing-existing-cluster-airgapped" [[redirects]] - from="https://docs.replicated.com/vendor/releases-promoting" - to="https://docs.replicated.com/vendor/releases-creating-releases" + from="/vendor/releases-promoting" + to="/vendor/releases-creating-releases" [[redirects]] - from="https://docs.replicated.com/vendor/packaging-private-registry-cname" - to="https://docs.replicated.com/vendor/custom-domains" + from="/vendor/packaging-private-registry-cname" + to="/vendor/custom-domains" [[redirects]] - from="https://docs.replicated.com/vendor/releases-semantic-versioning" - to="https://docs.replicated.com/vendor/releases-about" + from="/vendor/releases-semantic-versioning" + to="/vendor/releases-about" [[redirects]] - from="https://docs.replicated.com/vendor/helm-installing-native-helm" - to="https://docs.replicated.com/vendor/helm-native-about" + from="/vendor/helm-installing-native-helm" + to="/vendor/helm-native-about" [[redirects]] - from="https://docs.replicated.com/vendor/helm-processing" - to="https://docs.replicated.com/vendor/helm-native-about" + from="/vendor/helm-processing" + to="/vendor/helm-native-about" [[redirects]] - from="https://docs.replicated.com/vendor/team-management-rbac-about" - to="https://docs.replicated.com/vendor/team-management-rbac-configuring" + from="/vendor/team-management-rbac-about" + to="/vendor/team-management-rbac-configuring" [[redirects]] - from="https://docs.replicated.com/vendor/preflight-support-bundle-creating" - to="https://docs.replicated.com/vendor/preflight-support-bundle-about" + from="/vendor/preflight-support-bundle-creating" + to="/vendor/preflight-support-bundle-about" [[redirects]] - from="https://docs.replicated.com/vendor/custom-domains-download-portal" - to="https://docs.replicated.com/vendor/custom-domains-using" + from="/vendor/custom-domains-download-portal" + to="/vendor/custom-domains-using" [[redirects]] - from="https://docs.replicated.com/vendor/helm-release-creating-package" - to="https://docs.replicated.com/vendor/helm-install-release" + from="/vendor/helm-release-creating-package" + to="/vendor/helm-install-release" [[redirects]] - from="https://docs.replicated.com/vendor/helm-release" - to="https://docs.replicated.com/vendor/helm-native-v2-using" + from="/vendor/helm-release" + to="/vendor/helm-native-v2-using" [[redirects]] - from="https://docs.replicated.com/vendor/helm-overview" - to="https://docs.replicated.com/vendor/helm-install-overview" + from="/vendor/helm-overview" + to="/vendor/helm-install-overview" [[redirects]] - from="https://docs.replicated.com/vendor/helm-install" - to="https://docs.replicated.com/vendor/helm-install-overview" + from="/vendor/helm-install" + to="/vendor/helm-install-overview" [[redirects]] - from="https://docs.replicated.com/vendor/testing-replicated-instance-types" - to="https://docs.replicated.com/vendor/testing-supported-clusters" + from="/vendor/testing-replicated-instance-types" + to="/vendor/testing-supported-clusters" [[redirects]] - from="https://docs.replicated.com/vendor/testing-shared-networks" - to="https://docs.replicated.com/vendor/testing-how-to" + from="/vendor/testing-shared-networks" + to="/vendor/testing-how-to" [[redirects]] - from="https://docs.replicated.com/vendor/testing-vm-about" - to="https://docs.replicated.com/vendor/testing-about" + from="/vendor/testing-vm-about" + to="/vendor/testing-about" [[redirects]] - from="https://docs.replicated.com/vendor/testing-vm-networking" - to="https://docs.replicated.com/vendor/testing-ingress" + from="/vendor/testing-vm-networking" + to="/vendor/testing-ingress" [[redirects]] - from="https://docs.replicated.com/vendor/testing-transfer-files" - to="https://docs.replicated.com/vendor/testing-vm-create" + from="/vendor/testing-transfer-files" + to="/vendor/testing-vm-create" [[redirects]] - from="https://docs.replicated.com/vendor/repository-workflow-and-tagging-releases" - to="https://docs.replicated.com/vendor/ci-workflows" + from="/vendor/repository-workflow-and-tagging-releases" + to="/vendor/ci-workflows" [[redirects]] - from="https://docs.replicated.com/vendor/releases-about-channels" - to="https://docs.replicated.com/vendor/releases-about" + from="/vendor/releases-about-channels" + to="/vendor/releases-about" [[redirects]] - from="https://docs.replicated.com/vendor/replicated-sdk-rbac" - to="https://docs.replicated.com/vendor/replicated-sdk-customizing" + from="/vendor/replicated-sdk-rbac" + to="/vendor/replicated-sdk-customizing" [[redirects]] - from="https://docs.replicated.com/vendor/helm-kots-using-sdk" - to="https://docs.replicated.com/vendor/helm-native-about" + from="/vendor/helm-kots-using-sdk" + to="/vendor/helm-native-about" [[redirects]] - from="https://docs.replicated.com/vendor/helm-native-helm-install-order" - to="https://docs.replicated.com/vendor/orchestrating-resource-deployment" + from="/vendor/helm-native-helm-install-order" + to="/vendor/orchestrating-resource-deployment" [[redirects]] - from="https://docs.replicated.com/vendor/preflight-kots-defining" - to="https://docs.replicated.com/vendor/preflight-defining" + from="/vendor/preflight-kots-defining" + to="/vendor/preflight-defining" [[redirects]] - from="https://docs.replicated.com/vendor/preflight-helm-defining" - to="https://docs.replicated.com/vendor/preflight-defining" + from="/vendor/preflight-helm-defining" + to="/vendor/preflight-defining" [[redirects]] - from="https://docs.replicated.com/vendor/support-bundle-kots-customizing" - to="https://docs.replicated.com/vendor/support-bundle-customizing" + from="/vendor/support-bundle-kots-customizing" + to="/vendor/support-bundle-customizing" [[redirects]] - from="https://docs.replicated.com/vendor/support-bundle-helm-customizing" - to="https://docs.replicated.com/vendor/support-bundle-customizing" + from="/vendor/support-bundle-helm-customizing" + to="/vendor/support-bundle-customizing" [[redirects]] - from="https://docs.replicated.com/vendor/distributing-overview" - to="https://docs.replicated.com/intro-replicated" + from="/vendor/distributing-overview" + to="/intro-replicated" [[redirects]] - from="https://docs.replicated.com/vendor/distributing-workflow" - to="https://docs.replicated.com/vendor/replicated-onboarding" + from="/vendor/distributing-workflow" + to="/vendor/replicated-onboarding" [[redirects]] - from = "https://docs.replicated.com/vendor/tutorial-ci-cd-integration" - to = "https://docs.replicated.com/vendor/ci-overview" + from = "/vendor/tutorial-ci-cd-integration" + to = "/vendor/ci-overview" [[redirects]] - from = "https://docs.replicated.com/vendor/embedded-kubernetes-overview" - to = "https://docs.replicated.com/embedded-cluster/v3/embedded-overview" + from = "/vendor/embedded-kubernetes-overview" + to = "/embedded-cluster/v3/embedded-overview" ################################################### # Redirects To the Enterprise Section ################################################### [[redirects]] - from="https://docs.replicated.com/enterprise/updating-existing-cluster" - to="https://docs.replicated.com/enterprise/updating-app-manager" + from="/enterprise/updating-existing-cluster" + to="/enterprise/updating-app-manager" [[redirects]] - from="https://docs.replicated.com/enterprise/snapshots-restoring-partial" - to="https://docs.replicated.com/enterprise/snapshots-restoring-full" + from="/enterprise/snapshots-restoring-partial" + to="/enterprise/snapshots-restoring-full" [[redirects]] - from="https://docs.replicated.com/enterprise/snapshots-scheduling" - to="https://docs.replicated.com/enterprise/snapshots-creating" + from="/enterprise/snapshots-scheduling" + to="/enterprise/snapshots-creating" [[redirects]] - from="https://docs.replicated.com/enterprise//snapshots-config-workflow" - to="https://docs.replicated.com/enterprise/snapshots-velero-cli-installing" + from="/enterprise//snapshots-config-workflow" + to="/enterprise/snapshots-velero-cli-installing" [[redirects]] - from="https://docs.replicated.com/enterprise/image-registry-airgap" - to="https://docs.replicated.com/enterprise/installing-general-requirements" + from="/enterprise/image-registry-airgap" + to="/enterprise/installing-general-requirements" [[redirects]] - from="https://docs.replicated.com/enterprise/installing-app-setup" - to="https://docs.replicated.com/enterprise/installing-existing-cluster#install-app" + from="/enterprise/installing-app-setup" + to="/enterprise/installing-existing-cluster#install-app" [[redirects]] - from="https://docs.replicated.com/enterprise/installing-embedded-airgapped" - to="https://docs.replicated.com/embedded-cluster/v3/installing-embedded-air-gap" + from="/enterprise/installing-embedded-airgapped" + to="/embedded-cluster/v3/installing-embedded-air-gap" [[redirects]] - from="https://docs.replicated.com/enterprise/installing-embedded-cluster" - to="https://docs.replicated.com/embedded-cluster/v3/installing-embedded" + from="/enterprise/installing-embedded-cluster" + to="/embedded-cluster/v3/installing-embedded" [[redirects]] - from="https://docs.replicated.com/enterprise/updating-embedded-cluster" - to="https://docs.replicated.com/embedded-cluster/v3/updating-embedded" + from="/enterprise/updating-embedded-cluster" + to="/embedded-cluster/v3/updating-embedded" [[redirects]] - from="https://docs.replicated.com/enterprise/image-registry-embedded-cluster" - to="https://docs.replicated.com/enterprise/image-registry-kurl" + from="/enterprise/image-registry-embedded-cluster" + to="/enterprise/image-registry-kurl" [[redirects]] - from="https://docs.replicated.com/vendor/releases-configvalues" - to="https://docs.replicated.com/embedded-cluster/v2/installing-embedded-automation" + from="/vendor/releases-configvalues" + to="/embedded-cluster/v2/installing-embedded-automation" [[redirects]] - from="https://docs.replicated.com/enterprise/snapshots-understanding" - to="https://docs.replicated.com/vendor/snapshots-overview" + from="/enterprise/snapshots-understanding" + to="/vendor/snapshots-overview" ################################################### # Redirects To the References Section @@ -406,30 +515,30 @@ # Redirects from the removed packaging-template-functions topic [[redirects]] - from="https://docs.replicated.com/vendor/packaging-template-functions" - to= "https://docs.replicated.com/reference/template-functions-about" + from="/vendor/packaging-template-functions" + to= "/reference/template-functions-about" # Redirects from the old topic name KOTS Lint Rules to the new topic name Lint Rules [[redirects]] - from="https://docs.replicated.com/reference/kots-lint" - to="https://docs.replicated.com/reference/linter" + from="/reference/kots-lint" + to="/reference/linter" # Redirects from the reference section to the teams section for generating API tokens [[redirects]] - from="https://docs.replicated.com/reference/replicated-cli-tokens" - to="https://docs.replicated.com/vendor/replicated-api-tokens" + from="/reference/replicated-cli-tokens" + to="/vendor/replicated-api-tokens" [[redirects]] - from="https://docs.replicated.com/reference/custom-resource-sig-application" - to="https://docs.replicated.com/vendor/admin-console-adding-buttons-links" + from="/reference/custom-resource-sig-application" + to="/vendor/admin-console-adding-buttons-links" [[redirects]] - from="https://docs.replicated.com/reference/replicated-cli-app-delete" - to="https://docs.replicated.com/reference/replicated-cli-app-rm" + from="/reference/replicated-cli-app-delete" + to="/reference/replicated-cli-app-rm" [[redirects]] - from="https://docs.replicated.com/reference/replicated-cli-channel-delete" - to="https://docs.replicated.com/reference/replicated-cli-channel-rm" + from="/reference/replicated-cli-channel-delete" + to="/reference/replicated-cli-channel-rm" ################################################### # Redirects To the Release Notes Section From afc7f434bbb77f028c7e093a5e0af632205c3891 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Mon, 6 Apr 2026 16:44:17 -0600 Subject: [PATCH 27/31] corrections --- .../embedded-cluster/v3/_requirements.mdx | 2 +- embedded-cluster/embedded-config.mdx | 71 +------------------ embedded-cluster/embedded-overview.mdx | 18 ++--- embedded-cluster/embedded-v3-migrate.mdx | 20 ++---- .../installing-embedded-air-gap.mdx | 18 ++--- 5 files changed, 18 insertions(+), 111 deletions(-) diff --git a/docs/partials/embedded-cluster/v3/_requirements.mdx b/docs/partials/embedded-cluster/v3/_requirements.mdx index 5090e81621..106c0473a3 100644 --- a/docs/partials/embedded-cluster/v3/_requirements.mdx +++ b/docs/partials/embedded-cluster/v3/_requirements.mdx @@ -10,7 +10,7 @@ * The user performing the installation must have root access to the machine, such as with `sudo`. -* The data directory used by Embedded Cluster must have 40Gi or more of total space and be less than 80% full. By default, the data directory is `/var/lib/embedded-cluster`. The directory can be changed by passing the `--data-dir` flag with the Embedded Cluster `install` command. For more information, see [install](/embedded-cluster/v3/embedded-cluster-install). +* The data directory used by Embedded Cluster must have 40Gi or more of total space and be less than 80% full. By default, the data directory is `/var/lib/APP_SLUG`, where `APP_SLUG` is the unique slug of the application. The directory can be changed by passing the `--data-dir` flag with the Embedded Cluster `install` command. For more information, see [install](/embedded-cluster/v3/embedded-cluster-install). Note that in addition to the primary data directory, Embedded Cluster creates directories and files in the following locations: diff --git a/embedded-cluster/embedded-config.mdx b/embedded-cluster/embedded-config.mdx index eefd3e09f2..c24ba481e1 100644 --- a/embedded-cluster/embedded-config.mdx +++ b/embedded-cluster/embedded-config.mdx @@ -18,24 +18,10 @@ kind: Config metadata: name: my-embedded-cluster-config spec: - version: "3.0.0-alpha-27+k8s-1.34" - binaryOverrideUrl: "" - metadataOverrideUrl: "" + version: "3.0.0-alpha-31+k8s-1.34" domains: proxyRegistryDomain: proxy.example.com replicatedAppDomain: updates.example.com - roles: - controller: - name: controller-custom - labels: - controller-label: controller-label-value - custom: - - name: abc - labels: - abc-test-label: abc-test-label-value - - name: xyz - labels: - xyz-test-label: xyz-value unsupportedOverrides: builtInExtensions: - name: admin-console @@ -108,61 +94,6 @@ Replicated recommends that you update the version frequently to ensure that you -## binaryOverrideUrl and metadataOverrideUrl - -Use `spec.binaryOverrideUrl` and `spec.metadataOverrideUrl` to override the default locations of Embedded Cluster binary and metadata artifacts. - -## roles {#roles} - -Use the `roles` key to customize node roles. - -A common use case for customizing node roles is to assign workloads to specific nodes. For example, if your application has graphics processing unit (GPU) workloads, you could create a `custom` role that adds a `gpu=true` label to the node. You could then schedule GPU workloads on nodes labeled `gpu=true`. - -When you configure the `roles` key, users select one or more roles to assign to a node when they join it to the cluster. For more information, see [Managing Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). - -If the `roles` key is _not_ configured, Embedded Cluster assigns all nodes that join the cluster the `controller` role. The `controller` role designates nodes that run the Kubernetes control plane. Controller nodes can also run other workloads in addition to the control plane. - -#### Example - -```yaml -apiVersion: embeddedcluster.replicated.com/v1beta1 -kind: Config -spec: - roles: - controller: - name: app - labels: - app: "true" - custom: - - name: db - labels: - db: "true" - - name: gpu - labels: - gpu: "true" -``` - -### Limitation - -The first node added to the cluster is always a controller. You cannot assign custom roles to the first node. To add labels to the first node, set the `labels` field in the `roles.controller` key. - -### roles.controller - -In the `roles.controller` key, you can set the following fields to customize the default controller role: - -* `name`: Set the name for controller nodes. By default, controller nodes have the name “controller”. - :::note - If you plan to create any custom roles, Replicated recommends that you change the default name for the controller role to a clear, descriptive term, such as “app”. When you add custom roles, the user sees both the name of the controller role and the names of any custom roles when they join a node. - ::: -* `labels`: Kubernetes labels applied to any node in the cluster with the given role. - -### roles.custom - -In the `roles.custom` key, you can add custom roles. Each custom role includes the following fields: - -* `name`: (Required) A name for the custom role. -* `labels`: Kubernetes labels applied to any node in the cluster with the given role. - ## domains Configure the `domains` key so that Embedded Cluster uses your custom domains for the Replicated proxy registry and Replicated app service. diff --git a/embedded-cluster/embedded-overview.mdx b/embedded-cluster/embedded-overview.mdx index 39689a5390..66da19eab1 100644 --- a/embedded-cluster/embedded-overview.mdx +++ b/embedded-cluster/embedded-overview.mdx @@ -15,7 +15,9 @@ This topic provides an introduction to Replicated Embedded Cluster. * Embedded Cluster v3 (Beta) does not support disaster recovery. -* Some Replicated template functions are not implemented in Embedded Cluster v3, either because Replicated discourages their use or because they are not yet ported. Contact Replicated if a missing template function blocks your release. +* Some Replicated template functions are not implemented in Embedded Cluster v3 (Beta). Contact Replicated if a missing template function blocks your release. + +* Embedded Cluster v3 (Beta) does not support assigning node roles. For more information, see [roles](/v2/embedded-config#roles) in the Embedded Cluster v2 documentation. ## Built-in extensions {#built-in-extensions} @@ -23,11 +25,9 @@ Embedded Cluster includes several built-in extensions. The built-in extensions p The built-in extensions installed by Embedded Cluster include: -* **Embedded Cluster Operator**: The Operator handles reporting and some clean up operations. - * **OpenEBS:** Embedded Cluster uses OpenEBS to provide local PersistentVolume (PV) storage, including the PV storage for rqlite used by KOTS. For more information, see the [OpenEBS](https://openebs.io/docs/) documentation. -* **(Air Gap Only) Image registry:** For air gap installations in environments with limited or no outbound internet access, Embedded Cluster installs an image registry where it pushes the images required to install and run the application. For more information about installing in air-gapped environments, see [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). +* **Image registry:** Embedded Cluster installs an image registry where it pushes the images required to install and run the application. ## About installing with Embedded Cluster @@ -50,7 +50,7 @@ During installation, Embedded Cluster automatically runs a default set of _host If any of the Embedded Cluster host preflight checks fail, Embedded Cluster blocks installation and displays a message describing the failure. -For the full default host preflight spec for Embedded Cluster, see [`host-preflight.yaml`](https://github.com/replicatedhq/embedded-cluster/blob/main/pkg/preflights/host-preflight.yaml) in the `embedded-cluster` repository in GitHub. +For the full default host preflight spec for Embedded Cluster, see [`preflight/embedded`](https://github.com/replicatedhq/ec/tree/f845ba382719a6218ebdca1e0e712452cb3483a4/pkg/preflight/embedded) in the `ec` repository in GitHub. ### Limitations @@ -65,12 +65,6 @@ Embedded Cluster supports installations in mutli-node clusters. Your end custome ### High availability -Multi-node clusters are not highly available by default. Enabling high availability (HA) requires that at least three controller nodes are present in the cluster. Users can enable HA when joining the third node. +Embedded Cluster automatically enables high availability (HA) when at least three controller nodes are present in the cluster. For more information about creating HA multi-node clusters with Embedded Cluster, see [Enable High Availability](embedded-manage-nodes#ha) in _Managing Multi-Node Clusters with Embedded Cluster_. - -### Node roles - -You can optionally define node roles in the Embedded Cluster Config. For multi-node clusters, roles can be useful for assigning specific application workloads to nodes. If you define node roles, users assign one or more roles to a node when it joins the cluster. - -For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. diff --git a/embedded-cluster/embedded-v3-migrate.mdx b/embedded-cluster/embedded-v3-migrate.mdx index 1b7b3c0715..5cf8d0090c 100644 --- a/embedded-cluster/embedded-v3-migrate.mdx +++ b/embedded-cluster/embedded-v3-migrate.mdx @@ -50,7 +50,9 @@ To update your release to support installation with Embedded Cluster v3: 1. Ensure that your release has a corresponding HelmChart v2 custom resource for each of your Helm charts. For information about how to configure the HelmChart v2 custom resource, see [Support installations with HelmChart v2](/vendor/helm-native-v2-using). For information about how to migrate from HelmChart v1 or Kubernetes manifests to HelmChart v2, see [Migrate existing installations to HelmChart v2](/vendor/helm-v2-migrate). -1. In your Embedded Cluster Config, update `version` to **EMBEDDED_CLUSTER_V3_VERSION**. You can also optionally increment the Kubernetes version by one minor version. +1. In your Embedded Cluster Config, update `version` to the latest version of Embedded Cluster v3. You can also optionally increment the Kubernetes version by one minor version. + + **Example:** ```yaml apiVersion: embeddedcluster.replicated.com/v1beta1 @@ -58,7 +60,7 @@ To update your release to support installation with Embedded Cluster v3: metadata: name: my-embedded-cluster-config spec: - version: "" + version: "3.0.0-alpha-31+k8s-1.34" ``` 1. Update any existing Helm extensions to use the `extensions.helmChart` format. See [`extensions`](embedded-config#extensions). @@ -104,19 +106,7 @@ To migrate an existing installation to Embedded Cluster v3: 1. SSH into the VM where the Embedded Cluster v2 installation is running. -1. On the VM, run the commands to download and extract the installation assets for the target release. - - **Example:** - - ```bash - $ tar -xvzf slackernews-unstable.tgz - slackernews-service - slackernews - slackernews-web - license.yaml - release.tgz - ec-3.0.0-beta-1+k8s-1.34.online - ``` +1. On the VM, run the commands to download and extract the installation assets for the target release. The installation assets include the Embedded Cluster binary, the license file, and the release assets. 1. Run the following command to upgrade using the Embedded Cluster v3 upgrade wizard: diff --git a/embedded-cluster/installing-embedded-air-gap.mdx b/embedded-cluster/installing-embedded-air-gap.mdx index e9728ba131..4130cce32b 100644 --- a/embedded-cluster/installing-embedded-air-gap.mdx +++ b/embedded-cluster/installing-embedded-air-gap.mdx @@ -75,10 +75,6 @@ To install from the Vendor Portal: [View a larger version of this image](/images/customer-install-instructions-dropdown.png) - Embedded cluster install instruction dialog - - [View a larger version of this image](/images/embedded-cluster-install-dialog-airgap.png) - 1. In the **Select a version** field (or equivalent), choose the application version you promoted to that channel for testing, or leave the latest version selected if that is what you want to install. 1. On a machine **with internet access**, run the download command from the dialog to save the air gap installation assets as a `.tgz` archive. @@ -91,12 +87,10 @@ To install from the Vendor Portal: * The license file * The air gap bundle (`APP_SLUG.airgap`) - After extraction, you may see additional binaries and artifacts compared to Embedded Cluster 2.x. Embedded Cluster uses these internally. You can ignore them. - -1. On the air-gapped machine, run the `install` command from the dialog. It must include `--airgap-bundle` pointing at your `.airgap` file. For example: +1. On the air-gapped machine, run the `install` command from the dialog. It must include `--airgap` pointing at your `.airgap` file. For example: ```bash - sudo ./APP_SLUG install --license license.yaml --airgap-bundle APP_SLUG.airgap + sudo ./APP_SLUG install --license license.yaml --airgap APP_SLUG.airgap ``` Replace `APP_SLUG` with your application slug and use the correct paths for your license and bundle files. Add any other flags you need. For the full set of flags, see [install](embedded-cluster-install). @@ -109,7 +103,7 @@ To install from the Vendor Portal: 1. On the **Configure** page, enter the configuration values for your application. -1. On the **Set Up** page, provide any information required for the cluster installation. This corresponds to values you previously passed with install flags in Embedded Cluster 2.x (for example, proxy settings), where those options apply in your air gap environment. +1. On the **Set Up** page, provide any information required for the cluster installation. 1. On the **Run** page, start the installation and wait for it to complete. @@ -131,13 +125,11 @@ To install headlessly in an air gap environment: 1. On a machine **with internet access**, run the first two commands from the dialog (download the archive, then extract it). - After extraction, you may see additional binaries and artifacts compared to Embedded Cluster 2.x. Embedded Cluster uses these internally. You can ignore them. - 1. Copy the extracted directory (or the `.tgz` and extract on the air-gapped host) to the air-gapped machine. 1. On the air-gapped machine, run `install` with: - * `--airgap-bundle` and the path to the `APP_SLUG.airgap` file. + * `--airgap` and the `APP_SLUG.airgap` file. * `--headless` to skip the interactive installer UI. * `--config-values` with the path to your [ConfigValues](/reference/custom-resource-configvalues) file. * `--installer-password` with the password you will use to access the installer later. @@ -145,7 +137,7 @@ To install headlessly in an air gap environment: Example: ```bash - sudo ./APP_SLUG install --license license.yaml --airgap-bundle APP_SLUG.airgap --headless --config-values PATH_TO_CONFIGVALUES --installer-password INSTALLER_PASSWORD + sudo ./APP_SLUG install --license license.yaml --airgap APP_SLUG.airgap --headless --config-values PATH_TO_CONFIGVALUES --installer-password INSTALLER_PASSWORD ``` Replace placeholders with values for your environment. Add any other flags you need. For the full set of flags, see [install](embedded-cluster-install). From f0b04428d93668fbd60cb2c4dffca3c46c9b2316 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Mon, 6 Apr 2026 18:47:14 -0600 Subject: [PATCH 28/31] more correctinos --- .../embedded-cluster/_shell-command.mdx | 2 +- .../embedded-cluster/v3/_definition.mdx | 2 +- docs/vendor/replicated-onboarding.mdx | 2 +- embedded-cluster/embedded-manage-nodes.mdx | 45 +++++++++---------- embedded-cluster/embedded-overview.mdx | 14 +++--- embedded-cluster/embedded-using.mdx | 2 +- .../version-2.0.0/embedded-manage-nodes.mdx | 8 ++-- .../version-2.0.0/embedded-overview.mdx | 2 +- .../version-2.0.0/embedded-using.mdx | 2 +- 9 files changed, 36 insertions(+), 43 deletions(-) diff --git a/docs/partials/embedded-cluster/_shell-command.mdx b/docs/partials/embedded-cluster/_shell-command.mdx index 69e916731a..2cade74095 100644 --- a/docs/partials/embedded-cluster/_shell-command.mdx +++ b/docs/partials/embedded-cluster/_shell-command.mdx @@ -1,6 +1,6 @@ To access the cluster and use other included binaries: -1. SSH onto a controller node. +1. SSH into a controller node. :::note You cannot run the `shell` command on worker nodes. diff --git a/docs/partials/embedded-cluster/v3/_definition.mdx b/docs/partials/embedded-cluster/v3/_definition.mdx index 4c16a244ab..a7c4093791 100644 --- a/docs/partials/embedded-cluster/v3/_definition.mdx +++ b/docs/partials/embedded-cluster/v3/_definition.mdx @@ -1,5 +1,5 @@ Replicated Embedded Cluster allows you to distribute a Kubernetes cluster and your application together as a single appliance, making it easy for enterprise users to install, update, and manage the application and the cluster in tandem. Embedded Cluster is based on the open source Kubernetes distribution k0s. For more information, see the [k0s documentation](https://docs.k0sproject.io/stable/). -Software vendors can configure the Embedded Cluster Config manifest to define characteristics of the cluster and the installation. For example, you can define custom node roles to assign workloads to specific nodes. Or, you can add optional Helm extensions to deploy components in the cluster before Embedded Cluster installs your application. +Software vendors can configure the Embedded Cluster Config manifest to define characteristics of the cluster and the installation. For example, you can add optional Helm extensions to deploy components in the cluster before Embedded Cluster installs your application. For enterprise users, Embedded Cluster provides a built-in UI that guides users through installation and upgrades. Additionally, Embedded Cluster automatically updates the cluster infrastructure at the same time as application updates, allowing users to more easily keep the cluster up-to-date without needing to use kubectl. diff --git a/docs/vendor/replicated-onboarding.mdx b/docs/vendor/replicated-onboarding.mdx index 184b441327..74700c7d57 100644 --- a/docs/vendor/replicated-onboarding.mdx +++ b/docs/vendor/replicated-onboarding.mdx @@ -461,7 +461,7 @@ To add support for air gap installations: The Embedded Cluster Config supports roles for multi-node clusters. One or more roles can be selected and assigned to a node when it is joined to the cluster. Node roles can be used to determine which nodes run the Kubernetes control plane, and to assign application workloads to particular nodes. -For more information, see [roles](/reference/embedded-config#roles) in _Embedded Cluster Config_. +For more information, see [roles](/embedded-cluster/v2/embedded-config#roles) in _Embedded Cluster Config_. ### Add and map license entitlements diff --git a/embedded-cluster/embedded-manage-nodes.mdx b/embedded-cluster/embedded-manage-nodes.mdx index b8cbb3a8cf..5dac11a6d0 100644 --- a/embedded-cluster/embedded-manage-nodes.mdx +++ b/embedded-cluster/embedded-manage-nodes.mdx @@ -2,7 +2,7 @@ import ShellCommand from "../docs/partials/embedded-cluster/_shell-command.mdx" # Access and manage embedded clusters (Beta) -This topic describes managing nodes in clusters created with Replicated Embedded Cluster, including how to add nodes and enable high-availability for multi-node clusters. +This topic describes managing nodes in clusters created with Replicated Embedded Cluster. ## Access the cluster @@ -18,17 +18,17 @@ This section describes how to join nodes to a cluster with Embedded Cluster. Multi-node clusters with Embedded Cluster have the following limitations: -* The first node added to the cluster is always a controller and cannot have any custom roles. For more information about configuring node roles, see [roles](embedded-config#roles) in _Embedded Cluster Config_. - * All nodes joined to the cluster use the same Embedded Cluster data directory as the installation node. You cannot choose a different data directory for Embedded Cluster when joining nodes. * You should not join more than one controller node at the same time. When joining a controller node, Embedded Cluster prints a warning explaining that you should not attempt to join another node until the controller node joins successfully. +* You cannot change a node's role (`controller` or `worker`) after you join the node. If you need to change a node’s role, reset the node and add it again with the new role. + ### Requirement To deploy multi-node clusters with Embedded Cluster, you must enable the **Multi-node Cluster (Embedded Cluster only)** license field for the customer. For more information about managing customer licenses, see [Create and Manage Customers](/vendor/releases-creating-customer). -### Add nodes to a cluster {#add-nodes} +### Join nodes {#add-nodes} To join a node: @@ -37,18 +37,17 @@ To join a node: 1. Run the following command to generate the `.tar.gz` bundle for joining a node: ```bash - sudo ./APP_SLUG create-join-bundle [--role] + sudo ./APP_SLUG create-join-bundle --role [controller | worker] ``` Where: * `APP_SLUG` is the unique slug for the application. - * `--role` is an optional flag to set the role for the new node. is the See [roles](embedded-config#roles) in _Embedded Cluster Config_. + * `--role` is the role to assign the node (`controller` or `worker`). + :::note You cannot change the role after you add a node. If you need to change a node’s role, reset the node and add it again with the new role. ::: -1. SSH into the node that you want to join. - -1. Copy the `.tar.gz` to the node. +1. Use `scp` to copy the `.tar.gz` bundle to the node that you want to join. 1. Extract the `.tar.gz`. @@ -60,39 +59,35 @@ To join a node: 1. Repeat these steps for each node you want to add. -## Configure high availability for multi-node clusters {#ha} +## High availability for multi-node clusters {#ha} -Multi-node clusters are not highly available by default. The first node of the cluster holds important data for Kubernetes, such that the loss of this node would be catastrophic for the cluster. Enabling high availability requires that at least three controller nodes are present in the cluster. +Embedded Cluster automatically enables high availability (HA) when at least three `controller` nodes are present in the cluster. -Users are automatically prompted to enable HA when joining the third controller node to a cluster. Alternatively, users can enable HA with the `enable-ha` command after adding three or more controller nodes. +In HA installations, Embedded Cluster deploys multiple replicas of the OpenEBS and image registry built-in extensions. Also, any Helm [extensions](embedded-config#extensions) that you include in the Embedded Cluster Config are installed in the cluster depending on the given chart and whether or not it is configured to be deployed with high availability. ### Best practices for high availability -Consider the following best practices and recommendations for creating HA clusters: +Consider the following best practices and recommendations for HA clusters: -* HA requires at least three _controller_ nodes that run the Kubernetes control plane. This is because clusters use a quorum system, in which more than half the nodes must be up and reachable. In clusters with three controller nodes, the Kubernetes control plane can continue to operate if one node fails because the remaining two nodes can still form a quorum. By default, with Embedded Cluster, all new nodes added to a cluster are controller nodes. For information about customizing the controller node role, see [roles](embedded-config#roles) in _Embedded Cluster Config_. +* HA requires at least three _controller_ nodes that run the Kubernetes control plane. This is because clusters use a quorum system, in which more than half the nodes must be up and reachable. In clusters with three controller nodes, the Kubernetes control plane can continue to operate if one node fails because the remaining two nodes can still form a quorum. * Always use an odd number of controller nodes in HA clusters. Using an odd number of controller nodes ensures that the cluster can make decisions efficiently with quorum calculations. Clusters with an odd number of controller nodes also avoid split-brain scenarios where the cluster runs as two, independent groups of nodes, resulting in inconsistencies and conflicts. * You can have any number of _worker_ nodes in HA clusters. Worker nodes do not run the Kubernetes control plane, but can run workloads such as application workloads. -### Create a multi-node cluster with high availability {#create-ha} - -You can enable high availability for a multi-node cluster when joining the third controller node. Alternatively, you can enable HA for an existing cluster with three or more controller nodes. For more information, see [Enable High Availability For an Existing Cluster](#enable-ha-existing). - -To create a multi-node HA cluster: +### Create a multi-node cluster with HA -1. Set up a cluster with at least two controller nodes. You can do an online (internet-connected) or air gap installation. For more information, see [Online Installation with Embedded Cluster](installing-embedded) or [Air Gap Installation with Embedded Cluster](installing-embedded-air-gap). +To create a multi-node cluster with HA: -1. Follow the steps in [Add nodes to a cluster](#add-nodes) on this page to join a third controller node. Pass `--role controller` with the `create-join-bundle` command. +* During installation with Embedded Cluster, follow the steps in the Embedded Cluster UI to join a total of three `controller` nodes to the cluster. -1. In response to the prompt asking if you want to enable high availability, type `y` or `yes`. + Embedded Cluster automatically converts the installation to HA when three or more controller nodes are present. -1. Wait for the migration to HA to complete. +For more information about joining nodes, see [Join nodes](#add-nodes) on this page. -### Enable high availability for an existing cluster {#enable-ha-existing} +### Enable HA for an existing cluster {#enable-ha-existing} -To enable high availability for an existing Embedded Cluster installation with three or more controller nodes, run the following command: +To enable HA for an existing Embedded Cluster installation with three or more controller nodes, run the following command: ```bash sudo ./APP_SLUG enable-ha diff --git a/embedded-cluster/embedded-overview.mdx b/embedded-cluster/embedded-overview.mdx index 66da19eab1..7a2cc59475 100644 --- a/embedded-cluster/embedded-overview.mdx +++ b/embedded-cluster/embedded-overview.mdx @@ -17,18 +17,18 @@ This topic provides an introduction to Replicated Embedded Cluster. * Some Replicated template functions are not implemented in Embedded Cluster v3 (Beta). Contact Replicated if a missing template function blocks your release. -* Embedded Cluster v3 (Beta) does not support assigning node roles. For more information, see [roles](/v2/embedded-config#roles) in the Embedded Cluster v2 documentation. +* Embedded Cluster v3 (Beta) does not support custom node roles. You can assign nodes the `controller` or `worker` role. ## Built-in extensions {#built-in-extensions} -Embedded Cluster includes several built-in extensions. The built-in extensions provide capabilities such as application management and storage. Embedded Cluster installs each built-in extension in its own namespace. - The built-in extensions installed by Embedded Cluster include: -* **OpenEBS:** Embedded Cluster uses OpenEBS to provide local PersistentVolume (PV) storage, including the PV storage for rqlite used by KOTS. For more information, see the [OpenEBS](https://openebs.io/docs/) documentation. +* **OpenEBS:** Embedded Cluster uses OpenEBS to provide local PersistentVolume (PV) storage. For more information, see the [OpenEBS](https://openebs.io/docs/) documentation. * **Image registry:** Embedded Cluster installs an image registry where it pushes the images required to install and run the application. +Embedded Cluster installs each built-in extension in its own namespace. + ## About installing with Embedded Cluster Embedded Cluster supports installations in online (internet-connected) environments and air gap environments with no outbound internet access. @@ -61,10 +61,8 @@ Embedded Cluster host preflight checks have the following limitations: ## Multi-node installations -Embedded Cluster supports installations in mutli-node clusters. Your end customers can add nodes to a cluster during or after installation from the UI. For more information, see [Manage Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). - -### High availability +Embedded Cluster supports installations in mutli-node clusters. Your end customers can add nodes to a cluster during or after installation from the UI. Embedded Cluster automatically enables high availability (HA) when at least three controller nodes are present in the cluster. -For more information about creating HA multi-node clusters with Embedded Cluster, see [Enable High Availability](embedded-manage-nodes#ha) in _Managing Multi-Node Clusters with Embedded Cluster_. +For more information, see [Manage Multi-Node Clusters with Embedded Cluster](embedded-manage-nodes). diff --git a/embedded-cluster/embedded-using.mdx b/embedded-cluster/embedded-using.mdx index 8c3309104e..dde5ea337c 100644 --- a/embedded-cluster/embedded-using.mdx +++ b/embedded-cluster/embedded-using.mdx @@ -29,7 +29,7 @@ To add the Embedded Cluster Config: 1. After successfully installing your application with Embedded Cluster, customize the [Embedded Cluster Config](embedded-config) as desired: * Add your custom domain for the Replicated proxy registry and Replicated app service. See [domains](embedded-config#domains). * Add custom Helm extensions. Extensions allow you to provide Helm charts that Embedded Cluster deploys before your application. For example, you can add a Helm extension to ship an ingress controller. See [extensions](embedded-config#extensions). - * Define roles to assign workloads to specific nodes in multi-node installations. See [roles](embedded-config#roles). + * Define roles to assign workloads to specific nodes in multi-node installations. See [roles](/embedded-cluster/v2/embedded-config#roles). Replicated recommends that you work in small iterations and test your changes frequently in your development environment. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx index 57f782b814..53b82e3f85 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-manage-nodes.mdx @@ -19,9 +19,9 @@ This section describes how to join nodes to a cluster with Embedded Cluster. Multi-node clusters with Embedded Cluster have the following limitations: -* Setting node roles with the Embedded Cluster Config [roles](embedded-config#roles) key is Beta. +* Setting node roles with the Embedded Cluster Config [roles](/embedded-cluster/v2/embedded-config#roles) key is Beta. -* The first node added to the cluster is always a controller and cannot be assigned any custom roles. For more information about configuring node roles, see [roles](embedded-config#roles) in _Embedded Cluster Config_. +* The first node added to the cluster is always a controller and cannot be assigned any custom roles. For more information about configuring node roles, see [roles](/embedded-cluster/v2/embedded-config#roles) in _Embedded Cluster Config_. * The same Embedded Cluster data directory used at installation is used for all nodes joined to the cluster. This is either the default `/var/lib/embedded-cluster` directory or the directory set with the [`--data-dir`](embedded-cluster-install#flags) flag. You cannot choose a different data directory for Embedded Cluster when joining nodes. @@ -39,7 +39,7 @@ This section describes how to add nodes to a cluster with Embedded Cluster. To add a node to a cluster with Embedded Cluster: -1. (Optional) In the Embedded Cluster Config, configure the `roles` key to customize node roles. For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. When you are done, create and promote a new release with the updated Config. +1. (Optional) In the Embedded Cluster Config, configure the `roles` key to customize node roles. For more information, see [roles](/embedded-cluster/v2/embedded-config#roles) in _Embedded Cluster Config_. When you are done, create and promote a new release with the updated Config. 1. Do one of the following: @@ -126,7 +126,7 @@ Enabling high availability has the following requirements: Consider the following best practices and recommendations for creating HA clusters: -* At least three _controller_ nodes that run the Kubernetes control plane are required for HA. This is because clusters use a quorum system, in which more than half the nodes must be up and reachable. In clusters with three controller nodes, the Kubernetes control plane can continue to operate if one node fails because a quorum can still be reached by the remaining two nodes. By default, with Embedded Cluster, all new nodes added to a cluster are controller nodes. For information about customizing the controller node role, see [roles](embedded-config#roles) in _Embedded Cluster Config_. +* At least three _controller_ nodes that run the Kubernetes control plane are required for HA. This is because clusters use a quorum system, in which more than half the nodes must be up and reachable. In clusters with three controller nodes, the Kubernetes control plane can continue to operate if one node fails because a quorum can still be reached by the remaining two nodes. By default, with Embedded Cluster, all new nodes added to a cluster are controller nodes. For information about customizing the controller node role, see [roles](/embedded-cluster/v2/embedded-config#roles) in _Embedded Cluster Config_. * Always use an odd number of controller nodes in HA clusters. Using an odd number of controller nodes ensures that the cluster can make decisions efficiently with quorum calculations. Clusters with an odd number of controller nodes also avoid split-brain scenarios where the cluster runs as two, independent groups of nodes, resulting in inconsistencies and conflicts. diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx index c415739bf2..a5d2ce7032 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-overview.mdx @@ -67,7 +67,7 @@ For more information about creating HA multi-node clusters with Embedded Cluster You can optionally define node roles in the Embedded Cluster Config. For multi-node clusters, roles can be useful for the purpose of assigning specific application workloads to nodes. If nodes roles are defined, users assign one or more roles to a node when it is joined to the cluster. -For more information, see [roles](embedded-config#roles) in _Embedded Cluster Config_. +For more information, see [roles](/embedded-cluster/v2/embedded-config#roles) in _Embedded Cluster Config_. ## About configuring Embedded Cluster diff --git a/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx b/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx index 330f57acc5..8dcf8cdaec 100644 --- a/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx +++ b/embedded-cluster_versioned_docs/version-2.0.0/embedded-using.mdx @@ -49,7 +49,7 @@ To add the Embedded Cluster Config: 1. After successfully installing your application with Embedded Cluster, customize the [Embedded Cluster Config](embedded-config) as desired: * Add your custom domain for the Replicated proxy registry and Replicated app service. See [domains](embedded-config#domains). * Add custom Helm extensions. Extensions allow you to provide Helm charts that are deployed before your application. For example, you can add a Helm extension to ship an ingress controller. See [extensions](embedded-config#extensions). - * Define roles to assign workloads to specific nodes in multi-node installations. See [roles](embedded-config#roles). + * Define roles to assign workloads to specific nodes in multi-node installations. See [roles](/embedded-cluster/v2/embedded-config#roles). Replicated recommends that you work in small iterations and test your changes frequently in your development environment. From cca50e0f9b4bcfab24bbf1af189bbc6841962771 Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Mon, 6 Apr 2026 18:53:31 -0600 Subject: [PATCH 29/31] more corrections --- .../embedded-cluster/v3/_requirements.mdx | 2 +- embedded-cluster/embedded-config.mdx | 23 ++++--------------- embedded-cluster/embedded-troubleshooting.mdx | 4 +++- 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/docs/partials/embedded-cluster/v3/_requirements.mdx b/docs/partials/embedded-cluster/v3/_requirements.mdx index 106c0473a3..d5a7c7a3a7 100644 --- a/docs/partials/embedded-cluster/v3/_requirements.mdx +++ b/docs/partials/embedded-cluster/v3/_requirements.mdx @@ -31,7 +31,7 @@ - `/var/lib/kubelet` - `/var/log/calico` - `/var/log/containers` - - `/var/log/embedded-cluster` + - `/var/log/APP_SLUG`, where `APP_SLUG` is the unique slug for the application - `/var/log/pods` - `/usr/local/bin/k0s` diff --git a/embedded-cluster/embedded-config.mdx b/embedded-cluster/embedded-config.mdx index c24ba481e1..3505bbee0e 100644 --- a/embedded-cluster/embedded-config.mdx +++ b/embedded-cluster/embedded-config.mdx @@ -23,16 +23,6 @@ spec: proxyRegistryDomain: proxy.example.com replicatedAppDomain: updates.example.com unsupportedOverrides: - builtInExtensions: - - name: admin-console - values: | - labels: - release-custom-label: release-custom-value - - name: embedded-cluster-operator - values: | - global: - labels: - release-custom-label: release-custom-value k0s: | config: metadata: @@ -168,7 +158,7 @@ spec: Advanced users who understand the risks and ramifications of changing the default configuration should use this feature with caution. ::: -Use unsupported overrides to change Embedded Cluster's default configuration, including the k0s config and Helm values for built-in extensions like KOTS and the Embedded Cluster Operator. Use overrides carefully. Replicated has not tested these combinations and they can disrupt clusters. Replicated does not support issues caused by unsupported overrides. +Use unsupported overrides to change Embedded Cluster's default configuration, including the k0s config and Helm values for built-in extensions. Use overrides carefully. Replicated has not tested these combinations and they can disrupt clusters. Replicated does not support issues caused by unsupported overrides. While you should use them with caution, unsupported overrides are useful if you need to make changes that Embedded Cluster does not otherwise expose. @@ -205,7 +195,7 @@ spec: Embedded Cluster deploys built-in extensions with Helm. You can patch their values with `unsupportedOverrides.builtInExtensions`. Each item sets `name` (the chart to patch) and `values` (a multi-line YAML string). Embedded Cluster merges your values into the defaults it uses. -#### Example +{/* #### Example ```yaml apiVersion: embeddedcluster.replicated.com/v1beta1 @@ -213,16 +203,11 @@ kind: Config spec: unsupportedOverrides: builtInExtensions: - - name: admin-console + - name: openebs values: | labels: release-custom-label: release-custom-value - - name: embedded-cluster-operator - values: | - global: - labels: - release-custom-label: release-custom-value -``` +``` */} ### Configure the Kubelet diff --git a/embedded-cluster/embedded-troubleshooting.mdx b/embedded-cluster/embedded-troubleshooting.mdx index 96ae2dde9e..d758d799ff 100644 --- a/embedded-cluster/embedded-troubleshooting.mdx +++ b/embedded-cluster/embedded-troubleshooting.mdx @@ -30,7 +30,9 @@ To view installation logs for Embedded Cluster: 1. SSH onto a controller node. -1. Navigate to `/var/log/embedded-cluster` and open the `.log` file to view logs. +1. Navigate to `/var/log/APP_SLUG`, where `APP_SLUG` is the unique slug for the application. + +1. Open the `.log` file to view logs. ### View K0s logs From d119b45dfc8c5eff4433cb460e78e75dd5b5735f Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Mon, 6 Apr 2026 19:06:08 -0600 Subject: [PATCH 30/31] edits --- .../embedded-cluster/v3/_ec-config.mdx | 2 +- embedded-cluster/embedded-manage-nodes.mdx | 18 +++++++++--------- embedded-cluster/embedded-using.mdx | 2 +- embedded-cluster/embedded-v3-migrate.mdx | 10 ++-------- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/docs/partials/embedded-cluster/v3/_ec-config.mdx b/docs/partials/embedded-cluster/v3/_ec-config.mdx index 173181f5d7..e0c263cfcc 100644 --- a/docs/partials/embedded-cluster/v3/_ec-config.mdx +++ b/docs/partials/embedded-cluster/v3/_ec-config.mdx @@ -2,5 +2,5 @@ apiVersion: embeddedcluster.replicated.com/v1beta1 kind: Config spec: - version: 3.0.0-alpha-26+k8s-1.34 + version: 3.0.0-alpha-31+k8s-1.34 ``` diff --git a/embedded-cluster/embedded-manage-nodes.mdx b/embedded-cluster/embedded-manage-nodes.mdx index 5dac11a6d0..a032ef0a25 100644 --- a/embedded-cluster/embedded-manage-nodes.mdx +++ b/embedded-cluster/embedded-manage-nodes.mdx @@ -79,21 +79,21 @@ Consider the following best practices and recommendations for HA clusters: To create a multi-node cluster with HA: -* During installation with Embedded Cluster, follow the steps in the Embedded Cluster UI to join a total of three `controller` nodes to the cluster. +* During installation with Embedded Cluster, follow the steps in the Embedded Cluster UI to join a total of three `controller` nodes to the cluster. For more information about joining nodes, see [Join nodes](#add-nodes) on this page. - Embedded Cluster automatically converts the installation to HA when three or more controller nodes are present. - -For more information about joining nodes, see [Join nodes](#add-nodes) on this page. + Embedded Cluster automatically converts the installation to HA when three or more controller nodes are present. ### Enable HA for an existing cluster {#enable-ha-existing} -To enable HA for an existing Embedded Cluster installation with three or more controller nodes, run the following command: +To enable HA for an existing Embedded Cluster installation with three or more controller nodes: -```bash -sudo ./APP_SLUG enable-ha -``` +* On one of the controller nodes, run this command: -Where `APP_SLUG` is the unique slug for the application. + ```bash + sudo ./APP_SLUG enable-ha + ``` + + Where `APP_SLUG` is the unique slug for the application. ## Reset nodes and remove clusters diff --git a/embedded-cluster/embedded-using.mdx b/embedded-cluster/embedded-using.mdx index dde5ea337c..61903d1055 100644 --- a/embedded-cluster/embedded-using.mdx +++ b/embedded-cluster/embedded-using.mdx @@ -14,7 +14,7 @@ To add the Embedded Cluster Config: 1. Create a new release that includes your application and a unique [HelmChart v2](/reference/custom-resource-helmchart-v2) custom resource for each Helm chart in the release. - If you have not yet configured the HelmChart custom resource for your application, see [Onboard to the Replicated Platform](/vendor/replicated-onboarding). That guide provides detailed instructions for configuring releases that support installation with a Replicated installer. + If you have not yet configured the HelmChart custom resource for your application, see [Onboard to the Replicated Platform](/vendor/replicated-onboarding). The onboarding guide provides detailed instructions for configuring releases that support installation with a Replicated installer. 1. In the release, add an [Embedded Cluster Config](embedded-config) manifest that specifies the Embedded Cluster version to use: diff --git a/embedded-cluster/embedded-v3-migrate.mdx b/embedded-cluster/embedded-v3-migrate.mdx index 5cf8d0090c..d1b3f81a5a 100644 --- a/embedded-cluster/embedded-v3-migrate.mdx +++ b/embedded-cluster/embedded-v3-migrate.mdx @@ -1,4 +1,5 @@ import DependencyYaml from "../docs//partials/replicated-sdk/_dependency-yaml.mdx" +import EcConfig from "../docs/partials/embedded-cluster/v3/_ec-config.mdx" # Migrate from Embedded Cluster v2 @@ -54,14 +55,7 @@ To update your release to support installation with Embedded Cluster v3: **Example:** - ```yaml - apiVersion: embeddedcluster.replicated.com/v1beta1 - kind: Config - metadata: - name: my-embedded-cluster-config - spec: - version: "3.0.0-alpha-31+k8s-1.34" - ``` + 1. Update any existing Helm extensions to use the `extensions.helmChart` format. See [`extensions`](embedded-config#extensions). From c3e4a11a1a5e2a0c5a3642348b16489c664315da Mon Sep 17 00:00:00 2001 From: Paige Calvert Date: Tue, 7 Apr 2026 09:30:32 -0600 Subject: [PATCH 31/31] fix broken links to new ec docs --- .vale.ini | 1 + docs/enterprise/updating-apps.mdx | 2 +- docs/intro-replicated.mdx | 8 +- docs/intro.mdx | 10 +- .../configValues/_config-values-procedure.mdx | 2 +- .../_warning-do-not-downgrade.mdx | 2 +- .../getting-started/_test-your-changes.mdx | 2 +- .../install/_config-values-procedure.mdx | 2 +- docs/partials/kurl/_kurl-availability.mdx | 2 +- docs/partials/monitoring/_limitation-ec.mdx | 2 +- .../snapshots/_limitation-no-ec-support.mdx | 2 +- .../template-functions/_ne-comparison.mdx | 2 +- docs/reference/custom-resource-about.md | 2 +- .../reference/custom-resource-application.mdx | 32 +++---- .../custom-resource-configvalues.mdx | 2 +- docs/reference/template-functions-about.mdx | 2 +- .../reference/template-functions-examples.mdx | 2 +- docs/release-notes/rn-app-manager.md | 91 +++++++++---------- docs/release-notes/rn-embedded-cluster.md | 28 +++--- docs/release-notes/rn-kubernetes-installer.md | 2 +- docs/release-notes/rn-vendor-platform.md | 6 +- .../admin-console-adding-buttons-links.mdx | 2 +- docs/vendor/admin-console-port-forward.mdx | 2 +- docs/vendor/config-screen-conditional.mdx | 2 +- docs/vendor/custom-domains-using.md | 6 +- docs/vendor/custom-domains.md | 2 +- docs/vendor/enterprise-portal-use.mdx | 2 +- docs/vendor/environment-setup.mdx | 2 +- docs/vendor/firewall-openings.mdx | 2 +- docs/vendor/helm-native-v2-using.mdx | 2 +- docs/vendor/helm-packaging-airgap-bundles.mdx | 2 +- docs/vendor/kots-faq.mdx | 10 +- docs/vendor/kurl-nodeport-services.mdx | 4 +- docs/vendor/licenses-about.mdx | 2 +- docs/vendor/licenses-install-types.mdx | 4 +- docs/vendor/licenses-using-builtin-fields.mdx | 4 +- docs/vendor/packaging-kots-versions.md | 2 +- docs/vendor/policies-support-lifecycle.md | 2 +- docs/vendor/preflight-host-preflights.md | 2 +- .../vendor/preflight-support-bundle-about.mdx | 6 +- docs/vendor/quick-start.mdx | 2 +- docs/vendor/releases-about.mdx | 2 +- ...eleases-sharing-license-install-script.mdx | 2 +- .../replicated-onboarding-helm-only.mdx | 2 +- docs/vendor/replicated-onboarding.mdx | 14 +-- docs/vendor/replicated-sdk-installing.mdx | 4 +- docs/vendor/support-bundle-embedded.mdx | 2 +- docs/vendor/testing-network-policy.md | 2 +- docs/vendor/testing-supported-clusters.md | 2 +- docs/vendor/tutorial-cmx-airgap.mdx | 2 +- .../tutorial-embedded-cluster-automation.mdx | 4 +- embedded-cluster/embedded-cluster-install.mdx | 2 +- netlify.toml | 4 +- 53 files changed, 154 insertions(+), 154 deletions(-) diff --git a/.vale.ini b/.vale.ini index 9a5c6fefad..89c2a2c585 100644 --- a/.vale.ini +++ b/.vale.ini @@ -14,6 +14,7 @@ IgnoredScopes = code, tt, a, img mdx = md [*.{md,mdx}] +TokenIgnores = (\{#[^}]+\}) BasedOnStyles = Vale, Replicated diff --git a/docs/enterprise/updating-apps.mdx b/docs/enterprise/updating-apps.mdx index 766bec3641..292b98d2de 100644 --- a/docs/enterprise/updating-apps.mdx +++ b/docs/enterprise/updating-apps.mdx @@ -16,7 +16,7 @@ The Admin Console only deploys new versions automatically if preflight checks pa Automatic updates have the following limitations: -* Automatic updates are not supported for [Replicated Embedded Cluster](/vendor/embedded-overview) installations. +* Automatic updates are not supported for [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview) installations. * Automatic updates are not supported for applications installed in air gap environments with no outbound internet access. diff --git a/docs/intro-replicated.mdx b/docs/intro-replicated.mdx index 1f57063566..a5472d33ea 100644 --- a/docs/intro-replicated.mdx +++ b/docs/intro-replicated.mdx @@ -29,7 +29,7 @@ The following diagram demonstrates the process of using the Replicated Platform The diagram above shows an application that is packaged with the [**Replicated SDK**](/vendor/replicated-sdk-overview). The application is tested in clusters provisioned with the [**Replicated Compatibility Matrix (CMX)**](/vendor/testing-about), then added to a new release in the [**Vendor Portal**](/vendor/releases-about) using an automated CI/CD pipeline. -The application is then installed by a customer ("Big Bank") on a VM. To install, the customer downloads their license, which grants proxy access to the application images through the [**Replicated proxy registry**](/vendor/private-images-about). They also download the installation assets for the [**Replicated Embedded Cluster**](/vendor/embedded-overview) installer. +The application is then installed by a customer ("Big Bank") on a VM. To install, the customer downloads their license, which grants proxy access to the application images through the [**Replicated proxy registry**](/vendor/private-images-about). They also download the installation assets for the [**Replicated Embedded Cluster**](/embedded-cluster/v3/embedded-overview) installer. Embedded Cluster runs [**preflight checks**](/vendor/preflight-support-bundle-about) to verify that the environment meets the installation requirements, provisions a cluster on the VM, and installs [**Replicated KOTS**](intro-kots) in the cluster. KOTS provides an [**Admin Console**](intro-kots#kots-admin-console) where the customer enters application-specific configurations, runs application preflight checks, optionally joins nodes to the cluster, and then deploys the application. After installation, customers can manage both the application and the cluster from the Admin Console. @@ -45,7 +45,7 @@ Replicated Embedded Cluster is a Kubernetes installer based on the open source K Additionally, each version of Embedded Cluster includes a specific version of [Replicated KOTS](#kots) that is installed in the cluster during installation. KOTS is used by Embedded Cluster to deploy the application and also provides the Admin Console UI where users can manage both the application and the cluster. -For more information, see [Embedded Cluster Overview](/vendor/embedded-overview). +For more information, see [Embedded Cluster Overview](/embedded-cluster/v3/embedded-overview). ### KOTS (Admin Console) {#kots} @@ -169,9 +169,9 @@ Additionally, the Replicated proxy registry grants proxy access to private appli Applications distributed with the Replicated Platform can support multiple different installation methods from the same application release, helping you to meet your customers where they are. For example: -* Customers who are not experienced with Kubernetes or who prefer to deploy to a dedicated cluster in their environment can install on a VM or bare metal server with the Replicated Embedded Cluster installer. For more information, see [Embedded Cluster Overview](/vendor/embedded-overview). +* Customers who are not experienced with Kubernetes or who prefer to deploy to a dedicated cluster in their environment can install on a VM or bare metal server with the Replicated Embedded Cluster installer. For more information, see [Embedded Cluster Overview](/embedded-cluster/v3/embedded-overview). * Customers familiar with Kubernetes and Helm can install in their own existing cluster using the Helm CLI. For more information, see [Installing with Helm](/vendor/install-with-helm). -* Customers installing into environments with limited or no outbound internet access (often referred to as air-gapped environments) can securely access and push images to their own internal registry, then install using Helm or a Replicated installer. For more information, see [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap) and [Installing and Updating with Helm in Air Gap Environments](/vendor/helm-install-airgap). +* Customers installing into environments with limited or no outbound internet access (often referred to as air-gapped environments) can securely access and push images to their own internal registry, then install using Helm or a Replicated installer. For more information, see [Air Gap Installation with Embedded Cluster](/embedded-cluster/v3/installing-embedded-air-gap) and [Installing and Updating with Helm in Air Gap Environments](/vendor/helm-install-airgap). Additionally, to enhance the installation experience, the Enterprise Portal provides a customizable, web-based portal where your customers can view application install and update instructions, upload support bundles, view insights about their active and inactive instances, and more. For more information, see [About the Enteprise Portal](/vendor/enterprise-portal-about). diff --git a/docs/intro.mdx b/docs/intro.mdx index e0c6e118e6..48854ace8b 100644 --- a/docs/intro.mdx +++ b/docs/intro.mdx @@ -230,7 +230,7 @@ import clsx from "clsx";

- + Overview

@@ -241,7 +241,7 @@ import clsx from "clsx";

- + Embedded Cluster Config

@@ -252,7 +252,7 @@ import clsx from "clsx";

Online Installation with Embedded Cluster @@ -265,7 +265,7 @@ import clsx from "clsx";
Air Gap Installation with Embedded Cluster @@ -278,7 +278,7 @@ import clsx from "clsx";
Perform Updates with Embedded Cluster diff --git a/docs/partials/configValues/_config-values-procedure.mdx b/docs/partials/configValues/_config-values-procedure.mdx index 339a5ba4da..138da3b3ca 100644 --- a/docs/partials/configValues/_config-values-procedure.mdx +++ b/docs/partials/configValues/_config-values-procedure.mdx @@ -2,7 +2,7 @@ During installation, KOTS automatically generates a ConfigValues file and saves To get the ConfigValues file from an installed application instance: -1. Install the target release in a development environment. You can either install the release with Replicated Embedded Cluster or install in an existing cluster with KOTS. For more information, see [Online Installation with Embedded Cluster](/enterprise/installing-embedded) or [Online Installation in Existing Clusters with KOTS](/enterprise/installing-existing-cluster). +1. Install the target release in a development environment. You can either install the release with Replicated Embedded Cluster or install in an existing cluster with KOTS. For more information, see [Online Installation with Embedded Cluster](/embedded-cluster/v3/installing-embedded) or [Online Installation in Existing Clusters with KOTS](/enterprise/installing-existing-cluster). 1. Depending on the installer that you used, do one of the following to get the ConfigValues for the installed instance: diff --git a/docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx b/docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx index 5417f04188..1231e0a556 100644 --- a/docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx +++ b/docs/partials/embedded-cluster/_warning-do-not-downgrade.mdx @@ -1,3 +1,3 @@ :::important -Don't downgrade the Embedded Cluster version or the Kubernetes version. Also, only increase the Kubernetes version by one minor version at a time. For more information, see [Limitations](embedded-overview#ec-limitations) in _Embedded Cluster Overview_. +Don't downgrade the Embedded Cluster version or the Kubernetes version. Also, only increase the Kubernetes version by one minor version at a time. For more information, see [Limitations](/embedded-cluster/v3/embedded-overview#ec-limitations) in _Embedded Cluster Overview_. ::: \ No newline at end of file diff --git a/docs/partials/getting-started/_test-your-changes.mdx b/docs/partials/getting-started/_test-your-changes.mdx index 4bb8b32fe6..d5312766e1 100644 --- a/docs/partials/getting-started/_test-your-changes.mdx +++ b/docs/partials/getting-started/_test-your-changes.mdx @@ -1 +1 @@ -Install the release to test your changes. For Embedded Cluster installations, see [Performing Udpates in Embedded Clusters](/enterprise/updating-embedded). For existing cluster installations with KOTS, see [Perform Updates in Existing Clusters](/enterprise/updating-app-manager). \ No newline at end of file +Install the release to test your changes. For Embedded Cluster installations, see [Performing Udpates in Embedded Clusters](/embedded-cluster/v3/updating-embedded). For existing cluster installations with KOTS, see [Perform Updates in Existing Clusters](/enterprise/updating-app-manager). \ No newline at end of file diff --git a/docs/partials/install/_config-values-procedure.mdx b/docs/partials/install/_config-values-procedure.mdx index d9ba7a2026..09ce7c429b 100644 --- a/docs/partials/install/_config-values-procedure.mdx +++ b/docs/partials/install/_config-values-procedure.mdx @@ -1,6 +1,6 @@ To get the ConfigValues file from an installed application instance: -1. Install the target release in a development environment. You can either install the release with Replicated Embedded Cluster or install in an existing cluster with KOTS. For more information, see [Online Installation with Embedded Cluster](/enterprise/installing-embedded) or [Online Installation in Existing Clusters](/enterprise/installing-existing-cluster). +1. Install the target release in a development environment. You can either install the release with Replicated Embedded Cluster or install in an existing cluster with KOTS. For more information, see [Online Installation with Embedded Cluster](/embedded-cluster/v3/installing-embedded) or [Online Installation in Existing Clusters](/enterprise/installing-existing-cluster). 1. Depending on the installer that you used, do one of the following to get the ConfigValues for the installed instance: diff --git a/docs/partials/kurl/_kurl-availability.mdx b/docs/partials/kurl/_kurl-availability.mdx index 9944080fe6..aff2981a36 100644 --- a/docs/partials/kurl/_kurl-availability.mdx +++ b/docs/partials/kurl/_kurl-availability.mdx @@ -1,5 +1,5 @@ :::note -Replicated kURL is available only for existing customers. If you are not an existing kURL user, use Replicated Embedded Cluster instead. For more information, see [Use Embedded Cluster](/vendor/embedded-overview). +Replicated kURL is available only for existing customers. If you are not an existing kURL user, use Replicated Embedded Cluster instead. For more information, see [Use Embedded Cluster](/embedded-cluster/v3/embedded-overview). kURL is a Generally Available (GA) product for existing customers. For more information about the Replicated product lifecycle phases, see [Support Lifecycle Policy](/vendor/policies-support-lifecycle). ::: \ No newline at end of file diff --git a/docs/partials/monitoring/_limitation-ec.mdx b/docs/partials/monitoring/_limitation-ec.mdx index 62b32af924..e6cfe841c7 100644 --- a/docs/partials/monitoring/_limitation-ec.mdx +++ b/docs/partials/monitoring/_limitation-ec.mdx @@ -1 +1 @@ -Monitoring applications with Prometheus is not supported for installations with [Replicated Embedded Cluster](/vendor/embedded-overview). \ No newline at end of file +Monitoring applications with Prometheus is not supported for installations with [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview). \ No newline at end of file diff --git a/docs/partials/snapshots/_limitation-no-ec-support.mdx b/docs/partials/snapshots/_limitation-no-ec-support.mdx index 8a419e0155..973e284ecf 100644 --- a/docs/partials/snapshots/_limitation-no-ec-support.mdx +++ b/docs/partials/snapshots/_limitation-no-ec-support.mdx @@ -1 +1 @@ -The KOTS Snapshots feature is supported for existing cluster installations with KOTS and Replicated kURL installations only. Snapshots is not supported for Replicated Embedded Cluster installations. For more information about configuring backup and restore for Embedded Cluster, see [Disaster Recovery for Embedded Cluster](/vendor/embedded-disaster-recovery). \ No newline at end of file +The KOTS Snapshots feature is supported for existing cluster installations with KOTS and Replicated kURL installations only. Snapshots is not supported for Replicated Embedded Cluster installations. For more information about configuring backup and restore for Embedded Cluster, see [Disaster Recovery for Embedded Cluster](/embedded-cluster/v2/embedded-disaster-recovery). \ No newline at end of file diff --git a/docs/partials/template-functions/_ne-comparison.mdx b/docs/partials/template-functions/_ne-comparison.mdx index 66b7df17c7..aa242cd2e4 100644 --- a/docs/partials/template-functions/_ne-comparison.mdx +++ b/docs/partials/template-functions/_ne-comparison.mdx @@ -1,4 +1,4 @@ -In the example below, the `ingress_type` field is displayed on the **Config** page only when the distribution of the cluster is _not_ [Replicated Embedded Cluster](/vendor/embedded-overview). This ensures that only users deploying to their own existing cluster are able to select the method for ingress. +In the example below, the `ingress_type` field is displayed on the **Config** page only when the distribution of the cluster is _not_ [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview). This ensures that only users deploying to their own existing cluster are able to select the method for ingress. The following example uses: * KOTS [Distribution](/reference/template-functions-static-context#distribution) template function to return the Kubernetes distribution of the cluster where KOTS is running diff --git a/docs/reference/custom-resource-about.md b/docs/reference/custom-resource-about.md index 1da081019f..01d6c609c9 100644 --- a/docs/reference/custom-resource-about.md +++ b/docs/reference/custom-resource-about.md @@ -21,7 +21,7 @@ The following custom resources can be used in releases distributed with Replicat
embeddedcluster.replicated.com/v1beta1[Config](/reference/embedded-config)[Config](/embedded-cluster/v3/embedded-config) Defines a Replicated Embedded Cluster distribution
No
Supported for Embedded Cluster?Supported for Embedded Cluster? Yes
@@ -99,7 +99,7 @@ spec:

No
Supported for Embedded Cluster?Supported for Embedded Cluster? Yes
@@ -121,7 +121,7 @@ spec: No - Supported for Embedded Cluster? + Supported for Embedded Cluster? Yes @@ -150,8 +150,8 @@ spec: No - Supported for Embedded Cluster? - Embedded Cluster 1.17.0 and later supports partial rollbacks of the application version. Partial rollbacks are supported only when rolling back to a version where there is no change to the [Embedded Cluster Config](/reference/embedded-config) compared to the currently-installed version. For example, users can roll back to release version 1.0.0 after upgrading to 1.1.0 only if both 1.0.0 and 1.1.0 use the same Embedded Cluster Config. + Supported for Embedded Cluster? + Embedded Cluster 1.17.0 and later supports partial rollbacks of the application version. Partial rollbacks are supported only when rolling back to a version where there is no change to the [Embedded Cluster Config](/embedded-cluster/v3/embedded-config) compared to the currently-installed version. For example, users can roll back to release version 1.0.0 after upgrading to 1.1.0 only if both 1.0.0 and 1.1.0 use the same Embedded Cluster Config. @@ -176,7 +176,7 @@ spec: No - Supported for Embedded Cluster? + Supported for Embedded Cluster? Yes @@ -197,7 +197,7 @@ spec: No - Supported for Embedded Cluster? + Supported for Embedded Cluster? Yes @@ -218,7 +218,7 @@ spec: No - Supported for Embedded Cluster? + Supported for Embedded Cluster? Yes @@ -243,7 +243,7 @@ spec: No - Supported for Embedded Cluster? + Supported for Embedded Cluster? No @@ -268,7 +268,7 @@ spec: No - Supported for Embedded Cluster? + Supported for Embedded Cluster? No @@ -301,7 +301,7 @@ spec:

Go templates are supported in the `serviceName` and `applicationUrl` fields only.

Using Go templates in the `localPort` or `servicePort` fields results in an installation error similar to the following: `json: cannot unmarshal string into Go struct field ApplicationPort.spec.ports.servicePort of type int`.

- Supported for Embedded Cluster? + Supported for Embedded Cluster? Yes @@ -326,7 +326,7 @@ spec: Yes - Supported for Embedded Cluster? + Supported for Embedded Cluster? Yes @@ -349,7 +349,7 @@ spec: - Supported for Embedded Cluster? + Supported for Embedded Cluster? No @@ -395,7 +395,7 @@ spec: No - Supported for Embedded Cluster? + Supported for Embedded Cluster? Yes @@ -416,7 +416,7 @@ spec: No - Supported for Embedded Cluster? + Supported for Embedded Cluster? No. Setting targetKotsVersion to a version earlier than the KOTS version included in the specified version of Embedded Cluster will cause Embedded Cluster installations to fail with an error message like: Error: This version of App Name requires a different version of KOTS from what you currently have installed.. To avoid installation failures, do not use targetKotsVersion in releases that support installation with Embedded Cluster. @@ -437,7 +437,7 @@ spec: No - Supported for Embedded Cluster? + Supported for Embedded Cluster? No. Setting minKotsVersion to a version later than the KOTS version included in the specified version of Embedded Cluster will cause Embedded Cluster installations to fail with an error message like: Error: This version of App Name requires a different version of KOTS from what you currently have installed.. To avoid installation failures, do not use minKotsVersion in releases that support installation with Embedded Cluster. diff --git a/docs/reference/custom-resource-configvalues.mdx b/docs/reference/custom-resource-configvalues.mdx index 1c863dfe62..9055edd368 100644 --- a/docs/reference/custom-resource-configvalues.mdx +++ b/docs/reference/custom-resource-configvalues.mdx @@ -12,7 +12,7 @@ For information about the Replicated KOTS Config custom resource, which is used The ConfigValues resource lists the values and defaults for each application configuration item defined in the Replicated KOTS [Config](custom-resource-config) resource in the release. -In automated or headless installations, end users provide a ConfigValues resource with the install command to set the application configuration values from the command line rather than through the Admin Console UI. For more information about performing headless installations with Replicated Embedded Cluster, see [Automate Embedded Cluster Installations](/enterprise/installing-embedded-automation). For information about performing headless installations with KOTS in an existing cluster, see [Install with the KOTS CLI](/enterprise/installing-existing-cluster-automation). +In automated or headless installations, end users provide a ConfigValues resource with the install command to set the application configuration values from the command line rather than through the Admin Console UI. For more information about performing headless installations with Replicated Embedded Cluster, see [Online installation with Embedded Cluster](/embedded-cluster/v3/installing-embedded). For information about performing headless installations with KOTS in an existing cluster, see [Install with the KOTS CLI](/enterprise/installing-existing-cluster-automation). Additionally, for each installation, the Admin Console automatically generates a ConfigValues resource and makes it available for download in the Admin Console **View files** tab or with the [`kots get config`](/reference/kots-cli-get-config) command. For more information, see [Download the ConfigValues for an Installation](#download) below. diff --git a/docs/reference/template-functions-about.mdx b/docs/reference/template-functions-about.mdx index 7dd836c7cc..3d38caff9d 100644 --- a/docs/reference/template-functions-about.mdx +++ b/docs/reference/template-functions-about.mdx @@ -30,7 +30,7 @@ You can use Replicated template functions in Kubernetes manifest files for appli * Not all fields in the Config and Application custom resources support templating. For more information, see [Application](/reference/custom-resource-application) and [Item Properties](/reference/custom-resource-config#item-properties) in _Config_. -* Templating is not supported in the [Embedded Cluster Config](/reference/embedded-config) resource. +* Templating is not supported in the [Embedded Cluster Config](/embedded-cluster/v3/embedded-config) resource. * Replicated template functions are not directly supported in Helm charts. For more information, see [Helm Charts](#helm-charts) below. diff --git a/docs/reference/template-functions-examples.mdx b/docs/reference/template-functions-examples.mdx index 2c513a62e4..e2d0affb14 100644 --- a/docs/reference/template-functions-examples.mdx +++ b/docs/reference/template-functions-examples.mdx @@ -81,7 +81,7 @@ A common use case for string comparison is to compare the rendered value of a Re ### Not equal to comparison -It can be useful to compare the rendered value of a Replicated template function against another value to check if the two values are different. For example, you can conditionally show fields on the KOTS Admin Console **Config** page only when the Kubernetes distribution of the cluster where the application is deployed is _not_ [Replicated embedded cluster](/vendor/embedded-overview). +It can be useful to compare the rendered value of a Replicated template function against another value to check if the two values are different. For example, you can conditionally show fields on the KOTS Admin Console **Config** page only when the Kubernetes distribution of the cluster where the application is deployed is _not_ [Replicated embedded cluster](/embedded-cluster/v3/embedded-overview). diff --git a/docs/release-notes/rn-app-manager.md b/docs/release-notes/rn-app-manager.md index 4a41e5c582..0ddb2700d8 100644 --- a/docs/release-notes/rn-app-manager.md +++ b/docs/release-notes/rn-app-manager.md @@ -1009,7 +1009,7 @@ Support for Kubernetes: 1.26, 1.27, 1.28, and 1.29 * Adds the ability to update the config values for any app version using the admin console. ### Improvements {#improvements-1-108-0} -* Hides the **Application** and **Cluster Management** tabs on the admin console navbar during the initial installation flow with Replicated embedded cluster (Beta). For more information, see [Using Embedded Cluster](/vendor/embedded-overview). +* Hides the **Application** and **Cluster Management** tabs on the admin console navbar during the initial installation flow with Replicated embedded cluster (Beta). For more information, see [Using Embedded Cluster](/embedded-cluster/v3/embedded-overview). ### Bug fixes {#bug-fixes-1-108-0} * Fixes an issue where the license upload page flashed briefly before being redirected to the login page. @@ -1393,8 +1393,7 @@ Released on July 19, 2023 Support for Kubernetes: 1.24, 1.25, 1.26 and 1.27 ### New features {#new-features-1-101-0} -* KOTS now supports running preflight checks defined in a Helm chart. If any Helm charts in a release contain preflight specifications, KOTS runs those. If no Helm charts exist or no preflights are defined in any Helm charts, KOTS uses the previous behavior and runs any preflights defined in a `kind: Preflight` file in the root of the release. For more information about preflights in Helm charts, see [Define Preflight Checks for Helm Installations -](/vendor/preflight-helm-defining). +* KOTS now supports running preflight checks defined in a Helm chart. If any Helm charts in a release contain preflight specifications, KOTS runs those. If no Helm charts exist or no preflights are defined in any Helm charts, KOTS uses the previous behavior and runs any preflights defined in a `kind: Preflight` file in the root of the release. For more information about preflights in Helm charts, see [Define Preflight Checks for Helm Installations](/vendor/preflight-defining). ### Improvements {#improvements-1-101-0} * Updates the replicated/local-volume-provider image to v0.5.4 to resolve CVE-2023-0464 with high severity. @@ -1653,7 +1652,7 @@ Support for Kubernetes: 1.23, 1.24, 1.25, and 1.26 ### New features {#new-features-1-95-0} * Adds an `--undeploy` flag to the [kots remove](/reference/kots-cli-remove) command that allows you to completely undeploy the application and delete its resources from the cluster. -* Adds support for Azure Container Registry (ACR). For a full list of supported registries, see [Private Registry Requirements](/enterprise//installing-general-requirements#private-registry-requirements). +* Adds support for Azure Container Registry (ACR). For a full list of supported registries, see [Private Registry Requirements](/enterprise/installing-general-requirements#private-registry-requirements). * Status informers now support DaemonSets. See [Resource Statuses](/vendor/admin-console-display-app-status#resource-statuses). * When using custom branding for the admin console, you can more easily change the color of groups of elements in the admin console (Beta). @@ -1668,7 +1667,7 @@ Support for Kubernetes: 1.23, 1.24, 1.25, and 1.26 ### Known issue {#known-issues-1-95-0} -There is a known issue in the app manager v1.95.0 that causes application upgrades to fail for Helm charts that are deployed using the native Helm installation method. For more information about native Helm, see [How Replicated Deploys Helm Charts](/vendor/helm-overview#how-replicated-deploys-helm-charts) in _About Packaging with Helm_. +There is a known issue in the app manager v1.95.0 that causes application upgrades to fail for Helm charts that are deployed using the native Helm installation method. For more information about native Helm, see [How KOTS deploys Helm charts](/vendor/helm-native-about#how-kots-deploys-helm-charts) in _About distributing Helm charts with KOTS_. The upgrade failure occurs for a Helm chart when the following conditions are met: - The Helm chart in the application has been installed previously using the app manager v1.94.2 or earlier. @@ -1830,7 +1829,7 @@ Support for Kubernetes: 1.21, 1.22, 1.23, 1.24, and 1.25 ### Bug fixes {#bug-fixes-1-91-2} * Fixes overlapping labels on TLS configuration page. -* Fixes an issue that caused the login button to be stuck in the "Logging in" state in Helm-managed mode (Beta). For more information on Helm-managed mode, see [Supporting helm CLI Installations (Beta)](/vendor/helm-install). +* Fixes an issue that caused the login button to be stuck in the "Logging in" state in Helm-managed mode (Beta). For more information on Helm-managed mode, see [Supporting helm CLI Installations (Beta)](/vendor/install-with-helm). * Fixes an issue where snapshots to NFS storage locations failed due to file permission issues in environments running without MinIO. * Fixes an issue that caused the license upload to fail for applications that include Helm charts with [`required`](https://helm.sh/docs/howto/charts_tips_and_tricks/#using-the-required-function) values missing from configuration. * Fixes an issue where release notes did not display when the release notes icon was clicked on the dashboard. @@ -1892,7 +1891,7 @@ Support for Kubernetes: 1.21, 1.22, 1.23, 1.24, and 1.25 ### New features {#new-features-1-90-0} * Adds the ability to remove registry info from the **Registry settings** page. -* Adds the ability to use status informers for Helm charts when running in Helm-managed mode (Beta). For more information on Helm-managed mode, see [Supporting helm CLI Installations (Beta)](/vendor/helm-install). +* Adds the ability to use status informers for Helm charts when running in Helm-managed mode (Beta). For more information on Helm-managed mode, see [Supporting helm CLI Installations (Beta)](/vendor/install-with-helm). ### Improvements {#improvements-1-90-0} * Updates the golang.org/x/text module in the kurl-proxy image used for embedded cluster installations, to resolve CVE-2022-32149 with high severity. @@ -1913,7 +1912,7 @@ Support for Kubernetes: 1.21, 1.22, 1.23, 1.24, and 1.25 * Automatically migrates data from Postgres to rqlite and removes Postgres. Also introduces a new [kubectl kots enable-ha](/reference/kots-cli-enable-ha) command that runs rqlite as three replicas for higher availability. This command should only be run on clusters with at least three nodes. Now multiple node clusters deployed with the Kubernetes installer can use OpenEBS local PV, because data will be replicated across all three replicas of rqlite, allowing the app manager to run on any node in the cluster without requiring distributed storage like Rook provides. ### Bug fixes {#bug-fixes-1-89-0} -* Fixes an issue that causes the Released timestamp to be the same for all releases on the [version history](/enterprise/updating-apps#update-an-application-in-the-admin-console) page in [Helm managed mode (Alpha)](/vendor/helm-install). +* Fixes an issue that causes the Released timestamp to be the same for all releases on the [version history](/enterprise/updating-apps#update-an-application-in-the-admin-console) page in [Helm managed mode (Alpha)](/vendor/install-with-helm). * Allows kots CLI commands to use the kubeconfig namespace by default if a flag is not provided. * Fixes an issue where installing, updating, or configuring applications that have many images defined in KOTS custom resources (such as collectors, preflights, and analyzers) hangs or takes a long time. * Fixes an issue that could cause the preflight progress bar to be stuck at nearly 100% but never complete. @@ -1927,7 +1926,7 @@ Released on October 19, 2022 Support for Kubernetes: 1.21, 1.22, 1.23, 1.24, and 1.25 ### New features {#new-features-1-88-0} -* Adds ability to deploy an application with new values after syncing license from admin console in Helm-managed mode (Alpha). For more information on Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/helm-install). +* Adds ability to deploy an application with new values after syncing license from admin console in Helm-managed mode (Alpha). For more information on Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/install-with-helm). ### Improvements {#improvements-1-88-0} * Updates the kotsadm/dex image to v2.35.3 to resolve CVE-2022-27664 with high severity. @@ -1954,7 +1953,7 @@ Support for Kubernetes: 1.21, 1.22, 1.23, 1.24, 1.25 ### Bug fixes {#bug-fixes-1-87-0} * Fixes an issue where log tabs for Helm installs were hidden. -* Fixes a bug that caused pre-existing rows on the version history page in Helm-managed mode (Alpha) to be highlighted as newly available versions when the page is opened. For more information on Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/helm-install). +* Fixes a bug that caused pre-existing rows on the version history page in Helm-managed mode (Alpha) to be highlighted as newly available versions when the page is opened. For more information on Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/install-with-helm). * Fixes an issue that could cause embedded installations to fail with error "yaml: did not find expected node content" when installing behind an `HTTP_PROXY`. * Fixes an issue where APIs that require an auth token were called while the client was logged out. * Fixes an issue that caused the Troubleshoot page to display the support bundle collection progress bar even when a support bundle was not being collected. @@ -1978,7 +1977,7 @@ Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 * Fixes an issue where the identity service login redirected to the login page after a successful login. * Fixes an issue in the **Cluster Management** tab where the button for adding a primary node stopped working if the original join token expired. * Fixes a bug that allowed the identity service route to be accessed even if the feature was not enabled. -* Fixes a bug that caused the admin console Pod to terminate with an error due to a panic when checking for application updates in Helm-managed mode (Alpha). For more information on Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/helm-install). +* Fixes a bug that caused the admin console Pod to terminate with an error due to a panic when checking for application updates in Helm-managed mode (Alpha). For more information on Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/install-with-helm). ## 1.86.1 @@ -1993,7 +1992,7 @@ Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### Bug fixes {#bug-fixes-1-86-1} * Fixes an issue where automatic update checks failed when the interval is too short for pending updates to be fetched. * Fixes an issue where the automatic update checks modal didn't show custom schedules after they were saved. See [Configure Automatic Updates](/enterprise/updating-apps#configure-automatic-updates). -* Fixes an issue in Helm-managed mode where checking for updates from the version history page did not show the "License is expired" error when the check failed due to an expired license. For more information on Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/helm-install). +* Fixes an issue in Helm-managed mode where checking for updates from the version history page did not show the "License is expired" error when the check failed due to an expired license. For more information on Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/install-with-helm). * Fixes an issue where some icons displayed in a very large size on Firefox. See [Known Issue](#known-issues-1-86-0) under _1.86.0_. * Fixes an issue where the specified registry namespace was sometimes ignored for KOTS images if the specified registry hostname already included a namespace. @@ -2023,7 +2022,7 @@ Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 * Fixes a bug where versions with `pending_download` status caused the `View files` tab to navigate to a version that had not been downloaded yet, resulting in a UI error. * Fixes a bug where downloading an application version that is incompatible with the current admin console version made it impossible to check for updates until the admin console pod was restarted. * Fixes a bug that caused CLI feedback spinners to spin indefinitely. -* Fixes an issue that caused config templates to be applied to the wrong values.yaml file in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/helm-install). +* Fixes an issue that caused config templates to be applied to the wrong values.yaml file in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/install-with-helm). * Fixes an issue where the license was not synced when checking for application updates in Helm-managed mode (Alpha). * Fixes a bug in Helm-managed mode (Alpha) that required you to visit the config screen to deploy a new version with required config items, even if all of the config values had been set in a previously deployed version. * Fixes a bug that caused the currently deployed version to temporarily appear as a newly available version when an update check ran in Helm-managed mode (Alpha). @@ -2046,7 +2045,7 @@ Released on September 19, 2022 Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### New features {#new-features-1-85-0} -* Adds the ability to automatically check for new chart versions that are available when running in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/helm-install). +* Adds the ability to automatically check for new chart versions that are available when running in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/install-with-helm). * In Helm-managed mode, new Helm chart versions that introduce a required configuration value must be configured before they can be deployed. ### Improvements {#improvements-1-85-0} @@ -2098,11 +2097,11 @@ Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 * Icons supplied in the `icon` field of the Application custom resource can be square or circular. ### Bug fixes {#bug-fixes-1-83-0} -* Fixes an issue that could cause inadvertent application upgrades when redeploying or updating the config of the currently installed revision in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/helm-install). -* Fixes an issue where the namespace was omitted from `helm upgrade` commands displayed in the admin console in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/helm-install). -* Removes the checkbox to automatically deploy updates in Helm-managed mode, because this is unsupported. For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/helm-install). +* Fixes an issue that could cause inadvertent application upgrades when redeploying or updating the config of the currently installed revision in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/install-with-helm). +* Fixes an issue where the namespace was omitted from `helm upgrade` commands displayed in the admin console in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/install-with-helm). +* Removes the checkbox to automatically deploy updates in Helm-managed mode, because this is unsupported. For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/install-with-helm). * Fixes an issue where updating the registry settings fails due to permission issues even when the provided credentials have access to the registry. -* Fixes an issue in Helm-managed mode that could cause Replicated templates to show on the config page instead of the rendered values. For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/helm-install). +* Fixes an issue in Helm-managed mode that could cause Replicated templates to show on the config page instead of the rendered values. For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/install-with-helm). * Fixes an issue where trailing line breaks were removed during Helm chart rendering. ## 1.82.0 @@ -2114,7 +2113,7 @@ Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### New features {#new-features-1-82-0} * Adds support for a new air gap bundle format that supports image digests and deduplication of image layers shared across images in the bundle. The new air gap bundle format is in Beta. To enable this feature on your account, log in to your vendor portal account. Select **Support** > **Request a feature**, and submit a feature request for "new air gap bundle format". * Adds support for deploying images that are referenced by digest or by digest and tag, rather than by tag alone, in online installations that have a private registry configured. -* Adds support for displaying the config values for each revision deployed in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/helm-install). +* Adds support for displaying the config values for each revision deployed in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/install-with-helm). ### Improvements {#improvements-1-82-0} * Updates the `local-volume-provider image` to address CVE-2021-44716, CVE-2021-33194, and CVE-2022-21221 with high severity. @@ -2131,7 +2130,7 @@ Released on August 22, 2022 Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### Improvements {#improvements-1-81-1} -* Show deploy logs for Helm charts when running in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/helm-install). +* Show deploy logs for Helm charts when running in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Supporting helm CLI Installations (Alpha)](/vendor/install-with-helm). * Updates the Helm binary included in the kotsadm image from 3.8.2 to 3.9.3 to resolve CVE-2022-21698 and CVE-2022-27191 with high severity. * Updates the golang.org/x/net module in the kurl-proxy image used for embedded cluster installations, to resolve CVE-2021-44716 with high severity. * Updates the dex image from 2.32.0 to 2.33.0 to resolve CVE-2022-30065, CVE-2022-2097, and CVE-2022-27191 with high severity. @@ -2167,7 +2166,7 @@ Released on August 8, 2022 Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### New features {#new-features-1-80-0} -* Displays the `helm rollback` command when deploying previous revisions from the version history page in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Using Helm to Install an Application (Alpha)](/vendor/helm-install). +* Displays the `helm rollback` command when deploying previous revisions from the version history page in Helm-managed mode (Alpha). For more information about Helm-managed mode, see [Using Helm to Install an Application (Alpha)](/vendor/install-with-helm). ### Improvements {#improvements-1-80-0} * Password complexity rules will now be shown when changing the password in the admin console. @@ -2175,8 +2174,8 @@ Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### Bug fixes {#bug-fixes-1-80-0} * Fixes an issue where an ambiguous error message was shown when the endpoint field was modified in the license. -* Fixes a bug that caused values from the HelmChart custom resource that did not use Replicated template functions to be rendered into the downloaded values.yaml file after updating the configuration in Helm-managed mode. For more information about Helm-managed mode, see [Using Helm to Install an Application (Alpha)](/vendor/helm-install). -* Fixes an issue in Helm-managed mode that caused an error when clicking the **Analyze application** button on the Troubleshoot page in the admin console for an application that did not include a support bundle specification. For more information about Helm-managed mode, see [Helm-managed mode (Alpha)](/vendor/helm-install). For more information about analyzing an application, see [Create a Support Bundle Using the Admin Console](/enterprise/troubleshooting-an-app#create-a-support-bundle-using-the-admin-console) in *Troubleshooting an Application*. +* Fixes a bug that caused values from the HelmChart custom resource that did not use Replicated template functions to be rendered into the downloaded values.yaml file after updating the configuration in Helm-managed mode. For more information about Helm-managed mode, see [Using Helm to Install an Application (Alpha)](/vendor/install-with-helm). +* Fixes an issue in Helm-managed mode that caused an error when clicking the **Analyze application** button on the Troubleshoot page in the admin console for an application that did not include a support bundle specification. For more information about Helm-managed mode, see [Helm-managed mode (Alpha)](/vendor/install-with-helm). For more information about analyzing an application, see [Create a Support Bundle Using the Admin Console](/enterprise/troubleshooting-an-app#create-a-support-bundle-using-the-admin-console) in *Troubleshooting an Application*. ## 1.79.0 @@ -2186,16 +2185,16 @@ Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### New features {#new-features-1-79-0} * Adds an [HTTPSProxy](/reference/template-functions-static-context#httpsproxy) template function to return the address of the proxy that the Replicated admin console is configured to use. -* Dynamically adds collectors, analyzers, and custom redactors when collecting support bundles from the [troubleshoot](/enterprise/troubleshooting-an-app#create-a-support-bundle-using-the-admin-console) page in [Helm-managed mode (Alpha)](/vendor/helm-install). +* Dynamically adds collectors, analyzers, and custom redactors when collecting support bundles from the [troubleshoot](/enterprise/troubleshooting-an-app#create-a-support-bundle-using-the-admin-console) page in [Helm-managed mode (Alpha)](/vendor/install-with-helm). ### Improvements {#improvements-1-79-0} -* Removes the "Add new application" option when running the admin console in [Helm-managed mode (Alpha)](/vendor/helm-install). +* Removes the "Add new application" option when running the admin console in [Helm-managed mode (Alpha)](/vendor/install-with-helm). ### Bug fixes {#bug-fixes-1-79-0} * Fixes an issue that caused the [affix](/reference/custom-resource-config#affix) property of config items to be ignored. * Fixes an issue that caused the [help_text](/reference/custom-resource-config#help_text) property of config items to be ignored. * Fixes an issue that caused the license card to not be updated when switching applications in the admin console. -* Fixes the ordering of versions on the [version history](/enterprise/updating-apps#update-an-application-in-the-admin-console) page in [Helm-managed mode (Alpha)](/vendor/helm-install). +* Fixes the ordering of versions on the [version history](/enterprise/updating-apps#update-an-application-in-the-admin-console) page in [Helm-managed mode (Alpha)](/vendor/install-with-helm). * Fixes the display of node statistics in the Cluster Management tab. * Fixes an issue where legacy encryption keys were not loaded properly during snapshot restores. * Fixes an issue where snapshots would fail if a wildcard (`"*"`) was listed in the `additionalNamespaces` field of an Application manifest. @@ -2208,16 +2207,16 @@ Released on July 28, 2022 Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### New features {#new-features-1-78-0} -* The analyze application button on the [Troubleshoot tab](/enterprise/troubleshooting-an-app) now works in [Helm managed mode (Alpha)](/vendor/helm-install). -* Adds a deploy modal for versions on the [version history](/enterprise/updating-apps#update-an-application-in-the-admin-console) page in [Helm managed mode (Alpha)](/vendor/helm-install). +* The analyze application button on the [Troubleshoot tab](/enterprise/troubleshooting-an-app) now works in [Helm managed mode (Alpha)](/vendor/install-with-helm). +* Adds a deploy modal for versions on the [version history](/enterprise/updating-apps#update-an-application-in-the-admin-console) page in [Helm managed mode (Alpha)](/vendor/install-with-helm). ### Improvements {#improvements-1-78-0} * Upgrades the internal database (Postgres) used by the admin console from `10.21-alpine` to `14.4-alpine`. ### Bug fixes {#bug-fixes-1-78-0} * Fixes an issue where all [dashboard links](/vendor/admin-console-adding-buttons-links) were rewritten to use the admin console hostname instead of the hostname provided in the application manifest. -* Fixes a bug that caused errors when trying to generate `helm upgrade` commands from the [config page](/vendor/config-screen-about#admin-console-config-tab) in [Helm managed mode (Alpha)](/vendor/helm-install). -* Fixes a bug where the same version could be listed twice on the [version history](/enterprise/updating-apps#update-an-application-in-the-admin-console) page in [Helm managed mode (Alpha)](/vendor/helm-install). +* Fixes a bug that caused errors when trying to generate `helm upgrade` commands from the [config page](/vendor/config-screen-about#admin-console-config-tab) in [Helm managed mode (Alpha)](/vendor/install-with-helm). +* Fixes a bug where the same version could be listed twice on the [version history](/enterprise/updating-apps#update-an-application-in-the-admin-console) page in [Helm managed mode (Alpha)](/vendor/install-with-helm). ## 1.77.0 @@ -2226,9 +2225,9 @@ Released on July 22, 2022 Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### New features {#new-features-1-77-0} -* Displays version history information for Helm charts when running in Helm-managed mode (Alpha). For more information, see [Using Helm to Install an Application (Alpha)](/vendor/helm-install) -* License information can now be synced from the admin console's Dashboard and License pages for Helm charts when running in Helm-managed mode (Alpha). For more information, see [Using Helm to Install an Application (Alpha)](/vendor/helm-install) -* Admin console now supports limited RBAC mode when running in Helm-managed mode (Alpha). For more information, see [Using Helm to Install an Application (Alpha)](/vendor/helm-install) +* Displays version history information for Helm charts when running in Helm-managed mode (Alpha). For more information, see [Using Helm to Install an Application (Alpha)](/vendor/install-with-helm) +* License information can now be synced from the admin console's Dashboard and License pages for Helm charts when running in Helm-managed mode (Alpha). For more information, see [Using Helm to Install an Application (Alpha)](/vendor/install-with-helm) +* Admin console now supports limited RBAC mode when running in Helm-managed mode (Alpha). For more information, see [Using Helm to Install an Application (Alpha)](/vendor/install-with-helm) ### Improvements {#improvements-1-77-0} * Better handling for network errors on the Helm install modal in Helm-managed mode (Alpha). @@ -2238,7 +2237,7 @@ Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### Bug fixes {#bug-fixes-1-77-0} * Fixes an issue that caused automatic deployments not to work on channels where semantic versioning was disabled, unless the version labels were valid [semantic versions](https://semver.org/). * Fixes an issue that caused errors after the admin console pod restart until the Dashboard tab is visited in Helm-managed mode (Alpha). -* Begins using a temp directory instead of the current directory, to avoid file permissions issues when generating the `helm upgrade` command after editing the config. For more information, see [Using Helm to Install an Application (Alpha)](/vendor/helm-install). +* Begins using a temp directory instead of the current directory, to avoid file permissions issues when generating the `helm upgrade` command after editing the config. For more information, see [Using Helm to Install an Application (Alpha)](/vendor/install-with-helm). ## 1.76.1 @@ -2260,10 +2259,10 @@ Released on July 12, 2022 Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### New features {#new-features-1-76-0} -* Displays license information on the admin console Dashboard and License page for Helm charts when running in Helm-managed mode (Alpha). For more information, see [Using Helm to Install an Application (Alpha)](/vendor/helm-install) +* Displays license information on the admin console Dashboard and License page for Helm charts when running in Helm-managed mode (Alpha). For more information, see [Using Helm to Install an Application (Alpha)](/vendor/install-with-helm) ### Bug fixes {#bug-fixes-1-76-0} -* Fixes a bug that causes links defined in the [SIG Application custom resource](/reference/custom-resource-sig-application) to not be rewritten to the hostname used in the browser. +* Fixes a bug that causes links defined in the [SIG Application custom resource](/reference/custom-resource-application) to not be rewritten to the hostname used in the browser. ## 1.75.0 @@ -2272,7 +2271,7 @@ Released on July 5, 2022 Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### New features {#new-features-1-75-0} -* Adds a `helmUpgradeFlags` parameter to the [HelmChart custom resource](/reference/custom-resource-helmchart) when [Installing with Native Helm](/vendor/helm-overview). The specified flags are passed to the `helm upgrade` command. Note that the Replicated app manager uses `helm upgrade` for all installations, including initial installations, and not just when the application is upgraded. +* Adds a `helmUpgradeFlags` parameter to the [HelmChart custom resource](/reference/custom-resource-helmchart) when [Installing with Native Helm](/vendor/helm-native-about). The specified flags are passed to the `helm upgrade` command. Note that the Replicated app manager uses `helm upgrade` for all installations, including initial installations, and not just when the application is upgraded. ### Bug fixes {#bug-fixes-1-75-0} * Addresses the following critical severity CVEs: CVE-2022-26945, CVE-2022-30321, CVE-2022-30322, and CVE-2022-30323. @@ -2300,14 +2299,14 @@ Released on June 24, 2022 Support for Kubernetes: 1.21, 1.22, 1.23, and 1.24 ### New features {#new-features-1-73-0} -* Adds a `releaseName` parameter to the [HelmChart custom resource](/reference/custom-resource-helmchart) when [Installing with Native Helm](/vendor/helm-overview). Defaults to the chart name. Specifying a `releaseName` also allows you to deploy multiple instances of the same Helm chart, which was previously impossible. +* Adds a `releaseName` parameter to the [HelmChart custom resource](/reference/custom-resource-helmchart) when [Installing with Native Helm](/vendor/helm-native-about). Defaults to the chart name. Specifying a `releaseName` also allows you to deploy multiple instances of the same Helm chart, which was previously impossible. ### Improvements {#improvements-1-73-0} * Improved UX on the version history page when the application is up to date or when there are new available versions. ### Bug fixes {#bug-fixes-1-73-0} * Fixes an issue where the preflight screen was displayed even if no analyzers were run. -* Fixes an issue that prevented you from excluding a Helm chart that was previously included when [Installing with Native Helm](/vendor/helm-overview). +* Fixes an issue that prevented you from excluding a Helm chart that was previously included when [Installing with Native Helm](/vendor/helm-native-about). ## 1.72.2 @@ -2407,7 +2406,7 @@ Released on May 2, 2022 Support for Kubernetes: 1.21, 1.22, and 1.23 ### New features -* Adds a `weight` parameter to the [Helm custom resource](/reference/custom-resource-helmchart) when [Installing with Native Helm](/vendor/helm-overview). Charts are applied by weight in ascending order, with lower numbered weights applied first. +* Adds a `weight` parameter to the [Helm custom resource](/reference/custom-resource-helmchart) when [Installing with Native Helm](/vendor/helm-native-about). Charts are applied by weight in ascending order, with lower numbered weights applied first. * Adds the ability to change the admin console password from the **Change Password** link in the admin console page footer. * Adds the ability to download `Config` file types for a given application sequence. * Adds a template function `YamlEscape` to escape a string for inclusion in a YAML file. @@ -2494,9 +2493,9 @@ Released on March 21, 2022 Support for Kubernetes: 1.21, 1.22, and 1.23 ### New features -* Adds support for installing a specific application version. For more information about installing a specific application version, see [Online Installation in Existing Clusters](/enterprise/installing-existing-cluster and [Online Installation with the Kubernetes Installer](/enterprise/installing-embedded-cluster). +* Adds support for installing a specific application version. For more information about installing a specific application version, see [Online Installation in Existing Clusters](/enterprise/installing-existing-cluster) and [Online installation with kURL](/enterprise/installing-kurl). * Extends the ability of status informers to detect if the application is being updated. -* Adds the ability to provide a strict preflight, which cannot be skipped and must not have any failure outcomes. Any failure outcomes will prevent the user from deploying the application. For more information on strict preflights, see [Define KOTS Preflight Checks​](/vendor/preflight-kots-defining). +* Adds the ability to provide a strict preflight, which cannot be skipped and must not have any failure outcomes. Any failure outcomes will prevent the user from deploying the application. For more information on strict preflights, see [Define KOTS Preflight Checks​](/vendor/preflight-defining). * New versions can automatically be deployed in the admin console, regardless of whether the vendor uses semantic versioning. For more information about automatically deploying new versions, see [Configure Automatic Updates​](/enterprise/updating-apps#configure-automatic-updates) in Updating an Application. ### Bug fixes @@ -2514,7 +2513,7 @@ Support for Kubernetes: 1.21, 1.22, and 1.23 ### New features * Adds the ability to exclude the applications or the admin console from full snapshot restores using the [`kots restore`](/reference/kots-cli-restore-index) command. -* Adds the ability to display the command to restore only the admin console from a [full snapshot](/enterprise/snapshots-understanding#full-snapshots-recommended) on the Full Snapshots page in the admin console. +* Adds the ability to display the command to restore only the admin console from a [full snapshot](/enterprise/snapshots-creating#full) on the Full Snapshots page in the admin console. ### Improvements * Adds the [`--no-port-forward`](/reference/kots-cli-install#usage) flag to the `kots install` command to disable automatic port-forwarding. The old `--port-forward` flag has been deprecated. @@ -2605,7 +2604,7 @@ Supported on Kubernetes: 1.20, 1.21, 1.22, and 1.23 ### Bug fixes * Fixes a bug that caused images to be pushed to a private registry multiple times during an air gap installation. * Fixes a bug that erroneously displays a message to edit the current config when performing a new installation. -* Fixes an issue that caused [image garbage collection](../enterprise/image-registry-embedded-cluster#enable-and-disable-image-garbage-collection) to only remove images with the "latest" tag. +* Fixes an issue that caused [image garbage collection](/enterprise/image-registry-kurl#disable-image-garbage-collection) to only remove images with the "latest" tag. ## 1.60.0 @@ -2621,7 +2620,7 @@ Supported on Kubernetes: 1.20, 1.21, and 1.22 * Updates Postgres to version 10.19. ### Bug fixes -* Fixes an issue that caused images to be pushed multiple times during an [airgap installation](/enterprise/installing-existing-cluster-airgapped) when the [Native Helm](/vendor/helm-overview#native) feature is enabled. +* Fixes an issue that caused images to be pushed multiple times during an [airgap installation](/enterprise/installing-existing-cluster-airgapped) when the [Native Helm](/vendor/helm-native-about#v1beta1) feature is enabled. * Fixes an issue that prevented the deployment status labels from breaking into multiple lines on small displays. ## 1.59.3 @@ -2676,7 +2675,7 @@ Supported on Kubernetes: 1.19, 1.20, and 1.21 * Fixes a bug that caused analyzers to surface errors in namespaces not used by the application when the admin console has cluster access in existing cluster installations. * Fixes an issue that caused image pull secrets to be rendered in the admin console namespace instead of the `namespace` specified in the kots.io/v1beta1.HelmChart when using `useHelmInstall`. * Fixes the `kots pull` CLI command to properly inject `imagePullSecrets` when using Helm Charts with `useHelmInstall` set to `true`. -* Fixes a bug that causes application images to not be deleted from a [private registry](../enterprise/image-registry-embedded-cluster). +* Fixes a bug that causes application images to not be deleted from a [private registry](/enterprise/image-registry-kurl). * Fixes a bug that causes images included in support bundle's [`run` collector](https://troubleshoot.sh/docs/collect/run/#image-required) to not be deleted from a private registry. ## 1.58.2 diff --git a/docs/release-notes/rn-embedded-cluster.md b/docs/release-notes/rn-embedded-cluster.md index b8fe1f55ae..7c654c9714 100644 --- a/docs/release-notes/rn-embedded-cluster.md +++ b/docs/release-notes/rn-embedded-cluster.md @@ -6,7 +6,7 @@ pagination_prev: null # Embedded Cluster release notes -This topic contains release notes for the [Replicated Embedded Cluster](/vendor/embedded-overview) installer. The release notes list new features, improvements, bug fixes, known issues, and breaking changes. +This topic contains release notes for the [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview) installer. The release notes list new features, improvements, bug fixes, known issues, and breaking changes. Additionally, these release notes list the versions of Kubernetes and Replicated KOTS that are available with each version of Embedded Cluster. @@ -184,7 +184,7 @@ Released on January 14, 2026 ### New features {#new-features-2-13-3} -* Adds the ability to override CPU and memory requests and limits for kotsadm and rqlite through [unsupportedOverrides](/reference/embedded-config#unsupportedoverrides) in the Embedded Cluster config. +* Adds the ability to override CPU and memory requests and limits for kotsadm and rqlite through [unsupportedOverrides](/embedded-cluster/v3/embedded-config#unsupportedoverrides) in the Embedded Cluster config. ### Bug fixes {#bug-fixes-2-13-3} * Fixes an issue introduced in 2.13.1 and 2.13.2 where application upgrades could fail due to Helm v4’s default server-side apply by pinning to Helm v3 for compatibility. @@ -607,7 +607,7 @@ Released on July 2, 2025 ### Improvements {#improvements-2-7-1} -* Improves the default host support bundle generated by `./APP_SLUG support-bundle` with better diagnostics for different installation scenarios (such as air gap or proxy installations) and additional network diagnostics collecion. For more information, see [About the Default Embedded Cluster Support Bundle Spec](/vendor/embedded-troubleshooting#about-the-default-embedded-cluster-support-bundle-spec). +* Improves the default host support bundle generated by `./APP_SLUG support-bundle` with better diagnostics for different installation scenarios (such as air gap or proxy installations) and additional network diagnostics collecion. For more information, see [About the Default Embedded Cluster Support Bundle Spec](/embedded-cluster/v3/embedded-troubleshooting#about-the-default-embedded-cluster-support-bundle-spec). * Updates the Embedded Cluster CLI help menu to use the applciation name instead of the binary name (for example, "Manage the Wordpress Enterprise Admin Console" instead of "Manage the wordpress-enterprise Admin Console"). * Adds a preflight check to block XFS filesystems with `ftype=0` (`d_type` disabled), which are incompatible with the container runtime. @@ -669,7 +669,7 @@ Released on May 6, 2025 :::note Configuring node roles with the `roles` key is still beta. ::: -* Adds the `join print-command` command, which prints the commands that can be run on nodes to join them to the cluster. This command allows users to access the required join commands from the CLI, rather than needing to go to the Admin Console UI. This is particularly useful for CLI-based and automated creation of multi-node clusters. For more information, see [Automate Controller Node Joins](/enterprise/embedded-manage-nodes#automate-node-joins) in _Manage Multi-Node Clusters with Embedded Cluster_. +* Adds the `join print-command` command, which prints the commands that can be run on nodes to join them to the cluster. This command allows users to access the required join commands from the CLI, rather than needing to go to the Admin Console UI. This is particularly useful for CLI-based and automated creation of multi-node clusters. For more information, see [Automate Controller Node Joins](/embedded-cluster/v3/embedded-manage-nodes#automate-node-joins) in _Manage Multi-Node Clusters with Embedded Cluster_. * Adds support for the **Multi-node Cluster** license field, which allows you to choose whether a customer can install multi-node Embedded Clusters. If this license option is disabled, customers are not prompted to join nodes during the installation, and the **Add node** button is not present on the **Nodes** page. For more information, see [Built-In License Fields](/vendor/licenses-using-builtin-fields). ### Improvements {#improvements-2-4-0} @@ -679,17 +679,17 @@ Released on May 6, 2025 * Ensures that the version of the binary used to join a node is the same version that is currently installed on other nodes. * When prompted to enable high availability while joining a third or more controller node, the default response is yes to encourage users to enable high availability. - For more information about joining nodes, see [Manage Multi-Node Clusters with Embedded Cluster](/enterprise/embedded-manage-nodes#automate-node-joins). + For more information about joining nodes, see [Manage Multi-Node Clusters with Embedded Cluster](/embedded-cluster/v3/embedded-manage-nodes#automate-node-joins). * Adds support for configuring `--http-proxy`, `--https-proxy`, and `--no-proxy` for the `install` command through environment variables. The following environment variables can be used instead of the command line flags: * `http_proxy` or `HTTP_PROXY` * `https_proxy` or `HTTPS_PROXY` * `no_proxy` or `NO_PROXY` - For more information, see [Embedded Cluster Install Options](/reference/embedded-cluster-install). + For more information, see [Embedded Cluster Install Options](/embedded-cluster/v3/embedded-cluster-install). ### Bug fixes {#bug-fixes-2-4-0} * Fixes an issue that prevented a successful upgrade when a Helm extension was manually deleted or corrupted before the upgrade was attempted. -* Fixes an issue that prevented joining nodes after upgrading to a version that added [`workerProfiles`](/reference/embedded-config#configure-the-kubelet) in its `unsupportedOverrides` configuration. +* Fixes an issue that prevented joining nodes after upgrading to a version that added [`workerProfiles`](/embedded-cluster/v3/embedded-config#configure-the-kubelet) in its `unsupportedOverrides` configuration. * Fixes an issue where the `reset` command appeared to fail when parts of the installation were already cleaned up or were never successfully installed. ## 2.3.1 @@ -723,7 +723,7 @@ Released on April 8, 2025 ## 2.3.0 - Removed :::important -Embedded Cluster 2.3.0 has been removed because new installations do not work unless a worker profile is specified in the Embedded Cluster Config under `unsupportedOverrides`. For more information, see [Configure the Kubelet with k0s Worker Profiles](/reference/embedded-config#configure-the-kubelet). Upgrades to 2.3.0 were not affected because worker profiles are not used on upgrades. New upgrades to 2.3.0 are not available. Any users that already upgraded can continue to use 2.3.0. +Embedded Cluster 2.3.0 has been removed because new installations do not work unless a worker profile is specified in the Embedded Cluster Config under `unsupportedOverrides`. For more information, see [Configure the Kubelet with k0s Worker Profiles](/embedded-cluster/v3/embedded-config#configure-the-kubelet). Upgrades to 2.3.0 were not affected because worker profiles are not used on upgrades. New upgrades to 2.3.0 are not available. Any users that already upgraded can continue to use 2.3.0. ::: Released on April 3, 2025 @@ -957,7 +957,7 @@ Released on January 24, 2025 ### New features {#new-features-1-22-0} -* Updates the disaster recovery alpha feature so that rather than having to apply specific labels to all the resources you want backed up, you now have full control over how your application is backed up and restored. Specifically, you now provide a Velero Backup resource and a Restore resource in your application release. These resources are used to back up and restore your application, separate from the Embedded Cluster infrastructure. For more information, see [Disaster Recovery for Embedded Cluster](/vendor/embedded-disaster-recovery). +* Updates the disaster recovery alpha feature so that rather than having to apply specific labels to all the resources you want backed up, you now have full control over how your application is backed up and restored. Specifically, you now provide a Velero Backup resource and a Restore resource in your application release. These resources are used to back up and restore your application, separate from the Embedded Cluster infrastructure. For more information, see [Disaster Recovery for Embedded Cluster](/embedded-cluster/v2/embedded-disaster-recovery). ## 1.21.0 @@ -1086,7 +1086,7 @@ Released on November 4, 2024 ### New features {#new-features-1-17-0} -* Adds support for partial rollbacks. Partial rollbacks are supported only when rolling back to a version where there is no change to the Embedded Cluster Config compared to the currently-installed version. For example, users can roll back to release version 1.0.0 after upgrading to 1.1.0 only if both 1.0.0 and 1.1.0 use the same [Embedded Cluster Config](/reference/embedded-config). For more information about how to enable rollbacks for your application in the KOTS Application custom resource, see [allowRollback](/reference/custom-resource-application#allowrollback) in _Application_. +* Adds support for partial rollbacks. Partial rollbacks are supported only when rolling back to a version where there is no change to the Embedded Cluster Config compared to the currently-installed version. For example, users can roll back to release version 1.0.0 after upgrading to 1.1.0 only if both 1.0.0 and 1.1.0 use the same [Embedded Cluster Config](/embedded-cluster/v3/embedded-config). For more information about how to enable rollbacks for your application in the KOTS Application custom resource, see [allowRollback](/reference/custom-resource-application#allowrollback) in _Application_. * Introduces a new landing page and guided installation workflow for the Admin Console. ### Improvements {#improvements-1-17-0} @@ -1122,9 +1122,9 @@ Released on October 23, 2024 ### New features {#new-features-1-16-0} * Adds support for Kubernetes 1.30 and removes support for 1.28. -* Adds a `--data-dir` flag to the `install` and `restore` commands so the data directory can be specified. By default, the data directory is `/var/lib/embedded-cluster`. If the `--data-dir` flag was provided at install time, then the same data directory must be provided when restoring. For more information, see [install](/reference/embedded-cluster-install) and [Disaster Recovery for Embedded Cluster](/vendor/embedded-disaster-recovery). +* Adds a `--data-dir` flag to the `install` and `restore` commands so the data directory can be specified. By default, the data directory is `/var/lib/embedded-cluster`. If the `--data-dir` flag was provided at install time, then the same data directory must be provided when restoring. For more information, see [install](/embedded-cluster/v3/embedded-cluster-install) and [Disaster Recovery for Embedded Cluster](/embedded-cluster/v2/embedded-disaster-recovery). * Adds an `admin-console reset-password` command that allows resetting the password for the Admin Console. -* Adds a `--cidr` flag to the `install` command that replaces the `--pod-cidr` and `--service-cidr` flags. The CIDR range specified with the `--cidr` flag is split and used for both the Pod and Service CIDRs. See [install](/reference/embedded-cluster-install). +* Adds a `--cidr` flag to the `install` command that replaces the `--pod-cidr` and `--service-cidr` flags. The CIDR range specified with the `--cidr` flag is split and used for both the Pod and Service CIDRs. See [install](/embedded-cluster/v3/embedded-cluster-install). :::note The `--pod-cidr` and `--service-cidr` flags are hidden, but still functional. Replicated recommends that you update any automation that uses the `--pod-cidr` and `--service-cidr` flags to use the `--cidr` flag instead. @@ -1243,7 +1243,7 @@ Released on September 26, 2024 ### New features {#new-features-1-14-1} -* Adds host preflight checks to ensure that the required ports are open and available. For more information, see [Port Requirements](/vendor/embedded-overview#port-requirements). +* Adds host preflight checks to ensure that the required ports are open and available. For more information, see [Port Requirements](/embedded-cluster/v3/embedded-overview#port-requirements). ### Improvements {#improvements-1-14-1} @@ -1455,7 +1455,7 @@ Released on August 23, 2024 ### Improvements {#improvements-1-11-0} -* The default range available for NodePorts is now 80-32767 instead of 30000-32767. Many customers used [`unsupportedOverrides`](/reference/embedded-config#unsupportedoverrides) to configure this wider range for use with things like an ingress controller, so we have adjusted the default range accordingly. Changes to this range are not applied on upgrades, so existing installations will not be changed. +* The default range available for NodePorts is now 80-32767 instead of 30000-32767. Many customers used [`unsupportedOverrides`](/embedded-cluster/v3/embedded-config#unsupportedoverrides) to configure this wider range for use with things like an ingress controller, so we have adjusted the default range accordingly. Changes to this range are not applied on upgrades, so existing installations will not be changed. * Adds host preflight checks for connecting to replicated.app and proxy.replicated.com. If you use a custom domain for replicated.app, the custom domain will be used in the preflight check. * Adds a host preflight check to ensure that neither `nameserver localhost` nor `nameserver 127.0.0.1` is present in `resolv.conf`. diff --git a/docs/release-notes/rn-kubernetes-installer.md b/docs/release-notes/rn-kubernetes-installer.md index 1b0936ac4a..4cd5f5c55b 100644 --- a/docs/release-notes/rn-kubernetes-installer.md +++ b/docs/release-notes/rn-kubernetes-installer.md @@ -2178,7 +2178,7 @@ Released on March 21, 2022 ### Improvements - Adds [KOTS add-on](https://kurl.sh/docs/add-ons/kotsadm) version 1.67.0. -- Adds the [`app-version-label` flag](https://kurl.sh/docs/install-with-kurl/advanced-options#reference), which takes a version label as an argument and tells KOTS to install that particular version of an application. If this flag is not passed, the latest version of the application is installed. See [Online Installation with the Kubernetes Installer​](/enterprise/installing-embedded-cluster). +- Adds the [`app-version-label` flag](https://kurl.sh/docs/install-with-kurl/advanced-options#reference), which takes a version label as an argument and tells KOTS to install that particular version of an application. If this flag is not passed, the latest version of the application is installed. See [Online Installation with the Kubernetes Installer​](/enterprise/installing-kurl). ## Release v2022.03.11-0 diff --git a/docs/release-notes/rn-vendor-platform.md b/docs/release-notes/rn-vendor-platform.md index 1ec308c10c..17095f8d1a 100644 --- a/docs/release-notes/rn-vendor-platform.md +++ b/docs/release-notes/rn-vendor-platform.md @@ -485,7 +485,7 @@ Released on March 17, 2025 Released on March 13, 2025 ### New features {#new-features-v2025-03-13-5} -* Enforces that the custom domains set in the Embedded Cluster Config match the custom domains set on the channel when promoting a release. For more information about using custom domains for Embedded Cluster installations, see [domains](https://docs.replicated.com/reference/embedded-config#domains) in _Embedded Cluster Config_. +* Enforces that the custom domains set in the Embedded Cluster Config match the custom domains set on the channel when promoting a release. For more information about using custom domains for Embedded Cluster installations, see [domains](https://docs.replicated.com/embedded-cluster/v3/embedded-config#domains) in _Embedded Cluster Config_. ## V2025.03.08-0 @@ -1737,7 +1737,7 @@ Released on March 7, 2024 Released on March 7, 2024 ### New features {#new-features-v2024-03-07-0} -* Adds the Replicated embedded cluster (Beta) distribution to the compatibility matrix. For more information, see [Using Embedded Cluster](/vendor/embedded-overview). +* Adds the Replicated embedded cluster (Beta) distribution to the compatibility matrix. For more information, see [Using Embedded Cluster](/embedded-cluster/v3/embedded-overview). ## V2024.03.06-3 @@ -1758,7 +1758,7 @@ Released on February 29, 2024 Released on February 29, 2024 ### New features {#new-features-v2024-02-29-0} -* Enables the Embedded Cluster option on the customer license page. For more information, see [Using Embedded Cluster](/vendor/embedded-overview). +* Enables the Embedded Cluster option on the customer license page. For more information, see [Using Embedded Cluster](/embedded-cluster/v3/embedded-overview). ## V2024.02.27-1 diff --git a/docs/vendor/admin-console-adding-buttons-links.mdx b/docs/vendor/admin-console-adding-buttons-links.mdx index c1fa17e39c..83c0fd03e4 100644 --- a/docs/vendor/admin-console-adding-buttons-links.mdx +++ b/docs/vendor/admin-console-adding-buttons-links.mdx @@ -69,7 +69,7 @@ The following examples show how to use the KOTS [ConfigOption](/reference/templa - description: Open App url: 'http://{{repl ConfigOption "ingress_host" }}' ``` -* In the example below, both the URL hostname and a node port are user-supplied values. It might be necessary to include a user-provided node port if you are exposing NodePort services for installations on VMs or bare metal servers with [Replicated Embedded Cluster](/vendor/embedded-overview) or [Replicated kURL](/vendor/kurl-about). +* In the example below, both the URL hostname and a node port are user-supplied values. It might be necessary to include a user-provided node port if you are exposing NodePort services for installations on VMs or bare metal servers with [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview) or [Replicated kURL](/vendor/kurl-about). ```yaml apiVersion: app.k8s.io/v1beta1 diff --git a/docs/vendor/admin-console-port-forward.mdx b/docs/vendor/admin-console-port-forward.mdx index e820d06a5c..0edb85254a 100644 --- a/docs/vendor/admin-console-port-forward.mdx +++ b/docs/vendor/admin-console-port-forward.mdx @@ -204,7 +204,7 @@ To test this example: 1. Install the release into an existing cluster and confirm that the service was port-forwarded successfully by clicking **Open App** on the Admin Console dashboard. For more information, see [Online Installation in Existing Clusters with KOTS](/enterprise/installing-existing-cluster). -1. Install the release on a VM and confirm that you can open the application by clicking **Open App** on the Admin Console dashboard. For more information, see [Online Installation with Embedded Cluster](/enterprise/installing-embedded) or [Online Installation with kURL](/enterprise/installing-kurl). +1. Install the release on a VM and confirm that you can open the application by clicking **Open App** on the Admin Console dashboard. For more information, see [Online Installation with Embedded Cluster](/embedded-cluster/v3/installing-embedded) or [Online Installation with kURL](/enterprise/installing-kurl). :::note Ensure that the VM where you install allows HTTP traffic. diff --git a/docs/vendor/config-screen-conditional.mdx b/docs/vendor/config-screen-conditional.mdx index a59448afb2..ce68d69d65 100644 --- a/docs/vendor/config-screen-conditional.mdx +++ b/docs/vendor/config-screen-conditional.mdx @@ -31,7 +31,7 @@ In the following example, the `when` properties use the [Distribution](/referenc ### Embedded Cluster distribution check -It can be useful to show or hide configuration fields if the distribution of the cluster is [Replicated Embedded Cluster](/vendor/embedded-overview) because you can include extensions in embedded cluster distributions to manage functionality such as ingress and storage. This means that embedded clusters frequently have fewer configuration options for the user. +It can be useful to show or hide configuration fields if the distribution of the cluster is [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview) because you can include extensions in embedded cluster distributions to manage functionality such as ingress and storage. This means that embedded clusters frequently have fewer configuration options for the user. diff --git a/docs/vendor/custom-domains-using.md b/docs/vendor/custom-domains-using.md index 1ef76627e4..50a5224903 100644 --- a/docs/vendor/custom-domains-using.md +++ b/docs/vendor/custom-domains-using.md @@ -71,11 +71,11 @@ After you add one or more custom domains in the Vendor Portal, you can configure ### Configure Embedded Cluster to use custom domains {#ec} -You can configure Replicated Embedded Cluster to use your custom domains for the Replicated proxy registry and Replicated app service. For more information about Embedded Cluster, see [Embedded Cluster Overview](/vendor/embedded-overview). +You can configure Replicated Embedded Cluster to use your custom domains for the Replicated proxy registry and Replicated app service. For more information about Embedded Cluster, see [Embedded Cluster Overview](/embedded-cluster/v3/embedded-overview). To configure Embedded Cluster to use your custom domains for the proxy registry and app service: -1. In the [Embedded Cluster Config](/reference/embedded-config) spec for your application, add `domains.proxyRegistryDomain` and `domains.replicatedAppDomain`. Set each field to your custom domain for the given service. +1. In the [Embedded Cluster Config](/embedded-cluster/v3/embedded-config) spec for your application, add `domains.proxyRegistryDomain` and `domains.replicatedAppDomain`. Set each field to your custom domain for the given service. **Example:** @@ -89,7 +89,7 @@ To configure Embedded Cluster to use your custom domains for the proxy registry # Your app service custom domain replicatedAppDomain: updates.yourcompany.com ``` - For more information, see [domains](/reference/embedded-config#domains) in _Embedded Cluster Config_. + For more information, see [domains](/embedded-cluster/v3/embedded-config#domains) in _Embedded Cluster Config_. 1. Add the Embedded Cluster Config to a new release. Promote the release to a channel that your team uses for testing, and install with Embedded Cluster in a development environment to test your changes. diff --git a/docs/vendor/custom-domains.md b/docs/vendor/custom-domains.md index dbf9dbf57f..7a399cdead 100644 --- a/docs/vendor/custom-domains.md +++ b/docs/vendor/custom-domains.md @@ -40,7 +40,7 @@ Using custom domains has the following limitations: - Each custom domain can only be used by one team. -- For [Replicated Embedded Cluster](/vendor/embedded-overview) installations, any Helm [`extensions`](/reference/embedded-config) that you add in the Embedded Cluster Config do not use custom domains. During deployment, Embedded Cluster pulls both the repo for the given chart and any images in the chart as written. Embedded Cluster does not rewrite image names to use custom domains. +- For [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview) installations, any Helm [`extensions`](/embedded-cluster/v3/embedded-config) that you add in the Embedded Cluster Config do not use custom domains. During deployment, Embedded Cluster pulls both the repo for the given chart and any images in the chart as written. Embedded Cluster does not rewrite image names to use custom domains. ## Known issue diff --git a/docs/vendor/enterprise-portal-use.mdx b/docs/vendor/enterprise-portal-use.mdx index 2534364798..202709a450 100644 --- a/docs/vendor/enterprise-portal-use.mdx +++ b/docs/vendor/enterprise-portal-use.mdx @@ -18,7 +18,7 @@ Users can log in to the Enterprise Portal after they are invited to join a team. enterprise portal invitation email - [View a larger version of this image](enterprise-portal-invitation-email.png) + [View a larger version of this image](/images/enterprise-portal-invitation-email.png) ### Sign up for a self-service account diff --git a/docs/vendor/environment-setup.mdx b/docs/vendor/environment-setup.mdx index a6cf215f56..04a5d0cc65 100644 --- a/docs/vendor/environment-setup.mdx +++ b/docs/vendor/environment-setup.mdx @@ -269,7 +269,7 @@ Testing your releases is an important part of the commercial software distributi ### About creating a VM -You need access to a VM to test installations and updates with the [Replicated Embedded Cluster](/vendor/embedded-overview) installer: +You need access to a VM to test installations and updates with the [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview) installer: * **Option 1: Use Compatibility Matrix.** You can use Replicated Compatibility Matrix to create and SSH onto Linux VMs. For more information, see [Create and Manage Environments with CMX](/vendor/testing-how-to). diff --git a/docs/vendor/firewall-openings.mdx b/docs/vendor/firewall-openings.mdx index 45ba3029c6..832cea6e43 100644 --- a/docs/vendor/firewall-openings.mdx +++ b/docs/vendor/firewall-openings.mdx @@ -10,7 +10,7 @@ import FirewallOpeningsKurl from "../partials/install/_firewall-openings-kurl.md ## Replicated Embedded Cluster -For the complete list of Embedded Cluster installation requirements, see [Embedded Cluster Installation Requirements](/enterprise/installing-embedded-requirements). +For the complete list of Embedded Cluster installation requirements, see [Embedded Cluster Installation Requirements](/embedded-cluster/v3/installing-embedded-requirements). diff --git a/docs/vendor/helm-native-v2-using.mdx b/docs/vendor/helm-native-v2-using.mdx index fa874d34a9..4805b0d6ac 100644 --- a/docs/vendor/helm-native-v2-using.mdx +++ b/docs/vendor/helm-native-v2-using.mdx @@ -88,7 +88,7 @@ To support KOTS existing cluster or kURL installations with HelmChart v2, comple 1. For each HelmChart v2 resource in the release, configure the [optionalValues](/reference/custom-resource-helmchart-v2#optionalvalues) key to add the `kots.io/backup: velero` label and `kots.io/app-slug: APP_SLUG` annotation to all resources that you want to be included in backups with Replicated snapshots. Use a `when` statement so that these are added to resources only when the customer has the [`isSnapshotSupported`](/vendor/licenses-using-builtin-fields#admin-console-feature-options) field enabled for their license. :::note - The Replicated [snapshots](snapshots-overview) feature for backup and restore is supported only for KOTS existing cluster and kURL installations. Snapshots are not supported for installations with Embedded Cluster. For more information about disaster recovery for Embedded Cluster installations, see [Disaster Recovery for Embedded Cluster](/vendor/embedded-disaster-recovery.mdx). + The Replicated [snapshots](snapshots-overview) feature for backup and restore is supported only for KOTS existing cluster and kURL installations. Snapshots are not supported for installations with Embedded Cluster. For more information about disaster recovery for Embedded Cluster installations, see [Disaster Recovery for Embedded Cluster](/embedded-cluster/v2/embedded-disaster-recovery). ::: **Example**: diff --git a/docs/vendor/helm-packaging-airgap-bundles.mdx b/docs/vendor/helm-packaging-airgap-bundles.mdx index bb48e34fd2..183ae111aa 100644 --- a/docs/vendor/helm-packaging-airgap-bundles.mdx +++ b/docs/vendor/helm-packaging-airgap-bundles.mdx @@ -74,5 +74,5 @@ Many applications have images that are included or excluded based on a given con ## Related topics * [builder](/reference/custom-resource-helmchart-v2#builder) -* [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap) +* [Air Gap Installation with Embedded Cluster](/embedded-cluster/v3/installing-embedded-air-gap) * [Air Gap Installation in Existing Clusters with KOTS](/enterprise/installing-existing-cluster-airgapped) diff --git a/docs/vendor/kots-faq.mdx b/docs/vendor/kots-faq.mdx index f5f4d031eb..58e9132cad 100644 --- a/docs/vendor/kots-faq.mdx +++ b/docs/vendor/kots-faq.mdx @@ -41,7 +41,7 @@ It is also possible to use _virtual_ or _logical_ air gaps, in which security co Replicated supports installations into air-gapped environments. In an air gap installation, users first download the images and other assets required for installation on an internet-connected device. These installation assets are usually provided in an _air gap bundle_ that ISVs can build in the Replicated Vendor Portal. Then, users transfer the installation assets to their air-gapped machine where they can push the images to an internal private registry and install. For more information, see: -* [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap) +* [Air Gap Installation with Embedded Cluster](/embedded-cluster/v3/installing-embedded-air-gap) * [Installing and Updating with Helm in Air Gap Environments](/vendor/helm-install-airgap) ### What is the commercial sotware distribution lifecycle? @@ -103,7 +103,7 @@ To install with Embedded Cluster, users first download and extract the Embedded After the installation command finishes, users log in to the Admin Console to provide application configuration values, optionally join more nodes to the cluster, run preflight checks, and deploy the application. -Customer-specific Embedded Cluster installation instructions are provided in the Replicated Vendor Portal. For more information, see [Install with Embedded Cluster](/enterprise/installing-embedded). +Customer-specific Embedded Cluster installation instructions are provided in the Replicated Vendor Portal. For more information, see [Install with Embedded Cluster](/embedded-cluster/v3/installing-embedded). ### Does Replicated support installations into air gap environments? @@ -111,7 +111,7 @@ Yes. The Embedded Cluster and KOTS installers support installation in _air gap_ To support air gap installations, vendors can build air gap bundles for their application in the Vendor Portal that contain all the required assets for a specific release of the application. Additionally, Replicated provides bundles that contain the assets for the Replicated installers. -For more information about how to install with Embedded Cluster and KOTS in air gap environments, see [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap) and [Air Gap Installation in Existing Clusters with KOTS](/enterprise/installing-existing-cluster-airgapped). +For more information about how to install with Embedded Cluster and KOTS in air gap environments, see [Air Gap Installation with Embedded Cluster](/embedded-cluster/v3/installing-embedded-air-gap) and [Air Gap Installation in Existing Clusters with KOTS](/enterprise/installing-existing-cluster-airgapped). ### Can I deploy Helm charts with KOTS? @@ -125,7 +125,7 @@ Replicated Embedded Cluster is a successor to Replicated kURL. Compared to kURL, -For more information, see [Embedded Cluster Overview](/vendor/embedded-overview). +For more information, see [Embedded Cluster Overview](/embedded-cluster/v3/embedded-overview). ### How do I enable Embedded Cluster and KOTS installations for my application? @@ -133,7 +133,7 @@ Releases that support installation with KOTS include the manifests required by K In addition to the KOTS manifests, releases that support installation with Embedded Cluster also include the Embedded Cluster Config. The Embedded Cluster Config defines aspects of the cluster that will be provisioned and also sets the version of KOTS that will be installed. -For more information, see [Embedded Cluster Overview](/vendor/embedded-overview). +For more information, see [Embedded Cluster Overview](/embedded-cluster/v3/embedded-overview). ### Can I use my own branding? diff --git a/docs/vendor/kurl-nodeport-services.mdx b/docs/vendor/kurl-nodeport-services.mdx index d64ede731c..9e23e25eca 100644 --- a/docs/vendor/kurl-nodeport-services.mdx +++ b/docs/vendor/kurl-nodeport-services.mdx @@ -4,13 +4,13 @@ import KurlAvailability from "../partials/kurl/_kurl-availability.mdx" -This topic describes how to expose NodePort services in [Replicated Embedded Cluster](/vendor/embedded-overview) or [Replicated kURL](/vendor/kurl-about) installations on VMs or bare metal servers. +This topic describes how to expose NodePort services in [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview) or [Replicated kURL](/vendor/kurl-about) installations on VMs or bare metal servers. ## Overview For installations into existing clusters, KOTS automatically creates a port forward tunnel to expose the Admin Console. Unlike installations into existing clusters, KOTS does _not_ automatically open the port forward tunnel for installations in embedded clusters provisioned on virtual machines (VMs) or bare metal servers. This is because it cannot be verified that the ports are secure and authenticated. For more information about the KOTS port forward tunnel, see [Port Forwarding Services with KOTS](/vendor/admin-console-port-forward). -Instead, to expose the Admin Console in installations with [Embedded Cluster](/vendor/embedded-overview) or [kURL](/vendor/kurl-about), KOTS creates the Admin Console as a NodePort service so it can be accessed at the node's IP address on a node port (port 8800 for kURL installations and port 30000 for Embedded Cluster installations). Additionally, for kURL installations, the UIs of Prometheus, Grafana, and Alertmanager are also exposed using NodePorts. +Instead, to expose the Admin Console in installations with [Embedded Cluster](/embedded-cluster/v3/embedded-overview) or [kURL](/vendor/kurl-about), KOTS creates the Admin Console as a NodePort service so it can be accessed at the node's IP address on a node port (port 8800 for kURL installations and port 30000 for Embedded Cluster installations). Additionally, for kURL installations, the UIs of Prometheus, Grafana, and Alertmanager are also exposed using NodePorts. For installations on VMs or bare metal servers where your application must be accessible from the user's local machine rather than from inside the cluster, you can expose application services as NodePorts to provide access to the application after installation. diff --git a/docs/vendor/licenses-about.mdx b/docs/vendor/licenses-about.mdx index f5fdcf051b..5122dd20a5 100644 --- a/docs/vendor/licenses-about.mdx +++ b/docs/vendor/licenses-about.mdx @@ -116,7 +116,7 @@ Customers that install in online environments with a Replicated installer (Embed For online instances, Replicated installers pull license details from the Vendor Portal when: * A customer clicks **Sync license** in the Admin Console. * An automatic or manual update check is triggered -* The customer updates their instance with Replicated Embedded Cluster. See [Perform Updates with Embedded Cluster](/enterprise/updating-embedded). +* The customer updates their instance with Replicated Embedded Cluster. See [Perform Updates with Embedded Cluster](/embedded-cluster/v3/updating-embedded). * An application status changes. See [Current State](instance-insights-details#current-state) in _Instance Details_. For more information, see [Update Licenses in the Admin Console](/enterprise/updating-licenses). diff --git a/docs/vendor/licenses-install-types.mdx b/docs/vendor/licenses-install-types.mdx index 2992b3712d..6c8a3cf6a4 100644 --- a/docs/vendor/licenses-install-types.mdx +++ b/docs/vendor/licenses-install-types.mdx @@ -15,7 +15,7 @@ The following shows an example of the **Install types** field in a license: [View a larger version of this image](/images/license-install-types.png) The installation types that are enabled or disabled for a license determine the following: -* The Replicated installers ([Replicated KOTS](../intro-kots), [Replicated Embedded Cluster](/vendor/embedded-overview), [Replicated kURL](/vendor/kurl-about)) that the customer's license entitles them to use +* The Replicated installers ([Replicated KOTS](../intro-kots), [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview), [Replicated kURL](/vendor/kurl-about)) that the customer's license entitles them to use * The installation assets and/or instructions provided in the Replicated Enterprise Portal for the customer * The customer's KOTS Admin Console experience @@ -72,7 +72,7 @@ The following describes each installation type available, as well as the require
  • Your Vendor Portal team must have the Embedded Cluster entitlement
  • -
  • The latest release promoted to the channel where the customer is assigned must contain an Embedded Cluster Config custom resource. For more information, see Embedded Cluster Config.
  • +
  • The latest release promoted to the channel where the customer is assigned must contain an Embedded Cluster Config custom resource. For more information, see Embedded Cluster Config.
diff --git a/docs/vendor/licenses-using-builtin-fields.mdx b/docs/vendor/licenses-using-builtin-fields.mdx index 155aca71eb..6e80c0cfce 100644 --- a/docs/vendor/licenses-using-builtin-fields.mdx +++ b/docs/vendor/licenses-using-builtin-fields.mdx @@ -127,7 +127,7 @@ The table below describes the built-in license fields related to the supported i `isEmbeddedClusterDownloadEnabled` -

If a license supports installation with Replicated Embedded Cluster, this field is set to `true` or missing. If Embedded Cluster installations are not supported, this field is `false`.

This field requires that the vendor has the Embedded Cluster entitlement and that the release at the head of the channel includes an [Embedded Cluster Config](/reference/embedded-config) custom resource. This field also requires that the "Install Types" feature is enabled for your Vendor Portal team. Reach out to your Replicated account representative to get access.

+

If a license supports installation with Replicated Embedded Cluster, this field is set to `true` or missing. If Embedded Cluster installations are not supported, this field is `false`.

This field requires that the vendor has the Embedded Cluster entitlement and that the release at the head of the channel includes an [Embedded Cluster Config](/embedded-cluster/v3/embedded-config) custom resource. This field also requires that the "Install Types" feature is enabled for your Vendor Portal team. Reach out to your Replicated account representative to get access.

`isHelmInstallEnabled` @@ -180,7 +180,7 @@ The table below describes the built-in license fields related to the Admin Conso `isDisasterRecoverySupported` - If a license supports the Embedded Cluster disaster recovery feature, this field is set to `true`. If a license does not support disaster recovery for Embedded Cluster, this field is either missing or `false`. **Note**: Embedded Cluster Disaster Recovery is in Alpha. To get access to this feature, reach out to Alex Parker at [alexp@replicated.com](mailto:alexp@replicated.com). For more information, see [Disaster Recovery for Embedded Cluster](/vendor/embedded-disaster-recovery). + If a license supports the Embedded Cluster disaster recovery feature, this field is set to `true`. If a license does not support disaster recovery for Embedded Cluster, this field is either missing or `false`. **Note**: Embedded Cluster Disaster Recovery is in Alpha. To get access to this feature, reach out to Alex Parker at [alexp@replicated.com](mailto:alexp@replicated.com). For more information, see [Disaster Recovery for Embedded Cluster](/embedded-cluster/v2/embedded-disaster-recovery). `isGeoaxisSupported` diff --git a/docs/vendor/packaging-kots-versions.md b/docs/vendor/packaging-kots-versions.md index a633a7214d..3202b0e31a 100644 --- a/docs/vendor/packaging-kots-versions.md +++ b/docs/vendor/packaging-kots-versions.md @@ -4,7 +4,7 @@ This topic describes how to set minimum and target version for Replicated KOTS i ## Limitation -Setting minimum and target versions for KOTS is not supported for installations with [Replicated Embedded Cluster](/vendor/embedded-overview). +Setting minimum and target versions for KOTS is not supported for installations with [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview). This is because each version of Embedded Cluster includes a particular version of KOTS. Setting `targetKotsVersion` or `minKotsVersion` to a version of KOTS that does not coincide with the version that is included in the specified version of Embedded Cluster will cause Embedded Cluster installations to fail with an error message like: `Error: This version of App Name requires a different version of KOTS from what you currently have installed.`. diff --git a/docs/vendor/policies-support-lifecycle.md b/docs/vendor/policies-support-lifecycle.md index 9292caa5ed..d4a4068216 100644 --- a/docs/vendor/policies-support-lifecycle.md +++ b/docs/vendor/policies-support-lifecycle.md @@ -65,7 +65,7 @@ Replicated will provide support for products per our terms and services until th N/A - Replicated Embedded Cluster Installer + Replicated Embedded Cluster Installer GA N/A N/A diff --git a/docs/vendor/preflight-host-preflights.md b/docs/vendor/preflight-host-preflights.md index f4fcf59e7d..da5c48d936 100644 --- a/docs/vendor/preflight-host-preflights.md +++ b/docs/vendor/preflight-host-preflights.md @@ -1,6 +1,6 @@ # Customize host preflight checks for kURL -This topic provides information about how to customize host preflight checks for installations with Replicated kURL. For information about the default host preflight checks that run for installations with Replicated Embedded Cluster, see [About Host Preflight Checks](/vendor/embedded-overview#about-host-preflight-checks) in _Using Embedded Cluster_. +This topic provides information about how to customize host preflight checks for installations with Replicated kURL. For information about the default host preflight checks that run for installations with Replicated Embedded Cluster, see [About Host Preflight Checks](/embedded-cluster/v3/embedded-overview#about-host-preflight-checks) in _Using Embedded Cluster_. ## About host preflight checks You can include host preflight checks with kURL to verify that infrastructure requirements are met for: diff --git a/docs/vendor/preflight-support-bundle-about.mdx b/docs/vendor/preflight-support-bundle-about.mdx index 98a8427013..a7a7d53ea5 100644 --- a/docs/vendor/preflight-support-bundle-about.mdx +++ b/docs/vendor/preflight-support-bundle-about.mdx @@ -61,11 +61,11 @@ Thorough preflight checks provide increased confidence that an installation or u ### About host preflights {#host-preflights} -_Host preflight checks_ automatically run during [Replicated Embedded Cluster](/vendor/embedded-overview) and [Replicated kURL](/vendor/kurl-about) installations on a VM or bare metal server. The purpose of host preflight checks is to verify that the user's installation environment meets the requirements of the Embedded Cluster or kURL installer, such as checking the number of CPU cores in the system, available disk space, and memory usage. If any of the host preflight checks fail, installation is blocked and a message describing the failure is displayed. +_Host preflight checks_ automatically run during [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview) and [Replicated kURL](/vendor/kurl-about) installations on a VM or bare metal server. The purpose of host preflight checks is to verify that the user's installation environment meets the requirements of the Embedded Cluster or kURL installer, such as checking the number of CPU cores in the system, available disk space, and memory usage. If any of the host preflight checks fail, installation is blocked and a message describing the failure is displayed. Host preflight checks are separate from any application-specific preflight checks that are defined in the release, which run in the Admin Console before the application is deployed with KOTS. Both Embedded Cluster and kURL have default host preflight checks that are specific to the requirements of the given installer. For kURL installations, it is possible to customize the default host preflight checks. -For more information about the default Embedded Cluster host preflight checks, see [Host Preflight Checks](/vendor/embedded-overview#about-host-preflight-checks) in _Using Embedded Cluster_. +For more information about the default Embedded Cluster host preflight checks, see [Host Preflight Checks](/embedded-cluster/v3/embedded-overview#about-host-preflight-checks) in _Using Embedded Cluster_. For more information about kURL host preflight checks, including information about how to customize the defaults, see [Customize Host Preflight Checks for kURL](/vendor/preflight-host-preflights). @@ -135,7 +135,7 @@ The following diagram demonstrates how end customers can generate support bundle ### About host support bundles -For installations on VMs or bare metal servers with [Replicated Embedded Cluster](/vendor/embedded-overview) or [Replicated kURL](/vendor/kurl-about), it is possible to generate a support bundle that includes host-level information to help troubleshoot failures related to host configuration like DNS, networking, or storage problems. +For installations on VMs or bare metal servers with [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview) or [Replicated kURL](/vendor/kurl-about), it is possible to generate a support bundle that includes host-level information to help troubleshoot failures related to host configuration like DNS, networking, or storage problems. For Embedded Cluster installations, a default spec can be used to generate support bundles that include cluster- and host-level information. See [Generate Host Bundles for Embedded Cluster](/vendor/support-bundle-embedded). diff --git a/docs/vendor/quick-start.mdx b/docs/vendor/quick-start.mdx index a4267173bc..e753b46085 100644 --- a/docs/vendor/quick-start.mdx +++ b/docs/vendor/quick-start.mdx @@ -617,7 +617,7 @@ To get started, see [Onboard to the Replicated Platform](replicated-onboarding). For more information about the Replicated Platform features mentioned in this quick start, see: -* [Embedded Cluster Overview](/vendor/embedded-overview) +* [Embedded Cluster Overview](/embedded-cluster/v2/embedded-overview) * [About CMX](/vendor/testing-about) * [About Preflight Checks and Support Bundles](/vendor/preflight-support-bundle-about) * [About the Replicated SDK](/vendor/replicated-sdk-overview) diff --git a/docs/vendor/releases-about.mdx b/docs/vendor/releases-about.mdx index 04d4a8d64d..2cc014b7d5 100644 --- a/docs/vendor/releases-about.mdx +++ b/docs/vendor/releases-about.mdx @@ -62,7 +62,7 @@ This section provides additional information about releases, including details a ### Release files -A release contains your application files as well as the manifests required to install the application with the Replicated installers ([Replicated Embedded Cluster](/vendor/embedded-overview) and [Replicated KOTS](../intro-kots)). +A release contains your application files as well as the manifests required to install the application with the Replicated installers ([Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview) and [Replicated KOTS](../intro-kots)). The application files in releases can be Helm charts and/or Kubernetes manifests. Replicated strongly recommends that all applications are packaged as Helm charts because many enterprise customers will expect to be able to install with Helm. diff --git a/docs/vendor/releases-sharing-license-install-script.mdx b/docs/vendor/releases-sharing-license-install-script.mdx index 07e3bd894c..bbf87b5034 100644 --- a/docs/vendor/releases-sharing-license-install-script.mdx +++ b/docs/vendor/releases-sharing-license-install-script.mdx @@ -129,7 +129,7 @@ To get customer-specific Helm or Embedded Cluster installation instructions: [View a larger version of this image](/images/helm-install-instructions-dialog.png)
-

View the customer-specific Embedded Cluster installation instructions. For more information about installing with Embedded Cluster, see [Online Installation with Embedded Cluster](/enterprise/installing-embedded).

+

View the customer-specific Embedded Cluster installation instructions. For more information about installing with Embedded Cluster, see [Online Installation with Embedded Cluster](/embedded-cluster/v3/installing-embedded).

Embedded cluster install instructions [View a larger version of this image](/images/embedded-cluster-install-dialog-latest.png)
diff --git a/docs/vendor/replicated-onboarding-helm-only.mdx b/docs/vendor/replicated-onboarding-helm-only.mdx index d3577befb0..7ff8b01c83 100644 --- a/docs/vendor/replicated-onboarding-helm-only.mdx +++ b/docs/vendor/replicated-onboarding-helm-only.mdx @@ -251,6 +251,6 @@ For more information, see [Configure Custom Metrics](/vendor/custom-metrics). ### Add support for Replicated Embedded Cluster installations on a VM -Replicated Embedded Cluster is a UI-based installer that supports installations on VMs or bare metal servers. Embedded Cluster allows you to distribute a Kubernetes cluster and your application together as a single appliance, making it easy for enterprise users to install, update, and manage the application and the cluster in tandem. For more information, see [Embedded Cluster Overview](/vendor/embedded-overview). +Replicated Embedded Cluster is a UI-based installer that supports installations on VMs or bare metal servers. Embedded Cluster allows you to distribute a Kubernetes cluster and your application together as a single appliance, making it easy for enterprise users to install, update, and manage the application and the cluster in tandem. For more information, see [Embedded Cluster Overview](/embedded-cluster/v3/embedded-overview). Teams with the Business or Enterprise pricing plan can modify existing releases to support Embedded Cluster installations; it is not necessary to create and manage separate releases or channels for each installation method. For more information about how to get access to Embedded Cluster, reach out to your Replicated account representative. \ No newline at end of file diff --git a/docs/vendor/replicated-onboarding.mdx b/docs/vendor/replicated-onboarding.mdx index 74700c7d57..fd3ad050b7 100644 --- a/docs/vendor/replicated-onboarding.mdx +++ b/docs/vendor/replicated-onboarding.mdx @@ -111,7 +111,7 @@ To package your Helm chart with the Replicated SDK: After packaging your Helm chart, you can create a release. The initial release for your application will include the minimum files required to install a Helm chart with the Embedded Cluster installer: * The Helm chart `.tgz` archive * [HelmChart custom resource](/reference/custom-resource-helmchart-v2) -* [Embedded Cluster Config](/reference/embedded-config) +* [Embedded Cluster Config](/embedded-cluster/v2/embedded-config) If you have multiple charts, you will add each chart archive to the release, plus a corresponding HelmChart custom resource for each archive. @@ -137,7 +137,7 @@ To create the first release for your application: An Embedded Cluster Config must be included in the release to install with Embedded Cluster. The Embedded Cluster Config lets you define several aspects of the Kubernetes cluster that is created. - For more information, see [Use Embedded Cluster](/vendor/embedded-overview). + For more information, see [Use Embedded Cluster](/embedded-cluster/v2/embedded-overview). 1. Create a new YAML file named `YOUR_CHART_NAME.yaml`. For example, `samplechart.yaml`. In the file, add the following YAML to create a HelmChart custom resource. Update the values to match the name and version of your Helm chart. @@ -170,9 +170,9 @@ To create the first release for your application: This is a temporary measure to ensure the values get passed to the Helm chart during installation until you configure the Admin Console Config screen in a later onboarding task. If your default Helm values are sufficient for installation, you can skip this step. - 1. If your application requires that certain components are deployed before the application and as part of the Embedded Cluster itself, then update the Embedded Cluster Config to add [extensions](/reference/embedded-config#extensions). Extensions allow you to provide Helm charts that are deployed before your application. For example, one situation where this is useful is if you want to ship an ingress controller because Embedded Cluster does not include one. + 1. If your application requires that certain components are deployed before the application and as part of the Embedded Cluster itself, then update the Embedded Cluster Config to add [extensions](/embedded-cluster/v2/embedded-config#extensions). Extensions allow you to provide Helm charts that are deployed before your application. For example, one situation where this is useful is if you want to ship an ingress controller because Embedded Cluster does not include one. - For more information, see [extensions](/reference/embedded-config#extensions) in _Embedded Cluster Config_. + For more information, see [extensions](/embedded-cluster/v2/embedded-config#extensions) in _Embedded Cluster Config_. 1. From the `manifests` directory, create a release and promote it to the Unstable channel. For more information, see [Manage Releases with the Vendor Portal](releases-creating-releases) or [Managing Releases with the CLI](releases-creating-cli). @@ -182,7 +182,7 @@ To create the first release for your application: 1. Install the release in your development environment to test: - 1. Install with Embedded Cluster on a VM. See [Online Installation with Embedded Cluster](/enterprise/installing-embedded). + 1. Install with Embedded Cluster on a VM. See [Online Installation with Embedded Cluster](/embedded-cluster/v2/installing-embedded). 1. (Optional) Install in an existing cluster with KOTS. See [Online Installation in Existing Clusters with KOTS](/enterprise/installing-existing-cluster). @@ -451,7 +451,7 @@ To add support for air gap installations: 1. Create or edit a customer with the **Airgap Download Enabled** entitlement enabled so that you can test air gap installations. See [Create and Manage Customers](/vendor/releases-creating-customer). -1. Download the Embedded Cluster air gap installation assets, then install with Embedded Cluster on an air-gapped VM to test. See [Install in Air Gap Environments with Embedded Cluster](/enterprise/installing-embedded-air-gap). +1. Download the Embedded Cluster air gap installation assets, then install with Embedded Cluster on an air-gapped VM to test. See [Install in Air Gap Environments with Embedded Cluster](/embedded-cluster/v2/installing-embedded-air-gap). 1. Follow the steps in [Install and Update with Helm in Air Gap Environments](/vendor/helm-install-airgap) to access the Enterprise Portal for the customer and test air gap installation in a cluster with Helm. @@ -515,7 +515,7 @@ You can also view common examples of collectors and analyzers used in preflight Enable backup and restore with Velero for your application so that users can back up and restore their KOTS Admin Console and application data. There are different steps to configure backup and restore for Embedded Cluster and for existing cluster installations with KOTS: -* To configure the disaster recovery feature for Embedded Cluster, see [Disaster Recovery for Embedded Cluster](/vendor/embedded-disaster-recovery) +* To configure the disaster recovery feature for Embedded Cluster, see [Disaster Recovery for Embedded Cluster](/embedded-cluster/v2/embedded-disaster-recovery) * To configure the snapshots feature for existing cluster KOTS installations, see [Configure Snapshots](snapshots-configuring-backups). ### Add custom metrics diff --git a/docs/vendor/replicated-sdk-installing.mdx b/docs/vendor/replicated-sdk-installing.mdx index 01dcd97659..7b65d107c1 100644 --- a/docs/vendor/replicated-sdk-installing.mdx +++ b/docs/vendor/replicated-sdk-installing.mdx @@ -47,7 +47,7 @@ To install the SDK as a subchart: 1. Save and promote the release to an internal-only channel used for testing, such as the default Unstable channel. 1. Install the release using Helm or a Replicated installer. For more information, see: - * [Online Installation with Embedded Cluster](/enterprise/installing-embedded) + * [Online Installation with Embedded Cluster](/embedded-cluster/v3/installing-embedded) * [Installing with Helm](/vendor/install-with-helm) * [Online Installation in Existing Clusters with KOTS](/enterprise/installing-existing-cluster) * [Online Installation with kURL](/enterprise/installing-kurl) @@ -129,7 +129,7 @@ To add the SDK Helm chart to a release for a Kubernetes manifest-based applicati 1. Save and promote the release to an internal-only channel used for testing, such as the default Unstable channel. 1. Install the release using a Replicated installer. For more information, see: - * [Online Installation with Embedded Cluster](/enterprise/installing-embedded) + * [Online Installation with Embedded Cluster](/embedded-cluster/v3/installing-embedded) * [Online Installation in Existing Clusters with KOTS](/enterprise/installing-existing-cluster) * [Online Installation with kURL](/enterprise/installing-kurl) diff --git a/docs/vendor/support-bundle-embedded.mdx b/docs/vendor/support-bundle-embedded.mdx index 6180c2025e..b04ddddf36 100644 --- a/docs/vendor/support-bundle-embedded.mdx +++ b/docs/vendor/support-bundle-embedded.mdx @@ -3,7 +3,7 @@ import SupportBundleIntro from "../partials/support-bundles/_ec-support-bundle-i # Generate support bundles for Embedded Cluster -This topic describes how to generate a support bundle that includes cluster- and host-level information for [Replicated Embedded Cluster](/vendor/embedded-overview) installations. +This topic describes how to generate a support bundle that includes cluster- and host-level information for [Replicated Embedded Cluster](/embedded-cluster/v3/embedded-overview) installations. For information about generating host support bundles for Replicated kURL installations, see [Generate Host Bundles for kURL](/vendor/support-host-support-bundles). diff --git a/docs/vendor/testing-network-policy.md b/docs/vendor/testing-network-policy.md index bfefdc1ad2..fda5f71e1b 100644 --- a/docs/vendor/testing-network-policy.md +++ b/docs/vendor/testing-network-policy.md @@ -126,5 +126,5 @@ To view network reports from the CLI: ## Related topics -* [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap) +* [Air Gap Installation with Embedded Cluster](/embedded-cluster/v3/installing-embedded-air-gap) * [Install and Update with Helm in Air Gap Environments](/vendor/helm-install-airgap). \ No newline at end of file diff --git a/docs/vendor/testing-supported-clusters.md b/docs/vendor/testing-supported-clusters.md index 08ff45579d..0827b713f3 100644 --- a/docs/vendor/testing-supported-clusters.md +++ b/docs/vendor/testing-supported-clusters.md @@ -216,7 +216,7 @@ By default, kubeconfig context is set to the `kubeadmin` user. To switch to the ### Embedded Cluster -CMX supports creating clusters with Replicated Embedded Cluster. For more information, see [Embedded Cluster Overview](/vendor/embedded-overview). +CMX supports creating clusters with Replicated Embedded Cluster. For more information, see [Embedded Cluster Overview](/embedded-cluster/v3/embedded-overview). diff --git a/docs/vendor/tutorial-cmx-airgap.mdx b/docs/vendor/tutorial-cmx-airgap.mdx index 86018ddd79..a5e481f445 100644 --- a/docs/vendor/tutorial-cmx-airgap.mdx +++ b/docs/vendor/tutorial-cmx-airgap.mdx @@ -431,4 +431,4 @@ Congratulations! As part of this tutorial, you: For more information about testing with Compatibility Matrix in air-gapped environments, see [Test in Air Gap Environments](/vendor/testing-network-policy). -For more information about installing in air-gapped environments with Embedded Cluster, see [Air Gap Installation with Embedded Cluster](/enterprise/installing-embedded-air-gap). \ No newline at end of file +For more information about installing in air-gapped environments with Embedded Cluster, see [Air Gap Installation with Embedded Cluster](/embedded-cluster/v2/installing-embedded-air-gap). \ No newline at end of file diff --git a/docs/vendor/tutorial-embedded-cluster-automation.mdx b/docs/vendor/tutorial-embedded-cluster-automation.mdx index c2c263e2d5..1ed5fd3f34 100644 --- a/docs/vendor/tutorial-embedded-cluster-automation.mdx +++ b/docs/vendor/tutorial-embedded-cluster-automation.mdx @@ -8,7 +8,7 @@ This tutorial demonstrates how to perform an automated or _headless_ installatio ## Introduction -This tutorial shows how to install a Helm chart with Embedded Cluster from the command line without interacting with the Admin Console UI. This is also known as a _headless_ installation. Headless installations are often used for automating application deployment as part of CI/CD pipelines. For more information about headless installs with Embedded Cluster, see [Automating Installation with Embedded Cluster](/enterprise/installing-embedded-automation). +This tutorial shows how to install a Helm chart with Embedded Cluster from the command line without interacting with the Admin Console UI. This is also known as a _headless_ installation. Headless installations are often used for automating application deployment as part of CI/CD pipelines. For more information about headless installs with Embedded Cluster, see [Automate installation with Embedded Cluster](/embedded-cluster/v2/installing-embedded-automation). In this tutorial, you will: @@ -370,4 +370,4 @@ Congratulations! As part of this tutorial, you: * Created a ConfigValues file * Performed a headless install of the release on a VM with Embedded Cluster -For more information about headless installs with Embedded Cluster, see [Automating Installation with Embedded Cluster](/enterprise/installing-embedded-automation). \ No newline at end of file +For more information about headless installs with Embedded Cluster, see [Automate installation with Embedded Cluster](/embedded-cluster/v2/installing-embedded-automation). \ No newline at end of file diff --git a/embedded-cluster/embedded-cluster-install.mdx b/embedded-cluster/embedded-cluster-install.mdx index b5e06779e2..d5516733cc 100644 --- a/embedded-cluster/embedded-cluster-install.mdx +++ b/embedded-cluster/embedded-cluster-install.mdx @@ -1,6 +1,6 @@ # install (Beta) -This topic describes the options available with the Embedded Cluster `install` command. For procedural steps, see [Online installation with Embedded Cluster](installing-embedded), [Air gap installation with Embedded Cluster](installing-embedded-air-gap), and [Automate installation with Embedded Cluster](installing-embedded-automation). +This topic describes the options available with the Embedded Cluster `install` command. For procedural steps, see [Online installation with Embedded Cluster](installing-embedded), [Air gap installation with Embedded Cluster](installing-embedded-air-gap), and [Automate installation with Embedded Cluster](installing-embedded). ## Usage diff --git a/netlify.toml b/netlify.toml index 0d1e059c5e..7fd5166f1d 100644 --- a/netlify.toml +++ b/netlify.toml @@ -490,7 +490,7 @@ [[redirects]] from="/enterprise/installing-embedded-cluster" - to="/embedded-cluster/v3/installing-embedded" + to="/enterprise/installing-kurl" [[redirects]] from="/enterprise/updating-embedded-cluster" @@ -502,7 +502,7 @@ [[redirects]] from="/vendor/releases-configvalues" - to="/embedded-cluster/v2/installing-embedded-automation" + to="/reference/custom-resource-configvalues" [[redirects]]