> ## Documentation Index > Fetch the complete documentation index at: https://docs.ctrlplane.dev/llms.txt > Use this file to discover all available pages before exploring further. # Quickstart > Set up deployment orchestration with environment promotion and verification in 15 minutes. This guide walks you through setting up a complete deployment pipeline with staging → production promotion and automated verification. By the end, you'll have a working example of Ctrlplane's core capabilities. ## What You'll Build ```mermaid theme={null} flowchart LR CI["CI (build)"] --> Staging subgraph Staging["Staging"] direction TB S1["Deploy"] --> S2["Verify"] end Staging --> Production subgraph Production["Production"] direction TB P0["Approval"] --> P1["Deploy"] --> P2["Verify"] end ``` * **Deployment** with automatic version creation from CI * **Two environments** (staging, production) with resource selectors * **Verification** that checks deployment health before promotion * **Approval policy** requiring sign-off for production ## Prerequisites * Ctrlplane account ([app.ctrlplane.dev](https://app.ctrlplane.dev) or [self-hosted](./installation)) * API key (Settings → API Keys) * GitHub repository with CI workflow ## Step 1: Create a System A system groups related deployments. This is typically a product, platform, or bounded context. ```hcl Terraform theme={null} resource "ctrlplane_system" "quickstart" { name = "Tutorial Quickstart" description = "A tutorial on how to use Ctrlplane found in the Quickstart guide." } ``` ## Step 2: Register Resources Resources are your deployment targets. In production, you'd sync these from Kubernetes or cloud providers. For this quickstart, we'll create them manually. ```yaml YAML theme={null} # ctrlc apply -f resource.yaml --- type: Resource identifier: tutorial-quickstart-resource-staging kind: KubernetesCluster name: quickstart-staging-cluster version: tutorial/quickstart/v1 metadata: tutorial: quickstart environment: staging region: us-east-1 config: number: 1 string: "one" boolean: true array: - one - two - three --- type: Resource identifier: tutorial-quickstart-resource-production kind: KubernetesCluster name: quickstart-production-cluster version: tutorial/quickstart/v1 metadata: tutorial: quickstart environment: production region: us-east-1 config: number: 1 string: "one" boolean: true array: - one - two - three ``` ```hcl Terraform theme={null} resource "ctrlplane_resource" "quickstart_staging" { identifier = "tutorial-quickstart-resource-staging" kind = "KubernetesCluster" name = "quickstart-staging-cluster" version = "tutorial/quickstart/v1" metadata = { tutorial = "quickstart" environment = "staging" region = "us-east-1" } config = { number = 1 string = "one" boolean = true array = ["one", "two", "three"] } } resource "ctrlplane_resource" "quickstart_production" { identifier = "tutorial-quickstart-resource-production" kind = "KubernetesCluster" name = "quickstart-production-cluster" version = "tutorial/quickstart/v1" metadata = { tutorial = "quickstart" environment = "production" region = "us-east-1" } config = { number = 1 string = "one" boolean = true array = ["one", "two", "three"] } } ``` ```bash theme={null} ctrlc apply -f https://raw.githubusercontent.com/ctrlplanedev/ctrlplane/main/examples/quickstart/2-resources.yaml ``` ## Step 3: Create Environments Environments use selectors to dynamically match resources. When you add new clusters with matching metadata, they're automatically included. ```hcl Terraform theme={null} resource "ctrlplane_environment" "staging" { name = "Staging" description = "Pre-production validation" resource_selector = "resource.metadata['environment'] == 'staging'" } resource "ctrlplane_environment" "production" { name = "Production" description = "Live production environment" resource_selector = "resource.metadata['environment'] == 'production'" } ``` ## Step 4: Create a Job Agent Job agents execute your deployments. We'll use a simple test runner, but Ctrlplane supports GitHub Actions, Kubernetes jobs, ArgoCD, or custom agents. ```hcl Terraform theme={null} resource "ctrlplane_job_agent" "quickstart" { name = "Tutorial Quickstart Job Agent" description = "A tutorial on how to use Ctrlplane found in the Quickstart guide." test_runner { sleep = "5s" } } ``` ```bash theme={null} ctrlc apply -f https://raw.githubusercontent.com/ctrlplanedev/ctrlplane/main/examples/quickstart/4-job-agent.yaml ``` ## Step 5: Create a Deployment A deployment represents your application. The job agent config tells Ctrlplane how to trigger deployments. ```hcl Terraform theme={null} # Production environment resource "ctrlplane_deployment" "quickstart" { name = "Tutorial Quickstart Deployment" description = "A tutorial on how to use Ctrlplane found in the Quickstart guide." job_agent { id = ctrlplane_job_agent.quickstart.id } } ``` ## Step 6: Add Deployment Workflow Create `.github/workflows/deploy.yml` in your repository: ```yaml theme={null} name: Deploy on: workflow_dispatch: inputs: job_id: description: "Ctrlplane Job ID" required: true jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Get deployment context uses: ctrlplanedev/get-job-inputs@v1 id: job with: job_id: ${{ inputs.job_id }} api_key: ${{ secrets.CTRLPLANE_API_KEY }} - name: Deploy to Kubernetes run: | echo "Deploying ${{ steps.job.outputs.version_tag }}" echo "Environment: ${{ steps.job.outputs.environment_name }}" echo "Cluster: ${{ steps.job.outputs.resource_identifier }}" # Your deployment logic here # kubectl set image deployment/api-gateway \ # api-gateway=${{ steps.job.outputs.version_tag }} ``` Add `CTRLPLANE_API_KEY` to your repository secrets. ## Step 7: Integrate CI Build Add version creation to your build workflow (`.github/workflows/build.yml`): ```yaml theme={null} - name: Install Ctrlplane CLI uses: ctrlplanedev/cli@main with: api_key: ${{ secrets.CTRLPLANE_API_KEY }} - name: Create deployment version if: github.ref == 'refs/heads/main' run: | ctrlc api upsert version \ --workspace \ --deployment ${{ secrets.CTRLPLANE_DEPLOYMENT_ID }} \ --tag ${{ github.sha }} \ --name "${{ github.sha::7 }}" \ --metadata github/owner=${{ github.repository_owner }} \ --metadata github/repo=${{ github.event.repository.name }} \ --metadata git/sha=${{ github.sha }} \ --metadata git/branch=${{ github.ref_name }} \ --metadata github/run-number=${{ github.run_number }} \ --metadata github/run-id=${{ github.run_id }} \ --metadata github/run-attempt=${{ github.run_attempt }} ``` ## Step 8: Add Production Approval Create a policy requiring approval before production deployments ```hcl Terraform theme={null} resource "ctrlplane_policy" "production_approval" { name = "Production Approval Policy" description = "Production Approval Policy" selector { environments = "environment.metadata['requires-approval'] == 'true'" } approval { required = 1 } } ``` ## Step 9: Test the Pipeline 1. Push a commit to `main` 2. CI builds and creates a version in Ctrlplane 3. Ctrlplane creates releases for staging and production 4. Staging deployment executes immediately 5. Verification runs health checks 6. Production waits for approval 7. After approval, production deploys and verifies View the pipeline in the Ctrlplane UI: * **Deployments** → See version progression across environments * **Releases** → Track release progression across environments * **Jobs** → View execution details and logs ## What You've Built ✅ **Deployment orchestration** with automatic environment progression\ ✅ **Resource inventory** with metadata-based environment selectors\ ✅ **Verification** ensuring deployment health before promotion\ ✅ **Policy gates** requiring approval for production ## Next Steps Configure gradual rollouts, concurrency limits, and custom gates Add Datadog metrics, custom HTTP checks, and more Sync resources from Kubernetes, AWS, or custom providers Deploy with GitHub Actions, ArgoCD, or custom agents ## Troubleshooting **Jobs not being created:** * Verify resource metadata matches environment selectors * Check deployment has a job agent configured * Review policy denials in the Releases view **Verification failing:** * Test the health endpoint manually * Check the success condition syntax * Review measurement data in the verification details **GitHub workflow not triggering:** * Ensure job agent type is `github` * Verify workflow filename matches `jobAgentConfig` * Check GitHub App permissions Need help? [GitHub Discussions](https://github.com/ctrlplanedev/ctrlplane/discussions)