306 lines
8.6 KiB
Markdown
306 lines
8.6 KiB
Markdown
---
|
|
stage: Verify
|
|
group: Pipeline Execution
|
|
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
|
type: reference
|
|
---
|
|
|
|
# Pipeline architecture **(FREE)**
|
|
|
|
Pipelines are the fundamental building blocks for CI/CD in GitLab. This page documents
|
|
some of the important concepts related to them.
|
|
|
|
You can structure your pipelines with different methods, each with their
|
|
own advantages. These methods can be mixed and matched if needed:
|
|
|
|
- [Basic](#basic-pipelines): Good for straightforward projects where all the configuration is in one easy to find place.
|
|
- [Directed Acyclic Graph](#directed-acyclic-graph-pipelines): Good for large, complex projects that need efficient execution.
|
|
- [Parent-child pipelines](#parent-child-pipelines): Good for monorepos and projects with lots of independently defined components.
|
|
|
|
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
|
For an overview, see the [Parent-Child Pipelines feature demo](https://youtu.be/n8KpBSqZNbk).
|
|
|
|
- [Multi-project pipelines](downstream_pipelines.md#multi-project-pipelines): Good for larger products that require cross-project interdependencies,
|
|
like those with a [microservices architecture](https://about.gitlab.com/blog/2016/08/16/trends-in-version-control-land-microservices/).
|
|
|
|
For example, you might deploy your web application from three different GitLab projects.
|
|
With multi-project pipelines you can trigger a pipeline in each project, where each
|
|
has its own build, test, and deploy process. You can visualize the connected pipelines
|
|
in one place, including all cross-project interdependencies.
|
|
|
|
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
|
For an overview, see the [Multi-project pipelines demo](https://www.youtube.com/watch?v=g_PIwBM1J84).
|
|
|
|
## Basic Pipelines
|
|
|
|
This is the simplest pipeline in GitLab. It runs everything in the build stage concurrently,
|
|
and once all of those finish, it runs everything in the test and subsequent stages the same way.
|
|
It's not the most efficient, and if you have lots of steps it can grow quite complex, but it's
|
|
easier to maintain:
|
|
|
|
```mermaid
|
|
graph LR
|
|
subgraph deploy stage
|
|
deploy --> deploy_a
|
|
deploy --> deploy_b
|
|
end
|
|
subgraph test stage
|
|
test --> test_a
|
|
test --> test_b
|
|
end
|
|
subgraph build stage
|
|
build --> build_a
|
|
build --> build_b
|
|
end
|
|
build_a -.-> test
|
|
build_b -.-> test
|
|
test_a -.-> deploy
|
|
test_b -.-> deploy
|
|
```
|
|
|
|
Example basic `/.gitlab-ci.yml` pipeline configuration matching the diagram:
|
|
|
|
```yaml
|
|
stages:
|
|
- build
|
|
- test
|
|
- deploy
|
|
|
|
image: alpine
|
|
|
|
build_a:
|
|
stage: build
|
|
script:
|
|
- echo "This job builds something."
|
|
|
|
build_b:
|
|
stage: build
|
|
script:
|
|
- echo "This job builds something else."
|
|
|
|
test_a:
|
|
stage: test
|
|
script:
|
|
- echo "This job tests something. It will only run when all jobs in the"
|
|
- echo "build stage are complete."
|
|
|
|
test_b:
|
|
stage: test
|
|
script:
|
|
- echo "This job tests something else. It will only run when all jobs in the"
|
|
- echo "build stage are complete too. It will start at about the same time as test_a."
|
|
|
|
deploy_a:
|
|
stage: deploy
|
|
script:
|
|
- echo "This job deploys something. It will only run when all jobs in the"
|
|
- echo "test stage complete."
|
|
environment: production
|
|
|
|
deploy_b:
|
|
stage: deploy
|
|
script:
|
|
- echo "This job deploys something else. It will only run when all jobs in the"
|
|
- echo "test stage complete. It will start at about the same time as deploy_a."
|
|
environment: production
|
|
```
|
|
|
|
## Directed Acyclic Graph Pipelines
|
|
|
|
If efficiency is important to you and you want everything to run as quickly as possible,
|
|
you can use [Directed Acyclic Graphs (DAG)](../directed_acyclic_graph/index.md). Use the
|
|
[`needs` keyword](../yaml/index.md#needs) to define dependency relationships between
|
|
your jobs. When GitLab knows the relationships between your jobs, it can run everything
|
|
as fast as possible, and even skips into subsequent stages when possible.
|
|
|
|
In the example below, if `build_a` and `test_a` are much faster than `build_b` and
|
|
`test_b`, GitLab starts `deploy_a` even if `build_b` is still running.
|
|
|
|
```mermaid
|
|
graph LR
|
|
subgraph Pipeline using DAG
|
|
build_a --> test_a --> deploy_a
|
|
build_b --> test_b --> deploy_b
|
|
end
|
|
```
|
|
|
|
Example DAG `/.gitlab-ci.yml` configuration matching the diagram:
|
|
|
|
```yaml
|
|
stages:
|
|
- build
|
|
- test
|
|
- deploy
|
|
|
|
image: alpine
|
|
|
|
build_a:
|
|
stage: build
|
|
script:
|
|
- echo "This job builds something quickly."
|
|
|
|
build_b:
|
|
stage: build
|
|
script:
|
|
- echo "This job builds something else slowly."
|
|
|
|
test_a:
|
|
stage: test
|
|
needs: [build_a]
|
|
script:
|
|
- echo "This test job will start as soon as build_a finishes."
|
|
- echo "It will not wait for build_b, or other jobs in the build stage, to finish."
|
|
|
|
test_b:
|
|
stage: test
|
|
needs: [build_b]
|
|
script:
|
|
- echo "This test job will start as soon as build_b finishes."
|
|
- echo "It will not wait for other jobs in the build stage to finish."
|
|
|
|
deploy_a:
|
|
stage: deploy
|
|
needs: [test_a]
|
|
script:
|
|
- echo "Since build_a and test_a run quickly, this deploy job can run much earlier."
|
|
- echo "It does not need to wait for build_b or test_b."
|
|
environment: production
|
|
|
|
deploy_b:
|
|
stage: deploy
|
|
needs: [test_b]
|
|
script:
|
|
- echo "Since build_b and test_b run slowly, this deploy job will run much later."
|
|
environment: production
|
|
```
|
|
|
|
## Parent-child pipelines
|
|
|
|
As pipelines grow more complex, a few related problems start to emerge:
|
|
|
|
- The staged structure, where all steps in a stage must complete before the first
|
|
job in next stage begins, causes waits that slow things down.
|
|
- Configuration for the single global pipeline becomes
|
|
hard to manage.
|
|
- Imports with [`include`](../yaml/index.md#include) increase the complexity of the configuration, and can cause
|
|
namespace collisions where jobs are unintentionally duplicated.
|
|
- Pipeline UX has too many jobs and stages to work with.
|
|
|
|
Additionally, sometimes the behavior of a pipeline needs to be more dynamic. The ability
|
|
to choose to start sub-pipelines (or not) is a powerful ability, especially if the
|
|
YAML is dynamically generated.
|
|
|
|
![Parent pipeline graph expanded](img/parent_pipeline_graph_expanded_v14_3.png)
|
|
|
|
In the [basic pipeline](#basic-pipelines) and [directed acyclic graph](#directed-acyclic-graph-pipelines)
|
|
examples above, there are two packages that could be built independently.
|
|
These cases are ideal for using [parent-child pipelines](downstream_pipelines.md#parent-child-pipelines).
|
|
It separates out the configuration into multiple files, keeping things simpler.
|
|
You can combine parent-child pipelines with:
|
|
|
|
- The [`rules` keyword](../yaml/index.md#rules): For example, have the child pipelines triggered only
|
|
when there are changes to that area.
|
|
- The [`include` keyword](../yaml/index.md#include): Bring in common behaviors, ensuring
|
|
you are not repeating yourself.
|
|
- [DAG pipelines](#directed-acyclic-graph-pipelines) inside of child pipelines, achieving the benefits of both.
|
|
|
|
```mermaid
|
|
graph LR
|
|
subgraph Parent pipeline
|
|
trigger_a -.-> build_a
|
|
trigger_b -.-> build_b
|
|
subgraph child pipeline B
|
|
build_b --> test_b --> deploy_b
|
|
end
|
|
|
|
subgraph child pipeline A
|
|
build_a --> test_a --> deploy_a
|
|
end
|
|
end
|
|
```
|
|
|
|
Example `/.gitlab-ci.yml` configuration for the parent pipeline matching the diagram:
|
|
|
|
```yaml
|
|
stages:
|
|
- triggers
|
|
|
|
trigger_a:
|
|
stage: triggers
|
|
trigger:
|
|
include: a/.gitlab-ci.yml
|
|
rules:
|
|
- changes:
|
|
- a/*
|
|
|
|
trigger_b:
|
|
stage: triggers
|
|
trigger:
|
|
include: b/.gitlab-ci.yml
|
|
rules:
|
|
- changes:
|
|
- b/*
|
|
```
|
|
|
|
Example child `a` pipeline configuration, located in `/a/.gitlab-ci.yml`, making
|
|
use of the DAG `needs` keyword:
|
|
|
|
```yaml
|
|
stages:
|
|
- build
|
|
- test
|
|
- deploy
|
|
|
|
image: alpine
|
|
|
|
build_a:
|
|
stage: build
|
|
script:
|
|
- echo "This job builds something."
|
|
|
|
test_a:
|
|
stage: test
|
|
needs: [build_a]
|
|
script:
|
|
- echo "This job tests something."
|
|
|
|
deploy_a:
|
|
stage: deploy
|
|
needs: [test_a]
|
|
script:
|
|
- echo "This job deploys something."
|
|
environment: production
|
|
```
|
|
|
|
Example child `b` pipeline configuration, located in `/b/.gitlab-ci.yml`, making
|
|
use of the DAG `needs` keyword:
|
|
|
|
```yaml
|
|
stages:
|
|
- build
|
|
- test
|
|
- deploy
|
|
|
|
image: alpine
|
|
|
|
build_b:
|
|
stage: build
|
|
script:
|
|
- echo "This job builds something else."
|
|
|
|
test_b:
|
|
stage: test
|
|
needs: [build_b]
|
|
script:
|
|
- echo "This job tests something else."
|
|
|
|
deploy_b:
|
|
stage: deploy
|
|
needs: [test_b]
|
|
script:
|
|
- echo "This job deploys something else."
|
|
environment: production
|
|
```
|
|
|
|
It's also possible to set jobs to run before or after triggering child pipelines,
|
|
for example if you have common setup steps or a unified deployment at the end.
|