SiamCafe.net Blog
Technology

PagerDuty Incident Progressive Delivery

pagerduty incident progressive delivery
PagerDuty Incident Progressive Delivery | SiamCafe Blog
2025-06-18· อ. บอม — SiamCafe.net· 10,988 คำ

Progressive Delivery คืออะไรและทำไมถึงสำคัญ

Progressive Delivery เป็นแนวทางการ Deploy Software ที่ค่อยๆเปิดให้ผู้ใช้เข้าถึง Version ใหม่ทีละกลุ่ม แทนที่จะ Deploy ให้ทุกู้คืนพร้อมกัน วิธีนี้ช่วยลดความเสี่ยงเพราะหากเกิดปัญหา จะกระทบเฉพาะผู้ใช้กลุ่มเล็กเท่านั้น และสามารถ Rollback ได้ทันทีก่อนที่ปัญหาจะกระจายไปทั้งระบบ

รูปแบบหลักของ Progressive Delivery ได้แก่ Canary Release ที่เปิดให้ผู้ใช้ส่วันนี้อย (เช่น 5%) ใช้ Version ใหม่ก่อน, Blue-Green Deployment ที่มี Environment สองชุดและสลับ Traffic, Feature Flags ที่เปิด/ปิดฟีเจอร์ได้แบบ Real-time และ A/B Testing ที่ทดสอบ Version ต่างกันกับผู้ใช้ต่างกลุ่ม

PagerDuty เข้ามามีบทบาทสำคัญในฐานะ Incident Management Platform ที่ตรวจจับปัญหาระหว่าง Progressive Rollout และ Trigger การ Rollback อัตโนมัติเมื่อจำเป็น

สถาปัตยกรรม Progressive Delivery กับ PagerDuty

การ Integrate PagerDuty เข้ากับ Progressive Delivery Pipeline ต้องเชื่อมต่อหลาย Component เข้าด้วยกัน

การตั้งค่า Argo Rollouts กับ PagerDuty

Argo Rollouts เป็นเครื่องมือ Progressive Delivery สำหรับ Kubernetes ที่รองรับ Canary และ Blue-Green Deployment ต่อไปนี้เป็นวิธีตั้งค่าให้ทำงานร่วมกับ PagerDuty

# argo-rollout-canary.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: web-frontend
  namespace: production
spec:
  replicas: 10
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: web-frontend
  strategy:
    canary:
      canaryService: web-frontend-canary
      stableService: web-frontend-stable
      trafficRouting:
        istio:
          virtualServices:
            - name: web-frontend-vsvc
              routes:
                - primary
      analysis:
        templates:
          - templateName: canary-analysis
        startingStep: 2
        args:
          - name: service-name
            value: web-frontend-canary
      steps:
        - setWeight: 5
        - pause: { duration: 2m }
        - setWeight: 10
        - pause: { duration: 5m }
        - setWeight: 25
        - pause: { duration: 5m }
        - setWeight: 50
        - pause: { duration: 10m }
        - setWeight: 75
        - pause: { duration: 10m }
        - setWeight: 100
  template:
    metadata:
      labels:
        app: web-frontend
    spec:
      containers:
        - name: web-frontend
          image: registry.company.com/web-frontend:v2.1.0
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: 200m
              memory: 256Mi
            limits:
              cpu: 500m
              memory: 512Mi
          readinessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10

---
# canary-analysis-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: canary-analysis
spec:
  args:
    - name: service-name
  metrics:
    - name: error-rate
      interval: 60s
      successCondition: result[0] < 0.05
      failureLimit: 3
      provider:
        prometheus:
          address: http://prometheus.monitoring:9090
          query: |
            sum(rate(http_requests_total{service="{{args.service-name}}",status=~"5.."}[5m]))
            /
            sum(rate(http_requests_total{service="{{args.service-name}}"}[5m]))

    - name: latency-p99
      interval: 60s
      successCondition: result[0] < 500
      failureLimit: 3
      provider:
        prometheus:
          address: http://prometheus.monitoring:9090
          query: |
            histogram_quantile(0.99,
              sum(rate(http_request_duration_seconds_bucket{service="{{args.service-name}}"}[5m]))
              by (le)
            ) * 1000

    - name: success-rate
      interval: 60s
      successCondition: result[0] > 0.99
      failureLimit: 2
      provider:
        prometheus:
          address: http://prometheus.monitoring:9090
          query: |
            sum(rate(http_requests_total{service="{{args.service-name}}", status=~"2.."}[5m]))
            /
            sum(rate(http_requests_total{service="{{args.service-name}}"}[5m]))

การตั้งค่า PagerDuty Alert สำหรับ Canary Failure

เมื่อ Canary Analysis ล้มเหลว ต้องแจ้งเตือนทีมทันทีผ่าน PagerDuty พร้อมข้อมูลว่า Metric ไหนที่ล้มเหลวและ Rollback ได้สำเร็จหรือไม่

# Python script สำหรับ Webhook ที่รับ Event จาก Argo Rollouts แล้วส่งไป PagerDuty
from flask import Flask, request, jsonify
import requests
import json
from datetime import datetime

app = Flask(__name__)

PAGERDUTY_ROUTING_KEY = "R0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
SLACK_WEBHOOK = "https://hooks.slack.com/services/T00/B00/xxx"

@app.route("/webhook/rollout", methods=["POST"])
def rollout_webhook():
    """รับ Webhook จาก Argo Rollouts Notification"""
    data = request.json
    rollout_name = data.get("name", "unknown")
    phase = data.get("phase", "unknown")
    message = data.get("message", "")

    if phase in ("Degraded", "Failed"):
        # ส่ง PagerDuty Event
        pd_payload = {
            "routing_key": PAGERDUTY_ROUTING_KEY,
            "event_action": "trigger",
            "dedup_key": f"rollout-{rollout_name}-{phase.lower()}",
            "payload": {
                "summary": f"Canary Rollout Failed: {rollout_name} — {message}",
                "severity": "critical",
                "source": "argo-rollouts",
                "component": rollout_name,
                "group": "progressive-delivery",
                "class": "deployment",
                "custom_details": {
                    "rollout": rollout_name,
                    "phase": phase,
                    "message": message,
                    "timestamp": datetime.utcnow().isoformat(),
                    "dashboard": f"https://grafana.company.com/d/rollouts/{rollout_name}"
                }
            },
            "links": [
                {
                    "href": f"https://argocd.company.com/rollouts/{rollout_name}",
                    "text": "Argo Rollouts Dashboard"
                }
            ]
        }
        resp = requests.post(
            "https://events.pagerduty.com/v2/enqueue",
            json=pd_payload, timeout=10
        )
        print(f"PagerDuty response: {resp.status_code}")

        # ส่ง Slack Notification
        slack_msg = {
            "text": f":rotating_light: *Canary Rollout Failed*\n"
                    f"*Rollout:* {rollout_name}\n"
                    f"*Phase:* {phase}\n"
                    f"*Message:* {message}\n"
                    f"*Action:* Automatic rollback triggered"
        }
        requests.post(SLACK_WEBHOOK, json=slack_msg, timeout=10)

    elif phase == "Healthy":
        # Resolve PagerDuty Incident
        resolve_payload = {
            "routing_key": PAGERDUTY_ROUTING_KEY,
            "event_action": "resolve",
            "dedup_key": f"rollout-{rollout_name}-degraded"
        }
        requests.post(
            "https://events.pagerduty.com/v2/enqueue",
            json=resolve_payload, timeout=10
        )

    return jsonify({"status": "ok"}), 200

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=9095)

Blue-Green Deployment กับ PagerDuty

Blue-Green Deployment เป็นอีกรูปแบบของ Progressive Delivery ที่มี Environment สองชุด (Blue = ปัจจุบัน, Green = ใหม่) แล้วสลับ Traffic ทั้งหมดไปยัง Green เมื่อพร้อม ข้อดีคือ Rollback เร็วมากเพราะแค่สลับกลับ แต่ข้อเสียคือถ้ามีปัญหาจะกระทบผู้ใช้ทั้งหมดทันที

# blue-green-rollout.yaml สำหรับ Argo Rollouts
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: api-backend
  namespace: production
spec:
  replicas: 5
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: api-backend
  strategy:
    blueGreen:
      activeService: api-backend-active
      previewService: api-backend-preview
      autoPromotionEnabled: false
      scaleDownDelaySeconds: 300
      prePromotionAnalysis:
        templates:
          - templateName: smoke-test
        args:
          - name: preview-url
            value: "http://api-backend-preview.production.svc.cluster.local"
      postPromotionAnalysis:
        templates:
          - templateName: post-deploy-check
        args:
          - name: active-url
            value: "http://api-backend-active.production.svc.cluster.local"
  template:
    metadata:
      labels:
        app: api-backend
    spec:
      containers:
        - name: api-backend
          image: registry.company.com/api-backend:v3.0.0
          ports:
            - containerPort: 3000

---
# smoke-test.yaml — ทดสอบก่อน Promote
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: smoke-test
spec:
  args:
    - name: preview-url
  metrics:
    - name: health-check
      count: 5
      interval: 30s
      successCondition: result == "ok"
      provider:
        job:
          spec:
            template:
              spec:
                containers:
                  - name: smoke-test
                    image: curlimages/curl:latest
                    command:
                      - sh
                      - -c
                      - |
                        STATUS=$(curl -s -o /dev/null -w "%{http_code}" {{args.preview-url}}/healthz)
                        if [ "$STATUS" = "200" ]; then echo "ok"; else echo "fail"; exit 1; fi
                restartPolicy: Never
            backoffLimit: 0

Feature Flag กับ PagerDuty Integration

Feature Flags เป็นอีกวิธีหนึ่งของ Progressive Delivery ที่ช่วยให้สามารถเปิด/ปิดฟีเจอร์ได้แบบ Real-time โดยไม่ต้อง Deploy ใหม่ เมื่อ Feature Flag ทำให้เกิดปัญหา PagerDuty สามารถ Trigger การปิด Flag อัตโนมัติได้

#!/bin/bash
# feature-flag-rollback.sh
# Script สำหรับ Auto-disable Feature Flag เมื่อได้รับ PagerDuty Webhook
set -euo pipefail

LAUNCHDARKLY_API_KEY=""
PROJECT_KEY="default"
ENVIRONMENT_KEY="production"
FLAG_KEY=""

if [ -z "$FLAG_KEY" ]; then
    echo "Usage: $0 "
    exit 1
fi

echo "กำลังปิด Feature Flag: "

# ปิด Feature Flag ผ่าน LaunchDarkly API
curl -s -X PATCH \
  "https://app.launchdarkly.com/api/v2/flags//" \
  -H "Authorization: " \
  -H "Content-Type: application/json; domain-model=launchdarkly.semanticpatch" \
  -d "{
    \"instructions\": [{
      \"kind\": \"turnFlagOff\",
      \"environmentKey\": \"\"
    }],
    \"comment\": \"Auto-disabled by PagerDuty incident response\"
  }"

echo "Feature Flag  ถูกปิดเรียบร้อย"

# Resolve PagerDuty Incident
curl -s -X POST "https://events.pagerduty.com/v2/enqueue" \
  -H "Content-Type: application/json" \
  -d "{
    \"routing_key\": \"R0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",
    \"event_action\": \"resolve\",
    \"dedup_key\": \"feature-flag-\"
  }"

echo "PagerDuty Incident resolved"

Prometheus Alert Rules สำหรับ Progressive Delivery

ต้องมี Alert Rules เฉพาะสำหรับ Canary Traffic เพื่อตรวจจับปัญหาก่อนที่จะ Promote ให้ผู้ใช้ทั้งหมด

# prometheus-progressive-delivery-rules.yml
groups:
  - name: progressive_delivery
    interval: 15s
    rules:
      - alert: CanaryHighErrorRate
        expr: |
          (
            sum(rate(http_requests_total{canary="true", status=~"5.."}[5m]))
            /
            sum(rate(http_requests_total{canary="true"}[5m]))
          ) > 0.05
        for: 1m
        labels:
          severity: critical
          team: platform
          deployment_type: canary
        annotations:
          summary: "Canary Error Rate สูง {{ $value | humanizePercentage }}"
          description: "Error Rate ของ Canary Version สูงกว่า 5% ควร Rollback ทันที"
          runbook: "https://wiki.company.com/runbooks/canary-rollback"

      - alert: CanaryHighLatency
        expr: |
          (
            histogram_quantile(0.99,
              sum(rate(http_request_duration_seconds_bucket{canary="true"}[5m])) by (le)
            )
            /
            histogram_quantile(0.99,
              sum(rate(http_request_duration_seconds_bucket{canary="false"}[5m])) by (le)
            )
          ) > 1.5
        for: 2m
        labels:
          severity: warning
          team: platform
        annotations:
          summary: "Canary P99 Latency สูงกว่า Stable 1.5 เท่า"

      - alert: BlueGreenPostDeployError
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[2m]))
          /
          sum(rate(http_requests_total[2m])) > 0.01
        for: 30s
        labels:
          severity: critical
          team: platform
          deployment_type: blue-green
        annotations:
          summary: "Error Rate หลัง Blue-Green Switch สูง {{ $value | humanizePercentage }}"
          description: "ตรวจพบ Error Rate สูงหลัง Traffic Switch ควรพิจารณา Rollback"

Best Practices สำหรับ Progressive Delivery กับ Incident Management

Progressive Delivery คืออะไรและต่างจาก Continuous Delivery อย่างไร

Progressive Delivery คือการ Deploy แบบค่อยๆเปิดให้ผู้ใช้ทีละกลุ่ม เช่น Canary Release ที่เปิดให้ 5% ก่อนแล้วค่อยเพิ่ม ต่างจาก Continuous Delivery ที่ Deploy ให้ผู้ใช้ทั้งหมดพร้อมกัน ข้อดีคือลดความเสี่ยงและสามารถตรวจจับปัญหาได้ก่อนกระทบผู้ใช้ทั้งหมด

PagerDuty ช่วย Progressive Delivery ได้อย่างไร

PagerDuty ตรวจจับ Error Rate และ Latency ที่เพิ่มขึ้นระหว่าง Canary Release แล้วแจ้งเตือนทีมทันที สามารถ Trigger Automatic Rollback ผ่าน Webhook หรือ Automation Actions เมื่อ Incident เกิดขึ้นระหว่าง Progressive Rollout ช่วยให้ทีมตอบสนองได้เร็วขึ้น

ควรตั้ง Canary Analysis Threshold อย่างไร

ควรเปรียบเทียบ Canary กับ Baseline โดยดู Error Rate ไม่เกิน 1.5 เท่าของ Baseline, P99 Latency ไม่เกิน 1.3 เท่า และ Success Rate ไม่ต่ำกว่า 99% ค่าเหล่านี้ควรปรับตามลักษณะของ Application และ Traffic Pattern จริง

Blue-Green Deployment ต่างจาก Canary อย่างไรในแง่ Incident Management

Blue-Green สลับ Traffic ทั้งหมดไปยัง Environment ใหม่พร้อมกัน ทำให้ Rollback เร็ว (สลับกลับทันที) แต่ผลกระทบกว้างกว่าเพราะผู้ใช้ทั้งหมดโดน Canary ค่อยๆเพิ่ม Traffic ทำให้ผลกระทบจำกัดในกลุ่มเล็ก PagerDuty ต้องตั้ง Threshold ต่างกันตามรูปแบบ

สรุปและแนวทางปฏิบัติ

Progressive Delivery เป็นวิธี Deploy ที่ปลอดภัยและเป็นมาตรฐานสำหรับองค์กรที่ต้องการลดความเสี่ยงในการ Release ซอฟต์แวร์ การ Integrate PagerDuty เข้ากับ Progressive Delivery Pipeline ช่วยให้ทีมสามารถตรวจจับปัญหาได้เร็ว Rollback ได้อัตโนมัติ และมี Incident Response ที่ชัดเจน สิ่งสำคัญคือต้องกำหนด Rollback Criteria ล่วงหน้า ใช้ Automated Analysis ตัดสินใจ และ Review ผลลัพธ์หลังทุก Deploy เพื่อปรับปรุงกระบวนการอย่างต่อเนื่อง

📖 บทความที่เกี่ยวข้อง

Distributed Tracing Progressive Deliveryอ่านบทความ → C# Blazor Progressive Deliveryอ่านบทความ → WordPress WooCommerce Progressive Deliveryอ่านบทความ → Azure Front Door Progressive Deliveryอ่านบทความ → PagerDuty Incident Testing Strategy QAอ่านบทความ →

📚 ดูบทความทั้งหมด →