We are going to deploy two versions of the application, blue and green, and configure Istio routing so that both versions could be accessed at the same time.
Pre-requisites
We are using our Kubernetes homelab in this article. We will continue with the pii-demo application for blue/green that we had deployed some time ago with Istio mTLS.
Basic familiarity with Istio is required.
Blue/green deployment is an application release model that transfers user traffic from a previous version of a microservice to a new release, both of which are running in production, without downtime.
Source code is available on GitHub.
The Goal
To allow two versions of the pii-demo application to run simultaneously using blue/green deployment, and configure Istio routing rules to allow access to both versions based on a host header. Round robin routing should apply if no colour was specified by a user.
The following DNS names will be used:
- pii-demo.apps.hl.test – DNS of the application before blue/green, and round robin routing after. This can easily be managed at the DNS level to point to either blue or green using a CNAME, if required.
- pii-demo-blue.apps.hl.test – DNS of the blue version of the application.
- pii-demo-green.apps.hl.test – DNS of the green version of the application.
We should also configure Istio routing rules for the pod-to-pod communication within the mesh so that blue pods talk to other blue pods, and green pods talk to other green pods. For example, a blue version of the webserver should not be routed to the green version of the database to store data, and a blue webserver should not be routed to a green webserver if there was a need for such a pod-to-pod communication.
The PII Demo Application (Simple Database App)
The pii-demo application is a simple Apache/PHP/MySQL application that allows users to enter personally identifiable information (pii) and store it in a database. The application uses two containers: httpd and MySQL.
The block diagram showing Istio flow when an application request is made can be seen below. Yaml code of the application deployment can be found on GitHub.
We use a Gateway to describe a load balancer, operating at the edge of the mesh, that receives incoming HTTP connections. The specification describes a set of ports that should be exposed and the type of protocol to use, in our case 80 and HTTP, respectively (see below). A VirtualService can then be bound to a gateway to control the forwarding of traffic arriving at a particular host.
--- apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: pii-demo-gateway namespace: pii-demo spec: selector: istio: ingressgateway # use istio default ingress gateway servers: - port: number: 80 name: http protocol: HTTP hosts: - "*"
We use a VirtualService to define a set of traffic routing rules to apply when a host is addressed, in our case pii-demo.apps.hl.test. A routing rule defines matching criteria for traffic of a specific protocol (TCP, TLS or http), in our case http. If the traffic is matched, then it is sent to a named destination service (or version of it) defined in the registry, in our case httpd-server. See below.
--- apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpd-server namespace: pii-demo spec: hosts: - "pii-demo.apps.hl.test" gateways: - pii-demo-gateway http: - route: - destination: host: httpd-server port: number: 80 --- apiVersion: v1 kind: Service metadata: name: httpd-server namespace: pii-demo labels: app: httpd-server spec: selector: app: httpd-server type: NodePort ports: - port: 80 targetPort: 80 nodePort: 30080
If we were to release a new version of the application, we would have to update the deployment yaml with a new docker image version and apply it.
This is how the frontend looks like:
The PII Demo Application: Blue/Green Deployment
We are going to change the Istio configuration to allow us to do blue/green deployment. The block diagram showing Istio flow when a blue application request is made can be seen below. The same diagram would apply if a green application request was made, it would just go to a different pod.
Add a Version Label to Kubernetes Deployment Configuration
The first thing that we want to do is to separate deployments by adding a version label. Istio recommends adding an explicit app label and version label to the specification of the pods deployed using a Kubernetes Deployment. In our case the versions won’t be standard application versions such as 1.0.0, but blue/green instead. We will have two versions of the application, a blue version, and a green version. See below.
--- apiVersion: apps/v1 kind: Deployment metadata: name: httpd-server-blue namespace: pii-demo labels: app: httpd-server version: blue spec: replicas: 1 selector: matchLabels: app: httpd-server version: blue template: metadata: name: httpd-server labels: app: httpd-server version: blue spec: containers: - name: httpd-server image: lisenet/httpd-pii-demo:0.2 [... configuration omitted ...] --- apiVersion: apps/v1 kind: Deployment metadata: name: httpd-server-green namespace: pii-demo labels: app: httpd-server version: green spec: replicas: 1 selector: matchLabels: app: httpd-server version: green template: metadata: name: httpd-server labels: app: httpd-server version: green spec: containers: - name: httpd-server image: lisenet/httpd-pii-demo:0.3 [... configuration omitted ...]
Although not displayed here, the same versioning logic applies to the MySQL deployment configuration as well.
Use Named Service Ports
Istio requires named service ports. See below.
--- apiVersion: v1 kind: Service metadata: name: httpd-server namespace: pii-demo labels: app: httpd-server spec: selector: app: httpd-server type: NodePort ports: - name: http-80 # istio requires named service ports port: 80 protocol: TCP targetPort: 80 nodePort: 30080 --- apiVersion: v1 kind: Service metadata: name: mysql-server namespace: pii-demo labels: app: mysql-server spec: selector: app: mysql-server ports: - name: tcp-3306 # do not use "mysql" as a name, see https://github.com/istio/istio/issues/13484 port: 3306 protocol: TCP targetPort: 3306
Configure Istio Routing Rules for httpd
HttpMatchRequest allows us to specify a set of criterion to be met in order for the rule to be applied to the HTTP request. Then, each routing rule is further associated with one service version (blue or green) by using a DestinationRule. DestinationRule defines policies that apply to traffic intended for a service after routing has occurred.
Requests to the httpd webserver can either come from outside the Istio mesh via the Gateway, or from within the mesh when one pod communicates with another pod.
- When a request comes in to the Gateway, we want to match it based on HTTP headers.
- When a request is made from within the service mesh, we want to match it based on a sourceLabels.
When using sourceLabels, the top-level gateways field in the VirtualService definition must include the reserved gateway mesh for this field to be applicable.
A single VirtualService is used for sidecars inside the mesh as well as for one or more gateways. In order to apply the rules to both gateways and sidecars, we have to specify mesh as one of the gateway names.
--- apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpd-server namespace: pii-demo spec: # the destination hosts to which traffic is being sent to hosts: - pii-demo.apps.hl.test # cannot use "*" here since this is being combined with the mesh services - pii-demo-blue.apps.hl.test - pii-demo-green.apps.hl.test - httpd-server gateways: - mesh # applies internally as well as externally - pii-demo-gateway http: - match: - headers: host: exact: 'pii-demo-blue.apps.hl.test' gateways: - pii-demo-gateway # restricts this rule to apply only to ingress gateway - sourceLabels: version: blue # a blue httpd pod should only talk to another blue httpd pod route: - destination: host: httpd-server port: number: 80 subset: blue - match: - headers: host: exact: 'pii-demo-green.apps.hl.test' gateways: - pii-demo-gateway - sourceLabels: version: green # a green httpd pod should only talk to another green httpd pod route: - destination: host: httpd-server port: number: 80 subset: green - match: - headers: host: exact: 'pii-demo.apps.hl.test' gateways: - pii-demo-gateway route: - destination: host: httpd-server # no subset, round robin service routing applies port: number: 80 --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: httpd-server namespace: pii-demo spec: host: httpd-server subsets: - name: blue labels: version: blue - name: green labels: version: green
Configure Istio Routing Rules for MySQL
MySQL protocol uses TCP and not HTTP.
TCPRoute describes match conditions and actions for routing TCP traffic, and L4MatchAttributes describes L4 connection match attributes.
Requests to MySQL should never come from outside the service mesh, therefore the Gateway pii-demo-gateway has not been specified. See configuration below.
--- apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: mysql-server namespace: pii-demo spec: # the destination host to which traffic is being sent to hosts: - mysql-server gateways: - mesh # applies internally as well as externally tcp: - match: - sourceLabels: version: blue # a blue mysql pod should only talk to another blue mysql pod route: - destination: host: mysql-server port: number: 3306 subset: blue - match: - sourceLabels: version: green # a green mysql pod should only talk to another green mysql pod route: - destination: host: mysql-server port: number: 3306 subset: green --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: mysql-server namespace: pii-demo spec: host: mysql-server subsets: - name: blue labels: version: blue - name: green labels: version: green
Test the Blue/Green Deployment
Now that we have everything configured, we should test the application. Kiali provides an easy way to get Istio traffic data visualised in real time.
When a user makes a request to pii-demo-blue.apps.hl.test, only blue versions of pods are used.
When a request is made to pii-demo-green.apps.hl.test, only green versions of pods are used.
See the Istio workload graph below. The padlock indicates that connections are mTLS encrypted.
See the versioned application graph below.
If a user were to make a request to pii-demo.apps.hl.test, it would be routed to either blue or green version using round robin because of our configuration. As mentioned earlier, this behaviour can be changed by managing routing at the DNS level, e.g. pii-demo.apps.hl.test could be a CNAME pointing to pii-demo-blue.apps.hl.test before the deployment of the green version, and changed to point to pii-demo-green.apps.hl.test after the green version has been deployed.
References
https://istio.io/latest/docs/ops/deployment/requirements/
https://istio.io/latest/docs/reference/config/networking/virtual-service/