Setting up an automated deployment pipeline shouldn't require gluing together messy shell scripts or fighting proprietary configuration formats. Concourse CI offers a container-native approach where every task runs in an isolated environment, ensuring your builds are reproducible and completely self-contained.
Whether you're migrating legacy build servers or architecting a multi-stage release pipeline from scratch, understanding how Concourse structures jobs, resources, and credentials will save hours of trial and error. This guide breaks down the core architecture, practical pipeline setup steps, security best practices, and common troubleshooting patterns for engineering teams.
Understanding Concourse Architecture
Concourse relies on a clean separation of concerns across three primary components. Unlike traditional servers that maintain persistent state or local caches on the worker nodes, Concourse treats infrastructure as ephemeral.
- The ATC (API, Task, and Controller): Acts as the central brain. It parses your pipeline configurations, schedules jobs, manages triggers, and exposes the web UI and CLI interface.
- The Garden: The low-level container management daemon running on worker nodes. It provisions, isolates, and destroys containers for every task execution.
- The Baggageclaim: A volume management subsystem attached to workers. It handles caching, inputs, and outputs between jobs so artifacts stream efficiently without disk bloat.
Because workers don't store persistent local state, you can scale worker capacity up or down instantly. If a worker node crashes mid-build, the ATC simply reschedules the task on another healthy node in the pool.
Defining Your First Pipeline in YAML
Concourse pipelines are defined entirely in declarative YAML files. You push these configurations to the server using the Fly CLI. A standard pipeline consists of three core primitives: resources, resource types, and jobs.
- Resources: External state representations, such as a Git repository, an S3 bucket, a Docker image registry, or a pull request webhook.
- Resource Types: The underlying plugins that tell Concourse how to check, get, and put specific resource kinds.
- Jobs: Directed acyclic graphs (DAGs) made of steps that consume inputs, run tasks inside isolated containers, and produce outputs.
Here is a simple, production-ready pipeline structure that checks a GitHub repository, runs unit tests inside a container, and publishes the build artifact:
resources:
- name: source-repo
type: git
source:
uri: https://github.com/example/my-app.git
branch: main
- name: app-image
type: docker-image
source:
repository: registry.hub.docker.com/example/my-app
username: ((dockerhub-user))
password: ((dockerhub-password))
jobs:
- name: test-and-build
public: true
plan:
- get: source-repo
trigger: true
- task: run-tests
config:
platform: linux
image_resource:
type: docker-image
source: {repository: golang, tag: "1.22"}
inputs:
- name: source-repo
run:
path: source-repo/ci/test.sh
- put: app-image
params:
build: source-repo
Step-by-Step Implementation Workflow
Deploying and running a pipeline requires connecting your local development environment to the Concourse deployment via the Fly CLI. Follow these steps to initialize, set, and execute your build pipeline:
- Download and Configure Fly: Install the CLI matching your Concourse server version. Log in using your target cluster endpoint:
fly -t production login -c [https://ci.example.com](https://ci.example.com) -u admin. - Validate Pipeline Syntax: Before pushing changes, run
fly -t production validate-pipeline -p my-pipeline -c pipeline.ymlto catch YAML indentation or schema errors early. - Set the Pipeline: Upload your configuration to the server using
fly -t production set-pipeline -p my-pipeline -c pipeline.yml. Concourse stores the configuration as paused initially. - Unpause and Trigger: Enable the pipeline via the web UI or CLI using
fly -t production unpause-pipeline -p my-pipeline. Trigger a manual run withfly -t production trigger-job -j my-pipeline/test-and-buildto verify execution flow.
Managing Credentials Securely
Hardcoding API tokens, private keys, or passwords inside public pipeline YAML files is a critical security risk. Concourse solves this through variable interpolation using double parentheses, such as ((db-password)).
You can back these variables with secret managers like HashiCorp Vault or AWS Secrets Manager. When the ATC evaluates a pipeline step, it fetches secrets dynamically at runtime. This ensures developers have visibility into pipeline logic without exposing production keys in source control repositories.
- Credential Managers: Configure your Concourse deployment with a Vault backend to automatically scope secrets per team and pipeline.
- Least Privilege: Restrict worker nodes handling production deployments to dedicated isolation pools so test workloads cannot access sensitive network segments.
- Ephemeral Tokens: Rotate database credentials and container registry tokens automatically via short-lived auth tokens injected during task execution.
Common Pitfalls and How to Avoid Them
Teams transitioning from imperative build servers often run into specific anti-patterns when designing Concourse pipelines.
- Relying on Local Caches: Because workers are ephemeral, do not expect files written outside designated resource outputs to persist across builds. Use shared caching mechanisms or external artifact stores.
- Monolithic Tasks: Packing too many distinct build steps into a single monolithic shell script makes debugging difficult. Break steps down into discrete tasks so you can inspect logs for each individual phase in the UI.
- Ignoring Resource Check Intervals: Setting check intervals too aggressive on heavy Git repositories or private registries can exhaust rate limits. Tune check timeouts appropriately for your team's commit frequency.
Frequently Asked Questions
How does Concourse handle build failures?
When a job step fails, Concourse stops execution of that branch immediately, marks the build as failed, and preserves the container state for a configured retention window. Engineers can use fly intercept to log directly into the failed container instance for live debugging.
Can Concourse run Windows containers?
Yes. While Linux containers on Garden are the default, Concourse supports Windows workers capable of orchestrating native Windows Server container workloads and .NET Framework builds.
How do I share pipeline templates across multiple teams?
You can parameterize pipeline YAML files using external YAML template files passed during the set-pipeline command, or leverage community macro tools to generate repetitive pipeline structures programmatically.
What is the best way to handle database services in tests?
Concourse allows you to attach sidecar containers (called services) to task steps. You can spin up an ephemeral PostgreSQL or Redis container alongside your test runner container, ensuring tests execute against clean database instances every time.