Skip to main content

CI/CD Deployment Guide

Panduan Deployment dengan Gitea Runner

Dokumen ini menjelaskan langkah-langkah deployment otomatis untuk 3 microservices (users, products, orders) menggunakan CI/CD pipeline dengan Gitea Runner. Setiap tahap akan diukur waktunya untuk perbandingan dengan manual deployment.


Overview Deployment Process

Aplikasi yang Di-Deploy

ServicePortFungsiContainer
users-service3001User managementDocker image
products-service3002Product catalogDocker image
orders-service3003Order processingDocker image

Total Time Target

CI/CD deployment 3 services: <1 menit (60-90 detik)


Deployment Flow

Developer → Git Push (1 command)

Gitea Webhook (instant trigger)

Gitea Runner Pipeline Start (5-10 sec)

CI Stage: Build & Push Images (30-40 sec)

CD Stage: Deploy to K3s (20-30 sec)

Health Check & Verification (5-10 sec)

Deployment Complete ✅

Total: 60-90 seconds (ZERO manual intervention after git push)

Prerequisites

Sebelum deployment, pastikan sudah ada:

  • ✅ K3s cluster running dan accessible
  • ✅ Gitea server dengan repository aplikasi
  • ✅ Gitea Runner configured dan connected
  • ✅ Workflow file .gitea/workflows/deploy.yml sudah ada
  • ✅ Kubernetes deployment manifests di /k8s folder
  • ✅ Docker registry credentials configured

Step 1: Prepare Code Changes

⏱️ Estimated Time: Variable (developer coding time)

1.1 Make Code Changes

# Di local development machine
cd ~/projects/microservices-app

# Edit code di salah satu service
vim users-service/src/index.js

# Atau edit di semua services
vim products-service/src/controller.js
vim orders-service/src/routes.js

1.2 Test Locally (Optional)

# Test service locally
cd users-service
npm install
npm test
npm start

# Test di browser atau curl
curl http://localhost:3001/health

Time Checkpoint: ___ (development time, tidak dihitung dalam deployment)


Step 2: Commit Changes

⏱️ Estimated Time: 10-15 seconds

2.1 Stage Changes

# Add all changes
git add .

# Atau specific files
git add users-service/src/index.js
git add products-service/src/controller.js
git add orders-service/src/routes.js

2.2 Commit with Message

# Commit dengan message yang descriptive
git commit -m "feat: add new user validation logic"

# Atau
git commit -m "fix: resolve order calculation bug"

Output:

[main a1b2c3d] feat: add new user validation logic
3 files changed, 45 insertions(+), 12 deletions(-)

Time Checkpoint: ___ seconds


Step 3: Push to Gitea (Trigger Deployment)

⏱️ Estimated Time: 5-10 seconds

3.1 Push to Repository

# Push ke branch main (trigger CI/CD)
git push origin main

Output:

Enumerating objects: 15, done.
Counting objects: 100% (15/15), done.
Delta compression using up to 8 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (9/9), 2.43 KiB | 2.43 MiB/s, done.
Total 9 (delta 5), reused 0 (delta 0), pack-reused 0
To https://gitea.example.com/yourname/microservices-app.git
e4f5g6h..a1b2c3d main -> main

3.2 Webhook Triggered Automatically

Gitea otomatis trigger webhook ke Gitea Runner.

🎉 DEPLOYMENT DIMULAI OTOMATIS! 🎉

Time Checkpoint: ___ seconds


Step 4: Monitor CI/CD Pipeline

⏱️ Estimated Time: 60-90 seconds (automated)

4.1 Check Pipeline Status di Gitea UI

Buka browser:

https://gitea.example.com/yourname/microservices-app/actions

Atau via CLI:

# List recent workflow runs
gitea actions list

# Watch specific run
gitea actions view <run-id> --watch

4.2 Pipeline Stages

Pipeline akan menjalankan stages berikut secara otomatis:

Stage 1: Checkout Code (5 sec)

- name: Checkout code
uses: actions/checkout@v3

✅ Runner clone repository

Stage 2: Build Docker Images (30-40 sec)

- name: Build users-service
run: |
docker build -t gitea.example.com/yourname/users-service:${{ github.sha }} ./users-service

- name: Build products-service
run: |
docker build -t gitea.example.com/yourname/products-service:${{ github.sha }} ./products-service

- name: Build orders-service
run: |
docker build -t gitea.example.com/yourname/orders-service:${{ github.sha }} ./orders-service

✅ Build 3 Docker images (parallel)

Stage 3: Push to Registry (10-15 sec)

- name: Push images to registry
run: |
docker push gitea.example.com/yourname/users-service:${{ github.sha }}
docker push gitea.example.com/yourname/products-service:${{ github.sha }}
docker push gitea.example.com/yourname/orders-service:${{ github.sha }}

✅ Upload images ke Gitea container registry

Stage 4: Deploy to K3s (20-30 sec)

- name: Update K3s deployments
run: |
kubectl set image deployment/users-service \
users-service=gitea.example.com/yourname/users-service:${{ github.sha }}

kubectl set image deployment/products-service \
products-service=gitea.example.com/yourname/products-service:${{ github.sha }}

kubectl set image deployment/orders-service \
orders-service=gitea.example.com/yourname/orders-service:${{ github.sha }}

✅ Update deployments dengan rolling update (ZERO DOWNTIME)

Stage 5: Wait for Rollout (10-15 sec)

- name: Wait for deployments
run: |
kubectl rollout status deployment/users-service --timeout=60s
kubectl rollout status deployment/products-service --timeout=60s
kubectl rollout status deployment/orders-service --timeout=60s

✅ Tunggu semua pods ready

Stage 6: Health Check (5 sec)

- name: Health check
run: |
curl -f http://users-service:3001/health
curl -f http://products-service:3002/health
curl -f http://orders-service:3003/health

✅ Verify services responding

Time Checkpoint for entire pipeline: ___ seconds


Step 5: Verify Deployment Success

⏱️ Estimated Time: 10-20 seconds (manual verification)

5.1 Check Pipeline Status

Di Gitea UI, pastikan semua stages ✅ success:

✅ Checkout code          (5s)
✅ Build images (35s)
✅ Push to registry (12s)
✅ Deploy to K3s (25s)
✅ Wait for rollout (12s)
✅ Health check (5s)
━━━━━━━━━━━━━━━━━━━━━━━━━
Total: 94 seconds

5.2 Check K3s Deployments

# Check all deployments
kubectl get deployments

# Check pods
kubectl get pods

# Check services
kubectl get svc

Expected Output:

NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
users-service 3/3 3 3 2m
products-service 3/3 3 3 2m
orders-service 3/3 3 3 2m

5.3 Test Services

# Test each service health
kubectl port-forward svc/users-service 3001:3001 &
curl http://localhost:3001/health

kubectl port-forward svc/products-service 3002:3002 &
curl http://localhost:3002/health

kubectl port-forward svc/orders-service 3003:3003 &
curl http://localhost:3003/health

Expected Response:

{
"status": "ok",
"service": "users-service",
"version": "a1b2c3d",
"timestamp": "2024-01-15T10:35:22.123Z"
}

Time Checkpoint for verification: ___ seconds


Total Deployment Time Summary

StepEstimated TimeActual TimeManual?
1. Code changesVariableN/A✅ Yes
2. Git commit10-15 sec___ sec✅ Yes
3. Git push5-10 sec___ sec✅ Yes
4. CI/CD Pipeline60-90 sec___ sec❌ Automated
5. Verification10-20 sec___ sec✅ Yes (optional)
DEPLOYMENT TOTAL60-90 sec___ secMostly Automated

Total Downtime: 0 seconds (rolling update)


Metrics Collected

Manual Intervention Count

Total manual commands yang harus dijalankan:

  1. git add . - 1 command
  2. git commit -m "message" - 1 command
  3. git push origin main - 1 command
  4. Verification (optional) - 3 commands

Total: 3 mandatory commands (vs 17-21 pada manual deployment)

Actual deployment commands: 1 (git push only, sisanya otomatis)

Human Error Points

Potential errors yang bisa terjadi:

  • ❌ Lupa commit changes (prevented by Git)
  • ❌ Push ke branch yang salah (Git protection rules)
  • ⚠️ Build failure (automatic rollback)
  • ⚠️ Health check failure (automatic rollback)

Error Probability: <1% (automated & consistent)

Automation Benefits

  • ✅ No manual SSH required
  • ✅ No manual npm install
  • ✅ No manual service restart
  • ✅ Automatic image versioning
  • ✅ Automatic rollback on failure
  • ✅ Zero downtime deployment
  • ✅ Consistent every time

Rollout Strategy

Rolling Update (Default)

K3s menggunakan rolling update strategy:

strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 1 pod extra during update
maxUnavailable: 0 # Always keep minimum pods running

Process:

Old Pods: [V1] [V1] [V1]

Step 1: [V1] [V1] [V1] [V2] ← Start 1 new pod
Step 2: [V1] [V1] [V2] ← Kill 1 old pod
Step 3: [V1] [V1] [V2] [V2] ← Start another
Step 4: [V1] [V2] [V2] ← Kill old
Step 5: [V1] [V2] [V2] [V2] ← Start last
Step 6: [V2] [V2] [V2] ← Kill final old pod

Result: Zero downtime! Always have running pods.

Health Checks

Kubernetes health checks ensure safe rollout:

livenessProbe:
httpGet:
path: /health
port: 3001
initialDelaySeconds: 10
periodSeconds: 5

readinessProbe:
httpGet:
path: /health
port: 3001
initialDelaySeconds: 5
periodSeconds: 3
  • Liveness: Restart pod if unhealthy
  • Readiness: Don't send traffic until ready

Rollback Procedure

Automatic Rollback

Jika deployment gagal (health check fails), K3s otomatis rollback:

- name: Deploy with rollback
run: |
kubectl set image deployment/users-service users-service=new-image:tag
kubectl rollout status deployment/users-service --timeout=60s || \
kubectl rollout undo deployment/users-service

Manual Rollback

Jika perlu rollback manual:

# Check rollout history
kubectl rollout history deployment/users-service

# Rollback to previous version
kubectl rollout undo deployment/users-service

# Rollback to specific revision
kubectl rollout undo deployment/users-service --to-revision=2

# Verify rollback
kubectl rollout status deployment/users-service

Rollback Time: 10-20 seconds (automated)


Troubleshooting

Issue 1: Pipeline Failed at Build Stage

Error:

Error: failed to build image: exit status 1

Check Logs:

# Di Gitea UI, klik pada failed stage untuk lihat logs
# Atau via CLI
gitea actions logs <run-id> <job-id>

Common Causes:

  • Dockerfile syntax error
  • Missing dependencies in package.json
  • Build context issues

Solution:

# Fix the issue locally first
cd users-service
docker build -t test .

# If successful, commit and push again
git add .
git commit -m "fix: resolve build issue"
git push origin main

Issue 2: Deployment Timeout

Error:

Error: timed out waiting for deployment rollout

Check Pods:

# Check pod status
kubectl get pods

# Check pod logs
kubectl logs deployment/users-service

# Describe pod for events
kubectl describe pod <pod-name>

Common Causes:

  • Image pull failure
  • Health check failing
  • Resource limits exceeded

Solution:

# Check events
kubectl get events --sort-by='.lastTimestamp'

# Fix issue and redeploy
git commit -m "fix: adjust resource limits"
git push origin main

Issue 3: Health Check Failed

Error:

Health check failed: curl: (7) Failed to connect

Debug:

# Port-forward to pod
kubectl port-forward deployment/users-service 3001:3001

# Test locally
curl http://localhost:3001/health

# Check service logs
kubectl logs deployment/users-service --tail=100

Solution:

  • Ensure health endpoint is implemented
  • Check port configuration
  • Verify service is starting correctly

Monitoring Deployment

Real-time Monitoring

# Watch deployments
watch kubectl get deployments

# Watch pods
watch kubectl get pods

# Stream logs
kubectl logs -f deployment/users-service

# Monitor events
kubectl get events --watch

Gitea Actions Dashboard

Monitor di browser:

https://gitea.example.com/yourname/microservices-app/actions/runs/<run-id>

Features:

  • ✅ Real-time logs
  • ✅ Stage duration
  • ✅ Artifact download
  • ✅ Re-run failed jobs
  • ✅ Cancel running jobs

Best Practices

✅ Pre-Deployment

  • Test locally before pushing
  • Write meaningful commit messages
  • Review changes before push
  • Ensure tests pass locally
  • Check CI/CD pipeline status

✅ During Deployment

  • Monitor pipeline progress
  • Check logs for errors
  • Verify rollout status
  • Don't force-push during deployment
  • Keep Git history clean

✅ Post-Deployment

  • Verify all services healthy
  • Monitor error rates
  • Check application metrics
  • Review deployment logs
  • Tag release versions

Deployment Log

Pipeline automatically logs deployment:

- name: Log deployment
run: |
echo "Deployed by: ${{ github.actor }}"
echo "Commit: ${{ github.sha }}"
echo "Branch: ${{ github.ref }}"
echo "Time: $(date)"

View logs:

# Via Gitea UI
https://gitea.example.com/yourname/microservices-app/actions

# Via kubectl
kubectl logs deployment/users-service | grep "Started"

Comparison with Manual Deployment

MetricManual DeploymentCI/CD Deployment
TriggerSSH + 17-21 commands1 git push
Total Time3-5 minutes60-90 seconds
Downtime30-60 seconds0 seconds
Manual Steps17-213 (git workflow)
ConsistencyLow (human variance)High (automated)
Error ProneHigh (5-10%)Low (<1%)
RollbackManual (3-5 min)Automatic (10-20 sec)
Audit TrailManual logsGit history + pipeline logs
ScalabilityLimited (manual)Unlimited (automated)

Improvement:

  • ⏱️ 70-80% faster
  • 👤 94% less manual work (3 vs 21 commands)
  • 100% downtime elimination
  • Significantly more reliable

Workflow File Example

Sample .gitea/workflows/deploy.yml:

name: CI/CD Pipeline

on:
push:
branches:
- main

jobs:
build-and-deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Build Docker images
run: |
docker build -t gitea.example.com/app/users-service:${{ github.sha }} ./users-service
docker build -t gitea.example.com/app/products-service:${{ github.sha }} ./products-service
docker build -t gitea.example.com/app/orders-service:${{ github.sha }} ./orders-service

- name: Push to registry
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login gitea.example.com -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin
docker push gitea.example.com/app/users-service:${{ github.sha }}
docker push gitea.example.com/app/products-service:${{ github.sha }}
docker push gitea.example.com/app/orders-service:${{ github.sha }}

- name: Deploy to K3s
run: |
kubectl set image deployment/users-service users-service=gitea.example.com/app/users-service:${{ github.sha }}
kubectl set image deployment/products-service products-service=gitea.example.com/app/products-service:${{ github.sha }}
kubectl set image deployment/orders-service orders-service=gitea.example.com/app/orders-service:${{ github.sha }}

kubectl rollout status deployment/users-service --timeout=60s
kubectl rollout status deployment/products-service --timeout=60s
kubectl rollout status deployment/orders-service --timeout=60s

Conclusion

CI/CD deployment untuk 3 microservices menghasilkan:

  • ⏱️ Time: 60-90 detik (dari git push sampai deployed)
  • 👤 Manual effort: 3 commands (git add, commit, push)
  • 🤖 Automation: 100% setelah git push
  • Downtime: 0 detik (rolling update)
  • Risk: <1% (automated & konsisten)
  • 🔄 Rollback: Automatic dalam 10-20 detik

Hasil pengujian aktual akan didokumentasikan di Test Results untuk dibandingkan dengan manual deployment.


Next Steps

Setelah memahami CI/CD deployment, lihat hasil perbandingan:

👉 Manual Deployment - Bandingkan dengan cara manual
👉 Test Results - Hasil pengujian lengkap
👉 Operational Comparison - Perbandingan operasional detail