Zammad · Operate
This runbook deploys the service from apps/zammad/ and completes the configuration that Kubernetes cannot supply by itself. Start with the shared deployment workflow for repository rendering, credentials, and Argo CD ownership.
1. Prepare dependencies and inputs
-
Set
ZAMMAD_*variables, including database, Redis, Elasticsearch, S3, and ingress. Prepare CNPG, OpenEBS, Garage, and RTX quorum capacity. -
Reseal the Secret documents in
secrets.yaml. Wait for the chart’s init/migration job before evaluating Rails readiness.
2. Reconcile the application
Publish the reviewed manifests and shared variables to the branch tracked by your Argo CD Applications. Local edits are not deployment inputs until that branch contains them. Let the root app-of-apps discover this service and retain its declared hook order; do not apply files containing unresolved variable placeholders directly.
From the repository root, inspect the Application and its namespace:
/home/linuxbrew/.linuxbrew/bin/kubectl --kubeconfig kubeconfig \ -n argocd get application zammad
/home/linuxbrew/.linuxbrew/bin/kubectl --kubeconfig kubeconfig \ -n zammad get pods,svc,pvcWait for required controllers, database initialization, and migration Jobs before testing the user workflow. Synced configuration, ready workloads, and a successful user transaction are separate milestones.
3. Complete identity and first access
The deployment mounts an OIDC authorization adapter that maps verified zammad-users to Customer and zammad-admins to Admin plus Agent, synchronizing built-in roles on login while retaining custom roles. The underlying OIDC provider credentials remain post-deployment configuration. Complete the initial administrator wizard, then use Zammad’s supported third-party authentication settings for the deployed version. If integrating Authentik, copy the callback or service-provider metadata supplied by Zammad into the provider, configure the corresponding client secret or signing certificate, and map identities deliberately. Keep a local administrator until role and group access work for ordinary users.
4. Connect and operate the service
-
Configure support groups, roles, business hours, ticket states, and inbound/outbound email channels. Use a dedicated mailbox credential.
-
Send a message from an external mailbox, confirm ticket creation, reply, and confirm delivery. Exercise an attachment and search.
-
Establish database/object backups and document recovery of scheduled and real-time processing.
Website contact forms
Zammad’s built-in form channel creates customer tickets without distributing an
agent API token. Enable it under Channels → Form and select the receiving group.
These settings live in the Zammad database and must be preserved in backups.
Keep the honeypot and per-IP/global submission limits enabled. Browser clients
request /api/v1/form_config with a fingerprint, then submit its token and the
same fingerprint to /api/v1/form_submit. They must handle validation errors
returned with HTTP 200 and report success only when a ticket number is returned.
If CAPTCHA is enabled, the client must implement the selected provider’s challenge.
For a public website with a private Zammad hostname, proxy only the form
configuration and submission POST endpoints through the website’s origin.
apps/antblu/ supplies the portfolio container’s CONTACT_UPSTREAM from
ANTBLU_CONTACT_UPSTREAM in apps/variables.yaml. The website image owns
its Nginx template; publish that image together with the deployment input.
The proxy preserves Zammad’s honeypot and submission limits and forwards the
client address. It grants no access to authenticated ticket administration.
Ticket creation and delivery of an email reply are separate operations. Configure and verify the receiving group’s outbound email channel for replies. See the official form channel guide.
Availability before maintenance
Partially HA: paired HTTP tiers and data services, with singleton real-time/background roles and Redis/search caveats.
Chart init/migration Jobs gate the upgrade. PDB/paired HTTP replicas do not guarantee compatible schema operation or continuous scheduler/WebSocket service. Keep initialization status separate from current HTTP readiness.
Establish Redis election/rejoin correctness and shard-copy evidence, protect Garage, and assess whether the deployed version supports replication of scheduler/WebSocket roles. Record email-to-ticket, reply, attachment, and search behavior through one-node loss.
Use the component-by-component failure contract before a node drain, database promotion, or upgrade. Restoring a healthy replica count must include data resynchronization and restored voting capacity, not just Running pods.
5. Maintain and recover
Back up PostgreSQL, Garage objects, and application credentials. Elasticsearch indexes can be rebuilt from authoritative application data using the upstream procedure, but search remains degraded until rebuilding completes. Preserve identity and email-channel configuration stored in the database.
Before an upgrade, read the release notes for the pinned target and record a recovery point. A previous image tag is not a database rollback after a schema migration. Use routine operations and disaster recovery for the platform sequence.
Troubleshooting
If Argo remains Progressing while Rails serves traffic, inspect the current init Job, ownerReferences, and hook status. For missing email, inspect scheduler and channel errors. For search failures, inspect Elasticsearch quorum and indexing separately from ticket storage.
Manifest and upstream reference
Official Zammad documentation.
The pinned chart omits Deployment rollout settings. rollout-strategy.yaml sets
maxSurge: 0 and maxUnavailable: 1 for Rails and Nginx before updates, using a
scoped Sync hook. Argo excludes those hook-owned strategy fields from comparison.
This releases a worker slot while preserving one serving replica; the default
percentage budget otherwise stalls against required two-worker anti-affinity.
