- Restrict write access to a critical environment
- Ensure only one deployment job runs at a time
- Skip outdated deployment jobs
- Prevent deployments during deploy freeze windows
- Setting appropriate roles to your project
- Protect production secrets
- Separate project for deployments
- Protect
gitlab-ci.yml
from change - Troubleshooting
Deployment safety
Deployment jobs can be more sensitive than other jobs in a pipeline, and might need to be treated with extra care. GitLab has several features that help maintain deployment security and stability.
You can:
- Restrict write-access to a critical environment
- Prevent deployments during deploy freeze windows
- Set appropriate roles to your project
- Protect production secrets
- Separate project for deployments
If you are using a continuous deployment workflow and want to ensure that concurrent deployments to the same environment do not happen, you should enable the following options:
Restrict write access to a critical environment
By default, environments can be modified by any team member that has Developer permission or higher.
If you want to restrict write access to a critical environment (for example a production
environment),
you can set up protected environments.
Ensure only one deployment job runs at a time
Pipeline jobs in GitLab CI/CD run in parallel, so it’s possible that two deployment jobs in two different pipelines attempt to deploy to the same environment at the same time. This is not desired behavior as deployments should happen sequentially.
You can ensure only one deployment job runs at a time with the resource_group
keyword in your .gitlab-ci.yml
.
For example:
deploy:
script: deploy-to-prod
resource_group: prod
Example of a problematic pipeline flow before using the resource group:
-
deploy
job in Pipeline-A starts running. -
deploy
job in Pipeline-B starts running. This is a concurrent deployment that could cause an unexpected result. -
deploy
job in Pipeline-A finished. -
deploy
job in Pipeline-B finished.
The improved pipeline flow after using the resource group:
-
deploy
job in Pipeline-A starts running. -
deploy
job in Pipeline-B attempts to start, but waits for the firstdeploy
job to finish. -
deploy
job in Pipeline-A finishes. -
deploy
job in Pipeline-B starts running.
For more information, see resource_group
keyword in .gitlab-ci.yml
.
Skip outdated deployment jobs
The execution order of pipeline jobs can vary from run to run, which could cause undesired behavior. For example, a deployment job in a newer pipeline could finish before a deployment job in an older pipeline. This creates a race condition where the older deployment finished later, overwriting the “newer” deployment.
You can ensure that older deployment jobs are cancelled automatically when a newer deployment runs by enabling the Skip outdated deployment jobs feature.
Example of a problematic pipeline flow before enabling Skip outdated deployment jobs:
- Pipeline-A is created on the default branch.
- Later, Pipeline-B is created on the default branch (with a newer commit SHA).
- The
deploy
job in Pipeline-B finishes first, and deploys the newer code. - The
deploy
job in Pipeline-A finished later, and deploys the older code, overwriting the newer (latest) deployment.
The improved pipeline flow after enabling Skip outdated deployment jobs:
- Pipeline-A is created on the default branch.
- Later, Pipeline-B is created on the default branch (with a newer SHA).
- The
deploy
job in Pipeline-B finishes first, and deploys the newer code. - The
deploy
job in Pipeline-A is automatically cancelled, so that it doesn’t overwrite the deployment from the newer pipeline.
Prevent deployments during deploy freeze windows
If you want to prevent deployments for a particular period, for example during a planned vacation period when most employees are out, you can set up a Deploy Freeze. During a deploy freeze period, no deployment can be executed. This is helpful to ensure that deployments do not happen unexpectedly.
Setting appropriate roles to your project
GitLab supports several different roles that can be assigned to your project members. See Project members permissions for an explanation of these roles and the permissions of each.
Protect production secrets
Production secrets are needed to deploy successfully. For example, when deploying to the cloud, cloud providers require these secrets to connect to their services. In the project settings, you can define and protect CI/CD variables for these secrets. Protected variables are only passed to pipelines running on protected branches or protected tags. The other pipelines don’t get the protected variable. You can also scope variables to specific environments. We recommend that you use protected variables on protected environments to make sure that the secrets aren’t exposed unintentionally. You can also define production secrets on the runner side. This prevents other maintainers from reading the secrets and makes sure that the runner only runs on protected branches.
For more information, see pipeline security.
Separate project for deployments
All project maintainers have access to production secrets. If you need to limit the number of users that can deploy to a production environment, you can create a separate project and configure a new permission model that isolates the CD permissions from the original project and prevents the original project’s maintainers from accessing the production secret and CD configuration. You can connect the CD project to your development projects by using multi-project pipelines.
Protect gitlab-ci.yml
from change
A .gitlab-ci.yml
may contain rules to deploy an application to the production server. This
deployment usually runs automatically after pushing a merge request. To prevent developers from
changing the gitlab-ci.yml
, you can define it in a different repository. The configuration can
reference a file in another project with a completely different set of permissions (similar to
separating a project for deployments).
In this scenario, the gitlab-ci.yml
is publicly accessible, but can only be edited by users with
appropriate permissions in the other project.
For more information, see Custom CI/CD configuration path.
Troubleshooting
Pipelines jobs fail with The deployment job is older than the previously succeeded deployment job...
This is caused by the Skip outdated deployment jobs feature. If you have multiple jobs for the same environment (including non-deployment jobs), you might encounter this problem, for example:
build:service-a:
environment:
name: production
build:service-b:
environment:
name: production
The Skip outdated deployment jobs might not work well with this configuration, and must be disabled.