Programmatic Orchestration via GitLab Dynamic Child Pipelines

The architectural complexity of modern software delivery often renders static CI/CD configurations obsolete. In traditional pipeline models, the .gitlab-ci.yml file acts as a rigid blueprint, where every job and stage is predefined. However, when a deployment requires a variable number of environments or needs to scale tasks based on external input—such as triggering a create-env job multiple times—static definitions become a liability. This is where dynamic pipelines in GitLab CI emerge as the critical solution. By generating pipeline configurations programmatically based on specific conditions or parameters, GitLab allows the steps and tasks of a pipeline to shift dynamically according to the input or context.

This capability transforms the CI/CD pipeline from a fixed sequence of events into a flexible engine. For instance, if a developer needs to run the same task hundreds of times with subtle variations for each instance, manually writing these variations would be tedious and practically impossible. Dynamic pipelines eliminate the need for thousands of lines of manual code by automating the generation of the YAML configuration. This programmatic approach is essential for managing large-scale CI/CD ecosystems where tasks and dependencies are not constant but vary based on the operational context.

The Mechanics of Dynamic Pipeline Generation

The core objective of a dynamic pipeline is to move the definition of the pipeline from a static file to a runtime artifact. This is achieved through a parent-child relationship where the parent pipeline executes a "generator" job, and the resulting output is used as the configuration for a child pipeline.

The fundamental workflow involves the following components:

  • A master job: This job is responsible for executing the logic that determines the pipeline's structure.
  • A generation script: Typically written in a language like Python, this script processes input parameters to create a YAML file.
  • An artifact: The generated YAML file must be passed as an artifact so the GitLab runner can access it to trigger the child pipeline.

In a practical implementation, such as the bootstrap-env scenario, the structure typically consists of a .gitlab-ci.yml file, a generate_templates.py script, and a requirements.txt file for Python dependencies. The process begins in the templating stage, where the Python script takes a comma-separated list of environments (e.g., dev,prod,staging) as input and outputs a file named environments.yml. This file contains the actual job definitions that the child pipeline will execute.

Technical Implementation and Configuration

To implement a dynamic pipeline, the parent configuration must define the stages and the trigger mechanism. The following table outlines the primary components of a dynamic setup.

Component Purpose Example Implementation
Master Job Generates the YAML config generate-templates
Image Execution environment python:3.10
Input Variable User-defined parameters ENVIRONMENTS
Artifact The dynamic config file environments.yml
Trigger Initiation of child pipeline trigger: include: artifact

The implementation requires a specific sequence of operations. First, the generate-templates job is executed in the templating stage. This job utilizes a before_script to install necessary dependencies via pip install -r requirements.txt and then runs the generation script using a command such as python generate_templates.py --env $ENVIRONMENTS.

Once the environments.yml artifact is created, the deploy-envs job in the deployment stage triggers the child pipeline. The syntax used is as follows:

yaml deploy-envs: stage: deployment trigger: include: - artifact: environments.yml job: generate-templates strategy: depend

The strategy: depend keyword is vital here, as it ensures that the parent pipeline's status depends on the successful completion of the child pipeline.

Deep Dive into Artifact-Based Child Pipeline Creation

The ability to create child pipelines via artifact includes was a significant evolution in GitLab CI. Previously, the include keyword only supported local, file, template, and remote sources. The introduction of the artifact keyword allows for a tighter loop between generation and execution.

The technical flow for artifact-based triggers follows this logic:

  1. A job (e.g., generate-config) runs a script that generates one or more YAML files.
  2. These files (e.g., config-a.yml, config-b.yml) are saved as artifacts.
  3. Subsequent jobs use the trigger:include:artifact syntax to start child pipelines based on those specific files.

For example, a pipeline might have a build stage that generates different configurations for different services:

```yaml
generate-config:
stage: build
script:
- generateyaml --service=A > config-a.yml
- generate
yaml --service=B > config-b.yml
artifacts:
paths:
- config-a.yml
- config-b.yml

service-a:
stage: test
trigger:
include:
- artifact: config-a.yml
job: generate-config
```

This architecture allows the server-side artifact download to be evaluated during the trigger process, enabling the creation of child pipelines based on the specific outputs of the preceding jobs.

Constraints and Known Limitations

Despite the power of dynamic pipelines, there are critical technical hurdles and bugs that developers must navigate. A primary issue exists regarding variable resolution within dynamic child pipeline includes.

When defining an include inside a dynamically generated YAML file, using variables for attributes such as project, ref, or file often fails. The values of these variables are frequently resolved as empty, leading to a yaml invalid error, which prevents the child pipeline from starting.

The problematic scenario typically looks like this in a generated file:

yaml include: - project: '$MYLIB_PATH' ref: 'master' file: '/lib/gitlab/ci/templates/Jobs/Secret-Detection.gitlab-ci.yml'

Even if the parent pipeline uses forward: pipeline_variables: true or yaml_variables: true, the resolution may still fail if the child pipeline is triggered via an artifact. The only known reliable workaround for this behavior is to use the inputs feature instead of relying on standard CI/CD variables for these specific include definitions.

Advanced Input Selection and UI Configuration

To bridge the gap between technical pipeline power and non-technical user accessibility, GitLab has explored dynamic input selection. This allows users to configure pipeline inputs directly from the User Interface (UI) via dropdowns rather than manually editing variable strings.

The proposed technical structure for dynamic input selection involves a rules-based system. This allows the available options for an input to change based on the value of another input. For example, the available virtual machine sizes (instance_type) can change based on the selected cloud_provider and environment.

The logic for such a system is defined as follows:

  • If cloud_provider is aws and environment is development, the options are t3.micro and t3.small, with a default of t3.micro.
  • If cloud_provider is gcp and environment is production, the options are e2-standard-4 and e2-standard-8, with a default of e2-standard-4.

The API structure supporting this functionality represents the input as a complex object containing types, descriptions, and a list of rules. This ensures that non-technical users can trigger complex, dynamic pipelines without needing to understand the underlying YAML generation logic.

Integration with External Ecosystems and Security

A robust dynamic pipeline is rarely an island; it typically integrates with broader DevOps lifecycles and security tools. The use of GitLab CI for dynamic pipelines facilitates the implementation of GitOps best practices and the deployment of applications into Kubernetes.

Integration with security and compliance tools, such as FOSSA, is a common requirement in these pipelines. By incorporating FOSSA into the CI/CD setup, teams can automate license compliance and vulnerability management. This is often achieved by adding specific security stages to the .gitlab-ci.yml or the dynamically generated child pipelines, ensuring that every dynamically created environment is scanned for vulnerabilities before proceeding to deployment.

The synergy between dynamic pipelines and security tools allows for "security-as-code," where the security scans are not just static checks but are dynamically scaled based on the number of environments being deployed.

Conclusion: Analytical Assessment of Dynamic Orchestration

The shift from static to dynamic pipelines in GitLab CI represents a fundamental change in how infrastructure is managed. By treating the pipeline configuration as a runtime artifact rather than a source-control constant, organizations can achieve a level of scalability that was previously impossible. The ability to programmatically generate jobs based on user input effectively removes the "boilerplate" burden from developers, allowing them to focus on the logic of the generation script rather than the maintenance of massive YAML files.

However, the transition to dynamic pipelines introduces new complexities. The dependency on artifacts creates a tighter coupling between jobs, and the current limitations regarding variable resolution in child pipeline includes indicate that the feature is still evolving. The proposed movement toward "inputs" and UI-driven dynamic selection suggests that GitLab is moving toward a more abstracted, user-friendly orchestration layer.

Ultimately, the value of dynamic pipelines lies in their capacity to handle variability. Whether it is managing a variable number of cloud environments, scaling test suites based on the size of a commit, or integrating complex security audits via FOSSA, the programmatic approach provides the only viable path for enterprises operating at scale. The true mastery of this system requires not just knowledge of YAML, but proficiency in the scripting languages used to generate it and a deep understanding of the artifact lifecycle within the GitLab runner ecosystem.

Sources

  1. Theodo Blog - Complex GitLab Pipelines
  2. GitLab Issue 35632 - Dynamic child pipeline creation via artifact includes
  3. GitLab Issue 378717 - Dynamic Child Pipeline (artifact) can't use variables in include definitions
  4. GitLab Issue 520094 - Dynamic Input Selection in GitLab Pipelines planning/discussion
  5. FOSSA - GitLab CI/CD: Setup, Pipeline Configuration, and FOSSA Integration

Related Posts