GitOps with Flux CD
This tutorial walks through setting up a complete GitOps workflow with OpenChoreo and Flux CD using the sample-gitops repository. You will configure Flux to sync platform resources, build and deploy a multi-component application using OpenChoreo Workflows, and promote it across environments.
What you will learn:
- How to set up Flux CD to sync OpenChoreo resources from Git
- The structure of a GitOps repository for OpenChoreo (platform vs. projects)
- How to build and deploy components using OpenChoreo Workflows
- How ComponentReleases and ReleaseBindings drive environment promotion
- How to promote across the development β staging pipeline
Prerequisitesβ
Before you begin, ensure you have:
- kubectl configured to access your cluster
- git CLI installed
- A GitHub account (to fork the sample repository)
Install OpenChoreoβ
Follow the Run Locally on k3d guide to install OpenChoreo in your Kubernetes cluster.
Do not install the OpenChoreo default resources. Only create the default ClusterDataPlane and ClusterWorkflowPlane.
Install Flux CDβ
Install Flux CD in your cluster. Only the source-controller and kustomize-controller are required.
Follow the official Flux CD installation docs, or run:
kubectl apply -f https://github.com/fluxcd/flux2/releases/latest/download/install.yaml
This tutorial assumes you are using the k3d local setup from the "Try It Out" guide. If you are using a different cluster, adjust hostnames and ports accordingly.
Step 1: Fork and Clone the Sample Repositoryβ
- Navigate to https://github.com/openchoreo/sample-gitops
- Click the Fork button in the top-right corner
- Clone your fork locally:
git clone https://github.com/<your-github-username>/sample-gitops.git
cd sample-gitops
Repository Structureβ
The repository is organized to separate platform-level resources from application resources:
.
βββ flux/ # Flux CD configuration
β βββ gitrepository.yaml # Points Flux to this repo
β βββ namespaces-kustomization.yaml # Syncs namespaces/
β βββ platform-shared-kustomization.yaml # Syncs platform-shared/
β βββ oc-demo-platform-kustomization.yaml # Syncs platform/ (depends on namespaces, platform-shared)
β βββ oc-demo-projects-kustomization.yaml # Syncs projects/ (depends on platform)
β
βββ platform-shared/ # cluster-scoped resources
β βββ cluster-workflow-templates/
β βββ argo/
β βββ docker-with-gitops-release.yaml
β βββ google-cloud-buildpacks-gitops-release-template.yaml
β βββ react-gitops-release-template.yaml
β βββ bulk-gitops-release-template.yaml
β
βββ namespaces/ # namespace-scoped resources
βββ <namespace>/
βββ namespace.yaml
β
βββ platform/ # platform-level resources (managed by platform team)
β βββ infra/
β β βββ deployment-pipelines/
β β β βββ standard.yaml
β β βββ environments/
β β βββ development.yaml
β β βββ staging.yaml
β β βββ production.yaml
β βββ component-types/
β β βββ service.yaml
β β βββ webapp.yaml
β β βββ database.yaml
β β βββ message-broker.yaml
β βββ traits/
β β βββ persistent-volume.yaml
β β βββ api-management.yaml
β β βββ observability-alert-rule.yaml
β βββ workflows/
β βββ bulk-gitops-release.yaml
β βββ docker-with-gitops.yaml
β βββ google-cloud-buildpacks-gitops-release.yaml
β βββ react-gitops-release.yaml
β
βββ projects/ # application resources (managed by development teams)
βββ <project-name>/
βββ project.yaml
βββ components/
βββ <component-name>/
βββ component.yaml
βββ workload.yaml
βββ releases/
β βββ <component>-<date>-<revision>.yaml
βββ release-bindings/
βββ <component>-development.yaml
βββ <component>-staging.yaml
The platform/ directory is synced first, ensuring Environments, DataPlanes, and ComponentTypes exist before any Components are created. Flux enforces this ordering through the dependsOn field in oc-demo-projects-kustomization.yaml.
The sample repository's platform-shared/ directory only includes Argo ClusterWorkflowTemplates. In a production setup, this directory would also contain other cluster-scoped resources such as ClusterComponentTypes, ClusterTraits, ClusterDataPlanes, and ClusterAuthzRoles. See the GitOps Overview for the full directory structure.
Step 2: Update Repository URLsβ
Flux and the build Workflows need to know your fork's URL. Update the following files to point to your forked repository, then commit and push:
flux/gitrepository.yamlβ update thespec.urlfield:
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: sample-gitops
namespace: flux-system
spec:
interval: 1m
url: https://github.com/<your-github-username>/sample-gitops
ref:
branch: main
- Workflow files β update the
gitops-repo-urlparameter in each:namespaces/default/platform/workflows/docker-with-gitops.yamlnamespaces/default/platform/workflows/google-cloud-buildpacks-gitops-release.yamlnamespaces/default/platform/workflows/react-gitops-release.yaml
Commit and push the changes to your fork:
git add -A
git commit -m "Update repository URLs to point to my fork"
git push origin main
If your fork is a private repository, you will need to configure a Flux secret for Git authentication. See the Flux secret create guide for details.
Step 3: Create Git Secretsβ
OpenChoreo Workflows need access to your repositories to clone source code and push GitOps manifests. Store your GitHub Personal Access Token (PAT) in the OpenBao secret store:
-
Generate a GitHub PAT with read/write access to your forked repository
-
Store the secrets in OpenBao:
# Secret for cloning source repositories
kubectl exec -n openbao openbao-0 -- bao kv put secret/git-token git-token=<your_github_pat>
# Secret for pushing to and creating PRs in the GitOps repository
kubectl exec -n openbao openbao-0 -- bao kv put secret/gitops-token git-token=<your_github_pat>
Replace <your_github_pat> with your actual token.
Step 4: Deploy Flux Resourcesβ
Apply all Flux resources to start syncing the repository with your cluster:
kubectl apply -f flux/
This creates five resources:
- GitRepository (
sample-gitops): Tells Flux to monitor your fork - Kustomization (
namespaces): Syncs thenamespaces/directory (namespace definitions) - Kustomization (
platform-shared): Syncs theplatform-shared/directory (cluster-scoped resources) - Kustomization (
oc-demo-platform): Syncs thenamespaces/default/platform/directory (depends on namespaces and platform-shared) - Kustomization (
oc-demo-projects): Syncs thenamespaces/default/projects/directory (depends on platform being ready first)
Verify the Flux resources were created:
kubectl get gitrepository,kustomization -n flux-system
To trigger an immediate sync instead of waiting for the interval:
kubectl annotate gitrepository -n flux-system sample-gitops \
reconcile.fluxcd.io/requestedAt="$(date +%s)" --overwrite
Step 5: Verify Platform Resourcesβ
Within 1-2 minutes, Flux syncs the namespaces/default/platform/ directory. Verify the platform resources were created:
kubectl get environments # β development, staging, production
kubectl get dataplanes # β default
kubectl get deploymentpipelines # β standard
kubectl get componenttypes # β deployment/service, deployment/web-application, deployment/scheduled-task
The standard DeploymentPipeline defines the promotion flow: development β staging (auto-promote) β production (requires approval).
Step 6: Build and Deploy the Doclet Applicationβ
The sample uses the Doclet application β a multi-component app with two backend services and a frontend. You deploy it by triggering OpenChoreo Workflow runs that build container images and create pull requests in your GitOps repository.
Available Workflowsβ
| Workflow | When to Use |
|---|---|
| docker-gitops-release | Source repo has a Dockerfile β works with any language |
| google-cloud-buildpacks-gitops-release | Source repo has no Dockerfile β auto-detects Go, Java, Node.js, Python, .NET, Ruby, PHP |
| react-gitops-release | React or SPA apps β builds with Node.js and packages into nginx |
| bulk-gitops-release | Promote existing releases to a target environment (no build) |
Build the Document Serviceβ
kubectl apply -f - <<EOF
apiVersion: openchoreo.dev/v1alpha1
kind: WorkflowRun
metadata:
name: document-svc-manual-01
namespace: default
labels:
openchoreo.dev/project: "doclet"
openchoreo.dev/component: "document-svc"
spec:
workflow:
name: docker-gitops-release
kind: Workflow
parameters:
componentName: document-svc
projectName: doclet
docker:
context: /project-doclet-app/service-go-document
filePath: /project-doclet-app/service-go-document/Dockerfile
repository:
appPath: /project-doclet-app/service-go-document
revision:
branch: main
commit: ""
url: https://github.com/openchoreo/sample-workloads.git
workloadDescriptorPath: workload.yaml
EOF
Build the Collaboration Serviceβ
kubectl apply -f - <<EOF
apiVersion: openchoreo.dev/v1alpha1
kind: WorkflowRun
metadata:
name: collab-svc-manual-01
namespace: default
labels:
openchoreo.dev/project: "doclet"
openchoreo.dev/component: "collab-svc"
spec:
workflow:
kind: Workflow
name: docker-gitops-release
parameters:
componentName: collab-svc
projectName: doclet
docker:
context: /project-doclet-app/service-go-collab
filePath: /project-doclet-app/service-go-collab/Dockerfile
repository:
appPath: /project-doclet-app/service-go-collab
revision:
branch: main
commit: ""
url: https://github.com/openchoreo/sample-workloads.git
workloadDescriptorPath: workload.yaml
EOF
Build the Frontendβ
kubectl apply -f - <<EOF
apiVersion: openchoreo.dev/v1alpha1
kind: WorkflowRun
metadata:
name: frontend-workflow-manual-01
namespace: default
labels:
openchoreo.dev/project: "doclet"
openchoreo.dev/component: "frontend"
spec:
workflow:
kind: Workflow
name: docker-gitops-release
parameters:
componentName: frontend
projectName: doclet
docker:
context: /project-doclet-app/webapp-react-frontend
filePath: /project-doclet-app/webapp-react-frontend/Dockerfile
repository:
appPath: /project-doclet-app/webapp-react-frontend
revision:
branch: main
commit: ""
url: https://github.com/openchoreo/sample-workloads.git
workloadDescriptorPath: workload.yaml
EOF
The source code for the Doclet application is available at openchoreo/sample-workloads.
Merge the Pull Requestsβ
Once all three Workflow runs complete, 3 pull requests will be created in your forked GitOps repository β one for each component. Each PR contains the generated Workload, ComponentRelease, and ReleaseBinding manifests targeting the development environment.
Review and merge them, then wait for Flux to sync and deploy the components to your cluster.
Verify the Deploymentβ
kubectl get releasebindings -o wide
kubectl get deployments -A
kubectl get pods -A
The READY column on your ReleaseBindings should show True.
Step 7: How a Component Gets Deployedβ
In OpenChoreo, deploying a Component to an Environment requires three key resources:
- Component β defines the application, its ComponentType, and configuration parameters
- ComponentRelease β an immutable snapshot capturing the exact state of the Component, its ComponentType, and Workload at a point in time
- ReleaseBinding β binds a ComponentRelease to a specific Environment, triggering OpenChoreo to render and deploy the actual Kubernetes resources (Deployment, Service, etc.)
In a GitOps workflow, you commit all three as YAML manifests. The Workflow runs in the previous step generated these manifests and created pull requests β once merged, Flux synced them to your cluster automatically.
To deploy to additional Environments, you create new ReleaseBinding manifests that reference the same ComponentRelease but target a different Environment. The following step demonstrates this promotion workflow.
Step 8: Promote to Stagingβ
After validating in development, promote the entire Doclet project to staging using the bulk release Workflow:
kubectl apply -f - <<EOF
apiVersion: openchoreo.dev/v1alpha1
kind: WorkflowRun
metadata:
name: bulk-release-manual-01
namespace: default
spec:
workflow:
kind: Workflow
name: bulk-gitops-release
parameters:
scope:
all: false
projectName: "doclet"
gitops:
repositoryUrl: "https://github.com/<your-github-username>/sample-gitops"
branch: "main"
targetEnvironment: "staging"
deploymentPipeline: "standard"
EOF
Replace <your-github-username> with your GitHub username. Once the Workflow completes, a pull request will be created to promote all Doclet components from development to staging in a single operation.
Merge the PR and wait for Flux to sync. Then verify:
kubectl get releasebindings -o wide
You should see ReleaseBindings for both the development and staging Environments.
The same ComponentReleases are now deployed to both development and staging. This is the power of the ReleaseBinding model: one immutable release, multiple Environments.
Step 9: Environment-Specific Overridesβ
Different Environments often need different configurations β for example, a staging Environment might use a different database endpoint or log level than development. In OpenChoreo, the ReleaseBinding is where you define these environment-specific overrides.
The ReleaseBinding supports three types of overrides:
componentTypeEnvironmentConfigsβ override ComponentType parameters for a specific EnvironmenttraitEnvironmentConfigsβ override Trait configurations for a specific EnvironmentworkloadOverridesβ override workload-level settings such as environment variables and file mounts
This approach keeps the ComponentRelease immutable β the same release artifact is deployed everywhere, with only the configuration varying per Environment.
See the ReleaseBinding API reference for full details on available override fields.
To roll back, revert the releaseName in the ReleaseBinding to the previous ComponentRelease name and push. OpenChoreo handles the rest.
Summaryβ
You've successfully:
- Set up a GitOps repository with Flux CD for OpenChoreo
- Configured platform infrastructure (Environments, ComponentTypes, Workflows) via Git
- Built and deployed a multi-component application using OpenChoreo Workflows
- Promoted all components from development to staging using the bulk release Workflow
What to explore next:
- GitOps Overview - Repository patterns and best practices
- Getting Started with Flux CD - Reference guide for Flux configuration options
- DeploymentPipeline API - Customize promotion paths and approval gates
- ReleaseBinding API - Environment-specific overrides and workload customization
Advanced flows:
- Build and Release Workflows - Automate container builds and GitOps releases using Workflows
- Bulk Promote - Promote multiple components to an environment in a single operation
Clean Upβ
To remove the Flux resources:
kubectl delete -f flux/