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 IngressKubernetes 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 IngressHere 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 Ingress3.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. SummaryThis 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>