The cmp chart installs a complete Gentics Content Management Platform into a single Kubernetes namespace with one helm install. It is an umbrella chart: it does not contain the components themselves, it depends on the individual product charts and adds the pieces that only make sense when they are deployed together — a bundled MariaDB, a shared license secret, the database bootstrap job and cross-component wiring.

If you deploy the components individually (separate releases, separate lifecycles, external database), use the per-component charts instead — see Kubernetes installation of the individual charts.

    What the chart deploys

    ComponentValues sectionChartEnabled by default
    Gentics CMScmscmsyes
    Gentics Meshmeshgentics-meshyes
    Gentics Portal | Javaportal-javagentics-portal-javano
    Gentics Portal | PHPportal-phpgentics-portal-phpno
    MariaDB (bundled/or external)mariadb(templates of this chart)yes (global.mariadb.enabled)

    Each component is switched on and off with <section>.enabled. The switch is a Helm dependency condition, so a disabled component renders nothing at all.

    In addition to the component charts, the umbrella chart itself renders:

    ResourceNamePurpose
    StatefulSet, Service, PVC, ConfigMap, Secret <release>-mariadb bundled MariaDB (single instance)
    Secret <release>-license shared CMP license key (only when global.license.key is set)
    Secret <release>-cms-db, <release>-mesh-db generated database passwords for CMS and Mesh
    Job (post-install hook) <release>-db-init creates the cms and mesh databases, users and grants

    Both portal charts have no pre-built image — you build your own portal image and reference it. The single exception is the example installation, which ships a ready-made reference portal.

    Prerequisites

    • Kubernetes 1.23 or newer. The chart declares kubeVersion: ">=1.23.0-0"; Helm refuses to install on older clusters.
    • Helm 3. Several templates use lookup, so generated passwords survive upgrades.
    • A namespace for the installation. One CMP release per namespace is the recommended layout.
    • An image pull secret for docker.gentics.com, created in that namespace. Your Gentics technical customer consultant provides the credentials. The chart references it through global.imagePullSecrets (default: docker-gentics-com).
    • A CMP license key, also provided by your consultant.
    • A default StorageClass, or explicit storageClass values per volume. The chart requests ReadWriteOnce volumes for MariaDB and CMS data and ReadWriteMany for the Mesh shared volume (uploads, keystore) — the latter needs a shared filesystem (typically NFS) as soon as Mesh runs with more than one replica.
    • The Gentics Helm repository:
    helm repo add --username USERNAME --password PASSWORD \
      gentics https://repo.gentics.com/repository/helm/
    helm repo update
    

    Optional, depending on what you enable: Elasticsearch (Mesh search, Content RAG), Keycloak (Portal authentication), an external MariaDB.

    Installation

    Create the pull secret and inspect the defaults:

    kubectl -n NAMESPACE create secret docker-registry docker-gentics-com \
      --docker-server=docker.gentics.com \
      --docker-username=USERNAME --docker-password=PASSWORD
    
    helm show values gentics/cmp > my-cmp-values.yaml
    

    Keep your own my-cmp-values.yaml under version control and install with it:

    helm -n NAMESPACE upgrade --install -f my-cmp-values.yaml cmp gentics/cmp
    

    A minimal CMS + Mesh + MariaDB installation needs nothing but the license key:

    helm -n NAMESPACE upgrade --install cmp gentics/cmp \
      --set global.license.key='YOUR-LICENSE-KEY'
    

    cmp is the release name and prefixes every resource, so keep it short. All examples below assume it.

    Do not add --wait to the first install. The database bootstrap runs as a post-install hook, and Helm runs post-install hooks only after its readiness wait — while CMS and Mesh cannot become ready before their databases exist. --wait would therefore time out on a fresh install. Watch the rollout with kubectl get pods -w instead.

    To pin the chart version, add e.g. --version 8.4.5. The component images follow the appVersion explicitly, and the release process keeps those versions aligned with the CMP version.

    Configuration

    Values are organised in three groups:

    1. global.* — settings shared by all components.

    ValueDefaultEffect
    global.imageRegistry "" Replaces the registry of every image, including the Docker Hub ones (MariaDB, spellchecker, the API-key job's curl image). Your mirror must proxy those too.
    global.imagePullSecrets [{name: docker-gentics-com}] Pull secrets for all component pods.
    global.license.key "" Creates <release>-license; CMS, Mesh and Portal | Java read the key from it.
    global.mariadb.enabled true Deploys the bundled MariaDB and wires CMS and Mesh to it.
    global.mesh.enabled true Tells the portals that this release deploys Mesh, so their connection is auto-wired. Must match mesh.enabled.
    global.persistence.keepOnUninstall true Whether PVCs survive helm uninstall and Argo CD pruning.
    global.example.enabled false Example installation.

    2. <component>.* — everything the component chart itself offers. The keys under cms, mesh, portal-java and portal-php are passed to the respective sub-chart unchanged and merged with its own defaults, so anything the component chart supports works here too. The values file of this chart only carries the handful of keys that need a CMP-specific default; for the full list of options ask the component chart:

    helm show values gentics/cms
    helm show values gentics/gentics-mesh
    helm show values gentics/gentics-portal-java
    helm show values gentics/gentics-portal-php
    

    3. mariadb.* — the bundled MariaDB (image, root password, persistence, service, resources, probes, config). Only evaluated while global.mariadb.enabled is true.

    Precedence: a value set inside a component section always wins over the corresponding global.* value. Note the naming: the sub-charts are aliased, so the Mesh section is mesh (not gentics-mesh) and the portal sections are portal-java / portal-php. Because of the dash, --set needs quoting in most shells:

    helm ... --set 'portal-java.enabled=true'
    

    Rendering fails immediately, before anything is applied, when global.mesh.enabled and mesh.enabled disagree. Check any change without touching the cluster:

    helm -n NAMESPACE template cmp gentics/cmp -f my-cmp-values.yaml | less
    


    Database

    Bundled MariaDB

    global.mariadb.enabled: true deploys a single MariaDB instance and does the wiring for you:

    • CMS and Mesh get <release>-mariadb:3306 as their database host.
    • The <release>-db-init post-install job creates database cms with user node and database mesh with user mesh, using the passwords from <release>-cms-db and <release>-mesh-db.
    • The root password is taken from mariadb.auth.rootPassword, or generated once and persisted in <release>-mariadb.

    The bundled instance is a single pod with a ReadWriteOnce volume and no replication — convenient for evaluation, test stages and small installations. For production, weigh it against a managed or clustered database.

    Database names and users can be changed via cms.database.name / cms.database.username and mesh.database.name / mesh.database.username; the init job picks them up.

    The init job is a post-install hook — it does not run on upgrades. If you enable a component later (e.g. mesh.enabled: false → true on an existing release), its database, user and grants are not created for you. Create them in the bundled MariaDB by hand, using the password from the corresponding Secret:

    kubectl -n NAMESPACE exec -it cmp-mariadb-0 -- mariadb -u root -p
    


    External database

    Set global.mariadb.enabled: false and configure both components explicitly. Nothing is created or bootstrapped for you — database, users and grants have to exist:

    global:
      mariadb:
        enabled: false
    
    cms:
      database:
        host: db.example.com
        port: "3306"
        name: cms
        username: node
        passwordSecret: cms-db-secret     # Secret with key "password"
    
    mesh:
      database:
        host: db.example.com
        port: 3306
        name: mesh
        username: mesh
        passwordSecret: mesh-db-secret    # Secret with key "password"
    


    Instead of passwordSecret you may set password directly; the chart then creates the Secret from the value. Missing values are reported as database.host is required when global.mariadb.enabled is false at render time.


    Generated credentials

    Where a password is not configured, it is generated on first install, stored in a Secret and reused on every later upgrade (the templates read the existing Secret back). Read them out with:

    # CMS "node" user
    kubectl -n NAMESPACE get secret cmp-cms \
      -o jsonpath='{.data.node-user-password}' | base64 -d; echo
    
    # Mesh "admin" user
    kubectl -n NAMESPACE get secret cmp-mesh-admin \
      -o jsonpath='{.data.password}' | base64 -d; echo
    
    # MariaDB root
    kubectl -n NAMESPACE get secret cmp-mariadb \
      -o jsonpath='{.data.root-password}' | base64 -d; echo
    

    To set them yourself: cms.nodeUserPassword / cms.nodeUserPasswordSecret, mesh.credentials.initialAdminPassword / mesh.credentials.existingSecret, mariadb.auth.rootPassword / mariadb.auth.existingSecret.


    Mesh API key for the portals

    Both portals authenticate against Mesh with an API key. The Mesh chart can issue it itself, which is the intended path under the umbrella:

    mesh:
      generateApiKey: true
    

    A Job waits for Mesh to become ready, logs in as admin and patches the token into the Secret <release>-mesh-secret (key apikey) — exactly the Secret the portals read by default. Details that matter in operation:

    • The (empty) Secret is always rendered, so switching the flag off later removes only the Job; the stored key stays.
    • Create-once: an existing key is never regenerated, because Mesh invalidates the previous token whenever a new one is issued.
    • Issuing the token invalidates any other API token of that Mesh user.
    • Forced regeneration: kubectl -n NAMESPACE delete secret cmp-mesh-secret, then run helm upgrade (or an Argo CD sync) with the flag enabled.
    • A portal pod that starts before the key exists stays in CreateContainerConfigError until the Job has patched it in. That resolves itself.

    Alternatives: point the portal at a Secret you manage (portal-java.mesh.secretName, portal-php.mesh.secretName), or pass the key inline (portal-java.mesh.apiKeyFromSecret: false plus portal-java.mesh.apikey, portal-php.mesh.apikey).


    Exposing the services

    All Charts have the option to create a Ingress. The Ingress is disabled by default so an installation is only reachable within the cluster. You can use the built in Ingress or you create Ingress / VirtualServer on your own

    E.g for CMS a ingress can be enabled in the values.yaml

    cms:
      cms:
        ingress:
          enabled: true
          host: cms.example.com
          tls: true
          secretName: cms-example-com-tls
    

    Without an ingress, reach a component through a port-forward:

    kubectl -n NAMESPACE port-forward svc/cmp-cms 8080:80
    


    Persistence and Uninstall

    All PVCs created by the charts carry, by default:

    helm.sh/resource-policy: keep
    argocd.argoproj.io/sync-options: Delete=false
    

    so helm uninstall and Argo CD pruning leave the data behind, and reinstalling with the same release name picks the old volumes up again. An accidental uninstall is therefore never a data-loss event.

    For throwaway installations, turn that off — either globally or per component:

    global:
      persistence:
        keepOnUninstall: false      # all components
    
    mariadb:
      persistence:
        keepOnUninstall: true       # ... except this one
    

    Precedence, highest first: the component's own persistence.keepOnUninstall → global.example.enabled: true (forces "delete", see Example installation) → global.persistence.keepOnUninstall → keep.

    Removing volumes regardless of the flags:

    kubectl -n NAMESPACE delete pvc -l app.kubernetes.io/instance=cmp
    


    Example installation

    The example installation deploys a ready-made reference project instead of requiring you to build and supply your own portal image. It is meant for a first look at a complete CMP — CMS, Mesh, MariaDB and a working Portal | Java in front of them — not as a starting point for a real project.

    helm -n NAMESPACE upgrade --install cmp gentics/cmp \
      --set global.example.enabled=true \
      --set 'portal-java.enabled=true' \
      --set global.license.key='YOUR-LICENSE-KEY' \
      --set 'portal-java.portal.server.url=https://portal.example.com' \
      --set mesh.generateApiKey=true
    


    The same as a values file:

    global:
      example:
        enabled: true
      license:
        key: "YOUR-LICENSE-KEY"
    
    mesh:
      generateApiKey: true
      ingress:
        enabled: true
        hosts:
          - host: mesh.example.com
            paths: ["/"]
    
    portal-java:
      enabled: true
      portal:
        server:
          url: https://portal.example.com
      ingress:
        enabled: true
        host: portal.example.com
    

    What happens when global.example.enabled is true:

    • global.example.portalJavaImage replaces portal-java.image entirely — anything you configure under portal-java.image is ignored, and the otherwise mandatory portal-java.image.repository is not required.
    • The reference portal receives the extra environment from global.example.env: INIT_EXAMPLE=true, the in-cluster CMS URL, the CMS node password and the Mesh admin password from their Secrets, plus MESH_SCHEMA_PREFIX=example and MESH_PROJECT=Example. On first start the portal image uses these to create the demo project in Mesh and the matching content in the CMS.
    • Because the portal needs the CMS and Mesh credentials, the example only works together with the components of the same release (cms.enabled and mesh.enabled, both default).
    • Persistent volumes are no longer marked to be kept. The example is a throwaway demo, so the PVC keep annotations are dropped and helm uninstall takes its volumes with it. This overrides global.persistence.keepOnUninstall — setting that to true does not bring the annotations back. A per-component <component>.persistence.keepOnUninstall: true still wins, if you really want to keep one volume (e.g. mariadb.persistence.keepOnUninstall: true).

    Four values are required, and the chart checks them all at once — a single failed helm install reports the complete list rather than one problem per attempt:

    Watch the rollout and retrieve the credentials for the CMS and Mesh backends:

    kubectl -n NAMESPACE get pods -w
    
    kubectl -n NAMESPACE get secret cmp-cms \
      -o jsonpath='{.data.node-user-password}' | base64 -d; echo
    kubectl -n NAMESPACE get secret cmp-mesh-admin \
      -o jsonpath='{.data.password}' | base64 -d; echo
    

    To remove the demo again:

    helm -n NAMESPACE uninstall cmp
    

    Its volumes go with it (see above), so nothing is left behind.

    The Example Demo Installation is only for a Preview, it should not be used for a real Website

    Upgrading

    helm repo update
    helm -n NAMESPACE upgrade -f my-cmp-values.yaml cmp gentics/cmp --version 8.5.0
    
    • Always upgrade with your values file (or --reuse-values); a bare helm upgrade falls back to the chart defaults.
    • Review the changelog before a version jump.
    • Pin your version  --version 8.5.0  , this avoids unintentional version upgrades
    • Generated passwords are read back from their Secrets and stay stable across upgrades.
    • Component image tags follow the component chart's appVersion, so a chart upgrade moves the images too — unless you pinned <section>.image.tag.
    • helm upgrade --install is safe to use for the first install as well; that is what the --install flag is for.

    Uninstalling

    helm -n NAMESPACE uninstall cmp
    

    PVCs (and therefore CMS data, Mesh uploads and the database) remain unless keepOnUninstall was set to false; see Persistence and uninstall. Secrets created by the chart are removed with the release — copy out any password you still need before uninstalling.

    GitOps / Argo CD

    Two properties of the chart matter for a GitOps setup:

    • Generated passwords rely on lookup. Argo CD renders manifests without cluster access in some configurations, and a render without lookup would produce a new random password. Reference pre-created Secrets instead, so nothing is generated: mariadb.auth.existingSecret, mesh.credentials.existingSecret, cms.nodeUserPasswordSecret, cms.database.passwordSecret, mesh.database.passwordSecret, global.license.key replaced by per-component license.secret.
    • The Mesh API-key Job is a plain Job, not a Helm hook — deliberately, because post-install hooks deadlock with helm --wait and with Argo CD (both wait for the consumers to become healthy while the consumers wait for the key). It runs alongside the other resources and the portal pods start as soon as the key is patched in.

    The PVC annotation argocd.argoproj.io/sync-options: Delete=false keeps volumes out of Argo CD's pruning; see Persistence and uninstall.

    Troubleshooting

    SymptomCause and fix
    Inconsistent values: global.mesh.enabled is true but mesh.enabled is false Either enable the bundled Mesh, or set global.mesh.enabled=false and point the portals at your external Mesh (portal-java.mesh.host/port, portal-php.mesh.url).
    The example installation ... cannot be installed — N value(s) missing The list in the message is complete; see Example installation.
    database.host is required when global.mariadb.enabled is false Configure cms.database.* / mesh.database.*, or re-enable the bundled MariaDB.
    portal-java has no pre-built image Set portal-java.image.repository (and image.tag) to your own portal image, or use the example installation.
    Portal pod in CreateContainerConfigError The Mesh API key is not in <release>-mesh-secret yet. Check the <release>-mesh-apikey-* Job; see Mesh API key.
    Pods in ImagePullBackOff Pull secret missing or wrong in the namespace, or global.imageRegistry set to a mirror that does not proxy Docker Hub or does not have access to docker.gentics.com
    CMS or Mesh pod cannot reach the database Check the <release>-db-init Job — it creates databases, users and grants and retries until MariaDB answers.
    PVCs stay behind after helm uninstall By design, see Persistence and uninstall.

    Useful commands:

    kubectl -n NAMESPACE get pods,svc,pvc,jobs
    kubectl -n NAMESPACE logs job/cmp-db-init
    kubectl -n NAMESPACE logs -l app.kubernetes.io/name=mesh-apikey
    kubectl -n NAMESPACE describe pod POD          # events at the bottom
    helm -n NAMESPACE get values cmp               # what the release actually runs with
    helm -n NAMESPACE history cmp