> ## Documentation Index
> Fetch the complete documentation index at: https://controlplanecorporation-jakob-ess-2-0-0.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# CI/CD Usage

> Automate deployments and resource management with the Control Plane CLI in CI/CD pipelines.

Use the Control Plane CLI in CI/CD pipelines to automate resource provisioning, image builds, and deployments.

## Overview

The CLI enables CI/CD workflows for:

* **Resource provisioning** - Apply GVC, workload, and infrastructure configurations
* **Image delivery** - Build and push container images to Control Plane
* **GitOps** - Maintain infrastructure as code in version control

## Quick start

<Steps>
  <Step title="Create a service account">
    Create a service account with appropriate permissions for your pipeline.

    See [Create a Service Account](#service-account-setup) for details.
  </Step>

  <Step title="Store credentials and context">
    Generate a key and store these environment variables in your CI/CD platform:

    * `CPLN_TOKEN` - The service account key (required)
    * `CPLN_ORG` - Your organization name (recommended)
    * `CPLN_GVC` - Your target GVC name (recommended)

    <Tip>
      Setting `CPLN_ORG` and `CPLN_GVC` as environment variables means you don't need to pass `--org` and `--gvc` flags with every command.
    </Tip>

    <Warning>
      Never print `CPLN_TOKEN` in logs or commit it to version control.
    </Warning>
  </Step>

  <Step title="Install the CLI">
    Install a pinned version of the CLI in your pipeline:

    <Tabs>
      <Tab title="npm">
        ```bash theme={null}
        npm install -g @controlplane/cli@<version>
        cpln --version
        ```
      </Tab>

      <Tab title="Binary">
        Download and extract the binary for your platform. See [Installation](/cli-reference/installation).
      </Tab>
    </Tabs>

    <Info>
      Pin the CLI version for reproducible builds.
    </Info>
  </Step>

  <Step title="Create a profile">
    Create a default profile in your pipeline:

    ```bash theme={null}
    cpln profile create ci --default
    ```

    <Tip>
      When `CPLN_TOKEN` is set as an environment variable, the CLI uses it automatically.
    </Tip>
  </Step>

  <Step title="Run pipeline commands">
    Execute CLI commands to build images and apply resources:

    ```bash theme={null}
    # Build and push image (optional)
    cpln image build --name <image-name>:<image-tag> --push

    # Apply resources
    cpln apply --file resources.yaml
    ```
  </Step>
</Steps>

## Service account setup

### Create the service account

<Tabs>
  <Tab title="Console">
    1. Navigate to **Org** → **Service Accounts**
    2. Click **Create**
    3. Enter a name (e.g., `ci-pipeline`)
    4. Assign to a group with appropriate permissions (e.g., `superusers` or a custom group)
  </Tab>

  <Tab title="CLI">
    ```bash theme={null}
    cpln serviceaccount create --name ci-pipeline --description "CI/CD automation"
    ```

    Add to a group:

    ```bash theme={null}
    cpln group add-member <group-name> --serviceaccount ci-pipeline
    ```
  </Tab>
</Tabs>

### Generate a key

Create an authentication key for the service account:

<Tabs>
  <Tab title="Console">
    1. Open the service account you created
    2. Click the **Keys** link
    3. Enter a key description (e.g., `ci-pipeline-key`) and click **Add**
    4. Copy and download the generated key securely
  </Tab>

  <Tab title="CLI">
    ```bash theme={null}
    cpln serviceaccount add-key ci-pipeline --description ci-pipeline-key
    ```

    Save the returned key securely.
  </Tab>
</Tabs>

Store the key in your CI/CD platform's secret manager as `CPLN_TOKEN`.

## Environment variables

Set these variables in your CI/CD platform:

### Required

* `CPLN_TOKEN` - Service account key (keep secret)

### Optional but recommended

* `CPLN_ORG` - Default organization
* `CPLN_GVC` - Default GVC

### Optional

* `CPLN_SKIP_UPDATE_CHECK` - Any non-empty value opts out of the CLI's daily new-version check and the notice it prints

<CodeGroup>
  ```bash GitHub Actions theme={null}
  env:
    CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}
    CPLN_ORG: my-org
    CPLN_GVC: production
  ```

  ```bash GitLab CI theme={null}
  variables:
    CPLN_ORG: my-org
    CPLN_GVC: production
  ```

  ```bash CircleCI theme={null}
  environment:
    CPLN_ORG: my-org
    CPLN_GVC: production
  ```
</CodeGroup>

## Common pipeline workflows

### Build and push images

```bash theme={null}
# Build and push
cpln image build --name <image-name>:<image-tag> --push
```

<Note>
  `cpln image build --push` runs the build locally through Docker — a Dockerfile build shells out to `docker buildx build`, and a buildpacks build runs the `pack` CLI — so the runner needs a working Docker daemon, and `--push` requires `docker-credential-cpln` on PATH (installed alongside the CLI).

  On runners without a daemon (for example, GitLab runners without privileged Docker-in-Docker), build with a daemonless tool such as kaniko or buildah and push directly to the org registry: the registry is `<org>.registry.cpln.io`, the username is the literal string `<token>`, and the password is the service account key.
</Note>

Building remotely is also available: `cpln image build --name <image-name>:<image-tag> --remote` uploads the build folder, and the image is built and pushed to the org registry with only `CPLN_TOKEN` and `CPLN_ORG` (or `--org`) — no daemon and no `docker-credential-cpln`, though the local build options (`--dockerfile`, `--builder`, `--buildpack`, `--env`, `--platform`) do not apply. With `--repo <https-url>`, the remote build clones a GitHub or GitLab repository instead of uploading the folder.

For a private repository, run that command once from your own terminal: the CLI opens the provider's authorization page and continues the build once you grant the org access to the repository. The connection is bound to the org, so from then on pipelines build that repository without any further prompting. A pipeline cannot do this first run itself — with no terminal attached, the CLI prints the connect link and stops.

### Apply resources (GitOps)

```bash theme={null}
# Apply a single file
cpln apply --file gvc.yaml

# Apply multiple files
cpln apply --file workload.yaml --file secret.yaml

# Apply from stdin
cat resource.yaml | cpln apply --file -
```

<AccordionGroup>
  <Accordion title="Resource ordering">
    A single `cpln apply` invocation orders resources automatically — agent, secret, cloudaccount, gvc, identity, volumeset, policy, workload, then all remaining kinds — so a workload and the GVC it references can live in the same file (or directory) in any order.

    Ordering only matters across separate `cpln apply` invocations: if you split resources into multiple pipeline steps, apply the referenced resource (e.g., the GVC) before the resource that references it.
  </Accordion>

  <Accordion title="Multi-document YAML">
    Separate multiple resources with `---` in a single file:

    ```yaml theme={null}
    kind: gvc
    name: my-gvc
    ---
    kind: workload
    name: my-app
    ```

    Apply with:

    ```bash theme={null}
    cpln apply --file resources.yaml
    ```
  </Accordion>

  <Accordion title="Handling renames">
    Renaming a resource in YAML creates a new resource. The old resource must be deleted manually:

    ```bash theme={null}
    cpln <command> delete <old-name>
    ```
  </Accordion>
</AccordionGroup>

### Export existing resources

Export "known good" configurations as templates for GitOps:

<Tabs>
  <Tab title="Console">
    Use the **Export** action to download JSON or YAML.
  </Tab>

  <Tab title="CLI">
    ```bash bash theme={null}
    cpln gvc get <name> --output yaml-slim > gvc.yaml
    cpln workload get <name> --gvc <gvc> --output yaml-slim > workload.yaml
    cpln secret get <name> --output yaml-slim > secret.yaml
    ```
  </Tab>
</Tabs>

<Info>
  Use `json-slim` or `yaml-slim` to remove non-essential properties like IDs, versions, and timestamps. This gives you only what's necessary for applying the resource with `cpln apply`.
</Info>

## Platform-specific examples

Complete working examples for popular CI/CD platforms:

<CardGroup cols={2}>
  <Card title="GitHub Actions" icon="github" href="https://github.com/controlplane-com/github-actions-example-cli">
    Full workflow with build, push, and apply
  </Card>

  <Card title="GitLab CI" icon="gitlab" href="https://gitlab.com/controlplane-com/gitlab-pipeline-example-cli">
    Pipeline configuration for GitLab
  </Card>

  <Card title="Bitbucket Pipelines" icon="bitbucket" href="https://bitbucket.org/controlplane-com/bitbucket-pipeline-example-cli">
    Bitbucket pipeline with Docker build
  </Card>

  <Card title="CircleCI" icon="circle" href="https://github.com/controlplane-com/circle-ci-pipeline-example-cli">
    CircleCI config with multi-stage workflow
  </Card>

  <Card title="Google Cloud Build" icon="google" href="https://github.com/controlplane-com/google-cloud-build-example-cli">
    Cloud Build with Secret Manager
  </Card>
</CardGroup>

## Best practices

<AccordionGroup>
  <Accordion title="Pin the CLI version">
    Specify an exact CLI version for reproducible builds:

    ```bash theme={null}
    npm install -g @controlplane/cli@x.x.x
    ```

    Update the version explicitly when you want to adopt new features.
  </Accordion>

  <Accordion title="Use dedicated service accounts">
    Create separate service accounts for different environments:

    * `ci-dev` for development
    * `ci-staging` for staging
    * `ci-production` for production

    Assign each to groups with scoped permissions.
  </Accordion>

  <Accordion title="Store secrets securely">
    * Use your CI/CD platform's secret manager
    * Never commit tokens to version control
    * Rotate service account keys regularly
    * Avoid printing `CPLN_TOKEN` in logs
  </Accordion>

  <Accordion title="Test in non-production first">
    Apply changes to development or staging environments before production:

    ```bash theme={null}
    # Staging
    cpln apply --file resources.yaml --org staging

    # Production (after staging succeeds)
    cpln apply --file resources.yaml --org production
    ```
  </Accordion>

  <Accordion title="Use slim output for templates">
    Export resources with `yaml-slim` or `json-slim` to remove metadata:

    ```bash theme={null}
    cpln gvc get my-gvc --output yaml-slim > gvc.yaml
    ```

    This creates clean templates suitable for version control and `cpln apply`.
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Authentication failures">
    1. Verify `CPLN_TOKEN` is set correctly in your CI/CD secrets
    2. Check the token hasn't expired or been revoked
    3. Ensure the service account has the required permissions
  </Accordion>

  <Accordion title="Wrong org or GVC">
    Verify that the `CPLN_ORG` and `CPLN_GVC` environment variables are set correctly.

    Or explicitly set org and GVC in commands:

    ```bash theme={null}
    cpln apply --file workload.yaml --org my-org --gvc my-gvc
    ```

    Or set in the profile:

    ```bash theme={null}
    cpln profile update ci --org my-org --gvc my-gvc
    ```
  </Accordion>
</AccordionGroup>

<Info>
  For more troubleshooting help, see the [Troubleshooting](/cli-reference/using-cli/troubleshooting) page.
</Info>

## Next steps

<CardGroup cols={2}>
  <Card title="Container Images" href="/cli-reference/ci-cd-development/container-image" icon="docker">
    Use the CLI inside container images
  </Card>

  <Card title="Profiles" href="/cli-reference/get-started/profiles" icon="user">
    Learn about profile management
  </Card>

  <Card title="cpln apply" href="/guides/cpln-apply" icon="code">
    GitOps resource management guide
  </Card>

  <Card title="Service Accounts" href="/guides/create-service-account" icon="key">
    Create and manage service accounts
  </Card>
</CardGroup>
