Skip to content
Santekno.com | Level Up Your Engineering Skills
ID
📖 0%
23 Oct 2026 · 17 mnt baca ·Artikel 73 / 208
Go

Multi-Environment Deployment Golang CI: AI Checkpoint, Progressive Delivery

Setup multi-environment deployment untuk Go service dengan AI checkpoint. Progressive delivery dari staging ke production dengan automated verification dan rollback.

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

Multi-Environment Deployment dengan AI Checkpoint

Multi-environment deployment golang dengan AI checkpoint adalah cara paling aman untuk merilis Go service ke production tanpa deg-degan setiap kali menekan tombol deploy. Deployment ke production memang selalu jadi momen paling kritis dalam software delivery — sekali salah, dampaknya langsung dirasakan user.

Di artikel ini kita bangun pipeline deployment yang progressive dan aman: dari staging ke production, dengan AI checkpoint yang memverifikasi setiap tahap sebelum mempromosikan perubahan ke environment berikutnya. Idenya sederhana — semakin jauh perubahan bergerak menuju production, semakin banyak bukti yang kita kumpulkan bahwa deployment itu aman.


13.1 Arsitektur Multi-Environment

Fondasi dari deployment yang aman adalah rantai environment yang jelas, di mana setiap tahap memberikan gate tambahan sebelum perubahan sampai ke user. Diagram berikut menunjukkan environment chain yang kita pakai di Santekno Shop, dari mesin developer hingga production.

text
 1Environment chain Santekno Shop:
 2
 3DEVELOPMENT (local)
 4  Developer machine
 5  Docker Compose
 6  Tidak ada pipeline
 7
 8    ↓ PR merge ke develop
 9
10STAGING
11  Environment: staging.santekno.com
12  Deploy: otomatis setelah merge ke develop
13  Database: staging DB (data synthetic)
14  Kafka: staging cluster
15
16    ↓ AI health check + smoke test
17    ↓ Manual approval (optional, sprint demo)
18
19PRODUCTION
20  Environment: santekno.com
21  Deploy: manual trigger atau automatic setelah staging pass
22  Database: production DB
23  Kafka: production cluster
24
25    ↓ Progressive rollout (canary)
26    ↓ AI health monitoring
27    ↓ Rollback if needed

Perhatikan bahwa tidak ada perubahan yang bisa “lompat” langsung ke production — setiap environment adalah gerbang yang harus lolos dulu, dan itulah yang membuat progressive delivery ini aman.


13.2 Staging Deployment Workflow

Staging adalah gate wajib pertama, dan deployment ke sini harus otomatis penuh agar tidak ada friksi. Workflow GitHub Actions berikut membangun image, menjalankan test, deploy ke Kubernetes staging, lalu memicu AI health check sebagai checkpoint.

yaml
  1# .github/workflows/staging-deploy.yml
  2name: Deploy to Staging
  3
  4on:
  5  push:
  6    branches: [develop]
  7
  8env:
  9  GO_VERSION: '1.22'
 10  REGISTRY: ghcr.io
 11  IMAGE_NAME: ${{ github.repository }}
 12  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
 13
 14jobs:
 15  build:
 16    name: Build & Push Image
 17    runs-on: ubuntu-latest
 18    permissions:
 19      packages: write
 20      contents: read
 21    outputs:
 22      image_tag: ${{ steps.tag.outputs.tag }}
 23
 24    steps:
 25      - uses: actions/checkout@v4
 26
 27      - name: Set image tag
 28        id: tag
 29        run: |
 30          TAG="${{ github.sha }}"
 31          echo "tag=$TAG" >> $GITHUB_OUTPUT
 32
 33      - name: Build and test
 34        run: |
 35          go test -race ./...
 36          go build -o /tmp/app ./cmd/server/
 37
 38      - name: Build Docker image
 39        run: |
 40          docker build \
 41            --label "git.sha=${{ github.sha }}" \
 42            --label "git.branch=develop" \
 43            --label "build.timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
 44            -t "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}" \
 45            -t "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:staging-latest" \
 46            .
 47
 48      - name: Push image
 49        uses: docker/login-action@v3
 50        with:
 51          registry: ${{ env.REGISTRY }}
 52          username: ${{ github.actor }}
 53          password: ${{ secrets.GITHUB_TOKEN }}
 54
 55  deploy-staging:
 56    name: Deploy to Staging
 57    runs-on: ubuntu-latest
 58    needs: build
 59    environment:
 60      name: staging
 61      url: https://staging.santekno.com
 62    permissions:
 63      deployments: write
 64    steps:
 65      - uses: actions/checkout@v4
 66
 67      - name: Deploy to staging
 68        env:
 69          KUBECONFIG: ${{ secrets.STAGING_KUBECONFIG }}
 70        run: |
 71          kubectl set image deployment/santekno-shop \
 72            api="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag }}" \
 73            --namespace=staging
 74          kubectl rollout status deployment/santekno-shop \
 75            --namespace=staging \
 76            --timeout=120s
 77
 78      - name: Run database migrations
 79        env:
 80          DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
 81        run: |
 82          go run ./cmd/migrate/main.go up
 83
 84  staging-health-check:
 85    name: Staging Health Check
 86    runs-on: ubuntu-latest
 87    needs: deploy-staging
 88    steps:
 89      - uses: actions/checkout@v4
 90
 91      - name: Wait for services to stabilize
 92        run: sleep 30
 93
 94      - name: Run smoke tests
 95        id: smoke
 96        run: |
 97          chmod +x scripts/smoke-test.sh
 98          RESULTS=$(./scripts/smoke-test.sh staging.santekno.com)
 99          echo "results=$RESULTS" >> $GITHUB_OUTPUT
100
101      - name: AI Health Analysis
102        id: ai_health
103        continue-on-error: true
104        env:
105          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
106        run: |
107          chmod +x scripts/ai-deployment-check.sh
108          ANALYSIS=$(./scripts/ai-deployment-check.sh \
109            "staging.santekno.com" \
110            "${{ needs.build.outputs.image_tag }}")
111          echo "analysis=$ANALYSIS" >> $GITHUB_OUTPUT
112          VERDICT=$(echo "$ANALYSIS" | grep "VERDICT:" | grep -oP '(HEALTHY|DEGRADED|FAILING)' || echo "HEALTHY")
113          echo "verdict=$VERDICT" >> $GITHUB_OUTPUT
114
115      - name: Fail if staging is unhealthy
116        run: |
117          if [ "${{ steps.ai_health.outputs.verdict }}" == "FAILING" ]; then
118            echo "::error::Staging deployment is FAILING — investigate before production"
119            exit 1
120          fi

Kunci dari workflow ini adalah pemisahan tegas antara build, deploy-staging, dan staging-health-check — sehingga jika AI checkpoint memberi verdict FAILING, pipeline berhenti sebelum ada perubahan yang naik ke production.


13.3 Smoke Test Script

Sebelum AI menganalisis, kita butuh verifikasi deterministik bahwa deployment benar-benar berfungsi. Script smoke test berikut mengecek health endpoint, versi API, konektivitas database dan Redis, hingga response time — semuanya via HTTP call sederhana.

bash
 1#!/bin/bash
 2# scripts/smoke-test.sh
 3# Basic smoke tests untuk verify deployment berhasil
 4
 5set -euo pipefail
 6
 7HOST="${1:-staging.santekno.com}"
 8BASE_URL="https://${HOST}"
 9PASS=true
10RESULTS=()
11
12# Test 1: Health check endpoint
13HEALTH=$(curl -sf "${BASE_URL}/health" 2>/dev/null) || {
14  RESULTS+=("Health check: FAIL")
15  PASS=false
16}
17
18if [ -n "$HEALTH" ]; then
19  STATUS=$(echo "$HEALTH" | jq -r '.status' 2>/dev/null || echo "unknown")
20  if [ "$STATUS" == "ok" ]; then
21    RESULTS+=("Health check: OK")
22  else
23    RESULTS+=("Health check: $STATUS")
24    PASS=false
25  fi
26fi
27
28# Test 2: API version endpoint
29VERSION=$(curl -sf "${BASE_URL}/api/v1/version" 2>/dev/null | jq -r '.version' 2>/dev/null || echo "")
30if [ -n "$VERSION" ]; then
31  RESULTS+=("API version: $VERSION")
32else
33  RESULTS+=("API version: FAIL")
34  PASS=false
35fi
36
37# Test 3: Database connectivity (via health endpoint)
38DB_STATUS=$(curl -sf "${BASE_URL}/health" | jq -r '.checks.database' 2>/dev/null || echo "unknown")
39[ "$DB_STATUS" == "ok" ] && RESULTS+=("Database: connected") || RESULTS+=("Database: $DB_STATUS")
40
41# Test 4: Redis connectivity
42REDIS_STATUS=$(curl -sf "${BASE_URL}/health" | jq -r '.checks.redis' 2>/dev/null || echo "unknown")
43[ "$REDIS_STATUS" == "ok" ] && RESULTS+=("Redis: connected") || RESULTS+=("Redis: $REDIS_STATUS")
44
45# Test 5: Response time check
46RESPONSE_TIME=$(curl -sf -w "%{time_total}" -o /dev/null "${BASE_URL}/api/v1/orders" \
47  -H "Authorization: Bearer ${SMOKE_TEST_TOKEN:-}" 2>/dev/null || echo "999")
48
49if awk "BEGIN {exit ($RESPONSE_TIME < 2.0) ? 0 : 1}"; then
50  RESULTS+=("Response time: ${RESPONSE_TIME}s")
51else
52  RESULTS+=("Response time slow: ${RESPONSE_TIME}s")
53fi
54
55# Output
56echo "=== Smoke Test Results: $HOST ==="
57for result in "${RESULTS[@]}"; do
58  echo "  $result"
59done
60
61[ "$PASS" == "true" ] && echo "SMOKE_STATUS: PASS" || echo "SMOKE_STATUS: FAIL"

Smoke test yang baik tidak berhenti di /health saja — ia mengecek alur bisnis nyata (list orders, response time), karena itulah yang benar-benar dirasakan user, bukan sekadar apakah binary hidup.


13.4 AI Deployment Health Check

Metrics deterministik menangkap masalah yang jelas, tapi ada pola dalam log yang lolos dari threshold numerik. Script berikut mengumpulkan health response, metrics, dan log terbaru, lalu menyerahkannya ke AI untuk analisis semantik dan verdict HEALTHY | DEGRADED | FAILING.

bash
 1#!/bin/bash
 2# scripts/ai-deployment-check.sh
 3# AI analyze deployment health dari multiple data points
 4
 5set -euo pipefail
 6
 7HOST="${1}"
 8IMAGE_TAG="${2:-unknown}"
 9BASE_URL="https://${HOST}"
10
11# Collect metrics
12HEALTH=$(curl -sf "${BASE_URL}/health" 2>/dev/null || echo '{"status":"error"}')
13METRICS=$(curl -sf "${BASE_URL}/metrics" 2>/dev/null | head -50 || echo "metrics unavailable")
14LOGS=$(kubectl logs deployment/santekno-shop --namespace=staging \
15  --since=5m --tail=50 2>/dev/null || echo "logs unavailable")
16
17PROMPT="Analyze deployment health for Santekno Shop Go service.
18
19Environment: Staging
20Image: $IMAGE_TAG
21Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)
22
23HEALTH CHECK RESPONSE:
24$HEALTH
25
26RECENT LOGS (last 5 minutes):
27$LOGS
28
29METRICS:
30$METRICS
31
32Analyze:
331. Are there any ERROR or PANIC log entries?
342. Is the health check reporting all services healthy?
353. Are there unusual patterns in the metrics?
364. Any signs of memory leak, connection pool exhaustion, or high error rate?
37
38Output:
39VERDICT: HEALTHY | DEGRADED | FAILING
40Issues (if any):
41  - [issue]: [description and severity]
42RECOMMENDATION: [next steps if not HEALTHY]"
43
44RESULT=$(./scripts/claude-call.sh "$PROMPT" 500) || {
45  echo "AI analysis unavailable"
46  echo "VERDICT: HEALTHY"  # graceful: assume healthy if AI unavailable
47  exit 0
48}
49
50echo "$RESULT"

Yang penting dari script ini adalah pola graceful degradation: jika AI tidak tersedia, verdict default ke HEALTHY agar ketidaktersediaan tooling tidak pernah memblokir deployment yang sebenarnya sehat.


13.5 Production Deployment: Progressive Rollout

Setelah staging lolos, promosi ke production tidak dilakukan 100% sekaligus — kita pakai canary. Workflow berikut men-deploy ke sebagian kecil pod, memonitor error rate selama beberapa menit, lalu meminta AI menilai apakah aman dipromosikan penuh.

yaml
 1# .github/workflows/production-deploy.yml
 2name: Deploy to Production
 3
 4on:
 5  workflow_dispatch:
 6    inputs:
 7      image_tag:
 8        description: 'Image tag to deploy (default: staging-latest)'
 9        required: false
10        default: 'staging-latest'
11      rollout_percentage:
12        description: 'Canary rollout percentage (10, 25, 50, 100)'
13        required: false
14        default: '10'
15
16env:
17  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
18
19jobs:
20  pre-deploy-check:
21    name: Pre-Production Checks
22    runs-on: ubuntu-latest
23    steps:
24      - uses: actions/checkout@v4
25
26      - name: Verify staging is healthy
27        run: |
28          chmod +x scripts/smoke-test.sh
29          ./scripts/smoke-test.sh staging.santekno.com || {
30            echo "::error::Staging is not healthy — cannot proceed to production"
31            exit 1
32          }
33
34  canary-deploy:
35    name: Canary Deploy (${{ github.event.inputs.rollout_percentage }}%)
36    runs-on: ubuntu-latest
37    needs: pre-deploy-check
38    environment:
39      name: production
40      url: https://santekno.com
41    permissions:
42      deployments: write
43    steps:
44      - uses: actions/checkout@v4
45
46      - name: Deploy canary
47        env:
48          KUBECONFIG: ${{ secrets.PRODUCTION_KUBECONFIG }}
49          IMAGE_TAG: ${{ github.event.inputs.image_tag }}
50          ROLLOUT_PCT: ${{ github.event.inputs.rollout_percentage }}
51        run: |
52          TOTAL_REPLICAS=$(kubectl get deployment santekno-shop \
53            -n production -o jsonpath='{.spec.replicas}')
54          CANARY_REPLICAS=$(( TOTAL_REPLICAS * ROLLOUT_PCT / 100 ))
55          [ "$CANARY_REPLICAS" -lt 1 ] && CANARY_REPLICAS=1
56          echo "Deploying to $CANARY_REPLICAS/$TOTAL_REPLICAS pods ($ROLLOUT_PCT%)"
57          kubectl set image deployment/santekno-shop \
58            api="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${IMAGE_TAG}" \
59            --namespace=production
60          kubectl rollout status deployment/santekno-shop \
61            --namespace=production --timeout=180s
62
63      - name: Monitor canary (5 minutes)
64        run: |
65          for i in {1..5}; do
66            sleep 60
67            echo "Minute $i/5 check..."
68            ERROR_RATE=$(curl -sf "https://metrics.santekno.com/api/v1/query?query=rate(http_requests_errors[1m])" \
69              2>/dev/null | jq '.data.result[0].value[1]' 2>/dev/null || echo "0")
70            echo "  Error rate: $ERROR_RATE"
71            if awk "BEGIN {exit ($ERROR_RATE > 0.05) ? 0 : 1}"; then
72              echo "::error::Error rate $ERROR_RATE > 5% — triggering rollback"
73              kubectl rollout undo deployment/santekno-shop --namespace=production
74              exit 1
75            fi
76          done
77          echo "Canary monitoring passed"
78
79      - name: AI canary assessment
80        id: canary_check
81        continue-on-error: true
82        run: |
83          chmod +x scripts/ai-deployment-check.sh
84          ANALYSIS=$(./scripts/ai-deployment-check.sh "santekno.com" "${{ github.event.inputs.image_tag }}")
85          VERDICT=$(echo "$ANALYSIS" | grep "VERDICT:" | grep -oP '(HEALTHY|DEGRADED|FAILING)' || echo "HEALTHY")
86          echo "verdict=$VERDICT" >> $GITHUB_OUTPUT
87
88      - name: Promote or rollback
89        run: |
90          VERDICT="${{ steps.canary_check.outputs.verdict }}"
91          if [ "$VERDICT" == "FAILING" ]; then
92            echo "::error::Canary is FAILING — rolling back"
93            kubectl rollout undo deployment/santekno-shop --namespace=production
94            exit 1
95          elif [ "$VERDICT" == "DEGRADED" ]; then
96            echo "::warning::Canary is DEGRADED — review before full promotion"
97          else
98            echo "Canary healthy — ready for full promotion"
99          fi

Pola canary ini menggabungkan dua sinyal: threshold error rate yang deterministik (auto-rollback instan) dan verdict AI yang semantik — sehingga keputusan promote/rollback berdiri di atas bukti kuantitatif sekaligus kualitatif.


13.6 Automated Rollback

Jika metrics melewati batas aman, sistem harus bisa rollback tanpa menunggu manusia. Script berikut mengecek error rate dan P99 latency dari Prometheus, dan begitu ambang terlampaui, langsung menjalankan kubectl rollout undo lalu memberi notifikasi ke Slack.

bash
 1#!/bin/bash
 2# scripts/auto-rollback.sh
 3# Trigger rollback berdasarkan metrics threshold
 4
 5set -euo pipefail
 6
 7ENVIRONMENT="${1:-production}"
 8NAMESPACE="${ENVIRONMENT}"
 9
10MAX_ERROR_RATE=0.05     # 5%
11MAX_P99_LATENCY=2000    # 2 detik dalam ms
12
13TRIGGER_ROLLBACK=false
14REASON=""
15
16ERROR_RATE=$(curl -sf "https://metrics.santekno.com/api/v1/query" \
17  --data-urlencode "query=rate(http_requests_total{status=~'5..'}[2m])/rate(http_requests_total[2m])" \
18  2>/dev/null | jq '.data.result[0].value[1]' | tr -d '"' || echo "0")
19
20if awk "BEGIN {exit ($ERROR_RATE > $MAX_ERROR_RATE) ? 0 : 1}"; then
21  TRIGGER_ROLLBACK=true
22  REASON="Error rate ${ERROR_RATE} > ${MAX_ERROR_RATE} threshold"
23fi
24
25P99_LATENCY=$(curl -sf "https://metrics.santekno.com/api/v1/query" \
26  --data-urlencode "query=histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[2m])) * 1000" \
27  2>/dev/null | jq '.data.result[0].value[1]' | tr -d '"' || echo "0")
28
29if awk "BEGIN {exit ($P99_LATENCY > $MAX_P99_LATENCY) ? 0 : 1}"; then
30  TRIGGER_ROLLBACK=true
31  REASON="P99 latency ${P99_LATENCY}ms > ${MAX_P99_LATENCY}ms threshold"
32fi
33
34if [ "$TRIGGER_ROLLBACK" == "true" ]; then
35  echo "ROLLBACK TRIGGERED: $REASON"
36  kubectl rollout undo deployment/santekno-shop --namespace="$NAMESPACE"
37  kubectl rollout status deployment/santekno-shop --namespace="$NAMESPACE" --timeout=120s
38  echo "Rollback completed"
39  curl -X POST "$SLACK_WEBHOOK" \
40    -H "Content-Type: application/json" \
41    -d "$(jq -n --arg reason "$REASON" --arg env "$ENVIRONMENT" \
42      '{text: ("Auto-rollback triggered in *" + $env + "*\nReason: " + $reason)}')"
43  exit 1
44fi
45
46echo "Deployment healthy, no rollback needed"

Rollback otomatis berbasis threshold ini adalah jaring pengaman terakhir — ketika sesuatu benar-benar salah, service pulih dalam hitungan menit tanpa perlu ada engineer yang terbangun tengah malam.


13.7 Deployment Notification yang Informatif

Deployment yang selesai harus dikomunikasikan, tapi notifikasi generik “deploy sukses” tidak banyak membantu. Step berikut memakai AI untuk merangkai notifikasi Slack yang ringkas dan kontekstual dalam Bahasa Indonesia, apapun status akhirnya.

yaml
 1- name: Send deployment notification
 2  if: always()
 3  env:
 4    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
 5  run: |
 6    STATUS="${{ job.status }}"
 7    VERSION="${{ github.event.inputs.image_tag }}"
 8    ENVIRONMENT="production"
 9    ACTOR="${{ github.actor }}"
10
11    PROMPT="Generate a brief deployment notification (max 100 words, Bahasa Indonesia).
12    Deploy: $VERSION
13    Environment: $ENVIRONMENT
14    Status: $STATUS
15    Deployed by: $ACTOR
16    Time: $(date -u '+%Y-%m-%d %H:%M UTC')
17    Format sebagai Slack notification yang informative tapi concise."
18
19    NOTIFICATION=$(./scripts/claude-call.sh "$PROMPT" 150) || \
20      NOTIFICATION="Deploy $VERSION ke $ENVIRONMENT: $STATUS"
21
22    curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
23      -H "Content-Type: application/json" \
24      -d "$(jq -n --arg text "$NOTIFICATION" '{text: $text}')"

Dengan if: always() dan fallback string, notifikasi selalu terkirim — bahkan saat deploy gagal atau AI tidak tersedia — sehingga tim tidak pernah kehilangan visibilitas atas apa yang terjadi di production.


13.8 Feature Flags untuk Safe Deployment

Deployment kode dan aktivasi fitur sebaiknya dipisah, dan feature flag adalah mekanismenya. Kode Go berikut menunjukkan manager flag sederhana berbasis environment variable, lalu dipakai di handler untuk memilih alur baru atau lama secara runtime.

go
 1// internal/feature/flags.go
 2// Feature flags untuk gradual rollout tanpa deployment
 3
 4package feature
 5
 6import (
 7    "context"
 8    "os"
 9)
10
11type Flag string
12
13const (
14    NewCancelOrderFlow   Flag = "new_cancel_order_flow"
15    FlashSaleFeature     Flag = "flash_sale_feature"
16    AIProductDescription Flag = "ai_product_description"
17)
18
19type Manager struct {
20    // Bisa di-backed oleh Redis, LaunchDarkly, atau simple env vars
21    flags map[Flag]bool
22}
23
24func NewManager() *Manager {
25    return &Manager{
26        flags: map[Flag]bool{
27            NewCancelOrderFlow:   os.Getenv("FF_NEW_CANCEL_ORDER") == "true",
28            FlashSaleFeature:     os.Getenv("FF_FLASH_SALE") == "true",
29            AIProductDescription: os.Getenv("FF_AI_PRODUCT_DESC") == "true",
30        },
31    }
32}
33
34func (m *Manager) IsEnabled(ctx context.Context, flag Flag) bool {
35    return m.flags[flag]
36}
37
38// Usage di handler:
39func (h *OrderHandler) CancelOrder(c echo.Context) error {
40    if h.flags.IsEnabled(c.Request().Context(), feature.NewCancelOrderFlow) {
41        return h.newCancelOrderFlow(c)
42    }
43    return h.legacyCancelOrderFlow(c)
44}

Dengan feature flag, kamu bisa men-deploy kode fitur baru ke production dalam keadaan mati, lalu mengaktifkannya bertahap tanpa deployment ulang — mengurangi risiko dan mempermudah rollback fitur.


13.9 Deployment Checklist Generator

Setiap release punya risiko berbeda tergantung perubahannya, jadi checklist generik sering tidak relevan. Script berikut mengumpulkan commit dan jumlah migration sejak deploy terakhir, lalu meminta AI membuat checklist deployment yang spesifik untuk perubahan itu.

bash
 1#!/bin/bash
 2# scripts/generate-deployment-checklist.sh
 3# AI generate deployment checklist berdasarkan perubahan
 4
 5set -euo pipefail
 6
 7VERSION="${1}"
 8ENVIRONMENT="${2:-staging}"
 9
10LAST_DEPLOY_TAG=$(git tag -l "deploy-${ENVIRONMENT}-*" | sort -V | tail -1)
11COMMITS=$(git log "${LAST_DEPLOY_TAG}..HEAD" --no-merges --pretty=format:"%s" 2>/dev/null | head -20 || \
12  git log --no-merges --pretty=format:"%s" -20)
13
14MIGRATION_COUNT=$(git diff "${LAST_DEPLOY_TAG}..HEAD" --name-only -- 'migrations/**' 2>/dev/null | wc -l || echo "0")
15
16PROMPT="Generate deployment checklist untuk release $VERSION ke $ENVIRONMENT.
17
18Changes (commit messages):
19$COMMITS
20
21Migration count: $MIGRATION_COUNT
22
23Create a concise deployment checklist in Bahasa Indonesia:
241. Pre-deployment steps berdasarkan tipe perubahan
252. Deployment steps
263. Post-deployment verification steps
274. Rollback triggers (apa yang perlu di-monitor)
28
29Be specific berdasarkan changes. Skip generic steps yang tidak relevant."
30
31./scripts/claude-call.sh "$PROMPT" 500

Checklist yang di-generate dari diff nyata jauh lebih berguna daripada template statis — ia menyoroti risiko aktual (misalnya ada migration) alih-alih langkah generik yang sering di-skip karena terasa tidak relevan.


13.10 Tips & Gotchas

Sebelum masuk ke topik lanjutan, ada beberapa pelajaran praktis yang layak diingat saat membangun pipeline seperti ini.

Tip 1: Smoke test harus spesifik. Test yang hanya cek /health tidak cukup. Test alur bisnis nyata: bisa create order? bisa list products? Response time acceptable?

Tip 2: Canary dengan persentase kecil dulu. Mulai dengan 10% traffic. Jika 10% healthy selama 5 menit, promote ke 25%, lalu 50%, lalu 100%. Jangan langsung 100%.

Tip 3: Threshold auto-rollback yang realistis. 5% error rate mungkin terlalu rendah untuk canary yang traffic-nya memang sedikit. Kalibrasi threshold berdasarkan baseline error rate di production.

Tip 4: AI health check sebagai suplemen, bukan pengganti. AI bisa miss sesuatu. Pasangkan dengan deterministic metric checks (error rate, latency, CPU).

Gotcha 1: Deploy di peak hours. Notifikasi AI tidak cukup — timing butuh human judgment. Jangan auto-deploy ke production di jam sibuk (12-14 WIB untuk e-commerce).

Gotcha 2: Migration dan rollback. Jika deployment ter-rollback tapi migration sudah jalan, schema data mungkin tidak kompatibel dengan versi lama. Rencanakan ini dengan hati-hati.

Gotcha 3: Smoke test yang flaky. Smoke test yang intermittent fail akan memblokir semua deployment. Perbaiki test yang flaky sebelum menjadikannya deployment gate.

Intinya, tooling secanggih apapun tetap butuh kalibrasi dan penilaian manusia di titik-titik kritis — otomasi memperluas kapasitas, bukan menghapus tanggung jawab.


13.11 GitOps: Environment Configuration as Code

Perbedaan antar environment sebaiknya hidup di git, bukan tersembunyi di dashboard. Contoh values berikut menunjukkan bagaimana konfigurasi staging dan production dipisah sebagai file yang bisa di-review lewat PR.

yaml
 1# environments/staging/values.yaml
 2image: { tag: staging-latest }
 3replicas: 2
 4env:
 5  LOG_LEVEL: debug
 6  FEATURE_FLAG_CANCEL_ORDER: "true"
 7
 8# environments/production/values.yaml
 9image: { tag: v1.5.0 }  # pinned version
10replicas: 5
11env:
12  LOG_LEVEL: info
13  FEATURE_FLAG_CANCEL_ORDER: "false"  # off until fully tested

Dengan konfigurasi sebagai kode, setiap perubahan environment melewati review PR dan ter-track di git history — audit trail otomatis untuk pertanyaan “kenapa production di-set seperti ini?”.


13.12 Deployment Duration Tracking

Deployment yang makin lama adalah sinyal awal masalah pipeline. Script pendek berikut mengukur durasi deployment, memberi peringatan jika melewati ambang, dan mengirim angkanya sebagai metrics untuk analisis tren.

bash
 1#!/bin/bash
 2# scripts/track-deployment-duration.sh
 3
 4START_TIME=$(date +%s)
 5
 6# ... deployment steps run here ...
 7
 8END_TIME=$(date +%s)
 9DURATION=$((END_TIME - START_TIME))
10echo "Deployment duration: ${DURATION}s"
11
12[ "$DURATION" -gt 300 ] && echo "::warning::Slow deployment (${DURATION}s > 300s)"
13
14curl -sX POST "https://metrics.santekno.com/api/v1/events" \
15  -H "Content-Type: application/json" \
16  -d "{\"event\": \"deployment\", \"env\": \"$1\", \"duration\": $DURATION}" || true

Melacak durasi deployment dari waktu ke waktu membantu mendeteksi degradasi pipeline lebih awal — sebelum “deploy 3 menit” diam-diam berubah jadi “deploy 15 menit”.


13.13 Zero-Downtime Strategy

Deployment aman berarti user tidak pernah melihat error saat pod diganti. Konfigurasi rolling update berikut, dipasangkan dengan graceful shutdown di Go, memastikan tidak ada pod lama yang dimatikan sebelum pod baru siap melayani.

yaml
 1# Kubernetes rolling update strategy
 2strategy:
 3  type: RollingUpdate
 4  rollingUpdate:
 5    maxUnavailable: 0    # zero downtime: no pod removed before new one ready
 6    maxSurge: 1          # one extra pod during update
 7
 8# Coupled dengan graceful shutdown di Go (main.go):
 9# signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT)
10# <-quit
11# ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
12# defer cancel()
13# srv.Shutdown(ctx)  // wait up to 30s for in-flight requests

Kombinasi maxUnavailable: 0 dan graceful shutdown 30 detik ini menjamin request yang sedang berjalan selesai dulu sebelum pod lama dimatikan — dasar dari deployment tanpa downtime.


13.14 Deployment Audit Trail

Untuk kebutuhan audit, setiap deployment production harus meninggalkan jejak. Step berikut mencatat metadata deployment (timestamp, versi, aktor, hasil smoke test, verdict AI) sebagai artifact yang disimpan berbulan-bulan.

yaml
 1- name: Record deployment
 2  run: |
 3    cat > /tmp/deploy-record.json << EOF
 4    {
 5      "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
 6      "environment": "production",
 7      "version": "${{ github.ref_name }}",
 8      "actor": "${{ github.actor }}",
 9      "sha": "${{ github.sha }}",
10      "smoke_test": "${{ steps.smoke.outcome }}",
11      "ai_verdict": "${{ steps.ai_health.outputs.verdict }}"
12    }
13    EOF
14
15- uses: actions/upload-artifact@v4
16  with:
17    name: deploy-record-${{ github.sha }}
18    path: /tmp/deploy-record.json
19    retention-days: 90

Audit trail seperti ini menjawab pertanyaan penting saat menelusuri incident: “versi apa yang aktif saat itu, siapa yang men-deploy, dan apa verdict health check-nya?”.


13.15 Environment-Specific Config Management

Konfigurasi per environment harus tervalidasi sebelum deploy, bukan setelah service crash. Struktur direktori dan perintah validasi berikut memastikan setiap field wajib terisi dan tidak ada secret kosong sebelum perubahan naik.

bash
 1# configs/ diatur per environment dengan secrets terpisah
 2configs/
 3  base/         # shared config values
 4  staging/      # staging-specific overrides
 5  production/   # production-specific overrides (secrets via vault)
 6
 7# Validation: pastikan config valid sebelum deploy
 8go run ./cmd/validate-config/main.go --env staging
 9go run ./cmd/validate-config/main.go --env production
10# Checks: required fields, type validation, no empty secrets

Memvalidasi konfigurasi sebagai langkah pipeline mencegah kelas bug yang paling menyebalkan: service yang deploy sukses tapi langsung crash karena satu secret lupa di-set.


13.16 Ringkasan: Progressive Confidence Building

Multi-environment deployment dengan AI checkpoint pada intinya adalah tentang membangun keyakinan secara bertahap — setiap environment memberikan lebih banyak bukti bahwa perubahan aman untuk dipromosikan.

Elemen kunci:

  • Staging sebagai gate wajib sebelum production
  • Smoke test untuk verifikasi fungsional
  • AI health check untuk analisis semantik dari log dan metrics
  • Canary rollout bertahap (10% → 25% → 50% → 100%)
  • Auto-rollback berdasarkan threshold metrics

Filosofinya: manusia memutuskan kapan mempromosikan, sistem memonitor dan rollback secara otomatis. Dengan pola ini, deployment berhenti menjadi event menegangkan dan berubah menjadi proses berlapis yang setiap tahapnya bisa dipercaya.

Artikel Terkait

💬 Komentar