ASP.NET Core on K8S in-depth learning (12) Ingress

This article has been added to the Index of.NET Core on K8S Learning Practice Series Articles , you can click to see more articles related to container technology.

I. About Ingress

Kubernetes exposes its services in three main ways: NodePort, LoadBalancer, and Ingress.The first two are in our fourth article, " Service s you must know As already described in the article, here we'll mainly look at what kind of ghost Ingress is.

Official network defines Ingress as a collection of rules between external services and services within a cluster. In general, it defines rules that allow requests to enter a cluster to be forwarded to the corresponding services in the cluster and always implements Service leaks.Ingress can configure intra-cluster services as URL s accessible by external networks, traffic load balancing, terminating SSL, providing domain name-based access virtual hosts, and so on.

We can review once again the processes we typically visit in a business:

  • User enters a domain name in the browse
  • DNS to Business Entry, generally referred to as Load Balancer, such as SLB service in Ali Cloud
  • External Load Balancer reverse proxy to K8S entry, such as Ingress
  • Ingress forwards the request to the corresponding Service
  • Service maps the request to a specific Pod

Understanding the whole process, we combined with the definition of the official network to see Ingress, you can know that Ingress is a K8S cluster business entry, a unified access entry.We can use Traefik, Istio, Nginx, HAProxy as Ingress, here we mainly introduce Nginx Ingress, because we are familiar with Nginx a little.

2. Installation and Configuration of Nginx Ingress

Here we execute the following yaml file on k8s-master to deploy Nginx Ingress via DaemonSet, which can be obtained from the github of ingress-nginx, where I choose version 0.30.0.

Get it: https://github.com/kubernetes/ingress-nginx/tree/nginx-0.30.0/deploy

In the static directory, get the mandatory.yaml file as shown in the following code, and I've made a few modifications here (note my red configuration):

(1) Change the original Deployment type to DaemonSet

(2) Increase hostNetwork: true configuration for Ingress-Controller, i.e. directly occupy host port 80/443

(3) Deploy Ingress-Controller on the Node node of ingressHost: yes label, my k8s-node1 server

(4) Change the mirror source of Ingress-Controller to Ali Cloud Mirror Warehouse: registry.cn-hangzhou.aliyuncs.com

    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: DaemonSet**
    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
            **ingressHost: ****"yes"****
          hostNetwork: true**
          containers:
            - name: nginx-ingress-controller
              image: **registry.cn-hangzhou.aliyuncs.com/google_containers/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

By the way, there are two deployments of Ingress:

(1) NodePort-based

The NodePort-based deployment idea is to introduce traffic by opening a port for NodePort on each node, then forwarding it through iptables to the ingress-controller container (nginx container in the diagram), and then forwarding it to the corresponding application web container based on the rules of ingress.

(2) HostNetwork-based approach

By contrast, the HostNetwork mode no longer needs to create an svc for a nodePort, but instead creates a container for the ingress-controller directly at each node and sets the network mode for that container to HostNetwork.This means that ports 80 and 443 of each node's physical machine will be occupied by the nginx container in the ingress-controller.When traffic enters through port 80/443, it enters nginx directly.Then nginx forwards traffic to the corresponding web application container according to ingress rules.

OK, as we know from both modes, this paper uses the host network-based method to occupy the host port 80/443 as the traffic entry.

Then we can run the Create command to create the Ingress-Controller:

    kubectl apply -f mandatory.yaml

The executed image shows a series of creation tasks such as namespace, configmap, service account, rbac, daemonset, and so on:

After the Ingress-Controller is created, let's create a rule set, ingress-nginx.yaml, that guides Ingress to route forwarding, which is configured as follows:

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: /apple(/|$)(.*)
        backend:
          serviceName: apple-api-svc
          servicePort: 80
      - path: /banana(/|$)(.*)
        backend:
          serviceName: banana-api-svc
          servicePort: 80

It actually helps Nginx generate the correct Nginx.conf and Nginx forward requests to Service entries in different K8s clusters for processing.Here, I've defined two back-end Service Services, which I'll cover later, and now we'll create them:

kubectl apply -f ingress-nginx.yaml

Now you can see if Running is available through kubectl:

Okay, so far in the Setup and Configuration section, here we can prepare the two Service s just mentioned for a simple verification.

3. Quick Verification of Nginx Ingress

3.1 Backend API Project Preparation

Here I'm going to prepare two ASP.NET Core Web API projects whose code is simple, with only one HomeController responsible for returning a json when requesting an api/home route.

Where the AppleApi project returns:

// GET api/home
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
    return new string[] { "AppleApi-Home", "v1.0", "Welcome to use AppleApi!" };
}

The BananApi project returns:

// GET api/home
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
    return new string[] { "BananaApi-Home", "v1.0", "Welcome to use BananaApi!" };
}

This part of the code file is available on my github: Click here to get.

Then, we'll make a docker image of each project and upload it to docker hub. You can use my mirror directly for this experiment. I won't show you how to package and upload the image.

Direct pull mirror: docker pull xilife/apple-api-demo:1.0 / docker pull xilife/banana-api-demo:1.0

3.2 Deployment yaml file preparation

Next, we prepare to deploy a yaml file for two API projects and apply the yaml file to create pod s and service s:

(1)deploy-appleapi-svc.yaml

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

---

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

It is important to note that the namespace (xdp-poc here), Service name (apple-api-svc here), and port (80 here) defined in the Service here are consistent with the back-end Service name and port that we set in ingress-nginx.yaml before, otherwise request forwarding will not be possible.The BananaApi below also needs to be consistent, so let's not go into it.

(2)deploy-bananaapi-svc.yaml

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

---

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

Finally, we deploy it to the K8s cluster:

kubectl apply -f deploy-appleapi-svc
kubectl apply -f deploy-bananaapi-svc

Now you can see if Running is available through kubectl:

3.3 Quick validation of Ingress

Since we set the host to portal.k8s.xi-life.cn, we can now modify the hosts file on our own clients (in the case of Windows, system32/etc/drivers/hosts) to add a record, and then we can enter the domain name through the browser to access the test:

(1)apple-api

(2)banana-api

4. Summary

This paper introduces the basic concepts of Ingress and the installation and configuration of Nginx Ingress, then quickly validates Ingress by deploying two ASP.NET Core Web API services to the K8s cluster.Of course, we can also use our own gateway to replace Ingress as an external unified traffic entry, or LoadBalancer or API gateway for cloud products to replace Ingress (without running out of money).

Reference material

(1) Beam width, " Kubernetes Practice Guide to Never Step on a Pit>

(2) Li Zhenliang, A day to get started with Kubernets tutorials>

(3) Mago (Ma Yongliang), " Quick Start for Kubernetes>

(4) Faults made by Huatian, Introduction to K8S Nginx Ingress>

(5)Lucie_xxm,<Ingress Unified Access Entry>

Tags: Web Server Nginx Kubernetes network Docker

Posted on Sun, 10 May 2020 22:39:46 -0400 by argyrism