ArgoCD Deployment Patterns
1. Overview
EMS services are deployed to Kubernetes via ArgoCD. One ArgoCD Application manifest per (service × environment) declares which chart version to pull, which values to apply, and which namespace to deploy into. ArgoCD watches the manifest repository and reconciles the live cluster state against the declared state.
Manifests live outside this repository — in ~/dev/idl-xnl-jhb-rc01/argocd/ (locally; repository name idl-xnl-jhb-rc01). That repository is the source of truth for what runs where. This page documents the patterns so new services can slot in.
See also: Helm Chart Structure, Jib Docker Build.
2. Manifest Layout
idl-xnl-jhb-rc01/argocd/
├── event-admin-service-dev.yml
├── event-admin-service-stage.yml
├── event-admin-service-prod.yml
├── registration-portal-dev.yml
├── registration-portal-stage.yml
├── registration-portal-prod.yml
├── membership-ui-dev.yml
├── ...
├── admin-portal-dev.yml # future (WS7)
├── admin-portal-stage.yml
├── admin-portal-prod.yml
├── opentelemetry-collector.yml
├── mysql-idealogic-prod.yml
├── external-dns.yml
├── certificates.yml # cert-manager issuers
└── ...
Convention: one file per ArgoCD Application, named <service>-<env>.yml. Infrastructure (OTel collector, ingress certs, MySQL operator) has its own files at the top level.
3. Application Manifest Structure
Reference: idl-xnl-jhb-rc01/argocd/event-admin-service-prod.yml.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: event-admin-service-prod
namespace: argocd
spec:
project: default
destination:
name: idl-xnl-jhb1-rc01
namespace: event-prod
source:
repoURL: registry-1.docker.io
chart: christhonie/event-admin-service
targetRevision: 2.3.31-RELEASE
helm:
releaseName: prod-event-admin-service
valuesObject:
config:
profiles: "prod,kubernetes"
existingsecret: event-admin-service
db:
url: mysql://idealogic-prod.mysql.svc.cluster.local:6446/wpca_prod?useUnicode=true&characterEncoding=utf8
username: event-membership-prod
security:
oauth2:
enabled: false
issuer: https://...
mail:
host: myriadevents-co-za.mail.protection.outlook.com
port: 25
username: [email protected]
# password: via existingsecret, NOT inline
liquibase:
contexts: "prod"
otel:
enabled: true
url: "http://opentelemetry-collector.observability.svc.cluster.local:4318"
image:
pullPolicy: IfNotPresent
imagePullSecrets:
- name: christhonie-docker
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
Key fields:
| Field | Purpose |
|---|---|
|
|
|
|
|
ArgoCD cluster secret name (currently all one cluster: |
|
|
|
|
|
|
|
Pinned chart version — bump this to promote a release |
|
|
|
Environment-specific values; merged over chart defaults |
|
|
4. Environments
| Env | Namespace | Purpose |
|---|---|---|
dev |
|
Continuous deployment from |
stage |
|
Pre-release testing. Manual promotion of specific release versions. Prod-cloned data (see |
prod |
|
Live traffic. Manual promotion, approval gate, pinned versions only. |
Release flow:
-
Feature branch merged to
develop— CI buildsX.Y.Z-SNAPSHOT, dev ArgoCD picks up automatically. -
Release branch cut — CI builds
X.Y.Z-RELEASE. -
Stage ArgoCD manifest updated (commit to
idl-xnl-jhb-rc01) to point atX.Y.Z-RELEASE— ArgoCD reconciles within seconds. -
UAT in stage.
-
Prod ArgoCD manifest updated to
X.Y.Z-RELEASE— ArgoCD reconciles.
No latest tag ever referenced in stage or prod manifests.
5. Secret Management
Every prod manifest uses existingsecret: <name>. The secret is created out-of-band with kubectl create secret or via SealedSecrets. Never put secrets in the ArgoCD manifest — it is committed to git.
Known secret shapes:
5.1. event-admin-service secret (prod)
Keys:
-
jwtencryptionkey— admin-service signing key -
dbpassword— MySQL password -
mailpassword— SMTP password -
apikey— admin-service’s own copy of the portal-to-admin-service API key -
externalauthsecretkey— base64 secret for external-auth endpoints -
jasperreportspassword— credentials for the Jasper Reports integration
5.2. event-admin-portal secret (future prod)
Keys:
-
apikey— portal’s X-API-KEY for calling admin-service -
oidcclientsecret— OIDC client secret -
any portal-specific credentials
Create the secret when onboarding the environment:
kubectl create secret generic event-admin-portal \
-n event-prod \
--from-literal=apikey=<value> \
--from-literal=oidcclientsecret=<value>
Rotation is a runbook activity — see API-Key Injection § Rotation Procedure.
6. Promotion Pattern
Concrete steps to promote admin-service from stage to prod:
-
Verify stage has the new version running cleanly —
kubectl get deploy -n event-stage, smoke-test the URL. -
In
idl-xnl-jhb-rc01, editargocd/event-admin-service-prod.yml:spec: source: targetRevision: 2.3.32-RELEASE # was 2.3.31-RELEASE -
Commit + push. ArgoCD webhook or poll picks up the change within seconds.
-
Watch rollout:
argocd app get event-admin-service-prod --refresh kubectl rollout status deploy/prod-event-admin-service -n event-prod -
If rollout fails — rollback is reverting the commit (argocd auto-reconciles back to the previous version).
ArgoCD’s automated.selfHeal: true means manual kubectl edit on a live resource is reverted on the next sync. Always make changes via the manifest, not the cluster.
7. Infrastructure Applications
Non-service ArgoCD apps in the same repo:
| App | Purpose |
|---|---|
|
OTel Collector deployment — receives OTLP from all services, exports to the observability backend. See OpenTelemetry Configuration. |
|
Oracle MySQL Operator + cluster. Managed by the operator; we provide the |
|
The operator itself |
|
External-DNS configuration for ingress record management |
|
cert-manager ClusterIssuers (Let’s Encrypt prod + staging) |
|
Redis for session sharing (fallback to Hazelcast; keep for future needs) |
|
Memcached — legacy, under review |
|
GreenMail deployment in the dev cluster for SMTP testing |
|
StorageClass + PV setups |
|
Bastion host for MySQL / in-cluster debugging — see |
|
Adjacent systems; not EMS core but deployed by the same mechanism |
8. admin-portal ArgoCD Onboarding
WS7 tasks:
-
Create
admin-portal-dev.yml/admin-portal-stage.yml/admin-portal-prod.ymlinidl-xnl-jhb-rc01/argocd/. Copy from registration-portal-<env>.yml as the shape closest to admin-portal. -
Adjust:
-
chart: christhonie/event-admin-portal -
targetRevision: <first-published-version> -
releaseName: dev-event-admin-portal/stage-event-admin-portal/prod-event-admin-portal -
Namespace follows the convention (
event-dev/event-stage/event-prod) -
config.profiles:"dev,kubernetes,api-docs"for dev,"prod,kubernetes,api-docs,otlp"for prod -
config.services.eventadminservice: in-cluster URL -
config.security.oauth2: populated with the staff IdP -
Ingress host:
admin-dev.event.idealogic.co.za,admin-stage.event.idealogic.co.za,admin.event.idealogic.co.za
-
-
Create the
event-admin-portalsecret in each namespace withapikey+oidcclientsecret. -
Verify
christhonie-dockerimage-pull secret exists in each namespace. -
Push the manifests; ArgoCD reconciles.
9. Operational Notes
-
Sync hooks: none in current use. ArgoCD’s pre/post sync hooks (e.g. database migration jobs) are not needed because Liquibase runs on app startup.
-
Sync wave: ordering is not currently enforced via
argocd.argoproj.io/sync-wave. All resources come up simultaneously. -
Health checks: default Kubernetes health (Deployment Ready) is used. Custom health for Helm-managed resources relies on the chart’s own probes (
/livez,/readyz).
If a chart upgrade introduces a CRD or new resource type, ArgoCD may need a restart to recognise it — rare; the standard Kubernetes types cover every current resource.
10. Troubleshooting
10.1. ArgoCD app stays OutOfSync after chart bump
-
argocd app get <name> --refresh— force a re-read from the chart repo. -
If still stuck, inspect the rendered manifest:
argocd app manifests <name>— validate againstkubectl apply --dry-run=server -f -. -
Check the chart was actually published:
helm pull oci://registry-1.docker.io/christhonie/event-admin-service --version <ver>locally.
11. Reference
| File | Role |
|---|---|
|
Full prod Application example |
|
Portal-shaped Application example |
|
Infrastructure Application example |
|
The chart that ArgoCD templates |