百度智能云

All Product Document

          Cloud Container Engine

          Gated Launch

          This article introduces how to use the Ingress feature of Baidu AI Cloud container service, and realize the blue-green release.

          Background Information

          The gray and blue-green releases aim to create a production environment for the new version which is completely consistent with the old version. Under the premise of not impacting the old version, some traffic is switched to the new version according to certain rules. After the trial operation of the new version for a period without any problems, the total traffic of the user is migrated to the new version from the old version.

          And the A/B test is a kind of gray release mode. Some users continue to use the services of the old version, and the traffic of some users is switched to the new version. If the new version runs stably, all the users are migrated to the new version step by step.

          Ingress-Nginx Annotation Introduction

          Based on Nginx Ingress Controller, CCE realizes the project gateway, and serves as the external traffic ingress of the project and the reverse proxy of each service in the project. And Ingress-Nginx supports the configuration of Ingress Annotations to realize the gray release and test of different scenarios to satisfy the canary release, blue-green deployment and A/B test, and other business scenarios.

          The Nginx Annotations supports the following 4 Canary rules:

          • nginx.ingress.kubernetes.io/canary-by-header: The traffic segmentation based on Request Header is applicable to the gray release and A/B test. When the Request Header is set as always, the requests are delivered to the Canary version all the time; when the Request Header is set as never, the request is not sent to the Canary ingress; for any other Header values, the Header is ignored, and the requests and other canary rules are compared in priority through the priority.
          • nginx.ingress.kubernetes.io/canary-by-header-value: The value of the Request Header to be matched is used to give a notice to Ingress to route the request to the service specified in Canary Ingress. When the Request Header is set as this value, it is routed to the Canary Ingress. This rule allows the users to customize the value of the Request Header, and should be used together with the previous annotation (namely: canary-by-header).
          • nginx.ingress.kubernetes.io/canary-weight: The traffic segmentation based on the service weight is applicable to the blue-green deployment, the weigh range is within 0-100. The request is routed to the service specified in Canary Ingress in percentage. The weight of 0 means the canary rule can't send any request to the service of Canary Ingress. The weight of 100 means all requests are sent to the Canary Ingress.
          • nginx.ingress.kubernetes.io/canary-by-cookie: The traffic segmentation based on Cookie is applicable to the gray release and A/B test. It is used to give a notice to Ingress to route the request to cookie of the service specified in Canary Ingress. When the cookie value is set as always, it is routed to the Canary Ingress; when the cookie value is set as never, the request is not sent to the Canary ingress; for any other values, the cookie is ignored, and the requests and other canary rules are compared in priority.

          canary Rule priority: canary-by-header - > canary-by-cookie - > canary-weight

          Installation nginx-ingress-controller

          # yaml For the document contents, refer to the Appendix. 
          kubectl apply -f ingress-nginx.yaml 
          kubectl apply -f ingress-nginx-service.yaml 

          Deployment production task

          1.Create the production application resources

          kubectl apply -f production.yaml -n canary-demo 
          apiVersion: extensions/v1beta1 
          kind: Deployment 
          metadata: 
            name: production 
          spec: 
            replicas: 1 
            selector: 
              matchLabels: 
                app: production 
            template: 
              metadata: 
                labels: 
                  app: production 
              spec: 
                containers: 
                - name: production 
                  image: hub.baidubce.com/jpaas-public/echoserver:1.10 
                  ports: 
                  - containerPort: 8080 
                  env: 
                    - name: NODE_NAME 
                      valueFrom: 
                        fieldRef: 
                          fieldPath: spec.nodeName 
                    - name: POD_NAME 
                      valueFrom: 
                        fieldRef: 
                          fieldPath: metadata.name 
                    - name: POD_NAMESPACE 
                      valueFrom: 
                        fieldRef: 
                          fieldPath: metadata.namespace 
                    - name: POD_IP 
                      valueFrom: 
                        fieldRef: 
                          fieldPath: status.podIP 
           
          ---
           
          apiVersion: v1 
          kind: Service 
          metadata: 
            name: production 
            labels: 
              app: production 
          spec: 
            ports: 
            - port: 80 
              targetPort: 8080 
              protocol: TCP 
              name: http 
            selector: 
              app: production 

          2.Create the application route of Production version (Ingress)

          kubectl apply -f production.ingress.yaml -n canary-demo 
          apiVersion: extensions/v1beta1 
          kind: Ingress 
          metadata: 
            name: production 
            annotations: 
              kubernetes.io/ingress.class: nginx 
          spec: 
            rules: 
            - host: cce.canary.io 
              http: 
                paths: 
                - backend: 
                    serviceName: production 
                    servicePort: 80 

          3.Local machine access application:
          Binding hosts: vi /etc/hosts
          106.12.7.210 cce.canary.io
          image2020-3-9_15-7-30.png curl cce.canary.io Following access success
          image2020-3-9_15-8-44.png

          Create the Tasks of Canary Version

          1.Create the application resources of canary version

          kubectl apply -f canary.yaml -n canary-demo 
          apiVersion: extensions/v1beta1 
          kind: Deployment 
          metadata: 
            name: canary 
          spec: 
            replicas: 1 
            selector: 
              matchLabels: 
                app: canary 
            template: 
              metadata: 
                labels: 
                  app: canary 
              spec: 
                containers: 
                - name: canary 
                  image: hub.baidubce.com/jpaas-public/echoserver:1.10 
                  ports: 
                  - containerPort: 8080 
                  env: 
                    - name: NODE_NAME 
                      valueFrom: 
                        fieldRef: 
                          fieldPath: spec.nodeName 
                    - name: POD_NAME 
                      valueFrom: 
                        fieldRef: 
                          fieldPath: metadata.name 
                    - name: POD_NAMESPACE 
                      valueFrom: 
                        fieldRef: 
                          fieldPath: metadata.namespace 
                    - name: POD_IP 
                      valueFrom: 
                        fieldRef: 
                          fieldPath: status.podIP 
           
          ---
           
          apiVersion: v1 
          kind: Service 
          metadata: 
            name: canary 
            labels: 
              app: canary 
          spec: 
            ports: 
            - port: 80 
              targetPort: 8080 
              protocol: TCP 
              name: http 
            selector: 
              app: canary 

          2.Create the application route of canary version based on weight (Ingress)

          kubectl apply -f canary.ingress.yaml -n canary-demo 
          apiVersion: extensions/v1beta1 
          kind: Ingress 
          metadata: 
            name: canary 
            annotations: 
              kubernetes.io/ingress.class: nginx 
              nginx.ingress.kubernetes.io/canary: "true" 
              nginx.ingress.kubernetes.io/canary-weight: "30"
          spec: 
            rules: 
            - host: cce.canary.io 
              http: 
                paths: 
                - backend: 
                    serviceName: canary 
                    servicePort: 80 

          3.Verification of access application domain name

          for i in $(seq 1 10); do curl cce.canary.io| grep Hostname ; done 

          As shown in the figure below, some traffic flows into canary

          After the traffic segmentation of the Canary version of application based on weight (30%), the probability of accessing Canary version is close to 30%, and the traffic ratio may float in a small range. This is a normal phenomenon.
          image2020-3-9_15-23-19.png

          • ingress-nginx.yaml
          apiVersion: v1 
          kind: Namespace 
          metadata: 
            name: ingress-nginx 
            labels: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
           
          ---
           
          kind: ConfigMap 
          apiVersion: v1 
          metadata: 
            name: nginx-configuration 
            namespace: ingress-nginx 
            labels: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
           
          ---
          kind: ConfigMap 
          apiVersion: v1 
          metadata: 
            name: tcp-services 
            namespace: ingress-nginx 
            labels: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
           
          ---
          kind: ConfigMap 
          apiVersion: v1 
          metadata: 
            name: udp-services 
            namespace: ingress-nginx 
            labels: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
           
          ---
          apiVersion: v1 
          kind: ServiceAccount 
          metadata: 
            name: nginx-ingress-serviceaccount 
            namespace: ingress-nginx 
            labels: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
           
          ---
          apiVersion: rbac.authorization.k8s.io/v1beta1 
          kind: ClusterRole 
          metadata: 
            name: nginx-ingress-clusterrole 
            labels: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
          rules: 
            - apiGroups: 
                - ""
              resources: 
                - configmaps 
                - endpoints 
                - nodes 
                - pods 
                - secrets 
              verbs: 
                - list 
                - watch 
            - apiGroups: 
                - ""
              resources: 
                - nodes 
              verbs: 
                - get 
            - apiGroups: 
                - ""
              resources: 
                - services 
              verbs: 
                - get 
                - list 
                - watch 
            - apiGroups: 
                - ""
              resources: 
                - events 
              verbs: 
                - create 
                - patch 
            - apiGroups: 
                - "extensions" 
                - "networking.k8s.io"
              resources: 
                - ingresses 
              verbs: 
                - get 
                - list 
                - watch 
            - apiGroups: 
                - "extensions" 
                - "networking.k8s.io"
              resources: 
                - ingresses/status
              verbs: 
                - update 
           
          ---
          apiVersion: rbac.authorization.k8s.io/v1beta1 
          kind: Role 
          metadata: 
            name: nginx-ingress-role 
            namespace: ingress-nginx 
            labels: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
          rules: 
            - apiGroups: 
                - ""
              resources: 
                - configmaps 
                - pods 
                - secrets 
                - namespaces 
              verbs: 
                - get 
            - apiGroups: 
                - ""
              resources: 
                - configmaps 
              resourceNames: 
                # Defaults to "<election-id>-<ingress-class>" 
                # Here: "<ingress-controller-leader>-<nginx>" 
                # This has to be adapted if you change either parameter 
                # when launching the nginx-ingress-controller. 
                - "ingress-controller-leader-nginx"
              verbs: 
                - get 
                - update 
            - apiGroups: 
                - ""
              resources: 
                - configmaps 
              verbs: 
                - create 
            - apiGroups: 
                - ""
              resources: 
                - endpoints 
              verbs: 
                - get 
           
          ---
          apiVersion: rbac.authorization.k8s.io/v1beta1 
          kind: RoleBinding 
          metadata: 
            name: nginx-ingress-role-nisa-binding 
            namespace: ingress-nginx 
            labels: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
          roleRef: 
            apiGroup: rbac.authorization.k8s.io 
            kind: Role 
            name: nginx-ingress-role 
          subjects: 
            - kind: ServiceAccount 
              name: nginx-ingress-serviceaccount 
              namespace: ingress-nginx 
           
          ---
          apiVersion: rbac.authorization.k8s.io/v1beta1 
          kind: ClusterRoleBinding 
          metadata: 
            name: nginx-ingress-clusterrole-nisa-binding 
            labels: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
          roleRef: 
            apiGroup: rbac.authorization.k8s.io 
            kind: ClusterRole 
            name: nginx-ingress-clusterrole 
          subjects: 
            - kind: ServiceAccount 
              name: nginx-ingress-serviceaccount 
              namespace: ingress-nginx 
           
          ---
           
          apiVersion: apps/v1 
          kind: Deployment 
          metadata: 
            name: nginx-ingress-controller 
            namespace: ingress-nginx 
            labels: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
          spec: 
            replicas: 1 
            selector: 
              matchLabels: 
                app.kubernetes.io/name: ingress-nginx 
                app.kubernetes.io/part-of: ingress-nginx
            template: 
              metadata: 
                labels: 
                  app.kubernetes.io/name: ingress-nginx 
                  app.kubernetes.io/part-of: ingress-nginx
                annotations: 
                  prometheus.io/port: "10254" 
                  prometheus.io/scrape: "true" 
              spec: 
                # wait up to five minutes for the drain of connections 
                terminationGracePeriodSeconds: 300 
                serviceAccountName: nginx-ingress-serviceaccount 
                nodeSelector: 
                  kubernetes.io/os: linux 
                containers: 
                  - name: nginx-ingress-controller 
                    image: hub.baidubce.com/jpaas-public/nginx-ingress-controller:0.30.0 
                    args: 
                      - /nginx-ingress-controller
                      - --configmap=$(POD_NAMESPACE)/nginx-configuration 
                      - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services 
                      - --udp-services-configmap=$(POD_NAMESPACE)/udp-services 
                      - --publish-service=$(POD_NAMESPACE)/ingress-nginx 
                      - --annotations-prefix=nginx.ingress.kubernetes.io
                    securityContext: 
                      allowPrivilegeEscalation: true 
                      capabilities: 
                        drop: 
                          - ALL 
                        add: 
                          - NET_BIND_SERVICE
                      # www-data -> 101 
                      runAsUser: 101 
                    env: 
                      - name: POD_NAME 
                        valueFrom: 
                          fieldRef: 
                            fieldPath: metadata.name 
                      - name: POD_NAMESPACE 
                        valueFrom: 
                          fieldRef: 
                            fieldPath: metadata.namespace 
                    ports: 
                      - name: http 
                        containerPort: 80 
                        protocol: TCP 
                      - name: https 
                        containerPort: 443 
                        protocol: TCP 
                    livenessProbe: 
                      failureThreshold: 3 
                      httpGet: 
                        path: /healthz 
                        port: 10254 
                        scheme: HTTP 
                      initialDelaySeconds: 10 
                      periodSeconds: 10 
                      successThreshold: 1 
                      timeoutSeconds: 10 
                    readinessProbe: 
                      failureThreshold: 3 
                      httpGet: 
                        path: /healthz 
                        port: 10254 
                        scheme: HTTP 
                      periodSeconds: 10 
                      successThreshold: 1 
                      timeoutSeconds: 10 
                    lifecycle: 
                      preStop: 
                        exec: 
                          command: 
                            - /wait-shutdown
           
          ---
           
          apiVersion: v1 
          kind: LimitRange 
          metadata: 
            name: ingress-nginx 
            namespace: ingress-nginx 
            labels: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
          spec: 
            limits: 
            - min: 
                memory: 90Mi 
                cpu: 100m 
              type: Container 
          • ingress-nginx-service.yaml
          kind: Service 
          apiVersion: v1 
          metadata: 
            name: ingress-nginx 
            namespace: ingress-nginx 
            labels: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
          spec: 
            externalTrafficPolicy: Cluster 
            type: LoadBalancer 
            selector: 
              app.kubernetes.io/name: ingress-nginx 
              app.kubernetes.io/part-of: ingress-nginx
            ports: 
              - name: http 
                port: 80 
                protocol: TCP 
                targetPort: http 
              - name: https 
                port: 443 
                protocol: TCP 
                targetPort: https 
          Previous
          Create LoadBalancer Service
          Next
          Create CCE Ingress via YAML