Blue-Green Deployments with Spinnaker

From NovaOrdis Knowledge Base
Revision as of 18:52, 9 March 2022 by Ovidiu (talk | contribs)
Jump to navigation Jump to search

External

Internal

Overview

This article documents a pipeline that deploys a release in a Stage environment, waits for testing, removes the release from Stage, and deploys the same release in Prod, while preserving the previous release in Prod. The Stage and Prod are serviced by two different namespaces ('of-stage' and 'of-prod'). The application is a Helm-packaged Kubernetes application, but some of the Kubernetes resources, such as the Ingress and the Service, are created manually directly in Spinnaker, one for each namespace. Also, ReplicaSets are used instead of Deployments, because Spinnaker does not handle Deployments well.

Create the Ingresses and Services

For each namespace ('of-stage' and 'of-prod'), create an Ingress and a Service each:

of-stage

Load Balancers → Create Load Balancer Select the appropriate "account" (Kubernetes cluster)

Use the following manifest (do not forget to adjust the namespace):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: stage
  namespace: of-stage
  annotations:
    kubernetes.io/ingress.class: nginx
    ingress.beta.kubernetes.io/sni: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: 800m
    nginx.ingress.kubernetes.io/proxy-read-timeout: "200"
    nginx.ingress.kubernetes.io/upstream-hash-by: $binary_remote_addr
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
    - host: my-ingress.example.com
      http:
        paths:
          - path: /stage(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: stage
                port:
                  number: 8080
  tls:
    - hosts:
        - my-ingress.example.com
      secretName: my-secret
apiVersion: v1
kind: Service
metadata:
  name: stage
  namespace: of-stage
spec:
  type: ClusterIP
  selector:
    stage: 'true' # this label will be dynamically applied  to the workload pods during deployment by Spinnaker
  ports:
    - port: 8080
      name: http
      targetPort: 8080

of-prod

Load Balancers → Create Load Balancer Select the appropriate "account" (Kubernetes cluster)

Use the following manifest (do not forget to adjust the namespace):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: prod
  namespace: of-prod
  annotations:
    kubernetes.io/ingress.class: nginx
    ingress.beta.kubernetes.io/sni: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: 800m
    nginx.ingress.kubernetes.io/proxy-read-timeout: "200"
    nginx.ingress.kubernetes.io/upstream-hash-by: $binary_remote_addr
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
    - host: my-ingress.example.com
      http:
        paths:
          - path: /prod(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: prod
                port:
                  number: 8080
  tls:
    - hosts:
        - my-ingress.example.com
      secretName: my-secret
apiVersion: v1
kind: Service
metadata:
  name: prod
  namespace: of-prod
spec:
  type: ClusterIP
  selector:
    prod: 'true' # this label will be dynamically applied  to the workload pods during deployment by Spinnaker
  ports:
    - port: 8080
      name: http
      targetPort: 8080

Create the Pipeline

It will be a "deploy to stage → manual testing → manual judgement → deploy to prod" pipeline.

Name: "Stage - Manual Testing - Prod" (no "→" allowed in name)

Add stage → Bake (Manifest). Stage name: "Render Helm Chart". This stage will render the helm chart, apply the configuration overlay and overwrite the image tag. For more details, see:

Bake (Manifest)

Add stage → Deploy (Manifest). Stage name: "Deploy in Stage". This stage will deploy the Helm chart and associate the workload with the "stage" service. For more details, see:

Deploy (Manifest)

At this stage, we do enable Rollout Strategy Options, so we can associate the workload with the "stage" service.

Enable: "Spinnaker manages traffic based on your selected strategy" → Service(s) Namespace → Service(s): "stage" → Traffic: Send client requests to new pods → Strategy: "Highlander". ⚠️ "Highlander" rollout strategy will take care of removing previous stage releases.

  • Link to detailed explanations of what happens for each of the rollout strategies from the point of view of 1) services 2) replicasets 3) pods.
  • Understand the relationship between the replicasets and the Spinnaker cluster

Add stage → Manual Judgement. Stage name: "Wait on Stage Testing"

Add stage → Deploy (Manifest). Stage name: "Deploy in Prod". This stage will deploy the same Helm chart that was tested in Stage and associate the workload with the "prod" service. For more details, see:

Deploy (Manifest)

Enable: "Spinnaker manages traffic based on your selected strategy" → Service(s) Namespace → Service(s): "prod" → Traffic: Send client requests to new pods → Strategy: "Red/Black". ⚠️ "Red/Black" rollout strategy will preserve previous production release.

A certain number of ReplicaSets stay around, including the pods. How to manage them? They can be manually deleted from CLUSTERS → Select ReplicaSet to be deleted → ReplicaSet Actions → Delete.