@cdklib/argo-synth v0.2.0
@cdklib/argo-synth
A directory structure management library for cdk8s projects that enables GitOps-friendly output organization for ArgoCD.
Why This Exists
cdk8s is a great way to build Kubernetes applications. However, cdk8s's default synthesis behaviors are not argo-friendly.
ArgoCD works best with a directory structure that organizes Kubernetes resources by environment and application.
@cdklib/argo-synth provides a simple way to organize your cdk8s synthesized resources into a clean directory structure that's optimal for ArgoCD's path-based applications.
Key Features
- Simple - Offers a clear path-based organization approach for cdk8s projects
- ArgoCD-Optimized - Creates a directory structure that maps perfectly to ArgoCD application paths
- Path Inheritance - Supports path building for complex directory structures
- Multi-Environment - Easily manage multiple environments in a single GitOps repository
Table of Contents
- Installation
- Basic Usage
- Integrated Usage
- Directory Structure
- Path Management
- Integration with @cdklib/config
- Best Practices
- License
Installation
# Using npm
npm install @cdklib/argo-synth
# Using yarn
yarn add @cdklib/argo-synth
# Using pnpm
pnpm add @cdklib/argo-synthKey Features
- šļø Structured Output: Organize Kubernetes manifests in a directory structure that mirrors your environments and applications
- š GitOps Ready: Generate files in a format optimal for ArgoCD and GitOps workflows
- š Multi-Environment Support: Easily manage multiple environments in a single repository
- š App Synthesis: Synthesize multiple cdk8s apps seamlessly
- š Visibility: Clearly understand what changed by keeping generated kube manifests in a separate directory
Basic Usage
import { App, Chart } from 'cdk8s'
import { ArgoSynth } from '@cdklib/argo-synth'
// Create an app for each environment
const stagingApp = new App()
const prodApp = new App()
// Create charts for your services
const stagingWebChart = new Chart(stagingApp, 'web')
const prodWebChart = new Chart(prodApp, 'web')
// Set paths for ArgoCD directory structure
ArgoSynth.addPath(stagingWebChart, 'staging', 'web')
ArgoSynth.addPath(prodWebChart, 'prod', 'web')
// Synthesize to output directory
await ArgoSynth.synth('gitops', [stagingApp, prodApp])This creates a directory structure like:
gitops/
āāā staging/
ā āāā web/
ā āāā ... (manifests)
āāā prod/
āāā web/
āāā ... (manifests)Which maps cleanly to ArgoCD applications targeting paths like:
staging/webprod/web
Integrated Usage
A recommended approach is to create base classes that automatically handle path management:
import { App, Chart } from 'cdk8s'
import { Construct } from 'constructs'
import { CdkArgo } from '@cdklib/argo-synth'
// Create a base App class that handles environment path setup
class BaseApp extends App {
constructor(envId: EnvId, props?: AppProps) {
super(props)
// The environment ID becomes the first path segment
ArgoSynth.addPath(this, envId)
}
}
// Create a base Chart class that automatically adds service paths
class BaseChart extends Chart {
constructor(scope: Construct, id: string) {
super(scope, id)
// The chart ID becomes the service name in the path
ArgoSynth.addPath(this, id)
}
}
// Usage:
const stagingApp = new BaseApp('staging')
const prodApp = new BaseApp('prod')
// Service charts automatically get the correct paths
const stagingWebChart = new BaseChart(stagingApp, 'web')
const prodWebChart = new BaseChart(prodApp, 'web')
// Synthesize to output directory
await ArgoSynth.synth('gitops', [stagingApp, prodApp])Integration with @cdklib/config
The library works seamlessly with @cdklib/config for type-safe environment management:
import { App, Chart, ApiObject } from 'cdk8s'
import { ArgoSynth } from '@cdklib/argo-synth'
import { CdkConfig, setEnvContext, EnvId } from '@cdklib/config'
import { z } from 'zod'
const webConfig = new CdkConfig(k8sSchema)
.set('staging', {
replicas: 2,
namespace: 'staging',
image: 'web-app:latest',
})
.set('prod', {
replicas: 5,
namespace: 'production',
image: 'web-app:stable',
})
// Create a base App class that uses environment IDs from config
class EnvApp extends App {
constructor(
readonly envId: EnvId,
props?: AppProps,
) {
super(props)
// Set the environment context for @cdklib/config integration
setEnvContext(this, envId)
// Set the path for ArgoCD structure
ArgoSynth.addPath(this, envId)
}
}
// Usage
const stagingApp = new EnvApp('staging')
const prodApp = new EnvApp('prod')
// Create charts for specific services with built-in config handling
class WebChart extends Chart {
constructor(scope: Construct) {
super(scope, 'web')
// Set the path for ArgoCD structure
ArgoSynth.addPath(this, 'web')
// Access config directly using this construct
const { replicas, image } = webConfig.get(this)
// Create resources using the environment-specific config
new ApiObject(this, 'deployment', {
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: { name: 'web' },
spec: {
replicas: replicas,
template: {
spec: {
containers: [
{
name: 'web',
image: image,
},
],
},
},
// ... other properties
},
})
}
}
// Usage
const stagingApp = new EnvApp('staging')
const prodApp = new EnvApp('prod')
// Create service charts - configuration is handled internally
const stagingWebChart = new WebChart(stagingApp)
const prodWebChart = new WebChart(prodApp)
// Synthesize
await ArgoSynth.synth('gitops', [stagingApp, prodApp])Best Practices
Environment Base Classes: Create a base App class that handles environment paths:
class EnvApp extends App { constructor(envId: EnvId, props?: AppProps) { super(props) // Set up both ArgoCD paths and @cdklib/config context setEnvContext(this, envId) ArgoSynth.addPath(this, envId) } }Service Base Classes: Create a base Chart class for services:
class ServiceChart extends Chart { constructor(scope: Construct, id: string) { super(scope, id) ArgoSynth.addPath(this, id) } }ArgoCD Application Structure: Design your ArgoCD applications to match your path structure:
# staging-web.yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: staging-web namespace: argocd spec: project: default source: repoURL: https://github.com/your-org/your-gitops-repo.git targetRevision: main path: gitops/staging/web destination: server: https://kubernetes.default.svc namespace: stagingIntegration with Config: Leverage
@cdklib/configfor type-safe environment configuration management:// In your construct code const { replicas, image } = webConfig.get(scope)
License
MIT