DevOps & Cloud

GitLab CI/CD: Panduan Dasar untuk Developer

TOKEN

Pelajari GitLab CI/CD dari nol β€” konfigurasi .gitlab-ci.yml, jobs, stages, runners, variables, caching, artifacts, environment, dan pipeline automation untuk workflow DevOps yang efisien

1. Pengenalan GitLab CI/CD

GitLab CI/CD adalah sistem Continuous Integration dan Continuous Deployment yang terintegrasi langsung di dalam platform GitLab. Berbeda dengan Jenkins yang memerlukan instalasi terpisah, GitLab CI/CD sudah built-in β€” Anda hanya perlu menambahkan file .gitlab-ci.yml di root repository, dan pipeline akan berjalan otomatis setiap kali ada push atau merge request.

Konsep CI/CD

Konsep Penjelasan Contoh
CI (Continuous Integration)Otomasi build dan test setiap kali kode berubahRun unit test saat push ke branch
CD (Continuous Delivery)Otomasi deploy ke staging, manual approval untuk productionDeploy ke staging otomatis, production butuh approval
CD (Continuous Deployment)Otomasi deploy ke production tanpa intervensi manualDeploy ke production setelah semua test pass
Diagram: GitLab CI/CD Pipeline Flow
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    GITLAB CI/CD PIPELINE                          β”‚
β”‚                                                                   β”‚
β”‚  Developer                                                         β”‚
β”‚     β”‚                                                             β”‚
β”‚     β”‚  git push                                                  β”‚
β”‚     β–Ό                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚
β”‚  β”‚  BUILD  │──►│  TEST   │──►│ STAGING │──►│  PROD   β”‚        β”‚
β”‚  β”‚  Stage  β”‚   β”‚  Stage  β”‚   β”‚  Stage  β”‚   β”‚  Stage  β”‚        β”‚
β”‚  β”‚         β”‚   β”‚         β”‚   β”‚         β”‚   β”‚         β”‚        β”‚
β”‚  β”‚ β€’ Build β”‚   β”‚ β€’ Lint  β”‚   β”‚ β€’ Deployβ”‚   β”‚ β€’ Deployβ”‚        β”‚
β”‚  β”‚   Image β”‚   β”‚ β€’ Unit  β”‚   β”‚   to    β”‚   β”‚   to    β”‚        β”‚
β”‚  β”‚ β€’ Build β”‚   β”‚   Test  β”‚   β”‚   Stag- β”‚   β”‚   Pro-  β”‚        β”‚
β”‚  β”‚   App   β”‚   β”‚ β€’ Integ β”‚   β”‚   ing   β”‚   β”‚   duc-  β”‚        β”‚
β”‚  β”‚         β”‚   β”‚   Test  β”‚   β”‚ β€’ Smoke β”‚   β”‚   tion  β”‚        β”‚
β”‚  β”‚         β”‚   β”‚ β€’ Scan  β”‚   β”‚   Test  β”‚   β”‚         β”‚        β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚
β”‚                                                             β–²   β”‚
β”‚                                              (manual gate) β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

GitLab CI/CD vs Jenkins

Aspek GitLab CI/CD Jenkins
KonfigurasiYAML file di repoGUI + Jenkinsfile/Groovy
SetupBuilt-in di GitLabInstall terpisah
RunnerGitLab RunnerJenkins Agent/Node
Docker SupportNativeVia plugin
ScalabilityAuto-scaling runnersManual atau Cloud plugin
Learning Curve🟒 Lebih mudah🟑 Lebih kompleks

2. Anatomi .gitlab-ci.yml

File .gitlab-ci.yml adalah file konfigurasi utama yang mendefinisikan seluruh pipeline. File ini menggunakan format YAML dan harus ditempatkan di root repository.

Struktur Dasar

YAML β€” .gitlab-ci.yml Basic Structure
# .gitlab-ci.yml β€” Struktur dasar pipeline
# BeebaneLabs - GitLab CI/CD Tutorial

# ===========================
# GLOBAL CONFIGURATION
# ===========================

# Default image untuk semua jobs (bisa di-override per job)
default:
  image: node:20-alpine
  before_script:
    - echo "Setting up environment..."
    - node --version
    - npm --version

# Stages yang tersedia (urutan eksekusi)
stages:
  - build
  - test
  - security
  - deploy

# Global variables
variables:
  NODE_ENV: "production"
  npm_config_cache: "$CI_PROJECT_DIR/.npm"

# ===========================
# JOBS
# ===========================

# Build stage
build-app:
  stage: build
  script:
    - echo "Building application..."
    - npm ci --cache .npm --prefer-offline
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 hour

# Test stage
test-unit:
  stage: test
  script:
    - npm run test:unit
  coverage: '/Statements\s*:\s*(\d+\.?\d*)%/'

test-integration:
  stage: test
  script:
    - npm run test:integration

# Security stage
scan-vulnerabilities:
  stage: security
  image: aquasec/trivy:latest
  script:
    - trivy fs --exit-code 1 --severity CRITICAL .

# Deploy stage
deploy-staging:
  stage: deploy
  script:
    - echo "Deploying to staging..."
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - develop

Keyword Reference

Keyword Fungsi Level
imageDocker image untuk jobGlobal / Job
stagesDefinisi stages dan urutannyaGlobal
stageStage assignment untuk jobJob
scriptPerintah yang dijalankanJob (wajib)
before_scriptPerintah sebelum script utamaGlobal / Job
after_scriptPerintah setelah script utamaGlobal / Job
variablesEnvironment variablesGlobal / Job
artifactsFile yang di-pass ke job berikutnyaJob
cacheCache dependencies antar pipelineGlobal / Job
only / exceptKapan job dijalankanJob
rulesKondisi eksekusi (rekomendasi)Job
needsDependency antar jobs (DAG)Job
servicesService containers (DB, Redis)Global / Job
tagsPilih runner berdasarkan tagJob

3. Jobs & Stages

Jobs adalah unit pekerjaan terkecil dalam pipeline. Stages mengelompokkan jobs dan menentukan urutan eksekusi. Jobs dalam stage yang sama berjalan paralel, sementara stage berikutnya menunggu semua jobs di stage sebelumnya selesai.

Parallel Jobs in Stages

YAML β€” Jobs & Stages
# Jobs dalam stage yang sama berjalan PARALEL
stages:
  - build
  - test
  - deploy

# ===== BUILD STAGE =====
# Hanya satu job, berjalan duluan
build-frontend:
  stage: build
  image: node:20-alpine
  script:
    - cd frontend
    - npm ci
    - npm run build
  artifacts:
    paths:
      - frontend/dist/

build-backend:
  stage: build
  image: node:20-alpine
  script:
    - cd backend
    - npm ci
    - npm run build
  artifacts:
    paths:
      - backend/dist/

# ===== TEST STAGE =====
# Berjalan PARALEL setelah build selesai
test-unit:
  stage: test
  image: node:20-alpine
  script:
    - npm run test:unit
  needs:
    - build-backend

test-lint:
  stage: test
  image: node:20-alpine
  script:
    - npm run lint
  # Tidak perlu build artifacts, bisa jalan tanpa needs

test-e2e:
  stage: test
  image: cypress/included:13.6.0
  script:
    - cd frontend
    - npm run test:e2e
  needs:
    - build-frontend
    - build-backend

# ===== DEPLOY STAGE =====
# Berjalan setelah SEMUA test selesai
deploy-staging:
  stage: deploy
  script:
    - echo "Deploying..."
  needs:
    - test-unit
    - test-lint
    - test-e2e

Rules vs Only/Except

YAML β€” Pipeline Rules
# ===== RECOMMENDED: rules keyword =====
deploy-production:
  stage: deploy
  script:
    - ./deploy.sh production
  rules:
    # Jalankan saat ada tag baru
    - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
      when: on_success
    # Jalankan saat merge ke main
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual
      allow_failure: true
    # Jangan jalankan di branch lain
    - when: never

# ===== DEPRECATED: only/except =====
# Masih bekerja tapi kurang fleksibel
deploy-staging:
  stage: deploy
  script:
    - ./deploy.sh staging
  only:
    - develop
    - merge_requests
  except:
    - tags

# ===== COMMON RULE PATTERNS =====
test-mr:
  stage: test
  script:
    - npm test
  rules:
    # Hanya di merge request
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    # Hanya di branch tertentu
    - if: '$CI_COMMIT_BRANCH =~ /^(main|develop)$/'
    # Hanya saat file tertentu berubah
    - changes:
        - "src/**/*"
        - "tests/**/*"
    # Saat manual trigger
    - if: '$CI_PIPELINE_SOURCE == "web"'
      when: manual

Matrix Jobs (Parallel Variants)

YAML β€” Matrix Jobs
# Jalankan test di multiple Node.js versions secara paralel
test-matrix:
  stage: test
  parallel:
    matrix:
      - NODE_VERSION: ["18", "20", "22"]
        DB_TYPE: ["postgres", "mysql"]
  image: node:${NODE_VERSION}-alpine
  services:
    - name: ${DB_TYPE}:latest
      alias: db
  script:
    - echo "Testing with Node $NODE_VERSION and $DB_TYPE"
    - npm ci
    - npm test

# Hasil: 6 jobs paralel (3 Node versions Γ— 2 DB types)
# test-matrix: [18, postgres]
# test-matrix: [18, mysql]
# test-matrix: [20, postgres]
# test-matrix: [20, mysql]
# test-matrix: [22, postgres]
# test-matrix: [22, mysql]

4. GitLab Runners

GitLab Runner adalah agent yang menjalankan jobs. GitLab menyediakan shared runners secara gratis (dengan limit), tetapi Anda juga bisa menginstall runner sendiri untuk performa dan keamanan yang lebih baik.

Jenis Runner

Jenis Deskripsi Cocok Untuk
Shared RunnerDisediakan GitLab, digunakan bersamaProject kecil, eksperimen
Group RunnerKhusus untuk satu GitLab groupTim dengan kebutuhan serupa
Project RunnerKhusus untuk satu projectProject production, keamanan tinggi

Instalasi GitLab Runner

Bash
# ===========================
# INSTALL GITLAB RUNNER
# ===========================

# Linux (Ubuntu/Debian)
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install gitlab-runner

# Atau via Docker (tidak perlu install)
docker run -d --name gitlab-runner --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest

# ===========================
# REGISTER RUNNER
# ===========================

# Daftarkan runner ke GitLab
# Token didapat dari: Settings > CI/CD > Runners
sudo gitlab-runner register \
  --non-interactive \
  --url "https://gitlab.com/" \
  --registration-token "YOUR_TOKEN" \
  --executor "docker" \
  --docker-image "alpine:latest" \
  --description "my-docker-runner" \
  --tag-list "docker,linux" \
  --run-untagged="true" \
  --locked="false"

# Atau secara interaktif
sudo gitlab-runner register
# Masukkan URL, token, description, tags, dan executor

# Verifikasi runner
sudo gitlab-runner status
sudo gitlab-runner list
sudo gitlab-runner verify

Executor Types

Executor Cara Kerja Kelebihan Kekurangan
shellLangsung di host🟒 SederhanaπŸ”΄ Tidak isolasi
dockerContainer per job🟒 Isolasi, bersih🟑 Butuh Docker
docker+machineAuto-scaling VM🟒 Skalabel🟑 Kompleks setup
kubernetesPod per job🟒 Cloud-nativeπŸ”΄ Butuh K8s cluster
virtualboxVM per job🟒 Full isolationπŸ”΄ Berat

Runner Configuration

TOML β€” config.toml
# /etc/gitlab-runner/config.toml
# Konfigurasi GitLab Runner

concurrent = 4            # Max jobs paralel
check_interval = 3        # Cek job baru setiap 3 detik

[session_server]
  session_timeout = 1800  # Session timeout 30 menit

[[runners]]
  name = "my-docker-runner"
  url = "https://gitlab.com/"
  token = "xxxxx"
  executor = "docker"
  
  [runners.docker]
    image = "alpine:latest"
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    # Security: jangan mount docker socket
    # allowed_images = ["node:*", "python:*", "alpine:*"]
    
  [runners.cache]
    Type = "s3"
    Shared = true
    [runners.cache.s3]
      ServerAddress = "s3.amazonaws.com"
      BucketName = "gitlab-runner-cache"
      BucketLocation = "ap-southeast-1"
πŸ’‘ Tips

Gunakan tags pada runner dan jobs untuk mengarahkan pekerjaan ke runner yang tepat. Misalnya, tag gpu untuk runner dengan GPU, atau tag deploy untuk runner yang memiliki akses ke server production.

5. Variables & Secrets

GitLab CI/CD mendukung berbagai level variables, dari global hingga job-specific. Untuk secrets sensitif, gunakan CI/CD Variables di GitLab UI.

Variable Precedence (Prioritas)

Text
# Prioritas variables (dari terendah ke tertinggi):
# 1. GitLab predefined variables ($CI_COMMIT_SHA, dll)
# 2. Secret variables di GitLab UI (Settings > CI/CD > Variables)
# 3. .gitlab-ci.yml variables (global)
# 4. Job-level variables
# 5. Manual trigger variables (pipeline trigger)
# 6. Script-level export

# Predefined variables yang sering digunakan:
# $CI_COMMIT_SHA       β€” Git commit hash
# $CI_COMMIT_BRANCH    β€” Branch name
# $CI_COMMIT_TAG       β€” Tag name
# $CI_PIPELINE_ID      β€” Pipeline ID
# $CI_PROJECT_DIR      β€” Working directory
# $CI_PROJECT_NAME     β€” Project name
# $CI_REGISTRY_IMAGE   β€” Docker registry image path
# $CI_REGISTRY_USER    β€” Registry username
# $CI_REGISTRY_PASSWORD β€” Registry password
# $CI_MERGE_REQUEST_IID β€” MR number
# $CI_ENVIRONMENT_NAME β€” Environment name

Menggunakan Variables

YAML β€” Variables Usage
# Global variables
variables:
  APP_NAME: "myapp"
  DOCKER_IMAGE: "$CI_REGISTRY_IMAGE/$APP_NAME"

# Variables per job
build:
  stage: build
  variables:
    BUILD_TYPE: "production"
  script:
    - echo "Building $APP_NAME ($BUILD_TYPE)"
    - echo "Commit: $CI_COMMIT_SHA"
    - echo "Branch: $CI_COMMIT_BRANCH"

# Protected & masked variables diatur di:
# Settings > CI/CD > Variables
# - Protected: hanya tersedia di protected branches/tags
# - Masked: tidak terlihat di job logs
# - Variable type: Variable atau File

# Menggunakan variable bertipe File
deploy:
  stage: deploy
  script:
    # KUBE_CONFIG adalah variable bertipe File
    # Isinya berupa path ke temporary file
    - kubectl --kubeconfig=$KUBE_CONFIG apply -f k8s/

# Expand variables dalam string
release:
  script:
    - echo "Release ${APP_NAME}-v${CI_COMMIT_TAG}"
    - docker tag $APP_NAME $DOCKER_IMAGE:$CI_COMMIT_TAG
    - docker push $DOCKER_IMAGE:$CI_COMMIT_TAG

# Variable expansion rules
test:
  script:
    # Simple expansion
    - echo $VARIABLE
    # Braced expansion (saat perlu concat)
    - echo ${VARIABLE}_suffix
    # Default value
    - echo ${UNDEFINED_VAR:-default_value}
    # Variable dari file
    - cat $SECRET_KEY_FILE

6. Caching & Artifacts

Cache vs Artifacts

Aspek Cache Artifacts
TujuanPercepat job dengan reuse dependenciesPass file antar stages/jobs
ScopeBisa lintas pipelineHanya dalam satu pipeline
LokasiRunner cache / S3GitLab server
ExpirationBisa expired otomatisDiatur expire_in
Contohnode_modules, .m2, pip cacheBuild output, test reports, binaries
YAML β€” Cache & Artifacts
# ===========================
# CACHING
# ===========================

# Global cache configuration
default:
  cache:
    key:
      files:
        - package-lock.json    # Cache berubah saat lockfile berubah
    paths:
      - node_modules/
      - .npm/
    policy: pull-push          # pull-push (default), push, pull

# Per-job cache override
test:
  stage: test
  cache:
    key: test-$CI_COMMIT_REF_SLUG
    paths:
      - node_modules/
    policy: pull               # Hanya baca cache, tidak tulis
  script:
    - npm test

# Multiple caches
build:
  stage: build
  cache:
    - key: frontend-deps
      paths:
        - frontend/node_modules/
    - key: backend-deps
      paths:
        - backend/node_modules/
  script:
    - cd frontend && npm ci
    - cd ../backend && npm ci

# ===========================
# ARTIFACTS
# ===========================

build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/                  # Folder yang di-pass ke jobs berikutnya
      - package.json
    exclude:
      - dist/**/*.map          # Exclude source maps
    expire_in: 1 week          # Auto-delete setelah 1 minggu

test:
  stage: test
  script:
    - npm test -- --coverage --reporter=junit
  artifacts:
    paths:
      - coverage/
    reports:
      junit: test-results.xml      # Test report di MR
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml
    when: always               # Upload artifacts walau job gagal

deploy:
  stage: deploy
  script:
    - ls dist/                 # Bisa akses artifacts dari build
  dependencies:
    - build                    # Explicit dependency (alternatif: needs)

7. Docker Integration

GitLab CI/CD memiliki integrasi Docker yang sangat baik. Anda bisa build, push, dan deploy Docker images langsung dari pipeline. Lihat juga tutorial Docker Dasar untuk konsep dasar container.

Build & Push Docker Images

YAML β€” Docker Build Pipeline
# Build dan push Docker image ke GitLab Container Registry
build-docker:
  stage: build
  image: docker:24
  services:
    - docker:24-dind    # Docker-in-Docker service
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  before_script:
    # Login ke GitLab Container Registry
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    # Build image dengan tags
    - docker build
        --cache-from $CI_REGISTRY_IMAGE:latest
        --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
        --tag $CI_REGISTRY_IMAGE:latest
        .
    # Push ke registry
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - docker push $CI_REGISTRY_IMAGE:latest
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
    - if: '$CI_COMMIT_TAG'

# ===========================
# DOCKER BUILD WITH BUILDKIT
# ===========================
build-docker-buildkit:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  variables:
    DOCKER_BUILDKIT: 1
    DOCKER_TLS_CERTDIR: "/certs"
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    # Build dengan BuildKit untuk performa lebih baik
    - docker build
        --build-arg BUILDKIT_INLINE_CACHE=1
        --cache-from $CI_REGISTRY_IMAGE:latest
        --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
        --tag $CI_REGISTRY_IMAGE:latest
        .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - docker push $CI_REGISTRY_IMAGE:latest

# ===========================
# MULTI-ARCH BUILD
# ===========================
build-multi-arch:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    # Install buildx untuk multi-arch
    - docker buildx create --use
  script:
    - docker buildx build
        --platform linux/amd64,linux/arm64
        --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
        --push
        .

Using GitLab Registry Images

YAML β€” Using Registry Images
# Gunakan image dari GitLab Container Registry
deploy:
  stage: deploy
  image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  script:
    - echo "Running with our own built image"
    - npm start

# Deploy dengan Docker Compose
deploy-compose:
  stage: deploy
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - export IMAGE_TAG=$CI_COMMIT_SHA
    - docker compose -f docker-compose.prod.yml pull
    - docker compose -f docker-compose.prod.yml up -d
  environment:
    name: production
    url: https://example.com

8. Environments & Deployments

GitLab Environments memungkinkan Anda melacak deployment ke berbagai environment (staging, production, dll) dan menyediakan fitur rollback.

YAML β€” Environments
# Deploy ke Staging (otomatis)
deploy-staging:
  stage: deploy
  script:
    - ./deploy.sh staging
  environment:
    name: staging
    url: https://staging.example.com
    on_stop: stop-staging    # Cleanup job
  rules:
    - if: '$CI_COMMIT_BRANCH == "develop"'

# Stop staging environment
stop-staging:
  stage: deploy
  script:
    - ./cleanup.sh staging
  environment:
    name: staging
    action: stop
  rules:
    - if: '$CI_COMMIT_BRANCH == "develop"'
      when: manual

# Deploy ke Production (manual approval)
deploy-production:
  stage: deploy
  script:
    - ./deploy.sh production
  environment:
    name: production
    url: https://example.com
    kubernetes:
      namespace: production
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual
  # Auto-rollback jika deploy gagal
  allow_failure: false

Review Apps (Dynamic Environments)

YAML β€” Review Apps
# Dynamic review environment untuk setiap MR
review-app:
  stage: deploy
  script:
    - export NAMESPACE="review-$CI_MERGE_REQUEST_IID"
    - kubectl create namespace $NAMESPACE || true
    - helm upgrade --install myapp ./charts
        --namespace $NAMESPACE
        --set image.tag=$CI_COMMIT_SHA
        --set ingress.host=$NAMESPACE.review.example.com
  environment:
    name: review/$CI_MERGE_REQUEST_IID
    url: https://$CI_MERGE_REQUEST_IID.review.example.com
    on_stop: stop-review-app
    auto_stop_in: 1 week    # Auto-cleanup setelah 1 minggu
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

stop-review-app:
  stage: deploy
  script:
    - kubectl delete namespace "review-$CI_MERGE_REQUEST_IID" --ignore-not-found
  environment:
    name: review/$CI_MERGE_REQUEST_IID
    action: stop
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: manual

9. Advanced Pipeline Patterns

Reusable Templates (extends)

YAML β€” Reusable Templates
# ===========================
# REUSABLE TEMPLATES
# ===========================

# Base template untuk Node.js jobs
.node-base:
  image: node:20-alpine
  before_script:
    - npm ci --cache .npm --prefer-offline

# Base template untuk deploy jobs
.deploy-base:
  image: alpine:latest
  before_script:
    - apk add --no-cache curl openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -

# Menggunakan templates
test-unit:
  extends: .node-base
  stage: test
  script:
    - npm run test:unit

test-lint:
  extends: .node-base
  stage: test
  script:
    - npm run lint

deploy-staging:
  extends: .deploy-base
  stage: deploy
  script:
    - ssh $STAGING_USER@$STAGING_HOST "cd /app && ./deploy.sh"
  environment:
    name: staging

# Gabungkan multiple templates
deploy-production:
  extends:
    - .deploy-base
  stage: deploy
  script:
    - ssh $PROD_USER@$PROD_HOST "cd /app && ./deploy.sh"
  environment:
    name: production
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual

DAG Pipeline (needs keyword)

YAML β€” DAG Pipeline
# DAG (Directed Acyclic Graph) memungkinkan job
# berjalan secepat mungkin berdasarkan dependency

stages:
  - build
  - test
  - security
  - deploy

build-frontend:
  stage: build
  script: npm run build:frontend
  artifacts:
    paths: [dist/frontend]

build-backend:
  stage: build
  script: npm run build:backend
  artifacts:
    paths: [dist/backend]

test-unit:
  stage: test
  needs: [build-backend]        # Langsung setelah backend selesai
  script: npm test

test-e2e:
  stage: test
  needs: [build-frontend, build-backend]  # Butuh keduanya
  script: npm run test:e2e

scan-dependencies:
  stage: security
  needs: []                     # Tidak butuh apa-apa, jalan langsung
  script: trivy fs .

deploy:
  stage: deploy
  needs: [test-unit, test-e2e, scan-dependencies]
  script: ./deploy.sh

# Visualisasi DAG:
# build-frontend ──┐
#                   β”œβ”€β”€β–Ί test-e2e ──┐
# build-backend ───┼──► test-unit ──┼──► deploy
#                   β”‚               β”‚
# scan-dependenciesβ”€β”˜β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Include & Extends Across Files

YAML β€” Include Files
# .gitlab-ci.yml β€” Main pipeline
include:
  # Template lokal
  - local: '.gitlab/templates/common.yml'
  # Template dari project lain
  - project: 'devops/ci-templates'
    ref: main
    file: '/templates/nodejs.yml'
  # Template dari URL publik
  - remote: 'https://example.com/ci/template.yml'
  # Template dari GitLab template library
  - template: Security/SAST.gitlab-ci.yml
  - template: Security/Container-Scanning.gitlab-ci.yml

stages:
  - build
  - test
  - security
  - deploy

10. Troubleshooting

Common Issues

Masalah Penyebab Solusi
Pipeline tidak jalanFile .gitlab-ci.yml tidak ada atau syntax errorValidasi di CI/CD > Editor > Validate
Job stuck "pending"Tidak ada runner yang cocokCek tags, runner availability
Docker-in-Docker gagalRunner tidak privilegedGunakan socket binding atau set privileged
Cache tidak bekerjaKey berubah setiap kaliGunakan key berdasarkan lockfile
Variable tidak terbacaProtected variable di unprotected branchHilangkan centang "Protected"
Artifacts terlalu besarFile tidak perlu ikut ter-uploadGunakan exclude patterns

Pipeline Debugging Commands

Bash
# ===========================
# DEBUGGING TIPS
# ===========================

# Validasi .gitlab-ci.yml syntax
# GitLab UI: CI/CD > Pipelines > CI Lint
# Atau via API:
curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "https://gitlab.com/api/v4/ci/lint" \
  --data '{"content": "cat .gitlab-ci.yml"}'

# Debug job di dalam pipeline
# Tambahkan debug commands:
debug-job:
  stage: test
  script:
    - echo "CI_PIPELINE_SOURCE=$CI_PIPELINE_SOURCE"
    - echo "CI_COMMIT_BRANCH=$CI_COMMIT_BRANCH"
    - echo "CI_PROJECT_DIR=$CI_PROJECT_DIR"
    - pwd
    - ls -la
    - env | sort

# Interactive debug dengan SSH (GitLab.com SaaS Runner)
debug-ssh:
  stage: test
  script:
    - echo "Connecting to debug SSH session..."
    # Akan memberikan SSH command untuk connect
  environment:
    name: debug

# Cek runner logs
sudo journalctl -u gitlab-runner -f

# Test runner secara lokal
sudo gitlab-runner exec docker test-job

11. Quiz Pemahaman

Uji pemahaman Anda tentang GitLab CI/CD:

1. Apa fungsi file .gitlab-ci.yml?

2. Apa perbedaan cache dan artifacts?

3. Apa fungsi keyword needs?

4. Apa itu GitLab Runner?

5. Bagaimana cara deploy Docker image ke GitLab Registry?

πŸ” Zoom
100%
🎨 Tema