0.2.0 • Published 8 months ago

@cdklib/argo-synth v0.2.0

Weekly downloads
-
License
MIT
Repository
github
Last release
8 months ago

@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

# Using npm
npm install @cdklib/argo-synth

# Using yarn
yarn add @cdklib/argo-synth

# Using pnpm
pnpm add @cdklib/argo-synth

Key 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/web
  • prod/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

  1. 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)
      }
    }
  2. 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)
      }
    }
  3. 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: staging
  4. Integration with Config: Leverage @cdklib/config for type-safe environment configuration management:

    // In your construct code
    const { replicas, image } = webConfig.get(scope)

License

MIT

0.2.0

8 months ago

0.1.0

8 months ago