Setting Up a New Service

This guide walks through onboarding a new Java service into the deployment pipeline. It assumes the service is a JHipster/Spring Boot application using Maven.

Prerequisites

  • The service repository exists on GitHub under christhonie/

  • The service builds with Maven and produces a Docker image via Jib

  • The service has a <revision> property in its POM (e.g. 2.0.0-SNAPSHOT)

Step 1: Add Helm Chart

Create the Helm chart directory structure in the service repository:

src/main/helm/
├── Chart.yaml
├── values.yaml
└── templates/
    ├── config-map-application.yml
    └── ... (other JHipster-generated templates)

Chart.yaml

apiVersion: v2
name: <service-name>
description: Helm chart for <Service Display Name>.
type: application
version: 0.0.0
appVersion: 0.0.0

ConfigMap Template

Create templates/config-map-application.yml to render Spring Boot configuration. Use printf "jdbc:%s" for database URLs so that ArgoCD manifests can use the mysql:// format:

kind: ConfigMap
apiVersion: v1
metadata:
  name: {{ include "<service-name>.fullname" . }}
data:
  application.yaml: |-
    spring:
      datasource:
        url: {{ printf "jdbc:%s" .Values.config.db.url }}
        username: {{ .Values.config.db.username }}

See existing services for full ConfigMap examples with logging, mail, and management configuration.

Prettier Ignore

Add the Helm templates directory to .prettierignore:

src/main/helm/templates/

Step 2: Add Maven Plugin

Add the helm-maven-plugin to the POM:

<properties>
    <helm-maven-plugin.version>6.17.0</helm-maven-plugin.version>
</properties>

<!-- In build/plugins -->
<plugin>
    <groupId>io.kokuwa.maven</groupId>
    <artifactId>helm-maven-plugin</artifactId>
</plugin>

<!-- In build/pluginManagement/plugins -->
<plugin>
    <groupId>io.kokuwa.maven</groupId>
    <artifactId>helm-maven-plugin</artifactId>
    <version>${helm-maven-plugin.version}</version>
    <configuration>
        <chartDirectory>${project.basedir}/src/main/helm</chartDirectory>
        <helmVersion>3.17.3</helmVersion>
        <chartVersion>${project.version}-RELEASE</chartVersion>
        <appVersion>${project.version}</appVersion>
        <skipPushLogin>true</skipPushLogin>
        <uploadRepoStable>
            <name>dockerhub-christhonie</name>
            <url>registry-1.docker.io/christhonie</url>
        </uploadRepoStable>
        <uploadRepoSnapshot>
            <name>dockerhub-christhonie</name>
            <url>registry-1.docker.io/christhonie</url>
        </uploadRepoSnapshot>
    </configuration>
</plugin>

Step 3: Create GitHub Actions Workflows

push-dev.yml

Create .github/workflows/push-dev.yml for the develop branch:

name: 'Develop Push - Build and Test'

on:
  push:
    branches: [develop]
    paths-ignore: ['*.md', '*.adoc', '.devcontainer/**']

jobs:
  package:
    name: Package
    uses: christhonie/event/.github/workflows/maven-package.yml@main
    with:
      maven-profiles: dev,webapp    (1)
      jdk-version: 21               (2)
    secrets:
      MAVEN_PASSWORD: ${{ secrets.EVENT_PACKAGE_REPO_TOKEN }}

  docker-build:
    name: Docker
    needs: [package]
    uses: christhonie/event/.github/workflows/docker-build.yml@main
    with:
      maven-profiles: dev,webapp
      jdk-version: 21
    secrets:
      DOCKER_PAT: ${{ secrets.DOCKER_PAT }}

  helm-build:
    name: Helm
    needs: [docker-build]
    if: always() && needs.docker-build.result == 'success'
    uses: christhonie/event/.github/workflows/helm-build.yml@main
    with:
      maven-profiles: dev,webapp
      jdk-version: 21
    secrets:
      DOCKER_PAT: ${{ secrets.DOCKER_PAT }}

  update-argocd-dev:
    name: Deploy Dev
    needs: [helm-build]
    if: always() && needs.helm-build.result == 'success'
    uses: christhonie/event/.github/workflows/argocd-update.yml@main
    with:
      environment: dev
      service-name: <service-name>   (3)
      chart-version: ${{ needs.helm-build.outputs.chart-version }}  (4)
      build-sha: ${{ github.sha }}   (5)
    secrets:
      ARGOCD_REPO_TOKEN: ${{ secrets.ARGOCD_REPO_TOKEN }}
1 Adjust Maven profiles for your service
2 Use JDK 21 for new services
3 Must match the ArgoCD manifest filename prefix
4 Sets ArgoCD targetRevision to the Helm chart version
5 Forces SNAPSHOT rollouts via pod annotation

push-main.yml

Create .github/workflows/push-main.yml for the main branch:

name: 'Main Push - Package and Deploy'

on:
  push:
    branches: [main]

jobs:
  package:
    name: Package
    uses: christhonie/event/.github/workflows/maven-package.yml@main
    with:
      maven-profiles: prod,webapp
      jdk-version: 21
    secrets:
      MAVEN_PASSWORD: ${{ secrets.EVENT_PACKAGE_REPO_TOKEN }}

  docker-build:
    name: Docker
    needs: [package]
    uses: christhonie/event/.github/workflows/docker-build.yml@main
    with:
      maven-profiles: prod,webapp
      jdk-version: 21
    secrets:
      DOCKER_PAT: ${{ secrets.DOCKER_PAT }}

  helm-build:
    name: Helm
    needs: [docker-build]
    uses: christhonie/event/.github/workflows/helm-build.yml@main
    with:
      maven-profiles: prod,webapp
      jdk-version: 21
    secrets:
      DOCKER_PAT: ${{ secrets.DOCKER_PAT }}

  update-argocd-stage:
    name: Deploy Stage
    needs: [helm-build]
    if: always() && needs.helm-build.result == 'success'
    uses: christhonie/event/.github/workflows/argocd-update.yml@main
    with:
      environment: stage
      service-name: <service-name>
      chart-version: ${{ needs.helm-build.outputs.chart-version }}
    secrets:
      ARGOCD_REPO_TOKEN: ${{ secrets.ARGOCD_REPO_TOKEN }}

  gitflow-release-finish:
    name: Gitflow
    needs: [package]
    uses: christhonie/event/.github/workflows/gitflow-release-finish.yml@main

Step 4: Configure Repository Secrets

Add these secrets to the GitHub repository settings:

Secret Value

EVENT_PACKAGE_REPO_TOKEN

GitHub PAT with read:packages scope

DOCKER_PAT

Docker Hub PAT with push permissions

ARGOCD_REPO_TOKEN

GitHub PAT with write access to christhonie/idl-xnl-jhb-rc01

Step 5: Build Initial Helm Chart

Before creating ArgoCD manifests, the Helm chart must exist in the registry. Either push to develop or main to trigger the CI build (charts are built on every push), or build manually:

cd ~/dev/ems/<service-directory>
mvn helm:init helm:registry-login helm:package helm:push -Pprod
helm:registry-login is used here for local builds (where Maven settings handle credentials correctly). In CI, the Helm CLI login is used instead due to a bug in the Maven goal.

Verify the chart was published:

helm pull oci://registry-1.docker.io/christhonie/<chart-name> \
    --version <project-version>-RELEASE

Step 6: Create ArgoCD Manifests

Create Application manifests in christhonie/idl-xnl-jhb-rc01/argocd/.

Dev Environment

Create <service-name>-dev.yml:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: <service-name>-dev
  namespace: argocd
spec:
  project: default
  destination:
    name: idl-xnl-jhb1-rc01
    namespace: event-dev
  source:
    repoURL: registry-1.docker.io
    chart: christhonie/<chart-name>
    targetRevision: <version>-RELEASE
    helm:
      releaseName: dev-<service-name>
      valuesObject:
        config:
          profiles: "dev,kubernetes,api-docs"
          existingsecret: event-admin-service
          db:
            url: mysql://idealogic-prod.mysql.svc.cluster.local:6446/<db_name>_dev?useUnicode=true&characterEncoding=utf8
            username: dev
          logging:
            level:
              ROOT: DEBUG
        image:
          pullPolicy: Always
        imagePullSecrets:
          - name: christhonie-docker
        ingress:
          enabled: true
          className: "nginx"
          annotations:
            "cert-manager.io/cluster-issuer": "letsencrypt-prod"
            "external-dns.alpha.kubernetes.io/cloudflare-proxied": "false"
          hostname: <service-name>-dev.idealogic.co.za
          pathType: Prefix
          tls: true
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    syncOptions:
      - CreateNamespace=true
  revisionHistoryLimit: 3

Stage and Prod

Create <service-name>-stage.yml and <service-name>-prod.yml following the environment conventions.

Key differences for prod:

  • Logging level: INFO (not DEBUG)

  • Image pull policy: IfNotPresent (not Always)

  • No build-sha pod annotation

  • No faker Liquibase context

Step 7: Verify Deployment

  1. Push the ArgoCD manifests to christhonie/idl-xnl-jhb-rc01

  2. ArgoCD’s app-of-apps will detect the new manifests and create the Applications

  3. Monitor the deployment:

    export KUBECONFIG=/mnt/c/Users/chris/.kube/static/idl-xnl-jhb1-01.yaml
    kubectl -n event-dev get pods
    kubectl -n event-dev logs <pod-name> --tail=100

Checklist

Use this checklist when onboarding a new service:

  • Helm chart created in src/main/helm/

  • helm-maven-plugin configured in POM

  • src/main/helm/templates/ added to .prettierignore

  • push-dev.yml workflow created

  • push-main.yml workflow created

  • Repository secrets configured (DOCKER_PAT, EVENT_PACKAGE_REPO_TOKEN, ARGOCD_REPO_TOKEN)

  • Initial Helm chart published to Docker Hub

  • ArgoCD manifest created for dev

  • ArgoCD manifest created for stage

  • ArgoCD manifest created for prod

  • Deployment verified on dev environment