Backend

GitLab CI/CD 시리즈 #6: 외부 통합 - Triggers, Webhooks, API

2026-01-057 min read

GitLab CI/CD 시리즈 #6: 외부 통합 - Triggers, Webhooks, API

시리즈 개요

#주제핵심 내용
1기초.gitlab-ci.yml 구조, Stages, Jobs, Pipeline 흐름
2Variables & Secrets변수 유형, 우선순위, 외부 Vault 연동
3Runners & ExecutorsDocker, Kubernetes, Docker-in-Docker
4Pipeline 아키텍처Parent-Child, Multi-Project Pipeline
5고급 Job 제어rules, needs, DAG, extends
6외부 통합Triggers, Webhooks, API

Pipeline Triggers

외부 시스템에서 토큰 기반으로 파이프라인을 트리거합니다.

Trigger Token 생성

  1. Settings > CI/CD > Pipeline trigger tokens
  2. Add trigger 클릭
  3. 설명 입력 후 생성
  4. 생성된 토큰 복사

트리거 실행

# 기본 트리거
curl --request POST \
  --form "token=YOUR_TRIGGER_TOKEN" \
  --form "ref=main" \
  "https://gitlab.com/api/v4/projects/PROJECT_ID/trigger/pipeline"

# 변수와 함께
curl --request POST \
  --form "token=YOUR_TRIGGER_TOKEN" \
  --form "ref=main" \
  --form "variables[DEPLOY_ENV]=production" \
  --form "variables[VERSION]=1.2.3" \
  "https://gitlab.com/api/v4/projects/PROJECT_ID/trigger/pipeline"

파이프라인에서 트리거 감지

deploy:
  script:
    - ./deploy.sh
  rules:
    - if: $CI_PIPELINE_SOURCE == "trigger"
      variables:
        DEPLOY_TOKEN: $DEPLOY_TOKEN  # 트리거로 전달된 변수

Trigger 전용 Job

triggered-deploy:
  script:
    - echo "Deploying version $VERSION to $DEPLOY_ENV"
  rules:
    - if: $CI_PIPELINE_SOURCE == "trigger"
  needs: []  # 다른 Job 대기 없이 즉시 실행

Webhooks

외부 이벤트를 수신하여 파이프라인을 트리거합니다.

Webhook URL 형식

https://gitlab.com/api/v4/projects/PROJECT_ID/ref/REF_NAME/trigger/pipeline?token=TOKEN

실제 Webhook 설정

# GitHub → GitLab 트리거
# GitHub 저장소의 Webhooks에 등록
https://gitlab.com/api/v4/projects/12345/ref/main/trigger/pipeline?token=abc123

# AWS SNS → GitLab 트리거
# Lambda를 통해 변환 후 트리거

Webhook Payload 접근

process-webhook:
  script:
    - echo "$TRIGGER_PAYLOAD" | jq .
    - export EVENT_TYPE=$(echo "$TRIGGER_PAYLOAD" | jq -r '.event_type')
    - |
      if [ "$EVENT_TYPE" = "release" ]; then
        ./deploy-release.sh
      fi
  rules:
    - if: $CI_PIPELINE_SOURCE == "trigger"

GitLab API로 파이프라인 제어

파이프라인 생성

# Personal Access Token 사용
curl --request POST \
  --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "ref": "main",
    "variables": [
      {"key": "DEPLOY_ENV", "value": "staging"},
      {"key": "DEBUG", "value": "true"}
    ]
  }' \
  "https://gitlab.com/api/v4/projects/PROJECT_ID/pipeline"

파이프라인 상태 조회

# 특정 파이프라인
curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "https://gitlab.com/api/v4/projects/PROJECT_ID/pipelines/PIPELINE_ID"

# 최근 파이프라인
curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "https://gitlab.com/api/v4/projects/PROJECT_ID/pipelines?per_page=5"

Job 재시도

curl --request POST \
  --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "https://gitlab.com/api/v4/projects/PROJECT_ID/jobs/JOB_ID/retry"

파이프라인 취소

curl --request POST \
  --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "https://gitlab.com/api/v4/projects/PROJECT_ID/pipelines/PIPELINE_ID/cancel"

CI Job Token

파이프라인 내에서 GitLab API를 호출할 때 사용하는 임시 토큰입니다.

CI_JOB_TOKEN 사용

notify-other-project:
  script:
    # 다른 프로젝트 파이프라인 트리거
    - |
      curl --request POST \
        --form "token=$CI_JOB_TOKEN" \
        --form "ref=main" \
        "https://gitlab.com/api/v4/projects/OTHER_PROJECT_ID/trigger/pipeline"

아티팩트 다운로드

download-artifacts:
  script:
    - |
      curl --header "JOB-TOKEN: $CI_JOB_TOKEN" \
        --output artifacts.zip \
        "https://gitlab.com/api/v4/projects/PROJECT_ID/jobs/JOB_ID/artifacts"
    - unzip artifacts.zip

권한 설정

Settings > CI/CD > Token Access에서 허용할 프로젝트를 설정합니다.


ChatOps 연동

Slack 알림

notify-slack:
  stage: .post
  script:
    - |
      curl -X POST -H 'Content-type: application/json' \
        --data '{
          "channel": "#deployments",
          "username": "GitLab CI",
          "text": "✅ Pipeline succeeded for $CI_PROJECT_NAME",
          "attachments": [{
            "color": "good",
            "fields": [
              {"title": "Branch", "value": "'$CI_COMMIT_BRANCH'", "short": true},
              {"title": "Commit", "value": "'$CI_COMMIT_SHORT_SHA'", "short": true}
            ]
          }]
        }' \
        $SLACK_WEBHOOK_URL
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: on_success

배포 승인 (Slack → GitLab)

# Slack 버튼 클릭 → Lambda → GitLab API
request-approval:
  stage: deploy
  script:
    - |
      curl -X POST -H 'Content-type: application/json' \
        --data '{
          "text": "🚀 Production deployment pending",
          "attachments": [{
            "text": "Approve deployment?",
            "callback_id": "deploy_'$CI_PIPELINE_ID'",
            "actions": [
              {"name": "approve", "text": "Approve", "type": "button", "style": "primary"},
              {"name": "reject", "text": "Reject", "type": "button", "style": "danger"}
            ]
          }]
        }' \
        $SLACK_WEBHOOK_URL
  environment:
    name: production
    action: prepare

외부 CI/CD 시스템 연동

Jenkins → GitLab

// Jenkinsfile
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'make build'
            }
        }
        stage('Trigger GitLab') {
            steps {
                sh '''
                    curl --request POST \
                      --form "token=${GITLAB_TRIGGER_TOKEN}" \
                      --form "ref=main" \
                      --form "variables[JENKINS_BUILD]=${BUILD_NUMBER}" \
                      "https://gitlab.com/api/v4/projects/${GITLAB_PROJECT_ID}/trigger/pipeline"
                '''
            }
        }
    }
}

GitHub Actions → GitLab

# .github/workflows/trigger-gitlab.yml
name: Trigger GitLab Pipeline

on:
  push:
    branches: [main]

jobs:
  trigger:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger GitLab
        run: |
          curl --request POST \
            --form "token=${{ secrets.GITLAB_TRIGGER_TOKEN }}" \
            --form "ref=main" \
            --form "variables[GITHUB_SHA]=${{ github.sha }}" \
            "https://gitlab.com/api/v4/projects/${{ secrets.GITLAB_PROJECT_ID }}/trigger/pipeline"

GitOps 도구 연동

GitLab CI → ArgoCD

deploy-argocd:
  stage: deploy
  image: argoproj/argocd:latest
  script:
    # ArgoCD 로그인
    - argocd login $ARGOCD_SERVER --username admin --password $ARGOCD_PASSWORD --insecure
    
    # 이미지 태그 업데이트
    - argocd app set $APP_NAME --helm-set image.tag=$CI_COMMIT_SHA
    
    # Sync 트리거
    - argocd app sync $APP_NAME --prune
    
    # 배포 완료 대기
    - argocd app wait $APP_NAME --timeout 300
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

Image Updater 패턴

# CI는 이미지만 빌드 & 푸시
# ArgoCD Image Updater가 자동으로 감지하여 배포

build-and-push:
  stage: build
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    
    # SemVer 태그도 푸시 (Image Updater가 감지)
    - docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:v$VERSION
    - docker push $CI_REGISTRY_IMAGE:v$VERSION

[!TIP] CI/CD 분리 원칙: CI는 아티팩트 생성, CD는 GitOps Agent가 담당합니다. GitOps 시리즈 6편에서 자세히 다뤘습니다.


Scheduled Pipelines (cron)

정기적으로 파이프라인을 실행합니다.

설정

Build > Pipeline schedules > New schedule

nightly-test:
  script:
    - npm run test:full
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      variables:
        FULL_TEST: "true"

daily-backup:
  script:
    - ./backup.sh
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULE_TYPE == "backup"

Schedule 변수

# Schedule 설정에서 SCHEDULE_TYPE=security 지정

security-scan:
  script:
    - trivy image $CI_REGISTRY_IMAGE:latest
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULE_TYPE == "security"

실전 예제: 완전한 외부 연동

stages:
  - build
  - deploy
  - notify

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

build:
  stage: build
  script:
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

# ArgoCD 배포 트리거
trigger-argocd:
  stage: deploy
  image: curlimages/curl:latest
  script:
    - |
      # GitOps 레포에 이미지 태그 업데이트 PR 생성
      curl --request POST \
        --header "PRIVATE-TOKEN: $GITOPS_TOKEN" \
        --header "Content-Type: application/json" \
        --data '{
          "branch": "update-'$CI_COMMIT_SHORT_SHA'",
          "commit_message": "Update image to '$DOCKER_IMAGE'",
          "actions": [{
            "action": "update",
            "file_path": "apps/myapp/values.yaml",
            "content": "image:\n  tag: '$CI_COMMIT_SHA'"
          }]
        }' \
        "https://gitlab.com/api/v4/projects/GITOPS_PROJECT_ID/repository/commits"
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

# Slack 알림
notify-success:
  stage: notify
  script:
    - |
      curl -X POST -H 'Content-type: application/json' \
        --data '{
          "channel": "#deployments",
          "text": "✅ '$CI_PROJECT_NAME' deployed successfully",
          "attachments": [{
            "color": "good",
            "fields": [
              {"title": "Version", "value": "'$CI_COMMIT_SHORT_SHA'"},
              {"title": "Pipeline", "value": "'$CI_PIPELINE_URL'"}
            ]
          }]
        }' \
        $SLACK_WEBHOOK_URL
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: on_success

notify-failure:
  stage: notify
  script:
    - |
      curl -X POST -H 'Content-type: application/json' \
        --data '{
          "channel": "#deployments",
          "text": "❌ '$CI_PROJECT_NAME' deployment failed!",
          "attachments": [{
            "color": "danger",
            "fields": [
              {"title": "Pipeline", "value": "'$CI_PIPELINE_URL'"}
            ]
          }]
        }' \
        $SLACK_WEBHOOK_URL
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: on_failure

정리: 시리즈 완결

6편의 시리즈를 통해 GitLab CI/CD의 핵심을 다뤘습니다.

주제핵심 메시지
1기초.gitlab-ci.yml, Stages, Jobs, Pipeline
2VariablesPredefined, Protected, Masked, dotenv
3RunnersExecutors, DinD, Kubernetes
4아키텍처Parent-Child, Multi-Project, 동적 생성
5Job 제어rules, needs, DAG, extends
6외부 통합Triggers, Webhooks, API, GitOps

다음 단계

  • GitOps 시리즈: ArgoCD/Flux CD를 활용한 CD 자동화
  • Kubernetes 시리즈: 클러스터 운영 심화

참고 자료

Share

Related Articles

Comments

이 블로그는 제가 알고 있는 것들을 잊지 않기 위해 기록하는 공간입니다.
직접 작성한 글도 있고, AI의 도움을 받아 정리한 글도 있습니다.
정확하지 않은 내용이 있을 수 있으니 참고용으로 봐주세요.

© 2026 Seogyu Kim