ASP.NET Core on k8s in-depth learning (14) Ingress gray Publishing

This article has been added< . NET Core on K8S learning practice series index >, you can click to see more articles about containerization technology.

Previous article This paper introduces the basic concept of Ingress and the basic configuration and use of Nginx Ingress. In this paper, we continue to use Ingress to see how to use Ingress to achieve gray-scale publishing (Canary Publishing).

1, Preparations

1.1 WebAPI project preparation

First of all, we have two versions ASP.NET Core webapi project, specific project code See here.

The difference between them is that an interface returns JSON data. For example, Version: 1.0 is returned in V1.0, while Version: 1.1 is returned in V1.1.

    [Route("api/[controller]")]
    [ApiController]
    public class HomeController : ControllerBase
    {
        // GET api/home
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] {
                "Hello, welcome to EDC's demo. Version: 1.0"
            };
        }
    }

The operation result is:

(2) Image each version of the project according to the Dockerfile, which is xilife / Canary API- demo:1.0 ,1.1.

(3) push the local image to the remote image warehouse, where I transfer it to a public warehouse of docker hub:

docker push xilife/canary-api-demo:1.0
docker push xilife/canary-api-demo:1.1

1.2 web API project deployment

Secondly, we will deploy these two WebAPI projects to K8s cluster, or deploy them as services through familiar yaml files:

(1) Version V1.0 (assuming online version)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: canary-api-demo
  namespace: xdp-poc
  labels:
    name: canary-api-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      name: canary-api-demo
  template:
    metadata:
      labels:
        name: canary-api-demo
    spec:
      containers:
      - name: canary-api-demo
        image: xilife/canary-api-demo:1.0
        ports:
        - containerPort: 80
        imagePullPolicy: IfNotPresent

---

kind: Service
apiVersion: v1
metadata:
  name: canary-api-svc
  namespace: xdp-poc
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
  selector:
    name: canary-api-demo

(2) V1.1 Version (assuming grayscale version)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: canary-api-demo-gray
  namespace: xdp-poc
  labels:
    name: canary-api-demo-gray
spec:
  replicas: 2
  selector:
    matchLabels:
      name: canary-api-demo-gray
  template:
    metadata:
      labels:
        name: canary-api-demo-gray
    spec:
      containers:
      - name: canary-api-demo-gray
        image: xilife/canary-api-demo:1.1
        ports:
        - containerPort: 80
        imagePullPolicy: IfNotPresent

---

kind: Service
apiVersion: v1
metadata:
  name: canary-api-svc-gray
  namespace: xdp-poc
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
  selector:
    name: canary-api-demo-gray

Deploy these two applications to K8s cluster:

kubectl apply -f deploy-canary-api-svc.yml
kubectl apply -f deploy-canary-api-gray-svc.yml

2, Ingress gray publishing application

Ingress nginx supports the configuration of Ingress Annotations to realize gray-scale publishing and testing in different scenarios, which can meet the business scenarios such as Canary publishing, blue-green deployment and A/B testing.

So we prepare two versions of Ingress's yml file, which provides two ways:

One is traffic segmentation based on user's request, which specifically includes two ways: Request Header based traffic segmentation and Cookie based traffic segmentation, as shown in the following figure:

The second is traffic segmentation based on service weight, as shown in the following figure:

2.1 traffic segmentation based on Request Header

According to the traffic segmentation method of Request Header, it is applicable to gray level release and A/B test. When the Request Header is set to always, the request will be sent all the way to the Canary version; when the Request Header is set to never, the request will not be sent to the Canary entry; for any other Header value, the Header will be ignored, and the request will be compared with other Canary rules by priority.

Prepare an Ingress for version 1.0, and let it work first:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress
  namespace: xdp-poc
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /api/$2
spec:
  rules:
  - host: portal.k8s.xi-life.cn
    http:
      paths:
      - path: /api(/|$)(.*)
        backend:
          serviceName: canary-api-svc
          servicePort: 80

Apply to K8s cluster:

kubectl apply -f ingress-nginx.yaml

Then prepare an Ingress for version 1.1 to gradually replace the traffic access of the original v1 version as the entry of the gray version:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress-gray
  namespace: xdp-poc
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /api/$2
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "canary"
    nginx.ingress.kubernetes.io/canary-by-header-value: "true"
spec:
  rules:
  - host: portal.k8s.xi-life.cn
    http:
      paths:
      - path: /api(/|$)(.*)
        backend:
          serviceName: canary-api-svc-gray
          servicePort: 80

Apply to K8s cluster:

kubectl apply -f ingress-nginx.yaml

Quick verification:

2.2 Cookie based traffic segmentation

According to the protocol of Cookie based traffic segmentation, when the Cookie value is set to always, it will be routed to the Canary entry; when the Cookie value is set to never, the request will not be sent to the Canary entry; for any other value, the Cookie will be ignored and the request will be compared with other Canary rules for priority.

Prepare Ingress for grayscale version:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress-gray
  namespace: xdp-poc
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/proxy-body-size: "100m"
    nginx.ingress.kubernetes.io/limit-rps: '10'
    nginx.ingress.kubernetes.io/rewrite-target: /api/$2
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-cookie: "xdp-v2-cookie"
spec:
  rules:
  - host: portal.k8s.xi-life.cn
    http:
      paths:
      - path: /api(/|$)(.*)
        backend:
          serviceName: canary-api-svc-gray
          servicePort: 80

Apply to K8s cluster:

kubectl apply -f ingress-nginx-gray.yaml

Quick verification:

(1) No cookies added

(2) Add a Cookie for the domain name you want to access

(3) Request verification again

2.3 traffic segmentation based on service weight

According to the protocol of traffic segmentation based on service weight, it is applicable to blue-green deployment, and the weight range is 0-100 to route the request to the service specified in Canary Ingress by percentage. A weight of 0 means that the Canary rule does not send any requests to the service at the Canary portal. A weight of 100 means that all requests will be sent to the Canary entry.

Prepare Ingress for grayscale version:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress-gray
  namespace: xdp-poc
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/proxy-body-size: "100m"
    nginx.ingress.kubernetes.io/limit-rps: '10'
    nginx.ingress.kubernetes.io/rewrite-target: /api/$2
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "50"
spec:
  rules:
  - host: portal.k8s.xi-life.cn
    http:
      paths:
      - path: /api(/|$)(.*)
        backend:
          serviceName: canary-api-svc-gray
          servicePort: 80

Apply to K8s cluster:

kubectl apply -f ingress-nginx-gray.yaml

Quick verification: Here I test directly through the browser. It should be noted that 50% of the value here is an approximate distribution value, which may not be too accurate in practice.

3, Comparison of three ways

The priority order of the three gray-scale publishing methods provided by Nginx Ingress is:

canary-by-header -> canary-by-cookie -> canary-weight

Known limitations:

(1) Ingress nginx is a Canary feature introduced in version 0.21.0, so it is recommended to ensure that the version is 0.22.0 or later (it is said that the Cookie based mode of version 0.21.0 is a bit problematic);

(2) At present, only one canary entry can be applied in each Ingress rule at most!

4, Summary

This paper introduces three kinds of gray-scale publishing (canary) methods provided by Nginx Ingress, and then introduces how to use Nginx Ingress and configure it ASP.NET Finally, we compare the priority and limitation of the three methods, hoping to help you.

In addition, I have also recorded a small 10 min + video to introduce the basic concepts of blue-green release and Canary release, video entry click here .

reference material

(1)JadePeng,<K8s gray level publishing based on Nginx Ingress>

(2) My little bowl of soup< Nginx Ingres to realize gray scale and Canary release>

(3) Beam width< K8s Practice Guide for never stepping on the pit again>

(4)WangT,<K8s blue green deployment / Canary release based on Nginx Ingress>

(5)linus.lin,<1. White, blue and green deployment, rolling deployment, gray level release, Canary release>

Tags: Web Server Nginx Kubernetes Docker JSON

Posted on Mon, 25 May 2020 00:31:16 -0700 by twizler