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.yamltomy-values.yamland fill in the required fields; ② runinstall-production.sh. The installer automatically installs cert-manager, generates the service-password Secret, creates the database CA certificate Secret, and runshelm install. You only fill in the values and enter a few passwords at the interactive prompts.
Prerequisites
Cluster Requirements
| Item | Minimum |
|---|---|
| Kubernetes version | 1.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
| Port | Purpose |
|---|---|
| 443 | HTTPS access |
| 5432 | PostgreSQL |
| 2049 | NFS (if using NFS) |
| 6443 | Kubernetes 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 case | cluster can reach the internet; images in a public cloud registry | offline/intranet, or push images to your own private registry |
global.itomImage.registry | public cloud address, e.g. swr.cn-east-3.myhuaweicloud.com | private registry, e.g. registry.example.com:5000 |
global.registryAuth.enabled | false | true |
global.registryAuth.username | empty | private registry username |
global.registryAuth.plainHttp | false | true for HTTP; false for HTTPS |
global.imagePullSecrets | [] (template default, no change) | [] (script injects the real secret) |
| Offline image bundle | not needed, not loaded | required (auto-detected from ${package}/images or via --product-tar) |
| Registry password prompt at install | no | yes (or via --registry-password-stdin) |
Mode A (online, no auth) key snippet:
global:
itomImage:
registry: ®istry "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: ®istry "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
<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):
| Value | Single fill-in path | Description | Example |
|---|---|---|---|
| Image version | global.itomImage.tag | product image tag | actual version |
| Access domain ★ | app.host | FQDN; also the cert CN/SAN | cmdb.example.com |
| Context path | app.contextPath | default /itom; can be / or /cmdb | /itom |
| External DB host ★ | externalDatabase.host | PostgreSQL address | pg.internal |
| External DB port | externalDatabase.port | PostgreSQL port | 5432 |
| External DB user | externalDatabase.user | PostgreSQL username | itom_user |
| DB CA cert path | externalDatabase.ssl.caCertPath | required only for verify-ca/verify-full | conf/certificates/db-ca.pem |
★ items:
ingress.hosts/ingress.tls/env.HOSTfollow the domain;env.POSTGRES_HOSTfollows 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"
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)
| Mode | Use case | What to do |
|---|---|---|
selfSigned (default) | no own CA | do nothing — cert-manager self-signs and auto-renews |
userCA | have an enterprise CA | place 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.databasesare pre-filled (matching the SQL above). If you customize them, updateCREATE DATABASEandGRANT ... ON DATABASEaccordingly — 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 whenssl.modeisverify-caorverify-full—disable/prefercan 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 file | Platform |
|---|---|
examples/values-storage-alicloud-nas.yaml | Alibaba Cloud ACK NAS |
examples/values-storage-aws-efs.yaml | AWS EKS EFS |
examples/values-storage-azure-files.yaml | Azure AKS Files |
examples/values-storage-tencent-cfs.yaml | Tencent 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
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.
| Secret | Contents |
|---|---|
${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:
| key | Purpose |
|---|---|
keycloak-admin-password | Keycloak master realm admin (Keycloak ops only) |
keycloak-sysadmin-password | system-tenant sysadmin bootstrap credential |
keycloak-tenant-admin-password | default-tenant admin bootstrap credential |
keycloak-client-secret / keycloak-service-account-client-secret | OAuth client secrets |
postgres-password | external database password |
forwardauth-cookie-secret / forwardauth-encryption-key | Forwardauth session/encryption keys |
field-encryption-master-key | field-encryption master key (SM4; rotation makes encrypted fields undecryptable) |
csrfTokenSecret | CSRF 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.
| Value | Path | Description |
|---|---|---|
| Model name | services.aiAgent.env.ITOM_MODEL_NAME | LLM model identifier |
| Base URL | services.aiAgent.env.ITOM_MODEL_BASE_URL | OpenAI-compatible endpoint |
| API key | services.aiAgent.env.ITOM_MODEL_API_KEY | LLM 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
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]
| Subcommand | Description |
|---|---|
db-password | Change 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-password | Recreate the imagePullSecret, no restart needed (newly scheduled Pods use the new credential). |
ai-model | Update 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
| Symptom | Check / cause |
|---|---|
Pod CrashLoopBackOff | kubectl logs <pod> -n itom-prod --previous; common causes: image not loaded, DB not ready, insufficient resources |
| DB connection failure | kubectl 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 Pending | kubectl describe pvc <name> -n itom-prod; check StorageClass, NFS provisioner, NAS mount-point VPC |
| Browser certificate error | kubectl describe certificate itom-tls -n itom-prod (Events); confirm app.host DNS resolves correctly |
| Image pull failure | check imagePullSecret creation, registry connectivity, image present on all nodes |
Online-mode Pod ImagePullBackOff | confirm 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:
- Refer to Global Toolbar to learn basic interface operations
- Refer to Navigation Menu to learn module navigation
- Start using the Quick Start guide for initial setup