Skip to main content
Version: next

Enterprise Deployment Guide

The Enterprise Edition is intended for production deployment on Kubernetes + Helm, offering high availability, an external database, proper TLS certificates, and dynamic credential management — suitable for formal delivery and large-scale operations.

Production installation takes just two steps: ① copy values-production-template.yaml to my-values.yaml and fill in the required fields; ② run install-production.sh. The installer automatically installs cert-manager, generates the service-password Secret, creates the database CA certificate Secret, and runs helm install. You only fill in the values and enter a few passwords at the interactive prompts.

Prerequisites

Cluster Requirements

ItemMinimum
Kubernetes version1.24+
Nodes≥ 2 (≥ 3 recommended for production)
CPU / node≥ 8 cores
Memory / node≥ 16 GB
Disk / node≥ 100 GB

Required Tools

kubectl (matching the cluster version), helm 3.8+, openssl, and ctr (the containerd CLI, used for offline image loading).

For offline mode, skopeo is recommended: the installer auto-detects it and prefers pushing images directly to the private registry, skipping the containerd step and significantly speeding up import. If absent, it falls back to ctr.

External Dependencies

  • PostgreSQL 12+ (external database — see External Database)
  • ReadWriteMany shared storage (NFS / Alibaba NAS / AWS EFS / Azure Files / Tencent CFS — see Storage)
  • TLS certificate: issued by cert-manager (the installer installs cert-manager v1.13.0 automatically)

Firewall Ports

PortPurpose
443HTTPS access
5432PostgreSQL
2049NFS (if using NFS)
6443Kubernetes API

Installation Overview

Prepare cluster/deps → Create my-values.yaml → Prepare external DB → Prepare storage → Run installer

Prepare the values File

1. Copy the Template

cd <package-dir> # enter the package root
cp values-production-template.yaml my-values.yaml

2. Image Registry Configuration (choose one of two modes)

Where images come from and whether authentication is required is determined by global.registryAuth.enabled:

Mode A: True online (default, recommended)Mode B: Offline + private registry
Use casecluster can reach the internet; images in a public cloud registryoffline/intranet, or push images to your own private registry
global.itomImage.registrypublic cloud address, e.g. swr.cn-east-3.myhuaweicloud.comprivate registry, e.g. registry.example.com:5000
global.registryAuth.enabledfalsetrue
global.registryAuth.usernameemptyprivate registry username
global.registryAuth.plainHttpfalsetrue for HTTP; false for HTTPS
global.imagePullSecrets[] (template default, no change)[] (script injects the real secret)
Offline image bundlenot needed, not loadedrequired (auto-detected from ${package}/images or via --product-tar)
Registry password prompt at installnoyes (or via --registry-password-stdin)

Mode A (online, no auth) key snippet:

global:
itomImage:
registry: &registry "swr.cn-east-3.myhuaweicloud.com" # Huawei Cloud SWR public registry
tag: "<actual-version>"
vendorImage:
registry: *registry
customizedImage:
registry: *registry
registryAuth:
enabled: false # online mode: no auth
imagePullSecrets: [] # no pull secret online

Mode B (offline + private registry) key snippet:

global:
itomImage:
registry: &registry "registry.example.com:5000" # your private registry
tag: "<actual-version>"
vendorImage:
registry: *registry
customizedImage:
registry: *registry
registryAuth:
enabled: true # private/offline mode
username: "user" # username (password entered interactively at install)
plainHttp: true # true for HTTP; false for HTTPS
imagePullSecrets: [] # leave empty; script injects the real secret
Where to find the image version

<actual-version> (global.itomImage.tag) can be obtained from the IMAGE_TAG field in version.txt under the installation directory.

3. Fill in the Remaining Required Fields

Open my-values.yaml and search for TODO-SET-. The template uses YAML anchors so each value is filled in only once; other locations follow automatically (★ marks the single fill-in point):

ValueSingle fill-in pathDescriptionExample
Image versionglobal.itomImage.tagproduct image tagactual version
Access domain ★app.hostFQDN; also the cert CN/SANcmdb.example.com
Context pathapp.contextPathdefault /itom; can be / or /cmdb/itom
External DB host ★externalDatabase.hostPostgreSQL addresspg.internal
External DB portexternalDatabase.portPostgreSQL port5432
External DB userexternalDatabase.userPostgreSQL usernameitom_user
DB CA cert pathexternalDatabase.ssl.caCertPathrequired only for verify-ca/verify-fullconf/certificates/db-ca.pem

★ items: ingress.hosts / ingress.tls / env.HOST follow the domain; env.POSTGRES_HOST follows the DB host.

Domain and database key snippet:

app:
host: &domain "cmdb.example.com" # single fill-in point
contextPath: "/itom" # path prefix; can be / or /cmdb
externalDatabase:
enabled: true
host: &dbhost "pg.external" # single fill-in point
port: 5432
user: "itom_user"
ssl:
mode: "verify-full"
caCertPath: "conf/certificates/db-ca.pem"
Self-check

After filling in, run grep -n "TODO-SET-" my-values.yaml — it should return nothing. The installer also validates; any leftover TODO-SET- aborts the install.

4. TLS Mode (choose one)

ModeUse caseWhat to do
selfSigned (default)no own CAdo nothing — cert-manager self-signs and auto-renews
userCAhave an enterprise CAplace ca.crt / ca.key under conf/certificates/ and set tls.mode: "userCA" (the script imports it into cert-manager as a CA Issuer)

5. High Availability (optional)

The production template enables HA by default: business services replicaCount: 2; keycloak/forwardauth/traefik replicas: 2; nats cluster of 3 nodes. Increase replicas for higher availability, or lower them under resource constraints.

External Database

Production uses an external PostgreSQL (the template sets postgresql.enabled: false + externalDatabase.enabled: true).

Create in PostgreSQL Before Install

One user + three databases. Recommended names hyo_itom / hyo_proxy / hyo_keycloak (pre-filled in the template); you may customize them, but they must match the SQL below and my-values.yaml:

-- Create the application user (password must match the DB password entered interactively at install)
CREATE USER itom_user WITH PASSWORD 'your_strong_password';

-- Create databases and set OWNER (recommended: OWNER automatically has full privileges on the database, no extra GRANT needed)
CREATE DATABASE hyo_itom OWNER itom_user;
CREATE DATABASE hyo_proxy OWNER itom_user;
CREATE DATABASE hyo_keycloak OWNER itom_user;

-- ⚠️ If you prefer NOT to make itom_user the OWNER, you must grant schema and table privileges in each database separately:
-- \c hyo_itom
-- GRANT USAGE, CREATE ON SCHEMA public TO itom_user;
-- ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO itom_user;
-- ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO itom_user;
-- -- To access existing tables (created by superuser before migration):
-- GRANT ALL ON ALL TABLES IN SCHEMA public TO itom_user;
-- GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO itom_user;
-- -- (Repeat for hyo_proxy / hyo_keycloak by switching with \c)

Notes:

  • The three names in externalDatabase.databases are pre-filled (matching the SQL above). If you customize them, update CREATE DATABASE and GRANT ... ON DATABASE accordingly — all three must be identical.
  • The DB password is never written to a file: it is entered interactively at install (and must match the SQL above).
  • DB CA certificate: place it inside the package (e.g. conf/certificates/db-ca.pem); required only when ssl.mode is verify-ca or verify-fulldisable/prefer can omit it.
  • Ensure K8s nodes can reach PostgreSQL on port 5432.

Storage

Multi-node production requires ReadWriteMany shared storage. Storage is specified via a --storage-values overlay and is not written into my-values.yaml.

NFS (default)

Edit examples/values-storage-nfs.yaml with your NFS server and paths:

storage:
nfs:
server: "<nfs_server_ip>" # your NFS server address
dataPath: "<nfs_data_path>" # NFS data path
logsPath: "<nfs_logs_path>" # NFS logs path

Prerequisites: the NFS server exports these paths (recommend no_root_squash). The nfs-subdir-external-provisioner is auto-detected by the installer — if missing, it is installed automatically (online via the product SWR image; offline bundles include the chart and image). Pass --skip-nfs-provisioner to skip.

Cloud Shared Storage

The package ships with several cloud storage overlays — choose the one for your cloud and fill in its parameters:

Overlay filePlatform
examples/values-storage-alicloud-nas.yamlAlibaba Cloud ACK NAS
examples/values-storage-aws-efs.yamlAWS EKS EFS
examples/values-storage-azure-files.yamlAzure AKS Files
examples/values-storage-tencent-cfs.yamlTencent Cloud TKE CFS

For Alibaba NAS, the two StorageClasses (alicloud-nas-data / alicloud-nas-logs) are created automatically by the Helm chart at install (ACK ships the CSI NAS driver, so no separate provisioner is needed).

Verify the StorageClass

kubectl get sc

Run the Installation

./scripts/install-production.sh \
-n itom-prod \
-f my-values.yaml \
--storage-values examples/values-storage-nfs.yaml
Language

The installer auto-detects the OS language; use --lang en|zh to force a specific output language.

The script then prompts you for (each confirmed twice, no empty values):

  • Online mode (registryAuth.enabled=false): ① Keycloak system-tenant sysadmin password (tenant 100000000); ② Keycloak default-tenant admin password (tenant 100000001); ③ external database password.
  • Offline/private-registry mode (registryAuth.enabled=true): additionally ① registry password first (→ imagePullSecret), then as above.

Notes:

  • Online mode has no registry password prompt (images are pulled publicly).
  • Keycloak passwords must satisfy the policy: at least 8 characters with upper/lowercase/digit/special.
  • All other internal service keys are auto-generated (e.g. Keycloak master admin).
  • TLS is issued automatically by cert-manager per tls.mode — no certificate input required.
  • If AI config is empty, the script warns that AI is unavailable and (in interactive mode) asks whether to continue. AI is optional — you may continue.

Access URL

After installation, open this URL in a browser (<webSecurePort> is app.webSecurePort in my-values.yaml, default 31025 in the production template; contextPath defaults to /itom):

https://<app.host>:<webSecurePort><contextPath>/ui/100000001

To expose the service via a public load balancer, additionally pass --expose-values examples/values-expose-<cloud>.yaml (Alibaba CLB / AWS NLB / Azure LB / Tencent CLB are supported).

Credential Management

All passwords live only in cluster K8s Secrets — no plaintext credential file is left on disk.

SecretContents
${RELEASE}-secrets (default itom-secrets)service passwords: Keycloak, DB, encryption keys, etc.
${RELEASE}-registry-secret (default itom-registry-secret)registry credentials (offline/private mode only)

You already know the passwords you entered interactively; auto-generated passwords can be retrieved from the Secret at any time (example: DB password):

kubectl get secret itom-secrets -n itom-prod -o jsonpath='{.data.postgres-password}' | base64 -d

Common keys in ${RELEASE}-secrets:

keyPurpose
keycloak-admin-passwordKeycloak master realm admin (Keycloak ops only)
keycloak-sysadmin-passwordsystem-tenant sysadmin bootstrap credential
keycloak-tenant-admin-passworddefault-tenant admin bootstrap credential
keycloak-client-secret / keycloak-service-account-client-secretOAuth client secrets
postgres-passwordexternal database password
forwardauth-cookie-secret / forwardauth-encryption-keyForwardauth session/encryption keys
field-encryption-master-keyfield-encryption master key (SM4; rotation makes encrypted fields undecryptable)
csrfTokenSecretCSRF token signing key

AI Model Configuration (optional)

AI assistant and AI-driven operations require an OpenAI-compatible LLM. All three values are required to enable AI; leaving any empty disables AI.

ValuePathDescription
Model nameservices.aiAgent.env.ITOM_MODEL_NAMELLM model identifier
Base URLservices.aiAgent.env.ITOM_MODEL_BASE_URLOpenAI-compatible endpoint
API keyservices.aiAgent.env.ITOM_MODEL_API_KEYLLM bearer key (empty → AI disabled)

Set in my-values.yaml:

services:
aiAgent:
env:
ITOM_MODEL_NAME: "GLM-5"
ITOM_MODEL_BASE_URL: "https://open.bigmodel.cn/api/coding/paas/v4"
ITOM_MODEL_API_KEY: "xx-xxxx"

Or pass via CLI flags at install: --itom-model-name / --itom-model-base-url / --itom-model-api-key. Auxiliary task models (ITOM_MEMORY_* / ITOM_ARTIFACT_* / ITOM_PII_LLM_*) are optional cost knobs that fall back to the main model when empty. To enable AI later, run ./scripts/update-secret.sh ai-model (see Change Passwords).

Post-install Verification

# Pod status (should all be Running / Completed)
kubectl get pods -n itom-prod

# PVC status (should all be Bound)
kubectl get pvc -n itom-prod

# Certificate status
kubectl get certificate -n itom-prod

# Access (port-forward test)
kubectl port-forward -n itom-prod svc/itom-cmdb-ui 8000:8000
# Open in browser: http://localhost:8000

Upgrade and Rollback

Upgrade (preserve existing passwords)

For routine upgrades (e.g. changing the image version), do not re-run install-production.sh — it regenerates service passwords. Use helm upgrade directly; the existing ${RELEASE}-secrets is reused:

# 1. Edit my-values.yaml (e.g. update global.itomImage.tag)
# 2. Extract the chart from the package
tar xzf charts/itom-*.tgz -C /tmp
# 3. Upgrade (reuses existing Secret, does not regenerate passwords)
helm upgrade itom /tmp/itom -n itom-prod \
-f my-values.yaml \
-f examples/values-storage-nfs.yaml
tip

Only re-run install-production.sh if you intend to rotate all service passwords (e.g. a security audit), which rebuilds ${RELEASE}-secrets.

Rollback

helm history itom -n itom-prod
helm rollback itom <REVISION> -n itom-prod

Certificates are renewed automatically by cert-manager — no manual action. Back up the database before upgrading: pg_dump -h <host> -U <user> hyo_itom > hyo_itom_backup.sql.

Change Passwords

After install, use scripts/update-secret.sh to update an individual password without re-running the installer. All passwords are entered interactively or via stdin/env — never on the command line.

# General form
./scripts/update-secret.sh -n <namespace> [-r <release>] <subcommand> [options]
SubcommandDescription
db-passwordChange the external DB password. Order matters: first run ALTER USER ... WITH PASSWORD ... in PostgreSQL, then run this command to update the Secret and automatically roll the affected Deployments (brief connection interruption during rollout).
registry-passwordRecreate the imagePullSecret, no restart needed (newly scheduled Pods use the new credential).
ai-modelUpdate the AI model configuration (to enable/change AI after install).

Keycloak login passwords (sysadmin / tenant admin) live in Keycloak's own database; the corresponding Secret keys are bootstrap-only. To change the login password afterward, use the Keycloak admin console (master realm admin → target realm → Users → Credentials → Reset) — do not edit the Secret.

Troubleshooting

SymptomCheck / cause
Pod CrashLoopBackOffkubectl logs <pod> -n itom-prod --previous; common causes: image not loaded, DB not ready, insufficient resources
DB connection failurekubectl exec deploy/itom-cmdb -n itom-prod -- sh -c 'PGPASSWORD=$POSTGRES_PASSWORD psql -h $POSTGRES_HOST -U $POSTGRES_USER -d $POSTGRES_DB -c "SELECT 1"'; verify password and SSL mode
PVC stuck Pendingkubectl describe pvc <name> -n itom-prod; check StorageClass, NFS provisioner, NAS mount-point VPC
Browser certificate errorkubectl describe certificate itom-tls -n itom-prod (Events); confirm app.host DNS resolves correctly
Image pull failurecheck imagePullSecret creation, registry connectivity, image present on all nodes
Online-mode Pod ImagePullBackOffconfirm global.imagePullSecrets: [] (template default), image is public, nodes have egress

More diagnostics:

kubectl describe pod <pod-name> -n itom-prod | grep -A5 Events
kubectl logs <pod-name> -n itom-prod --tail=100

Next Steps

After installation is complete, you can: