Blue/Green Deployment on Kubernetes
Read and follow me on Medium (opens in a new tab)
Blue/Green deployment pattern
The concept of blue/green deployment involves the implementation of two identical application deployments, as depicted in the following diagram.
Source: https://cloud.google.com/architecture/application-deployment-and-testing-strategies#bluegreen_deployment_patter
Within the diagram, the color blue represents the existing version of the application, while the color green represents the new version. At any given time, only one version remains active and receives traffic. During the creation and testing phase of the green deployment, traffic continues to be directed toward the blue deployment.
Upon the successful completion of testing, the traffic is then redirected to the new version. At this point, you can retain or decommission the blue deployment for potential rollback scenarios. Alternatively, you can utilize the blue environment as a staging area for deploying a newer version of the application.
Overall, blue/green deployment offers a seamless and controlled approach to updating and releasing applications, ensuring smooth transitions and efficient management of different application versions.
Key benefits (opens in a new tab)
- Zero downtime
- Instant rollback
- Environment separation
Considerations (opens in a new tab)
- Cost and operational overhead
- Backward compatibility
- Cutover
Compare with other popular deployment patterns
Blue/Green Deployment on Kubernetes using Helm chart, Skaffold, and Istio VirtualService
To achieve this deployment approach, the crucial factor is identifying a method that allows for the flexible routing of client requests to the Blue or Green environments. In this scenario, I utilize a cookie for routing in Istio, which is established in the Istio VirtualService.
...
headers:
cookie:
regex: ^(.\*?;)?(test=true)(;.\*)?$
...
Source: https://candost.blog/images/content/posts/blue-green-deployment
In my environment, with a GKE (opens in a new tab) cluster utilizing Istio, I intend to employ a Custom Resource Definition (CRD) called VirtualService (opens in a new tab) in Istio. Further details on this strategy will be provided below. If you need to gain a better understanding of Istio, first go through the basic concepts, such as the Gateway (opens in a new tab) and VirtualService (opens in a new tab). You can see the general folder structure as follows:
go
└──services
└──example
└──blue-green-helm-deploy
├── example
│ ├── Chart.yaml
│ ├── templates
│ │ ├── example-deployment.yaml
│ │ ├── example-service.yaml
│ └── values-prod.yaml
├── manifest
│ ├── example-virtual-service-blue-test.yaml
│ ├── example-virtual-service-blue.yaml
│ ├── example-virtual-service-green-test.yaml
│ └── example-virtual-service-green.yaml
└── skaffold.yaml
To bring this idea to fruition, I utilize a Helm (opens in a new tab) chart and Skaffold (opens in a new tab) to streamline and expedite the deployment process. The example folder (Helm Chart template) is where the deployment, service, and helm values files are defined.
# example-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.service }}-{{ .Values.release }}-{{ .Values.testColor }}
namespace: {{ .Values.namespace }}
labels:
app: {{ .Values.service}}
release: {{ .Values.release }}
color: {{ .Values.testColor }}
spec:
replicas: {{ .Values.replicaCount}}
selector:
matchLabels:
app: {{ .Values.service }}
release: {{ .Values.release }}
color: {{ .Values.testColor }}
template:
metadata:
labels:
app: {{ .Values.service }}
release: {{ .Values.release }}
color: {{ .Values.testColor }}
spec:
containers:
- name: {{ .Values.service }}
image: {{ .Values.image }}
command: {{ .Values.cmd | toJson }}
livenessProbe:
httpGet:
path: /health
port: 8088
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8088
initialDelaySeconds: 10
periodSeconds: 10
ports:
- containerPort: 8088
name: http
resources:
requests:
cpu: {{ .Values.reqCpu | quote }}
memory: {{ .Values.reqMem | quote }}
limits:
cpu: {{ .Values.limCpu | quote }}
memory: {{ .Values.limMem | quote }}
# example-service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.service }}-{{ .Values.testColor }}
namespace: {{ .Values.namespace }}
labels:
app: {{ .Values.service}}
release: {{ .Values.release }}
spec:
type: NodePort
ports:
- port: 8088
name: http
selector:
app: {{ .Values.service }}
color: {{ .Values.testColor }}
# values-prod.yaml
replicaCount: 1
service: example
namespace: test
image: asia.gcr.io/your-project/example
release: prod
reqCpu: 50m
reqMem: 50Mi
limCpu: 100m
limMem: 128Mi
cmd: ['go/services/example/example',
'--default_env=PROD',
]
In addition, the manifest folder contains the definition files for the VirtualService.
# example-virtual-service-blue-test.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: example
namespace: test
spec:
hosts:
- your-domain.com
gateways:
- istio-system/default-gateway
http:
- name: example-test
match:
- uri:
prefix: /example
headers:
cookie:
regex: ^(.\*?;)?(test=true)(;.\*)?$
route:
- destination:
host: example-blue
port:
number: 8088
- name: example-default
match:
- uri:
prefix: /example
route:
- destination:
host: example-green
port:
number: 8088
# example-virtual-service-blue.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: example
namespace: test
spec:
hosts:
- your-domain.com
gateways:
- istio-system/default-gateway
http:
- name: example-default
match:
- uri:
prefix: /example
route:
- destination:
host: example-blue
port:
number: 8088
# example-virtual-service-green-test.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: example
namespace: test
spec:
hosts:
- your-domain.com
gateways:
- istio-system/default-gateway
http:
- name: example-test
match:
- uri:
prefix: /example
headers:
cookie:
regex: ^(.\*?;)?(test=true)(;.\*)?$
route:
- destination:
host: example-green
port:
number: 8088
- name: example-default
match:
- uri:
prefix: /example
route:
- destination:
host: example-blue
port:
number: 8088
# example-virtual-service-green.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: example
namespace: test
spec:
hosts:
- your-domain.com
gateways:
- istio-system/default-gateway
http:
- name: example-default
match:
- uri:
prefix: /example
route:
- destination:
host: example-green
port:
number: 8088
Lastly, I establish the skaffold.yaml file, which is utilized during the deployment process.
# skaffold.yaml
apiVersion: skaffold/v2beta24
kind: Config
profiles:
- name: prod-blue
deploy:
helm:
releases:
- name: example-blue
chartPath: go/services/example/blue-green-helm-deploy/example
valuesFiles:
- go/services/example/blue-green-helm-deploy/example/values-prod.yaml
setValueTemplates:
testColor: blue
artifactOverrides:
image: asia.gcr.io/your-project/example
imageStrategy:
fqn: {}
- name: prod-green
deploy:
helm:
releases:
- name: example-green
chartPath: go/services/example/blue-green-helm-deploy/example
valuesFiles:
- go/services/example/blue-green-helm-deploy/example/values-prod.yaml
setValueTemplates:
testColor: green
artifactOverrides:
image: asia.gcr.io/your-project/example
imageStrategy:
fqn: {}
To illustrate the step-by-step deployment of the example service using the blue/green strategy, a diagram will be provided, showcasing the progression of each stage. In the example service, I establish a GET API (/example/get) that confirms the server’s successful deployment by returning its response as “OK”.
Blue/Green deployment strategy
# Blue deployment
1.1/ skaffold run -f go/services/example/blue-green-helm-deploy/skaffold.yaml -p prod-blue --tail
1.2/ kubectl apply -f go/services/example/blue-green-helm-deploy/manifest/example-virtual-service-blue-test.yaml
1.3/ curl --cookie 'test=true' --location 'https://your-domain.com/example/get'
1.4/ kubectl apply -f go/services/example/blue-green-helm-deploy/manifest/example-virtual-service-blue.yaml
(1.5/) kubectl delete deployments/example-prod-green -n test
--
# Green deployment
2.1/ skaffold run -f blue-green-helm-deploy/skaffold.yaml -p prod-green --tail
2.2/ kubectl apply -f blue-green-helm-deploy/manifest/example-virtual-service-green-test.yaml
2.3/ curl --cookie 'test=true' --location 'https://your-domain.com/example/get'
2.4/ kubectl apply -f blue-green-helm-deploy/manifest/example-virtual-service-green.yaml
(2.5/) kubectl delete deployments/example-prod-blue -n test
You can find all the code and files from this demo in my GitHub repository:
github.com/hungngph/blue-green-deployment (opens in a new tab)
Conclusion
In this piece, we jointly explored the application of Blue/Green Deployment on Kubernetes. This approach allows developers to ensure consistent and reliable deployments, minimize downtime, and maintain high availability of applications. It also offers a mechanism to roll back to a previous application version in case of a failed deployment. The combination of Kubernetes, Helm, Skaffold, and Istio VirtualService simplifies the complexities of managing microservices and facilitates continuous development, integration, and deployment.
Reference
- https://www.itwonderlab.com/istio-patterns-traffic-splitting-in-kubernetes-header-based/ (opens in a new tab)
- https://dev.to/semaphore/continuous-blue-green-deployments-with-kubernetes-and-istio-4n75 (opens in a new tab)
- https://heretse.medium.com/blue-green-deployment-on-kubernetes-using-helm-charts-and-istio-gateway-4ccc8e5b9d21 (opens in a new tab)