gitlabgitlab-ci

Controlling prod deployment with GitLab CI/CD


I'm trying to write a GitLab CI/CD pipeline that

  1. Runs a deployment job only if

    • a schedule pipeline starts with the env variable $CI_EVENT == "security_updates"
    • any push reaches the main branch
    • a user hits the run button at the Environments in the GitLab UI
  2. Runs a stop job only if

    • a user hits the stop button at the Environments in the GitLab UI

The following configuration does nearly what I want:

# other jobs and pipeline triggers...

deploy:
  stage: deploy
  environment:
    name: prod
    url: https://***.***.com/
    on_stop: stop
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule" && $CI_EVENT == "security_updates"
    - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "main"
      when: on_success
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual
  script:
    - docker compose up --build -d

stop:
  stage: deploy
  environment:
    name: prod
    action: stop
  when: manual
  script:
    - docker compose down

The issue is that the stop job is being scheduled for Merge Requests builds. Setting a rule for it specifying it should run only at the main branch solves the issue, except that it breaks the GitLab UI requirements.

stop:
  stage: deploy
  environment:
    name: prod
    action: stop
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual
  script:
    - docker compose down

After some research, I found many similar threads (Stop environment shows a note about not having an effect on any existing deployment, Gitlab doesn’t recognize stop action for environment, Stop environment shows a note about not having an effect on any existing deployment), but none of them seems to address exactly my issue.

Any ideas on how to fix this?


Solution

  • you'll need to refine your pipeline configuration to ensure the deploy and stop jobs only trigger under the specific conditions you want. Here's how you can adjust it:

    Deploy Job Your deploy job needs to run in three scenarios:

    When a scheduled pipeline with the $CI_EVENT variable set to security_updates is triggered. When any push to the main branch occurs. When a user manually triggers a deployment in the GitLab UI. To accomplish this, your deploy job should look like this:

    deploy:
      stage: deploy
      environment:
        name: prod
        url: https://***.***.com/
        on_stop: stop
      rules:
        - if: $CI_PIPELINE_SOURCE == "schedule" && $CI_EVENT == "security_updates"
        - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "main"
          when: on_success
        - if: $CI_PIPELINE_SOURCE == "pipeline" && $CI_COMMIT_BRANCH == "main"
          when: manual
      script:
        - docker compose up --build -d
    

    for the stop job, you want it to run only when a user clicks the stop button in the GitLab ui, and avoid triggering it during merge requests or other situations.

    here's how you can se it up:

    stop:
      stage: deploy
      environment:
        name: prod
        action: stop
      rules:
        - if: $CI_PIPELINE_SOURCE == "pipeline" && $CI_COMMIT_BRANCH == "main"
          when: manual
      script:
        - docker compose down
    

    the first rule checks for a scheduled pipeline with the security_updates event the second rule automatically triggers the deploy on any push to the main branch. the third rule allows the user to manually trigger the deployment from the GitLab UI when needed. and for the stop Job rules the stop job will only run manually when a user clicks the stop button in the environments section of the GitLab ui and only on the main branch.