CI/CD Pipeline

Denomas GitLab CI/CD yapılandırması — pipeline aşamaları, kalite kapıları, deployment stratejisi

CI/CD Pipeline

Denomas, tüm projelerinde GitLab CI/CD kullanır. Pipeline, kodun commit edilmesinden üretim ortamına deploy edilmesine kadar tüm aşamaları otomatize eder. CI/CD altyapısı code.denomas.com ve code.ilimteknoloji.com adreslerindeki self-hosted GitLab instance'ları üzerinde çalışır.

Pipeline Aşamaları

┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌────────────────┐   ┌──────────────┐
│  lint    │ → │  test    │ → │  build   │ → │  scan    │ → │ deploy-staging │ → │ deploy-prod  │
└──────────┘   └──────────┘   └──────────┘   └──────────┘   └────────────────┘   └──────────────┘

1. lint

  • Pre-commit hook doğrulaması (pre-commit run --all-files)
  • Python: ruff lint + ruff-format kontrolü + mypy tip kontrolü
  • JavaScript: ESLint (airbnb-base preset)
  • YAML/JSON format kontrolü (yamllint)
  • Ansible: ansible-lint
  • Docker: hadolint
  • Shell: shellcheck
  • Docstring kontrolü (public fonksiyonlarda zorunlu)
  • Conventional Commit format kontrolü

2. test

  • Birim testleripytest --cov=src --cov-fail-under=80
  • Entegrasyon testleri — API endpoint testleri, veritabanı migration testleri
  • Odoo testleri — Odoo test framework ile modül testleri (odoo-bin --test-enable)
  • Ansible testlerimolecule test ile rol doğrulaması
  • Kapsam raporu oluşturma (Cobertura formatı, GitLab MR'da görselleştirme)

3. build

  • Docker image oluşturma (multi-stage build)
  • Semantic versiyon etiketi ($CI_COMMIT_TAG veya $CI_COMMIT_SHORT_SHA)
  • Docker image'ı GitLab Container Registry'ye push
  • Ansible artifact'ları paketleme (roller + playbook'lar)
  • Hugo site build (handbook ve website projeleri için)

4. scan

  • SAST: Bandit (Python), Semgrep (p/owasp-top-ten ruleset), GitLab SAST template
  • Dependency Scan: Trivy (container + dependency CVE taraması)
  • Lisans Kontrolü: Uyumsuz lisans tespiti (GPL kontrol)
  • Container Image Scan: Trivy ile Docker image güvenlik taraması
  • Secret Detection: GitLab Secret Detection template

5. deploy-staging

  • Ansible playbook ile staging ortamına deploy (ansible-playbook deploy-staging.yml)
  • Otomatik smoke testleri (ansible-playbook smoke-test.yml)
  • Performans testi (k6 ile yük testi)
  • Staging URL'i MR'a yorum olarak eklenir

6. deploy-prod

  • Dual-track deployment stratejisine göre
  • Track 1 (SaaS): main merge sonrası when: manual onay → canary deploy → kademeli rollout
  • Track 2 (Self-Managed): Release tag'i sonrası paketleme ve dağıtım
  • Production deploy sonrası otomatik health check

Tam .gitlab-ci.yml Örneği

# .gitlab-ci.yml — Denomas standart pipeline
image: python:3.10-slim

variables:
  # Genel
  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
  PRE_COMMIT_HOME: "$CI_PROJECT_DIR/.cache/pre-commit"
  # Docker
  DOCKER_IMAGE: "$CI_REGISTRY_IMAGE"
  DOCKER_TAG: "$CI_COMMIT_SHORT_SHA"
  # Deployment
  ANSIBLE_INVENTORY: "inventory/$CI_ENVIRONMENT_NAME"
  ANSIBLE_FORCE_COLOR: "true"
  # SAST
  SAST_EXCLUDED_PATHS: "tests/,migrations/,docs/"
  SECURE_LOG_LEVEL: "warn"

cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - .cache/pip
    - .cache/pre-commit
    - .venv/

stages:
  - lint
  - test
  - build
  - scan
  - deploy-staging
  - deploy-prod

# ─── LINT ─────────────────────────────────────────────
lint:pre-commit:
  stage: lint
  script:
    - pip install pre-commit
    - pre-commit run --all-files
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == "develop"'

lint:mypy:
  stage: lint
  script:
    - pip install -r requirements-dev.txt
    - mypy src/ --ignore-missing-imports
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  allow_failure: false

# ─── TEST ─────────────────────────────────────────────
test:unit:
  stage: test
  services:
    - postgres:15-alpine
    - redis:7-alpine
  variables:
    POSTGRES_DB: test_db
    POSTGRES_USER: test_user
    POSTGRES_PASSWORD: $CI_DB_PASSWORD
    DATABASE_URL: "postgresql://test_user:$CI_DB_PASSWORD@postgres:5432/test_db"
    REDIS_URL: "redis://redis:6379/0"
  script:
    - pip install -r requirements-dev.txt
    - pytest --cov=src --cov-report=xml --cov-report=term --cov-fail-under=80
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml
    expire_in: 30 days
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == "develop"'

test:integration:
  stage: test
  services:
    - postgres:15-alpine
    - redis:7-alpine
  script:
    - pip install -r requirements-dev.txt
    - pytest tests/integration/ -v --tb=short
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

# ─── BUILD ────────────────────────────────────────────
build:docker:
  stage: build
  image: docker:24.0
  services:
    - docker:24.0-dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $DOCKER_IMAGE:$DOCKER_TAG -t $DOCKER_IMAGE:latest .
    - docker push $DOCKER_IMAGE:$DOCKER_TAG
    - docker push $DOCKER_IMAGE:latest
  rules:
    - if: '$CI_COMMIT_BRANCH == "develop"'
    - if: '$CI_COMMIT_BRANCH == "main"'
    - if: '$CI_COMMIT_TAG'

# ─── SCAN ─────────────────────────────────────────────
scan:bandit:
  stage: scan
  script:
    - pip install bandit[toml]
    - bandit -c pyproject.toml -r src/ -f json -o bandit-report.json
  artifacts:
    paths:
      - bandit-report.json
    expire_in: 30 days
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

scan:semgrep:
  stage: scan
  image: returntocorp/semgrep
  script:
    - semgrep --config=p/owasp-top-ten --config=p/python --json -o semgrep-report.json src/
  artifacts:
    paths:
      - semgrep-report.json
    expire_in: 30 days
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

scan:trivy:
  stage: scan
  image:
    name: aquasec/trivy:latest
    entrypoint: [""]
  script:
    - trivy image --exit-code 1 --severity HIGH,CRITICAL $DOCKER_IMAGE:$DOCKER_TAG
  rules:
    - if: '$CI_COMMIT_BRANCH == "develop"'
    - if: '$CI_COMMIT_BRANCH == "main"'

include:
  - template: Security/SAST.gitlab-ci.yml
  - template: Security/Secret-Detection.gitlab-ci.yml

# ─── DEPLOY STAGING ───────────────────────────────────
deploy_staging:
  stage: deploy-staging
  image: ansible/ansible-runner:latest
  script:
    - ansible-playbook deploy-staging.yml -e "docker_tag=$DOCKER_TAG"
    - ansible-playbook smoke-test.yml -e "environment=staging"
  environment:
    name: staging
    url: https://staging.denomas.com
  rules:
    - if: '$CI_COMMIT_BRANCH == "staging"'

# ─── DEPLOY PRODUCTION ───────────────────────────────
deploy_canary:
  stage: deploy-prod
  image: ansible/ansible-runner:latest
  script:
    - ansible-playbook deploy-canary.yml -e "docker_tag=$DOCKER_TAG canary_weight=5"
  environment:
    name: canary
    url: https://canary.denomas.com
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
  when: manual

deploy_production:
  stage: deploy-prod
  image: ansible/ansible-runner:latest
  script:
    - ansible-playbook deploy-production.yml -e "docker_tag=$DOCKER_TAG"
    - ansible-playbook smoke-test.yml -e "environment=production"
  environment:
    name: production
    url: https://denomas.com
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
  when: manual
  needs: ["deploy_canary"]

Ortam Değişkenleri (CI/CD Variables)

DeğişkenTürKapsamAçıklama
CI_REGISTRY_USERProtectedTüm projelerGitLab Container Registry kullanıcı
CI_REGISTRY_PASSWORDProtected, MaskedTüm projelerGitLab Container Registry parola
CI_DB_PASSWORDProtected, MaskedTüm projelerTest veritabanı parolası
ANSIBLE_SSH_KEYProtected, FileDeploy projeleriDeployment SSH anahtarı
SENTRY_DSNProtectedProductionHata izleme DSN
GRAFANA_API_KEYProtected, MaskedMonitoringGrafana dashboard API
VAULT_TOKENProtected, MaskedProductionHashiCorp Vault erişim token

Ortamlar

OrtamURLAmaçDeploy Tetikleme
Developmentdev.denomas.comGeliştirici testleri, feature branch doğrulamasıHer MR push (otomatik)
Stagingstaging.denomas.comCanlıya çıkmadan önceki son teststaging dalına merge (otomatik)
Canarycanary.denomas.comÖn-üretim doğrulama, %5 trafikmain merge sonrası (manuel onay)
Productiondenomas.comCanlı ortamCanary başarılı sonrası (manuel onay)

Artifact Yönetimi

Artifact TipiDepolamaSaklama Süresi
Test kapsam raporları (Cobertura XML)GitLab Job Artifacts30 gün
SAST raporları (JSON)GitLab Job Artifacts30 gün
Docker image'larGitLab Container RegistrySon 10 tag + latest
Ansible playbook arşivleriGitLab Package RegistrySüresiz (release tag'leri)
k6 performans raporlarıGitLab Job Artifacts90 gün

Pipeline Performans Hedefleri

AşamaHedef SüreMevcut Ortalama
lint< 2 dakikaPipeline metriklerinden izlenir
test< 10 dakikaPipeline metriklerinden izlenir
build< 5 dakikaPipeline metriklerinden izlenir
scan< 8 dakikaPipeline metriklerinden izlenir
Toplam Pipeline< 25 dakikaHaftalık raporlanır

İlgili Sayfalar