GitHub Actions ve Jenkins ile Çok Ortamlı CI/CD Pipeline
Genel Bakış
Bu kılavuz, bir API projesinin main branch'e gönderilen her değişikliği otomatik olarak test ettiği, Docker image ürettiği ve dört Kubernetes ortamına (dev → test → UAT → prod) sıralı şekilde deploy ettiği bir CI/CD altyapısının nasıl kurulduğunu gösterir. Her deployment adımı Apinizer üzerindeki API proxy ile senkronize edilir.
Kullanılan Teknolojiler ve Versiyonlar
| Teknoloji | Versiyon |
|---|---|
| Jenkins | jenkins/jenkins:lts |
| GitHub Actions | — |
| Kubernetes + Kustomize | v1.32.9 - v5.5.0 |
| Apinizer | v2026.01.5 |
Pipeline Akışı
GitHub Push (main)
└─► GitHub Actions
├─ Test (pytest)
├─ Semantic version tag (vX.Y.Z)
├─ Docker build & push → Docker Hub
└─ Jenkins tetikleme (VERSION_TAG parametresi ile)
└─► Jenkins — CD Pipeline
├─ Deploy Dev → Apinizer Sync → Smoke Test
├─ [Manuel Onay] → Deploy Test → Apinizer Sync → Smoke Test
├─ [Manuel Onay] → Deploy UAT → Apinizer Sync → Smoke Test
└─ [Manuel Onay] → Deploy Prod → Apinizer Promote → Smoke Test
Bu pipeline'a ek olarak, herhangi bir ortama belirli bir versiyonu doğrudan deploy eden bağımsız bir Targeted Deploy job'ı da mevcuttur. Bu job, tam pipeline çalıştırmadan tek ortam güncellemesi veya rollback senaryoları için kullanılır.
Proje Yapısı
your-project/
├── .github/
│ └── workflows/
│ └── ci.yaml # GitHub Actions CI pipeline
├── app/ # Uygulama kaynak kodu
├── jenkins/
│ ├── Jenkinsfile # Ana CD pipeline
│ ├── Jenkinsfile.targeted # Hedefli deploy pipeline
│ └── shared-library/
│ └── vars/
│ ├── apinizerProxySync.groovy # Apinizer create/update/deploy
│ ├── apinizerPromoteProd.groovy # UAT → Prod promotion
│ ├── smokeTest.groovy # Health check
│ └── retryWithDelay.groovy # Retry wrapper
├── k8s/
│ ├── base/ # Ortak Kubernetes manifests
│ └── overlays/ # Environment-specific Kustomize patch'leri
│ ├── dev/
│ ├── test/
│ ├── uat/
│ └── prod/
└── Dockerfile
1. GitHub Actions — CI Pipeline
CI pipeline, main branch'e her push geldiğinde tetiklenir. İki iş (job) içerir: önce testler çalışır, testler geçmeden build başlamaz.
Workflow Dosyası
Aşağıdaki içeriği .github/workflows/ci.yaml olarak oluşturun ve reponuza push edin.
name: CI
on:
push:
branches:
- main
env:
IMAGE_NAME: ${{ secrets.DOCKERHUB_USERNAME }}/YOUR_IMAGE_NAME
jobs:
test:
name: Run Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run pytest
run: pytest tests/ -v
build:
name: Build & Push Docker Image
runs-on: ubuntu-latest
needs: test
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Bump version and push tag
id: tag_version
uses: anothrNick/github-tag-action@1.64.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
WITH_V: true
DEFAULT_BUMP: patch
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: .
push: true
build-args: |
APP_VERSION=${{ steps.tag_version.outputs.new_tag }}
BUILD_SHA=${{ github.sha }}
tags: |
${{ env.IMAGE_NAME }}:${{ steps.tag_version.outputs.new_tag }}
${{ env.IMAGE_NAME }}:latest
- name: Trigger Jenkins Pipeline
env:
JENKINS_JOB_NAME_ENCODED: ${{ secrets.JENKINS_JOB_NAME }}
run: |
JOB=$(python3 -c "import urllib.parse, os; print(urllib.parse.quote(os.environ['JENKINS_JOB_NAME_ENCODED']))")
curl -X POST \
"${{ secrets.JENKINS_URL }}/job/${JOB}/buildWithParameters?VERSION_TAG=${{ steps.tag_version.outputs.new_tag }}" \
--user "${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }}" \
--fail
Jenkins job adı boşluk içeriyorsa urllib.parse.quote() ile URL-encode edilmesi gerekir. Aksi hâlde curl isteği hatalı gönderilir.
GitHub Secrets Yapılandırması
Repository Settings > Secrets and Variables > Actions ekranından aşağıdaki secret'ları tanımlayın:
| Secret | Açıklama |
|---|---|
DOCKERHUB_USERNAME | Docker Hub kullanıcı adınız |
DOCKERHUB_TOKEN | Docker Hub access token |
JENKINS_URL | Jenkins instance URL'iniz |
JENKINS_JOB_NAME | Jenkins'teki CD job adı |
JENKINS_USER | Jenkins kullanıcı adı |
JENKINS_TOKEN | Jenkins API token |
2. Kubernetes Altyapısı
Base Manifests
k8s/base/ dizini tüm ortamların ortak kullandığı Deployment ve Service manifest'lerini içerir. ENVIRONMENT değeri her ortamda ayrı bir ConfigMap üzerinden uygulamaya iletilir.
# k8s/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: YOUR_DEPLOYMENT_NAME
labels:
app: YOUR_APP_LABEL
spec:
replicas: 1
selector:
matchLabels:
app: YOUR_APP_LABEL
template:
metadata:
labels:
app: YOUR_APP_LABEL
spec:
containers:
- name: YOUR_CONTAINER_NAME
image: YOUR_DOCKERHUB_USERNAME/YOUR_IMAGE_NAME:latest
ports:
- containerPort: 8000
env:
- name: ENVIRONMENT
valueFrom:
configMapKeyRef:
name: YOUR_CONFIGMAP_NAME
key: ENVIRONMENT
# k8s/base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: YOUR_SERVICE_NAME
spec:
type: NodePort
selector:
app: YOUR_APP_LABEL
ports:
- port: 8000
targetPort: 8000
Kustomize Overlay'leri
Her ortam için k8s/overlays/<env>/kustomization.yaml dosyası bulunur. Bu dosya ortama özgü namespace, ConfigMap değerleri ve aktif image tag'ini tanımlar. Jenkins, her başarılı deployment sonrasında newTag değerini otomatik olarak günceller.
# k8s/overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: YOUR_NAMESPACE_DEV
resources:
- ../../base
patches:
- path: service-patch.yaml
configMapGenerator:
- name: YOUR_CONFIGMAP_NAME
literals:
- ENVIRONMENT=dev
images:
- name: YOUR_DOCKERHUB_USERNAME/YOUR_IMAGE_NAME
newName: YOUR_DOCKERHUB_USERNAME/YOUR_IMAGE_NAME
newTag: latest # Jenkins tarafından güncellenir
Her ortamın NodePort değeri bir service patch ile tanımlanır:
# k8s/overlays/dev/service-patch.yaml
apiVersion: v1
kind: Service
metadata:
name: YOUR_SERVICE_NAME
spec:
ports:
- port: 8000
targetPort: 8000
nodePort: YOUR_DEV_NODEPORT
Aynı yapıyı test, uat ve prod overlay'leri için tekrarlayın; her birinde farklı namespace ve NodePort değerleri kullanın.
3. Jenkins — Ana CD Pipeline
Tetiklenme: GitHub Actions'tan buildWithParameters çağrısıyla, VERSION_TAG parametresi ile.
Jenkins Job Kurulumu
Jenkins'te New Item > Pipeline seçin. Job adı olarak CD pipeline'ınızı temsil eden bir isim girin.
Pipeline sekmesinde Pipeline script from SCM seçin. SCM olarak Git seçin, repository URL'inizi girin ve branch'i */main olarak belirtin. Script Path alanına jenkins/Jenkinsfile yazın.
This project is parameterized kutusunu işaretleyin. String Parameter ekleyin: Name: VERSION_TAG, Default Value boş bırakın.