In our previous post, How to Deploy dotCMS Using Helm Charts on Kubernetes – A Step-by-Step Guide, we walked through the basics of deploying dotCMS using Helm on a local Kubernetes cluster. That guide covered how to get dotCMS up and running quickly with a straightforward setup.
In this follow-up, we take a step further into GitOps by introducing ArgoCD, a continuous delivery tool designed for Kubernetes. While Helm packages and templates your application, ArgoCD continuously ensures that your cluster matches the desired state stored in Git. Together, Helm and ArgoCD provide a powerful, automated, and GitOps-friendly workflow for managing dotCMS deployments.
What is ArgoCD?
ArgoCD is a declarative GitOps continuous delivery tool for Kubernetes. It continuously monitors your Git repositories and ensures that what’s running in your cluster matches what’s defined there.
Instead of manually applying YAML files or running helm install, ArgoCD automatically reconciles your environment whenever changes are committed to Git.
Key features include:
Applications as code: Deployments are defined declaratively as Kubernetes CRDs.
Automated sync: Changes pushed to Git are reflected automatically in the cluster.
Health & drift detection: Monitors resource health and reverts unexpected changes.
Auditability: Every change is traceable through Git history.
Why Use ArgoCD with dotCMS?
Deploying dotCMS via Helm already simplifies packaging and configuration. Adding ArgoCD brings consistency, automation, and transparency:
A visual dashboard to monitor the health and sync status of dotCMS over time.
Version-controlled configurations being the single source of truth.
Rapid and safe updates: push a change in Git (e.g. bump version), ArgoCD picks it up.
Easy rollbacks by reverting Git commits.
Stronger audit trails and consistency across environments (dev, staging, prod).
Also, dotCMS publishes stable and unique Docker image tags (for example, dotcms/dotcms:latest or dotcms/dotcms:<release-number>) which makes version upgrades clean.
Technical Specifications for Local Deployment (Assumptions)
These are the assumptions for the examples in this post:
Local Kubernetes cluster via Docker Desktop (macOS or similar).
kubectl and helm already installed and working.
Access to ArgoCD (you’ll install it).
Git repository (public or private) for storing Helm chart configuration (values, etc.) for dotCMS.
Step-by-Step Example: Deploy dotCMS with ArgoCD
Let’s walk through setting up ArgoCD and deploying dotCMS via its Helm chart.
Step 1: Install ArgoCD
This installs the ArgoCD controllers, API server and CRDs via the official Helm chart.
helm install argocd argo/argo-cd -n argocd --create-namespace
Step 2: Access the ArgoCD UI
Forward the ArgoCD server port:
kubectl port-forward svc/argocd-server -n argocd 8080:443
Now open https://localhost:8080.
Step 3: Login to ArgoCD
Retrieve the initial admin password:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
Username: admin
Password: the decoded value above.
Organizing Your dotCMS Helm Values
Rather than embedding Helm values directly inside your Application definition, it’s a better GitOps practice to store your values.yaml files in a dedicated configuration repository.
This separation keeps the Helm chart immutable and lets you version and promote configurations easily across environments.
Recommended structure:
dotcms-gitops-argocd/
└── environments/
├── dev/
│ └── values.yaml
├── staging/
│ └── values.yaml
└── prod/
└── values.yaml
Example values.yaml (dev):
# dotCMS Development Environment Configuration
# This file contains environment-specific values for dotCMS deployment
#
# Note: Database secrets are preserved across deployments (prune: false)
# to maintain compatibility with the persistent PostgreSQL instance
# Use the latest stable image for development
repository: dotcms/dotcms
tag: "25.09.18-1"
# Single replica for development
replicas: 1
# Reduced resources for development
resources:
requests:
cpu: "500m"
memory: "2Gi"
limits:
cpu: "1"
memory: "3Gi"
# Enable local services (database, opensearch, redis)
database:
local:
enabled: true
opensearch:
local:
enabled: true
redis:
local:
enabled: true
# Ingress configuration for local development
ingress:
host: "dev.dotcms.local"
hostSuffix: "dotcms.local"
type: "nginx"
# Enable management port for health checks
management:
enabled: true
port: 8090
# Enable Prometheus metrics
prometheus:
enabled: true
# Force pod restart with annotation
podAnnotations:
restart: "2025-09-22-17-50"
This way, any update (e.g., changing the dotCMS version tag) is committed and version-controlled in Git.
Step 4: Creating the ArgoCD Application for dotCMS
With ArgoCD ≥ 2.6, you can use multi-source applications:
One source points to the official dotCMS Helm chart.
Another source points to your repo containing the values.yaml.
Here’s an example Application manifest:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: dotcms-dev
namespace: argocd
spec:
project: default
sources:
- repoURL: https://dotcms.github.io/helm-charts/
chart: dotcms
targetRevision: 1.0.34
helm:
valueFiles:
- $values/dotcms-gitops-argocd/environments/dev/values.yaml
- repoURL: https://github.com/dotCMS/examples.git
targetRevision: main
ref: values
destination:
server: https://kubernetes.default.svc
namespace: dotcms-dev
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- RespectIgnoreDifferences=true
# Ignore database secrets to prevent password regeneration on re-sync
# This is critical for stateful databases that persist credentials in PVCs
# Without this, ArgoCD regenerates random passwords that don't match the DB
ignoreDifferences:
- group: ""
kind: Secret
name: corp-dotcms-dev-localsecret-prod-database
jsonPointers:
- /data/password
- /data/username
- group: ""
kind: Secret
name: corp-dotcms-dev-localsecret-db-local-admin
jsonPointers:
- /data/password
- /data/username
Why ignoreDifferences for dotcms local databases: When using local PostgreSQL with persistent volumes (PVCs), the database credentials are initialized once and stored in the persistent storage. On subsequent ArgoCD syncs, Helm regenerates secrets with new random passwords, but the database continues using the original credentials stored in the PVC. This mismatch causes authentication failures. By using ignoreDifferences, ArgoCD preserves the original secret values across deployments, maintaining consistency with the persisted database credentials. This issue doesn't occur with external databases where credentials are managed outside the Kubernetes cluster and remain static across deployments.
Apply the Application:
kubectl apply -f dotcms-application.yaml
ArgoCD now deploys dotCMS using the Helm chart and the values defined in your Git repo.
Watch the Sync in Action
ArgoCD automatically deploys dotCMS via Helm. From the UI, you’ll see your dotCMS application, its sync status, and the health of each Kubernetes object.
We can also see the docker image deployed.
Step 5: Upgrading dotCMS Version via Git
Here’s a more concrete illustration of how you can change your dotCMS version and let ArgoCD do the rest.
Change the image tag in your repo
In environments/dev/values.yaml:
image:
repository: dotcms/dotcms
tag: "25.09.18-01"
You want to upgrade to a newer (stable) version, e.g.:
image:
repository: dotcms/dotcms
tag: "latest" # or "25.10.20-01" (if available) or any unique/stable
Commit and push
git add environments/dev/values.yaml
git commit -m "Upgrade dotCMS to 25.10.20-01"
git push
ArgoCD Detects and Syncs
ArgoCD monitors the Git repo, detects the new commit.
Marks the Application as OutOfSync.
Because syncPolicy.automated.selfHeal is enabled, it starts the sync process.
Kubernetes deployment will roll out new pods with dotcms/dotcms:25.10.20-01 (or the version you specified).
Old pods are terminated once new ones are healthy.
View Progress in the ArgoCD Dashboard
Watch for status to move from OutOfSync → Synced.
Check health status (should become Healthy).
Check the changes you made before (image tag: 25.10.20-01)
Optionally inspect events/logs to see rollout, image pull, etc.
Status synced and healthy.
New image deployed.
Observability and Drift Detection
Dashboard gives you real-time view: sync status, health of Deployments, Services, etc.
Drift detection: when someone manually applies changes outside Git, ArgoCD will show the divergence.
Rollbacks are easy: just revert the Git change (e.g. version tag) and ArgoCD syncs back.
You can manage multiple environments by having different branches or directories in Git, each with different values files (e.g. dev vs prod).
Best Practices (Related to ArgoCD + dotCMS)
Here are some tips to make your setup more robust:
Always use immutable image tags (not just latest) for production—unique tags reduce the risk of unexpected changes.
Separate configuration and application code repos (or separate directories) to keep things clean.
Keep your Helm chart versions and dotCMS image versions in your Git repo, so everything that defines your infrastructure and app state is versioned.
Enable automated sync and self-heal cautiously; test in dev first.
Monitor resource usage; dotCMS can need non-trivial CPU/RAM depending on usage.
Conclusion
With ArgoCD, you move from manual or semi-manual deployments to a fully automated GitOps workflow. For dotCMS teams, this means more consistency, faster updates, and clearer visibility into what is running in each environment. By storing deployments in Git and letting ArgoCD handle the syncs, you reduce the chance of drift and deployment surprises.
If you enjoyed the first post (How to Deploy dotCMS Using Helm Charts on Kubernetes – A Step-by-Step Guide) this deeper dive into ArgoCD shows how to build on that foundation.
References
ArgoCD Documentation: https://argo-cd.readthedocs.io
dotCMS Helm Charts: https://github.com/dotCMS/helm-charts
dotCMS Docs: https://dotcms.com/docs/latest
GitOps Fundamentals: https://www.gitops.tech
Helm Documentation: https://helm.sh/docs/
Example repository: https://github.com/dotCMS/examples.git