Chapter 8: Argo Project Integration Practice

Learn how to integrate Argo CD, Argo Workflows, Argo Rollouts and Argo Events to build a complete cloud-native CI/CD platform

作者
30min

Argo Project Integration Practice

Chapter 8: Building a Complete Cloud-Native CI/CD Platform

This chapter will introduce how to integrate various components of the Argo ecosystem together to build a complete cloud-native CI/CD platform.

8.1 Integration Architecture Overview

8.1.1 Overall Architecture

🔄 正在渲染 Mermaid 图表...

8.1.2 Component Interaction Flow

🔄 正在渲染 Mermaid 图表...

8.2 Infrastructure Preparation

8.2.1 Install All Argo Components

#!/bin/bash
# install-argo-stack.sh

# Create namespaces
kubectl create namespace argo
kubectl create namespace argo-events
kubectl create namespace argo-rollouts

# Install Argo Workflows
kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/latest/download/install.yaml

# Install Argo CD
kubectl apply -n argo -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# Install Argo Events
kubectl apply -n argo-events -f https://raw.githubusercontent.com/argoproj/argo-events/stable/manifests/install.yaml
kubectl apply -n argo-events -f https://raw.githubusercontent.com/argoproj/argo-events/stable/manifests/install-validating-webhook.yaml

# Install Argo Rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml

# Wait for all Pods to be ready
echo "Waiting for Argo components to be ready..."
kubectl wait --for=condition=Ready pods --all -n argo --timeout=300s
kubectl wait --for=condition=Ready pods --all -n argo-events --timeout=300s
kubectl wait --for=condition=Ready pods --all -n argo-rollouts --timeout=300s

echo "All Argo components installed successfully!"

8.2.2 Configure ServiceAccount and RBAC

# argo-rbac.yaml
# Argo Workflows ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: argo-workflow
  namespace: argo
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: argo-workflow-role
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log", "secrets", "configmaps"]
  verbs: ["*"]
- apiGroups: ["argoproj.io"]
  resources: ["workflows", "workflowtemplates", "cronworkflows"]
  verbs: ["*"]
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets"]
  verbs: ["get", "list", "watch", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: argo-workflow-binding
subjects:
- kind: ServiceAccount
  name: argo-workflow
  namespace: argo
roleRef:
  kind: ClusterRole
  name: argo-workflow-role
  apiGroup: rbac.authorization.k8s.io
---
# Argo Events ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: argo-events-sa
  namespace: argo-events
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: argo-events-role
rules:
- apiGroups: ["argoproj.io"]
  resources: ["workflows", "workflowtemplates"]
  verbs: ["*"]
- apiGroups: [""]
  resources: ["pods", "configmaps", "secrets"]
  verbs: ["*"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: argo-events-binding
subjects:
- kind: ServiceAccount
  name: argo-events-sa
  namespace: argo-events
roleRef:
  kind: ClusterRole
  name: argo-events-role
  apiGroup: rbac.authorization.k8s.io

8.2.3 Configure EventBus

# eventbus.yaml
apiVersion: argoproj.io/v1alpha1
kind: EventBus
metadata:
  name: default
  namespace: argo-events
spec:
  nats:
    native:
      replicas: 3
      auth: token
      persistence:
        storageClassName: standard
        accessMode: ReadWriteOnce
        volumeSize: 10Gi

8.3 CI Pipeline Configuration

8.3.1 GitHub EventSource

# github-eventsource.yaml
apiVersion: argoproj.io/v1alpha1
kind: EventSource
metadata:
  name: github
  namespace: argo-events
spec:
  service:
    ports:
    - port: 12000
      targetPort: 12000
  github:
    app-repo:
      repositories:
      - owner: myorg
        names:
        - myapp
      events:
      - push
      - pull_request
      webhook:
        endpoint: /push
        port: "12000"
        method: POST
      apiToken:
        name: github-access
        key: token
      webhookSecret:
        name: github-webhook
        key: secret
      insecure: false
      active: true
      contentType: json
---
# Ingress for webhook
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: github-webhook
  namespace: argo-events
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: webhook.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: github-eventsource-svc
            port:
              number: 12000

8.3.2 CI WorkflowTemplate

# ci-workflow-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
  name: ci-pipeline
  namespace: argo
spec:
  entrypoint: ci-pipeline
  arguments:
    parameters:
    - name: repo
    - name: branch
    - name: commit
    - name: registry
      value: docker.io/myorg
  volumeClaimTemplates:
  - metadata:
      name: workspace
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 5Gi

  templates:
  - name: ci-pipeline
    dag:
      tasks:
      - name: checkout
        template: git-checkout
        arguments:
          parameters:
          - name: repo
            value: "{{workflow.parameters.repo}}"
          - name: branch
            value: "{{workflow.parameters.branch}}"
      - name: build
        dependencies: [checkout]
        template: docker-build
        arguments:
          parameters:
          - name: image
            value: "{{workflow.parameters.registry}}/myapp"
          - name: tag
            value: "{{workflow.parameters.commit}}"
      - name: unit-test
        dependencies: [checkout]
        template: run-tests
        arguments:
          parameters:
          - name: test-type
            value: unit
      - name: lint
        dependencies: [checkout]
        template: run-lint
      - name: security-scan
        dependencies: [build]
        template: trivy-scan
        arguments:
          parameters:
          - name: image
            value: "{{workflow.parameters.registry}}/myapp:{{workflow.parameters.commit}}"
      - name: integration-test
        dependencies: [build, unit-test]
        template: run-tests
        arguments:
          parameters:
          - name: test-type
            value: integration
      - name: push-image
        dependencies: [security-scan, integration-test, lint]
        template: docker-push
        arguments:
          parameters:
          - name: image
            value: "{{workflow.parameters.registry}}/myapp"
          - name: tag
            value: "{{workflow.parameters.commit}}"
      - name: update-manifest
        dependencies: [push-image]
        template: update-gitops
        arguments:
          parameters:
          - name: image
            value: "{{workflow.parameters.registry}}/myapp:{{workflow.parameters.commit}}"

  - name: git-checkout
    inputs:
      parameters:
      - name: repo
      - name: branch
    container:
      image: alpine/git:latest
      command: ["/bin/sh", "-c"]
      args:
      - |
        git clone https://github.com/{{inputs.parameters.repo}}.git /workspace/source
        cd /workspace/source
        git checkout {{inputs.parameters.branch}}
      volumeMounts:
      - name: workspace
        mountPath: /workspace

  - name: docker-build
    inputs:
      parameters:
      - name: image
      - name: tag
    container:
      image: docker:dind
      command: ["/bin/sh", "-c"]
      args:
      - |
        cd /workspace/source
        docker build -t {{inputs.parameters.image}}:{{inputs.parameters.tag}} .
        docker save {{inputs.parameters.image}}:{{inputs.parameters.tag}} > /workspace/image.tar
      volumeMounts:
      - name: workspace
        mountPath: /workspace
      env:
      - name: DOCKER_HOST
        value: tcp://localhost:2375
    sidecars:
    - name: docker
      image: docker:dind
      securityContext:
        privileged: true
      mirrorVolumeMounts: true

  - name: run-tests
    inputs:
      parameters:
      - name: test-type
    container:
      image: node:18
      command: ["/bin/sh", "-c"]
      args:
      - |
        cd /workspace/source
        npm ci
        npm run test:{{inputs.parameters.test-type}}
      volumeMounts:
      - name: workspace
        mountPath: /workspace

  - name: run-lint
    container:
      image: node:18
      command: ["/bin/sh", "-c"]
      args:
      - |
        cd /workspace/source
        npm ci
        npm run lint
      volumeMounts:
      - name: workspace
        mountPath: /workspace

  - name: trivy-scan
    inputs:
      parameters:
      - name: image
    container:
      image: aquasec/trivy:latest
      command: ["/bin/sh", "-c"]
      args:
      - |
        trivy image --input /workspace/image.tar --severity HIGH,CRITICAL --exit-code 1
      volumeMounts:
      - name: workspace
        mountPath: /workspace

  - name: docker-push
    inputs:
      parameters:
      - name: image
      - name: tag
    container:
      image: docker:latest
      command: ["/bin/sh", "-c"]
      args:
      - |
        docker load < /workspace/image.tar
        echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
        docker push {{inputs.parameters.image}}:{{inputs.parameters.tag}}
      volumeMounts:
      - name: workspace
        mountPath: /workspace
      env:
      - name: DOCKER_USERNAME
        valueFrom:
          secretKeyRef:
            name: docker-credentials
            key: username
      - name: DOCKER_PASSWORD
        valueFrom:
          secretKeyRef:
            name: docker-credentials
            key: password

  - name: update-gitops
    inputs:
      parameters:
      - name: image
    container:
      image: alpine/git:latest
      command: ["/bin/sh", "-c"]
      args:
      - |
        # Clone config repository
        git clone https://$GIT_TOKEN@github.com/myorg/gitops-config.git /tmp/config
        cd /tmp/config

        # Update image tag
        sed -i "s|image:.*|image: {{inputs.parameters.image}}|g" apps/myapp/deployment.yaml

        # Commit changes
        git config user.email "ci@example.com"
        git config user.name "CI Bot"
        git add .
        git commit -m "Update image to {{inputs.parameters.image}}"
        git push
      env:
      - name: GIT_TOKEN
        valueFrom:
          secretKeyRef:
            name: github-access
            key: token

8.3.3 CI Sensor

# ci-sensor.yaml
apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
  name: ci-sensor
  namespace: argo-events
spec:
  template:
    serviceAccountName: argo-events-sa
  dependencies:
  - name: github-push
    eventSourceName: github
    eventName: app-repo
    filters:
      data:
      - path: body.ref
        type: string
        value:
        - refs/heads/main
        - refs/heads/develop
      - path: headers.X-GitHub-Event
        type: string
        value:
        - push
  triggers:
  - template:
      name: trigger-ci
      argoWorkflow:
        operation: submit
        source:
          resource:
            apiVersion: argoproj.io/v1alpha1
            kind: Workflow
            metadata:
              generateName: ci-
              namespace: argo
            spec:
              workflowTemplateRef:
                name: ci-pipeline
              arguments:
                parameters:
                - name: repo
                - name: branch
                - name: commit
        parameters:
        - src:
            dependencyName: github-push
            dataKey: body.repository.full_name
          dest: spec.arguments.parameters.0.value
        - src:
            dependencyName: github-push
            dataTemplate: "{{ .Input.body.ref | replace \"refs/heads/\" \"\" }}"
          dest: spec.arguments.parameters.1.value
        - src:
            dependencyName: github-push
            dataKey: body.after
          dest: spec.arguments.parameters.2.value

8.4 CD Configuration

8.4.1 Argo CD Application

# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
  namespace: argo
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/gitops-config.git
    targetRevision: HEAD
    path: apps/myapp
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
    - ApplyOutOfSyncOnly=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

8.4.2 GitOps Configuration Repository Structure

gitops-config/
├── apps/
│   └── myapp/
│       ├── kustomization.yaml
│       ├── deployment.yaml
│       ├── service.yaml
│       ├── rollout.yaml
│       └── analysis-template.yaml
├── base/
│   ├── namespace.yaml
│   └── secrets.yaml
└── overlays/
    ├── development/
    │   └── kustomization.yaml
    ├── staging/
    │   └── kustomization.yaml
    └── production/
        └── kustomization.yaml

8.4.3 Rollout Configuration

# apps/myapp/rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: myapp
  namespace: production
spec:
  replicas: 10
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: app
        image: docker.io/myorg/myapp:latest
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 512Mi
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 10
  strategy:
    canary:
      canaryService: myapp-canary
      stableService: myapp-stable
      trafficRouting:
        nginx:
          stableIngress: myapp-ingress
      analysis:
        templates:
        - templateName: success-rate
        startingStep: 2
        args:
        - name: service-name
          value: myapp-canary
      steps:
      - setWeight: 5
      - pause: {duration: 1m}
      - setWeight: 20
      - pause: {duration: 2m}
      - setWeight: 50
      - pause: {duration: 5m}
      - setWeight: 80
      - pause: {duration: 5m}
---
apiVersion: v1
kind: Service
metadata:
  name: myapp-stable
  namespace: production
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: myapp-canary
  namespace: production
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  namespace: production
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-stable
            port:
              number: 80

8.4.4 Analysis Template

# apps/myapp/analysis-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
  namespace: production
spec:
  args:
  - name: service-name
  metrics:
  - name: success-rate
    interval: 30s
    count: 10
    successCondition: result[0] >= 0.95
    failureCondition: result[0] < 0.90
    failureLimit: 3
    provider:
      prometheus:
        address: http://prometheus.monitoring:9090
        query: |
          sum(rate(http_requests_total{
            service="{{args.service-name}}",
            status=~"2.."
          }[2m])) /
          sum(rate(http_requests_total{
            service="{{args.service-name}}"
          }[2m]))
  - name: latency-p95
    interval: 30s
    count: 10
    successCondition: result[0] < 200
    failureCondition: result[0] > 500
    failureLimit: 3
    provider:
      prometheus:
        address: http://prometheus.monitoring:9090
        query: |
          histogram_quantile(0.95,
            sum(rate(http_request_duration_seconds_bucket{
              service="{{args.service-name}}"
            }[2m])) by (le)
          ) * 1000

8.5 Complete Example: Microservices CI/CD

8.5.1 Microservices Architecture

🔄 正在渲染 Mermaid 图表...

8.5.2 ApplicationSet Multi-Service Deployment

# applicationset-microservices.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: microservices
  namespace: argo
spec:
  generators:
  - list:
      elements:
      - name: frontend
        path: apps/frontend
        namespace: production
      - name: api-gateway
        path: apps/api-gateway
        namespace: production
      - name: user-service
        path: apps/user-service
        namespace: production
      - name: order-service
        path: apps/order-service
        namespace: production
      - name: product-service
        path: apps/product-service
        namespace: production
  template:
    metadata:
      name: '{{name}}'
      namespace: argo
    spec:
      project: default
      source:
        repoURL: https://github.com/myorg/gitops-config.git
        targetRevision: HEAD
        path: '{{path}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{namespace}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
        - CreateNamespace=true

8.5.3 Multi-Service CI WorkflowTemplate

# multi-service-ci.yaml
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
  name: microservice-ci
  namespace: argo
spec:
  entrypoint: ci-pipeline
  arguments:
    parameters:
    - name: services
      value: '[]'
    - name: commit
  templates:
  - name: ci-pipeline
    dag:
      tasks:
      - name: detect-changes
        template: detect-changes
      - name: build-services
        dependencies: [detect-changes]
        template: build-service
        arguments:
          parameters:
          - name: service
            value: "{{item}}"
          - name: commit
            value: "{{workflow.parameters.commit}}"
        withParam: "{{tasks.detect-changes.outputs.parameters.changed-services}}"
      - name: update-manifests
        dependencies: [build-services]
        template: update-manifests
        arguments:
          parameters:
          - name: commit
            value: "{{workflow.parameters.commit}}"

  - name: detect-changes
    outputs:
      parameters:
      - name: changed-services
        valueFrom:
          path: /tmp/changed.json
    container:
      image: alpine/git:latest
      command: ["/bin/sh", "-c"]
      args:
      - |
        git clone https://github.com/myorg/microservices.git /workspace
        cd /workspace

        # Detect which services have changes
        CHANGED=$(git diff --name-only HEAD~1 | grep -E "^services/" | cut -d'/' -f2 | sort -u | jq -R . | jq -s .)
        echo $CHANGED > /tmp/changed.json

  - name: build-service
    inputs:
      parameters:
      - name: service
      - name: commit
    dag:
      tasks:
      - name: build
        template: docker-build
        arguments:
          parameters:
          - name: service
            value: "{{inputs.parameters.service}}"
          - name: commit
            value: "{{inputs.parameters.commit}}"
      - name: test
        template: run-tests
        arguments:
          parameters:
          - name: service
            value: "{{inputs.parameters.service}}"
      - name: scan
        dependencies: [build]
        template: security-scan
        arguments:
          parameters:
          - name: service
            value: "{{inputs.parameters.service}}"
          - name: commit
            value: "{{inputs.parameters.commit}}"
      - name: push
        dependencies: [build, test, scan]
        template: docker-push
        arguments:
          parameters:
          - name: service
            value: "{{inputs.parameters.service}}"
          - name: commit
            value: "{{inputs.parameters.commit}}"

  - name: docker-build
    inputs:
      parameters:
      - name: service
      - name: commit
    container:
      image: docker:dind
      command: ["/bin/sh", "-c"]
      args:
      - |
        cd /workspace/services/{{inputs.parameters.service}}
        docker build -t myorg/{{inputs.parameters.service}}:{{inputs.parameters.commit}} .

  - name: run-tests
    inputs:
      parameters:
      - name: service
    container:
      image: node:18
      command: ["/bin/sh", "-c"]
      args:
      - |
        cd /workspace/services/{{inputs.parameters.service}}
        npm ci && npm test

  - name: security-scan
    inputs:
      parameters:
      - name: service
      - name: commit
    container:
      image: aquasec/trivy:latest
      command: ["/bin/sh", "-c"]
      args:
      - |
        trivy image myorg/{{inputs.parameters.service}}:{{inputs.parameters.commit}} \
          --severity HIGH,CRITICAL --exit-code 1

  - name: docker-push
    inputs:
      parameters:
      - name: service
      - name: commit
    container:
      image: docker:latest
      command: ["/bin/sh", "-c"]
      args:
      - |
        docker push myorg/{{inputs.parameters.service}}:{{inputs.parameters.commit}}

  - name: update-manifests
    inputs:
      parameters:
      - name: commit
    container:
      image: alpine/git:latest
      command: ["/bin/sh", "-c"]
      args:
      - |
        git clone https://$GIT_TOKEN@github.com/myorg/gitops-config.git /tmp/config
        cd /tmp/config

        # Update all changed service images
        for service in $(cat /tmp/changed.json | jq -r '.[]'); do
          sed -i "s|image: myorg/$service:.*|image: myorg/$service:{{inputs.parameters.commit}}|g" \
            apps/$service/deployment.yaml
        done

        git add .
        git commit -m "Update images to {{inputs.parameters.commit}}"
        git push

8.6 Monitoring and Alerting Integration

8.6.1 Prometheus Monitoring Configuration

# prometheus-servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: argo-workflows
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: argo-workflow-controller
  endpoints:
  - port: metrics
    interval: 30s
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: argo-rollouts
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: argo-rollouts
  endpoints:
  - port: metrics
    interval: 30s

8.6.2 Alert Rules

# argo-alerts.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: argo-alerts
  namespace: monitoring
spec:
  groups:
  - name: argo-workflows
    rules:
    - alert: WorkflowFailed
      expr: |
        argo_workflows_count{status="Failed"} > 0
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "Workflow failed"
        description: "Workflow {{ $labels.name }} has failed"

    - alert: WorkflowStuck
      expr: |
        argo_workflows_count{status="Running"} > 0 and
        time() - argo_workflow_start_time > 3600
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: "Workflow stuck"
        description: "Workflow {{ $labels.name }} has been running for over 1 hour"

  - name: argo-rollouts
    rules:
    - alert: RolloutFailed
      expr: |
        kube_rollout_status_phase{phase="Failed"} == 1
      for: 1m
      labels:
        severity: critical
      annotations:
        summary: "Rollout failed"
        description: "Rollout {{ $labels.rollout }} has failed"

    - alert: RolloutDegraded
      expr: |
        kube_rollout_status_phase{phase="Degraded"} == 1
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "Rollout degraded"
        description: "Rollout {{ $labels.rollout }} is degraded"

8.6.3 Slack Notification Configuration

# notification-sensor.yaml
apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
  name: notification-sensor
  namespace: argo-events
spec:
  dependencies:
  - name: workflow-status
    eventSourceName: resource-events
    eventName: workflow
    filters:
      data:
      - path: body.status.phase
        type: string
        value:
        - Failed
        - Succeeded
  triggers:
  - template:
      name: slack-notification
      http:
        url: https://hooks.slack.com/services/xxx/yyy/zzz
        method: POST
        payload:
        - src:
            dependencyName: workflow-status
            dataTemplate: |
              {
                "attachments": [{
                  "color": "{{ if eq .Input.body.status.phase \"Succeeded\" }}good{{ else }}danger{{ end }}",
                  "title": "Workflow {{ .Input.body.status.phase }}",
                  "fields": [
                    {"title": "Name", "value": "{{ .Input.body.metadata.name }}", "short": true},
                    {"title": "Namespace", "value": "{{ .Input.body.metadata.namespace }}", "short": true},
                    {"title": "Duration", "value": "{{ .Input.body.status.duration }}", "short": true}
                  ]
                }]
              }
          dest: body

8.7 Chapter Summary

This chapter detailed how to integrate the Argo ecosystem into a complete CI/CD platform:

🔄 正在渲染 Mermaid 图表...

Key Points:

  1. Event-Driven: Use Argo Events to listen for Git events and trigger CI
  2. CI Pipeline: Use Argo Workflows to execute build, test, and security scans
  3. GitOps CD: Use Argo CD to sync Git configuration to cluster
  4. Progressive Delivery: Use Argo Rollouts for safe production releases
  5. Full Observability: Integrate Prometheus monitoring and Slack notifications

In the next chapter, we will learn about Argo security and permission management.