Deploy with GitOps (Argo CD)
Deploy the complete SWIM ecosystem using GitOps — a declarative
approach where Git is the single source of truth for your entire infrastructure and
application stack. Every change is a Git commit, every deployment is auditable,
and rollback is a git revert.
This tutorial uses Argo CD for continuous delivery and Tekton for continuous integration. This tutorial demonstrates how to set up a fully self-contained local environment on OpenShift Local (CRC) using Gitea as the local Git server — with zero dependency on external services. Once validated locally, the same configuration can be deployed to any remote Kubernetes or OpenShift cluster by simply reconfiguring the Git source URL — see Moving to Production at the end of this page.
Recommended path
This is the recommended deployment method for new adopters. It provides full CI/CD automation, Git-based audit trail, and reproducible environments. First, replicate the full flow locally on OpenShift Local (CRC), then promote to production. For alternative approaches, see OpenShift Local (Helm) or OpenShift (Operator).
How It Works
The swim-gitops repository (cloned from GitHub) contains everything needed to deploy the SWIM platform. After initial clone, all runtime Git operations use a local Gitea instance — the CRC environment has zero dependency on GitHub:
What Gets Deployed
The GitOps repository manages 16 Argo CD Applications organized in layers:
Prerequisites
This tutorial walks through the full GitOps setup on OpenShift Local (CRC). If you haven't set up CRC yet, see Deploy on OpenShift Local first.
oc is included with CRC. make and git are pre-installed on Linux/macOS. On Windows: choco install make git
choco install kubernetes-helm (Windows), brew install helm (macOS), sudo snap install helm --classic (Linux)
sudo dnf install skopeo (Fedora/RHEL), brew install skopeo (macOS), choco install skopeo (Windows)
choco install make) and Git for Windows (default install location). The Makefile auto-detects bash from Git for Windows — no additional configuration needed.
1. Clone the GitOps Repository
git clone https://github.com/swim-developer/swim-gitops.git
cd swim-gitops
2. Start OpenShift Local
Download your pull secret from
console.redhat.com/openshift/create/local
and save it as pull-secret.txt in the repository root.
# One-time setup (first time only)
make crc-setup
# Place pull-secret.txt next to the Makefile
cp ~/Downloads/pull-secret.txt ./pull-secret.txt
# Start CRC (first run takes a few minutes)
make crc-start
# Point oc to CRC
eval $(crc oc-env)
make crc-use-local
Windows: The Makefile automatically adds CRC's oc to PATH, so all
make targets work without manual setup. If you need oc directly
in PowerShell (outside of make), run:
crc oc-env --shell powershell | Invoke-Expression
Customizing CRC resources
make crc-setup configures CRC with defaults suitable for a single
stack: 8 CPUs, 20 GB RAM, 100 GB disk. You can override any of these:
# Deploy all 3 stacks (more resources needed)
make crc-setup SWIM_STACKS=all # auto: 10 CPUs, 24 GB RAM, 100 GB disk
# Or set each value individually
make crc-setup CRC_CPUS=8 CRC_MEMORY_MB=20480 CRC_DISK_GB=80
Changing CRC resources requires crc delete and crc start
to take effect (the VM is recreated).
3. Deploy Gitea (Local Git Server)
Gitea is the local Git server that serves as the single source of truth for the entire GitOps flow. Argo CD will read from it, and all changes (commits, reverts, releases) happen here. It must be deployed before Argo CD:
# Install Gitea via Helm
make gitea-deploy
# Create admin user and all repositories
make gitea-init
# Push swim-gitops to Gitea
make gitea-push
# Mirror all service and library repos from GitHub to Gitea
make gitea-mirror SWIM_STACKS=ed254
gitea-mirror clones the service repos and shared libraries from
GitHub and pushes them to Gitea. This is a one-time operation that ensures
the CRC environment is fully self-contained with zero runtime dependency
on GitHub. Use SWIM_STACKS=all to mirror all stacks.
You can browse the Gitea UI at
https://gitea.apps-crc.testing
(login: swimadmin / Swim@Local1).
From this point forward, all Git operations (commits, releases, reverts) happen
exclusively through Gitea — GitHub is no longer used.
4. Install Argo CD
Install Argo CD into the cluster. The Makefile creates the operator subscription and waits for the Argo CD server pod to become ready:
make gitops-install
5. Bootstrap GitOps (App of Apps)
Create the swim AppProject and deploy the selected stacks.
Argo CD reads directly from the local Gitea.
By default, only DNOTAM is deployed:
# Deploy DNOTAM only (default)
make gitops-bootstrap
# Or deploy ED-254
# make gitops-bootstrap SWIM_STACKS=ed254
# Or deploy all 3 stacks
# make gitops-bootstrap SWIM_STACKS=all
# Or pick specific stacks
# make gitops-bootstrap SWIM_STACKS="dnotam ed254"
Consistency: Use the same SWIM_STACKS value
across all commands: crc-setup, gitea-mirror,
gitops-bootstrap, and ci-bootstrap-images.
Argo CD immediately begins syncing from Gitea. Platform operators are deployed first (wave 0), followed by infrastructure (waves 1-2), then the selected stack services. This is fully automatic.
6. Wait for Infrastructure
The operator CRDs (Kafka, cert-manager, Artemis, Keycloak) take a few minutes to install. Wait for them, then check Argo CD status:
# Wait for all operator CRDs
make operators-wait
# Check Argo CD Application states
make argocd-status
Timing
Kafka and Keycloak are the slowest to initialize. Run
make argocd-status periodically to check progress.
Wait until swim-core-infra and swim-shared-brokers
show Synced / Healthy before proceeding.
7. Create Artemis TLS Secrets
All SWIM components use mTLS. Certificates are generated automatically by cert-manager — Keycloak, Kafka, and the SWIM services consume them directly in PEM format. Artemis is the only component that requires a manual step: it needs JKS (Java KeyStore) format, so we extract the PEM certificates and convert them:
make artemis-ssl
8. Bootstrap Pre-built Images
All service deployments reference the cluster's internal registry. Before running CI, import pre-built images from Quay.io so that every pod starts immediately:
make ci-bootstrap-images
This uses skopeo to copy the latest images from
quay.io/masales
into the OpenShift internal registry. After a few seconds, pods that were in
ImagePullBackOff will automatically pull the imported images and start running.
The images imported in this step serve as a baseline. In the next steps, you will run the CI pipelines to build your own images from source, which will overwrite these pre-built versions in the internal registry.
9. Install Tekton CI
Install the 12 CI pipelines, tasks, and triggers. The CRC overlay configures pipelines to push images to the cluster's internal registry instead of an external one:
# Apply Tekton pipelines, tasks, triggers, and registry credentials
make ci-install-crc
This creates the swim-pipeline namespace with 12 pipelines
covering all DNOTAM, ED-254, and FF-ICE services.
10. Run a CI Pipeline
Validate the CI flow by building one service. Each pipeline clones the source from Gitea (not GitHub), compiles a self-contained uber-JAR, creates a release in Gitea with the JAR as a downloadable artifact, and builds a container image that overwrites the pre-built image imported in Step 8:
# Build a validator (fastest — fewer dependencies)
make ci-run CI_SERVICE=ed254-consumer-validator
# Or for DNOTAM:
# make ci-run CI_SERVICE=dnotam-consumer-validator
# Monitor the pipeline
make ci-status
When the pipeline completes, check the Gitea release at
https://gitea.apps-crc.testing
→ your service repo → Releases.
Build modes
Set build-native: "false" (default) for a JVM JAR build
(~1 Gi RAM, 2 minutes). Set build-native: "true" for a
GraalVM native binary (requires 12+ Gi RAM, 4+ CPUs, 10+ minutes).
The JAR mode is recommended for validation on resource-constrained CRC.
11. Validate All Pipelines
Run all 4 pipelines for the stack you deployed. Each creates a Gitea release with a downloadable uber-JAR and pushes a container image to the internal registry, replacing the pre-built images from Step 8 with your own locally-built versions:
# ED-254 stack:
make ci-run CI_SERVICE=ed254-consumer-validator
make ci-run CI_SERVICE=ed254-provider-validator
make ci-run CI_SERVICE=ed254-consumer
make ci-run CI_SERVICE=ed254-provider
# DNOTAM stack:
# make ci-run CI_SERVICE=dnotam-consumer-validator
# make ci-run CI_SERVICE=dnotam-provider-validator
# make ci-run CI_SERVICE=dnotam-consumer
# make ci-run CI_SERVICE=dnotam-provider
# Check results
make ci-status
All 4 should show SUCCEEDED. Verify:
- Releases: each service has a downloadable uber-JAR at
https://gitea.apps-crc.testing - Container images:
oc get imagestream -n swim-demoshows all 4 images updated - Pods:
oc get pods -n swim-democonfirms services are running with the newly-built images
12. Verify the Deployment
# Argo CD Applications
oc get applications -n openshift-gitops
# Container images in the internal registry
oc get imagestream -n swim-demo
# Tekton pipelines
oc get pipelines -n swim-pipeline
# All pods
oc get pods -n swim-demo
Key endpoints on CRC:
https://openshift-gitops-server-openshift-gitops.apps-crc.testing
(user: admin / pass: oc get secret openshift-gitops-cluster -n openshift-gitops -o jsonpath='{.data.admin\.password}' | base64 -d)
https://gitea.apps-crc.testing (user: swimadmin / pass: Swim@Local1)
https://rhbk.apps-crc.testing
Keycloak admin credentials are auto-generated per deployment. Retrieve them with:
# Username
oc get secret keycloak-initial-admin -n swim-demo -o jsonpath='{.data.username}' | base64 -d
# Password
oc get secret keycloak-initial-admin -n swim-demo -o jsonpath='{.data.password}' | base64 -d
https://console-openshift-console.apps-crc.testing
GitOps vs Other Deployment Paths
| Aspect | GitOps (this tutorial) | Helm / make all | Operator |
|---|---|---|---|
| Deployment method | Git commit → Argo CD syncs | helm upgrade / make all |
oc apply CR |
| Audit trail | Full Git history | Manual / shell history | Controller logs |
| Rollback | git revert |
helm rollback |
Delete/recreate CR |
| CI included | Yes (12 Tekton pipelines) | No | No |
| Drift detection | Automatic (Argo CD) | Manual | Operator reconciliation |
| Best for | Production, teams, CI/CD | Quick local testing | Single-CR provisioning |
Troubleshooting
| Symptom | Fix |
|---|---|
swim-gitops-root shows Unknown |
oc apply -f argocd/projects/swim.yaml -n openshift-gitops |
| App stays OutOfSync | Check oc get application <name> -n openshift-gitops -o yaml |
| PipelineRun Pending (insufficient resources) | Use build-native: "false" or scale down unused services |
| Buildah push TLS error | CRC overlay sets TLSVERIFY: "false" for the internal registry |
| Kafka NotReady | Check Kafka version in infra/overlays/crc-local/values.yaml |
oc targets wrong cluster |
eval $(crc oc-env) && make crc-use-local |
Moving to Production
This tutorial is designed for OpenShift Local (CRC). All Git operations use a local Gitea instance, and container images are stored in the internal OpenShift registry. No hardcoded URLs exist — everything is configurable for your target environment.
Once you have validated the full GitOps flow on CRC, the same configuration can be deployed to any remote environment:
make gitops-bootstrap
argocd/ manifests. Replace oc with kubectl
Step 1: Reconfigure the Git source
The most important change is pointing all Argo CD applications and CI pipelines to your production Git server. A single Makefile command replaces all internal Gitea URLs with your target:
# GitHub
make configure-git GIT_REPO_BASE=https://github.com/my-org
# GitLab
make configure-git GIT_REPO_BASE=https://gitlab.com/my-group
# Self-hosted Gitea / Forgejo
make configure-git GIT_REPO_BASE=https://git.mycompany.com/swim
This updates every repoURL in Argo CD Application definitions,
every git-url and dep-repos default in Tekton
pipelines and tasks, and the bootstrap files. After running, review the
changes with git diff, then commit and push.
Step 2: Adjust environment-specific values
- Image registry: Update the CRC-local values overlays
(
apps/*/overlays/crc-local/values.yaml) to pointimage.repositoryat your production registry (Quay.io, Docker Hub, ECR, etc.). Create a new overlay directory (e.g.overlays/production/) for environment separation. - TLS certificates: Set
certManager.issuerKind: ClusterIssuer(the default) and configure a productionClusterIssuerbacked by a real CA (Let’s Encrypt, Venafi, etc.) instead of the self-signed issuer used on CRC. - Release artifacts: Configure Tekton tasks to publish JARs and binaries to your artifact repository (GitHub Releases, Nexus, Artifactory, etc.).
- Resource limits: Adjust CPU and memory requests/limits in the values overlays for production workloads.
Step 3: Deploy to the production cluster
# Log in to your production cluster
oc login https://api.my-cluster.example.com:6443
# Apply the same bootstrap (no Gitea needed — your Git server is external)
make gitops-bootstrap SWIM_STACKS=all
For detailed step-by-step instructions, see the Production Migration Guide in the swim-gitops repository.
Next Steps
- Compare deployment paths: Read GitOps vs Operator vs Helm for a detailed comparison
- Explore services: After deploying, follow the Digital NOTAM and ED-254 tutorials to explore individual services
- Build your own: Use the Create Consumer tutorial to build a new SWIM service from scratch