Skip to content

Argo CD on GKE

The smallest example of the three-layer split: Chant authors typed manifests, Argo CD reconciles them, and Temporal (not needed here) orchestrates anything procedural. A single GKE cluster runs Argo CD, and one Chant-authored workload is deployed through a K8s::Argo::Application declared in TypeScript with ArgoAppFor.

This mirrors the argo-cd-gke example.

GKE cluster (Autopilot)
└── Argo CD (namespace argocd)
└── Application "web" ──watches──▶ git repo (dist/app/)
└── reconciles ──▶ Deployment + Service (namespace demo)

The key idea: the k8s lexicon stays runtime-agnostic. The workload (src/app) is plain Chant k8s — it knows nothing about Argo. Argo is opt-in, added by one ArgoAppFor call in src/bootstrap.

src/
config.ts # repo URL, paths, namespaces, the demo image
app/web.ts # the workload — WebApp (Deployment + Service)
bootstrap/application.ts # ArgoAppFor → the Argo Application that syncs src/app

Two build outputs:

  • dist/app/manifests.yaml — the workload. Commit it to the repo Argo watches.
  • dist/argo.yaml — the Argo Application. Apply it once to bootstrap the GitOps loop.

src/app/web.ts is ordinary Chant — a WebApp composite. No Argo anywhere:

import { WebApp } from "@intentius/chant-lexicon-k8s";
import { config } from "../config";
const { deployment, service } = WebApp({
name: config.appName,
image: config.appImage,
port: config.appPort,
namespace: config.appNamespace,
replicas: 2,
});
export { deployment, service };

src/bootstrap/application.ts adds Argo in one call:

import { ArgoAppFor } from "@intentius/chant-lexicon-k8s";
import { config } from "../config";
export const web = ArgoAppFor(config.appName, {
repo: config.repo,
path: config.appPath,
destination: { server: config.destinationServer, namespace: config.appNamespace },
});

That renders to ~20 lines of Application YAML with a safe automated, non-pruning, self-healing sync policy:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/argo-cd-gke-demo
path: dist/app
targetRevision: HEAD
destination:
server: https://kubernetes.default.svc
namespace: demo
syncPolicy:
automated: { prune: false, selfHeal: true }
syncOptions: ["CreateNamespace=true"]
Terminal window
npm install
npm run build # → dist/app/manifests.yaml + dist/argo.yaml

Commit dist/app/ to the repo referenced by ARGO_REPO so Argo has something to sync.

Terminal window
npm run cluster # GKE Autopilot cluster (idempotent)
npm run configure-kubectl
npm run install-argocd # Argo CD v2.13.3 into namespace argocd
Terminal window
npm run bootstrap # kubectl apply dist/argo.yaml
npm run wait # block until the Application is Healthy
npm run status
$ npm run status
NAME SYNC STATUS HEALTH STATUS
web Synced Healthy

The web Deployment and Service exist in the demo namespace — created by Argo, not by kubectl apply of the workload. Change src/app, rebuild, push to git, and Argo reconciles the diff on its own.

  • Scope the Application to a real AppProject for RBAC (ARGO002).
  • Fan out across regional clusters with ArgoAppSetForRegions.
  • Gate procedural steps on Argo finishing with the temporal lexicon’s waitForArgoSync activity — see the CockroachDB multi-region tutorial, which uses Argo for the apply layer and Temporal for the procedural one.