Canary Deployments with Argo Rollouts and Istio

A canary deployment is more complex than a blue-green deployment. It requires a service mesh to route traffic to the canary version of the application. In this example, we will use Istio.

Requirements

  • Istio

  • ArgoCD

  • Argo Rollouts

  • Prometheus (required for analysis templates)

Configuration

Create a service definition:

apiVersion: v1
kind: Service
metadata:
  name: demo-app
spec:
  selector:
    app: demo-app
  ports:
    - name: http-web
      appProtocol: http
      port: 80

Create a destination rule definition:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: demo-app-destination-rule
spec:
  host: demo-app.demo-app.svc.cluster.local
  subsets:
  - name: stable
    labels:
      app: demo-app
  - name: canary
    labels:
      app: demo-app

Create a virtual service definition with destination routing rules:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: demo-app-vs
spec:
  hosts:
  - "demo-app.ms1.com"
  gateways:
  - demo-app-gateway
  http:
  - name: primary
    route:
    - destination:
        host: demo-app.demo-app.svc.cluster.local
        subset: stable
      weight: 100
    - destination:
        host: demo-app.demo-app.svc.cluster.local
        subset: canary
      weight: 0

Create a gateway definition:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: demo-app-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http-web
      protocol: HTTP
    hosts:
    - "demo-app.ms1.com"

Create an analysis template

apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: istio-success-rate
spec:
  args:
  - name: demo-app
  - name: demo-app
  metrics:
  - name: success-rate
    initialDelay: 60s
    interval: 20s
    successCondition: result[0] > 0.90
    provider:
      prometheus:
        address: http://prometheus.istio-system:9090
        query: >+
          sum(irate(istio_requests_total{
            reporter="source",
            destination_service=~"{{args.service}}.{{args.namespace}}.svc.cluster.local",
            response_code!~"5.*"}[40s])
          )
          /
          sum(irate(istio_requests_total{
            reporter="source",
            destination_service=~"{{args.service}}.{{args.namespace}}.svc.cluster.local"}[40s])
          )

Create a rollout resource with the following configuration:

A rollout configuration encapulates a replicaset definition. No need to write both the rollout and the replicaset.

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: demo-app-canary-rollout
spec:
  strategy:
    canary:
      trafficRouting:
        istio:
          virtualService: 
            name: demo-app-vs
            routes:
              - primary
          destinationRule:
            name: demo-app-destination-rule
            canarySubsetName: canary
            stableSubsetName: stable
      steps:
        - setWeight: 10
        - pause:
            duration: 2s
        - setWeight: 30
        - pause:
            duration: 2s
        - setWeight: 50
        - pause:
            duration: 2s
      analysis:
          templates:
            - templateName: istio-success-rate
          startingStep: 1
          args:
            - name: service
              value: demo-app.demo-app.svc.cluster.local
            - name: namespace
              value: demo-app
  selector:
    matchLabels:
      app: demo-app
  template:
    metadata:
      labels:
        app: demo-app
    spec:
      serviceAccountName: demo-app
      containers:
        - name: demo-app
          image: memogarcia10/demo-app:v4
          imagePullPolicy: Always
          ports:
            - containerPort: 80
              name: http-web
          securityContext:
            runAsUser: 1000
          resources:
            limits:
              cpu: 5m
              memory: 64Mi

Last updated