ArgoCD Deployment

This document explains how we manage deployments using ArgoCD and provides guidance for creating new deployments.

Overview

ArgoCD is used for GitOps-based continuous deployment. Application definitions are stored in a Git repository and ArgoCD reconciles the desired state with the cluster.

ArgoCD Application Structure

OCI Helm Chart Deployment

For applications with Helm charts published to Docker Hub:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: registration-portal-dev
  namespace: argocd
spec:
  project: default
  destination:
    name: idl-xnl-jhb1-rc01  # Cluster name
    namespace: event-dev
  source:
    repoURL: registry-1.docker.io
    chart: christhonie/registration-portal
    targetRevision: 1.2.4-SNAPSHOT-RELEASE  # Chart version
    helm:
      releaseName: dev-registration-portal
      valuesObject:
        # Helm values go here
        config:
          profiles: "dev,kubernetes,api-docs"
        image:
          pullPolicy: Always
          # No tag. The chart resolves it from the chart's own appVersion —
          # see "Image Configuration" below.
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    syncOptions:
      - CreateNamespace=true
  revisionHistoryLimit: 3

Git Source Deployment

For raw Kubernetes manifests (like GreenMail):

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: greenmail-dev
  namespace: argocd
spec:
  project: default
  destination:
    name: idl-xnl-jhb1-rc01
    namespace: event-dev
  source:
    repoURL: [email protected]:christhonie/idl-xnl-jhb-rc01.git
    targetRevision: HEAD
    path: event-membership/greenmail-dev
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Version Conventions

targetRevision is the single version knob in an ArgoCD manifest. Everything else follows from it.

Component Format Example

Helm Chart Version (targetRevision)

<MAVEN_VERSION>-RELEASE

1.2.4-SNAPSHOT-RELEASE

Docker Image Tag

Derived — chart appVersion, set by Maven to <MAVEN_VERSION>

1.2.4-SNAPSHOT

Database Name

<app>_<env> (underscores)

registration_ui_dev

The helm-maven-plugin configuration sets both from the same source:

<chartVersion>${project.version}-RELEASE</chartVersion>
<appVersion>${project.version}</appVersion>

So a chart tagged 1.2.4-SNAPSHOT-RELEASE already carries appVersion: 1.2.4-SNAPSHOT. Bumping targetRevision moves the image with it, automatically and without a second edit.

Common Values Configuration

Application Profiles

config:
  profiles: "dev,kubernetes,api-docs"

Common profiles:

  • dev - Development settings, verbose logging

  • kubernetes - Enables Spring Cloud Kubernetes

  • api-docs - Enables Swagger/OpenAPI documentation

  • otlp - Enables OpenTelemetry instrumentation

Database Configuration

config:
  db:
    # URL format WITHOUT driver prefix (jdbc: or r2dbc:)
    url: mysql://idealogic-prod.mysql.svc.cluster.local:6446/registration_ui_dev?useUnicode=true&characterEncoding=utf8
    username: dev
  existingsecret: event-admin-service  # Password from shared secret

Email Configuration (GreenMail)

config:
  mail:
    host: greenmail.event-dev.svc.cluster.local
    port: 25
    from: [email protected]
    username: ""
    password: ""
    protocol: smtp
    tls: false
    properties.mail.smtp:
      auth: false
      starttls.enable: false

OpenTelemetry Configuration

config:
  otel:
    enabled: true
    url: "http://opentelemetry-collector.observability.svc.cluster.local:4317"

Logging Configuration

config:
  logging:
    level:
      ROOT: DEBUG
      za.co.idealogic.registration.ui: DEBUG
      org.springframework.security: DEBUG

Liquibase Contexts

config:
  liquibase:
    contexts: "dev,faker"  # Include faker for test data

Image Configuration

image:
  pullPolicy: Always  # Use Always for SNAPSHOT versions

imagePullSecrets:
  - name: christhonie-docker  # Docker Hub credentials

Never set image.tag in an ArgoCD manifest.

The chart resolves the image as:

image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"

image.tag is therefore an override that suppresses the chart’s own appVersion, not a companion field to keep in sync with it. Nothing in the pipeline ever clears it: push-dev.yml and push-main.yml pass only chart-version to argocd-update.yml, so once image.tag is written it is frozen. Every later release bumps targetRevision to a new chart whose appVersion is then ignored, and the pods keep running the pinned image.

This has happened. registration-portal-stage.yml carried image.tag: "2.3.12" from 2.3.5 onwards while the automated chore(stage) commits bumped targetRevision through five releases. It was removed in idl-xnl-jhb-rc01 commit 8b379f34:

The chart’s appVersion (2.3.13) provides the correct Docker image tag as a default. The explicit image.tag override was pinning both environments to 2.3.12.

Leave image.tag unset and let targetRevision drive the deployment. No manifest in idl-xnl-jhb-rc01 sets it today.

Ingress Configuration

ingress:
  enabled: true
  className: "nginx"
  annotations:
    "cert-manager.io/cluster-issuer": "letsencrypt-prod"
    "external-dns.alpha.kubernetes.io/cloudflare-proxied": "false"
  hostname: registration-portal-dev.idealogic.co.za
  pathType: Prefix
  tls: true

Scaling Configuration

replicaCount: 1  # Set to 0 to disable deployment

Setting replicaCount: 0 is useful when:

  • Debugging deployment issues

  • Waiting for dependencies to be ready

  • Temporarily disabling an environment

Creating a New Deployment

Step 1: Create ArgoCD Application File

Create a new YAML file in argocd/ directory:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: <app-name>-<env>
  namespace: argocd
spec:
  project: default
  destination:
    name: idl-xnl-jhb1-rc01
    namespace: event-<env>
  source:
    repoURL: registry-1.docker.io
    chart: christhonie/<chart-name>
    targetRevision: <version>-RELEASE
    helm:
      releaseName: <env>-<app-name>
      valuesObject:
        # ... values configuration
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    syncOptions:
      - CreateNamespace=true
  revisionHistoryLimit: 3

Step 2: Configure Values

Add the appropriate values for your environment. Reference existing deployments for patterns.

Step 3: Commit and Push

git add argocd/<app-name>-<env>.yml
git commit -m "Add ArgoCD Application for <app-name>-<env>"
git push

Step 4: Verify Deployment

Check ArgoCD UI or CLI:

argocd app get <app-name>-<env>
argocd app sync <app-name>-<env>  # If not auto-syncing

Updating Deployments

Updating Chart Version

Normally you do not: push-dev.yml (dev) and push-main.yml (stage) call argocd-update.yml and bump targetRevision for you. Prod manifests are promoted by hand.

To do it manually, edit targetRevision and nothing else:

source:
  targetRevision: 1.2.5-SNAPSHOT-RELEASE  # New chart; image follows via appVersion

Do not add an image.tag alongside it — see the warning under Image Configuration.

Updating Configuration

Simply edit the valuesObject section and commit. ArgoCD will automatically sync the changes.

Common Issues and Solutions

Application OutOfSync but Won’t Sync

Cause: Resource has been manually modified or has invalid fields.

Solution:

argocd app sync <app-name> --force

Pod CrashLoopBackOff

Check the pod logs:

kubectl logs -n event-<env> -l app.kubernetes.io/name=<app-name> --previous

Common causes:

  • Missing secrets: Verify existingsecret points to valid secret

  • Database connection failed: Check database URL and credentials

  • Missing K8s dependencies: Ensure spring-cloud-starter-kubernetes-fabric8-config is included

CreateContainerError: no command specified

Cause: Docker image built without proper entrypoint.

Solution: Rebuild the Docker image with proper ENTRYPOINT or CMD in Dockerfile.

Chart Not Found

Cause: Chart version doesn’t exist in registry.

Solution:

  1. Verify chart exists: helm show chart oci://registry-1.docker.io/christhonie/<chart> --version <version>

  2. Run Helm release workflow if chart needs to be published

Wrong Database Name

Cause: Database name format mismatch.

Solution: Use underscores in database names (e.g., registration_ui_dev, not registration-ui-dev).

Environment Conventions

Environment Namespace Hostname Pattern

Development

event-dev

<app>-dev.idealogic.co.za

Staging

event-staging

<app>-staging.idealogic.co.za

Production

event-prod

<app>.myriadevents.co.za