Blog Outline:
Introduction to Ingress
1) Ingress Composition
2) How Ingress works
3) What can Ingress solve?
Configuring Ingress-nginx
1) Build registry private warehouse
2) Create a Pod for testing
2) Create tomcat services and their services
3) Ensure that the above resource objects are successfully created
4) Create Ingress-controller resource object
5) Create Ingress Resource Object
6) Create a service resource object for the Ingress-controller resource object
7) Create virtual host-based Ingress rules
Configuring HTTPS
Introduction to Ingress
In Kubernetes, the IP addresses of services and Pod s are used only within the internal network of the cluster and are not visible to cluster applications.
To enable external applications to access services within a cluster, the following options are currently available in Kubernetes:
1)NodePort
2)LoadBalancer
3)Ingress
1) Ingress Composition
Ingress is a reverse proxy rule that specifies which Service an HTTP/S request should be forwarded to, such as dropping a request on a different Service based on different Host and url paths in the request;
Ingress Controller is a reverse proxy program that resolves the reverse proxy rules of Ingress. If there are changes in Ingress, all Ingress Controllers update their own forwarding rules in time. When Ingress Controller receives a request, it forwards the request to the corresponding Service according to these rules.
2) How Ingress works
1) Ingress controllers dynamically perceive changes in Ingress rules in a cluster by interacting with the Kubernetes api;
2) Then read it and, according to the custom rule, specify which domain name corresponds to which service and generate a nginx configuration;
3) Write to the pod of the nginx-ingress-controller, which runs a Nginx service in the pod of the Ingress controller, and the controller writes the resulting nginx configuration to the/etc/nginx.conf file;
4) Then reload it to make the configuration work.In order to achieve the domain name configuration and dynamic update issues;
3) What can Ingress solve?
1) Dynamic configuration of services
Traditionally, when a new service is added, we may need to deploy a reverse proxy server at the traffic entry to point to our new K8s service. If Ingress is used, we only need to configure this service. When the service starts, it will be automatically registered with Ingress without additional operations.
2) Reduce unnecessary port mappings
It is clear that the first step to configure k8s is to turn off the firewall, mainly because many services of k8s are mapped out in NodePort mode, which is equivalent to making holes in the host machine, neither secure nor elegant.
Configuring Ingress-nginx
1) Build registry private warehouse
Private warehouses are built only for faster mirroring and can be skipped if the network is stable!
[root@master ~]# docker run -itd --name registry --restart=always -p 5000:5000 -v /registry:/var/lib/registry registry:2 #Build registry private warehouse [root@master ~]# vim /usr/lib/systemd/system/docker.service #Modify the docker configuration file to point to the private repository ExecStart=/usr/bin/dockerd --insecure-registry 192.168.1.4:5000 [root@master ~]# scp /usr/lib/systemd/system/docker.service root@node01:/usr/lib/systemd/system/ [root@master ~]# scp /usr/lib/systemd/system/docker.service root@node02:/usr/lib/systemd/system/ #Send the modified configuration file to each node in the Kubernetes cluster [root@master ~]# systemctl daemon-reload [root@master ~]# systemctl restart docker #All nodes need to restart the service [root@master ~]# docker pull httpd [root@master ~]# docker pull tomcat:8.5.45 [root@master ~]# docker tag httpd:latest 192.168.1.4:5000/httpd:v1 [root@master ~]# docker tag tomcat:8.5.45 192.168.1.4:5000/tomcat:v1 [root@master ~]# docker push 192.168.1.4:5000/httpd:v1 [root@master ~]# docker push 192.168.1.4:5000/tomcat:v1 #Download the used image and upload it to the private repository
2) Create a Pod for testing
1) Create httpd services and their services
[root@master ~]# vim httpd01.yaml apiVersion: v1 kind: Namespace metadata: name: test-ns #Create namespace test-ns --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: httpd01 namespace: test-ns spec: replicas: 2 template: metadata: labels: app: httpd-01 spec: containers: - name: httpd image: 192.168.1.4:5000/httpd:v1 #Create Deployment resources using a mirror of httpd with two copies labeled httpd-01 --- apiVersion: v1 kind: Service metadata: name: httpd-svc namespace: test-ns spec: selector: app: httpd-01 ports: - protocol: TCP port: 80 targetPort: 80 #Create a service resource object to associate with how Deployment resources use labels [root@master ~]# kubectl apply -f httpd01.yaml
2) Create tomcat services and their services
[root@master ~]# vim tomcat01.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: tomcat01 namespace: test-ns spec: replicas: 2 template: metadata: labels: app: tomcat-01 spec: containers: - name: tomcat image: 192.168.1.4:5000/tomcat:v1 #Create Deployment resources using tomcat's mirror with two copies labeled tomcat-01 --- apiVersion: v1 kind: Service metadata: name: tomcat-svc namespace: test-ns spec: selector: app: tomcat-01 ports: - protocol: TCP port: 8080 targetPort: 8080 #Create a service resource object to associate with how Deployment resources use labels [root@master ~]# kubectl apply -f tomcat01.yaml
3) Ensure that the above resource objects are successfully created
[root@master ~]# kubectl get pod -n test-ns #Ensure that the pod is working properly NAME READY STATUS RESTARTS AGE httpd01-6575d9cdcd-kjcmm 1/1 Running 0 13m httpd01-6575d9cdcd-tjkwk 1/1 Running 0 13m tomcat01-65b74df4d4-6b9vz 1/1 Running 0 11m tomcat01-65b74df4d4-wfhfz 1/1 Running 0 11m [root@master ~]# kubectl get svc -n test-ns #Ensure successful service creation NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd-svc ClusterIP 10.104.32.150 <none> 80/TCP 13m tomcat-svc ClusterIP 10.99.184.215 <none> 8080/TCP 11m [root@master ~]# curl -I 10.104.32.150 HTTP/1.1 200 OK Date: Fri, 21 Feb 2020 11:09:16 GMT Server: Apache/2.4.41 (Unix) Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT ETag: "2d-432a5e4a73a80" Accept-Ranges: bytes Content-Length: 45 Content-Type: text/html [root@master ~]# curl -I 10.99.184.215:8080 HTTP/1.1 200 Content-Type: text/html;charset=UTF-8 Transfer-Encoding: chunked Date: Fri, 21 Feb 2020 11:09:28 GMT #Access the cluster IP+ port of the SVC to make sure the back-end Pod is accessible
4) Create Ingress-controller resource object
Create mirror links for ingress-nginx resources: https://pan.baidu.com/s/1skhA3jSCH7-c-iStCXbuNQ
Extraction Code: nx6o
Get the yaml file of Ingress-nginx as follows:
[root@master ~]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.29.0/deploy/static/mandatory.yaml [root@master ~]# vim mandatory.yaml #Simple modifications to the downloaded yaml file spec: #Navigate to line 212, that is, the line hostNetwork: true #Add this line to indicate use of the host network # wait up to five minutes for the drain of connections terminationGracePeriodSeconds: 300 serviceAccountName: nginx-ingress-serviceaccount nodeSelector: Ingress: nginx ##Set the label selector for the node, specifying which node to run on containers: - name: nginx-ingress-controller image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.29.0 #The resource uses a mirror that is slowly downloaded and can be linked using the disk provided at the beginning of the steps! [root@master ~]# kubectl label nodes node01 Ingress=nginx #Label the node01 node to specify that Ingress-nginx runs on node01 [root@master ~]# kubectl get nodes node01 --show-labels #Check if the label for node01 exists [root@node01 ~]# docker load < nginx-ingress.tar #Node 01 Import Mirror (also self-downloadable) [root@master ~]# kubectl apply -f mandatory.yaml
Specific explanation about "hostNetwork: true" written in the yaml file above: If this field is added, it means that the application running in the pod can use the port of the node directly, so that other hosts on the network where the node host is located can access the application by accessing the port.(Similar to the port docker maps to the host.)
[root@master ~]# kubectl get pod -n ingress-nginx -o wide #Verify that the Ingress-nginx container is functioning properly NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-ingress-controller-577ffd8c54-zntwl 1/1 Running 0 9s 192.168.1.5 node01 <none> <none>
5) Create Ingress Resource Object
[root@master ~]# vim ingress.yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test-ingress namespace: test-ns annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - host: www.lzj.com http: paths: - path: / backend: serviceName: httpd-svc servicePort: 80 - path: /tomcat backend: serviceName: tomcat-svc servicePort: 8080 #Access the services provided by our backend httpd container through www.lzj.com; #Access the services provided by our backend Tomcat via www.lzj.com/tomcat [root@master ~]# kubectl apply -f ingress.yaml ingress.extensions/test-ingress created [root@master ~]# kubectl get ingresses. -n test-ns #Create Ingress Resource Object NAME HOSTS ADDRESS PORTS AGE test-ingress www.lzj.com 80 23s
In fact, we have achieved what we want, provided we configure DNS resolution by ourselves or modify the hosts file of the client directly.Visit the page as follows (Note: Be sure to solve the problem of domain name resolution yourself. If you do not know which IP the domain name corresponds to, skip these two diagrams and see the text explanation below):
Access httpd service (custom home page content):
Access the tomcat service:
In the access test above, although the corresponding service was accessed, one drawback is that only the node IP where the Ingress-nginx container is located can be specified when DNS resolution is performed.The IP (including master) of other nodes within the specified k8s cluster is inaccessible, and if the node goes down, the Ingress-nginx container is moved to run on other nodes (regardless of the node label, each node has that label if the default label in the yaml file of Ingress-nginx is maintained).It would then be cumbersome for us to manually change the DNS resolved IP (to change to the IP of the node where the Ingress-nginx container is located, which can be seen by the command "kubectl get pod-n ingress-nginx-o wide").
Is there a simpler way?The answer is yes, that is, we create another Service of type nodePort for the Ingress-nginx rule, so that when configuring DNS resolution, we can use www.lzj.com to bind all node nodes, including master's IP, which is flexible.
6) Create a service resource object for the Ingress-controller resource object
From the page where you just obtained the yaml file of the Ingress-controller resource object, and then the drop-down page, you can see that you can choose the yaml file that suits you based on the k8s cluster environment.If you are a K8s cluster built on the Azure cloud platform, you can just choose to copy the commands under Azure. I am your own test environment here, so choose the yaml file under Bare-metal, as shown in the figure:
There are two ways to create this Service: one is to directly copy the command of its web page to the master node, the other is to copy its link address to the terminal and download it using wget, this time using the second method, you can view the contents of the file.
[root@master ~]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.29.0/deploy/static/provider/baremetal/service-nodeport.yaml [root@master ~]# cat service-nodeport.yaml apiVersion: v1 kind: Service metadata: name: ingress-nginx namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: type: NodePort ports: - name: http port: 80 targetPort: 80 protocol: TCP - name: https port: 443 targetPort: 443 protocol: TCP selector: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- [root@master ~]# kubectl apply -f service-nodeport.yaml [root@master ~]# kubectl get svc -n ingress-nginx #View running service objects NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx NodePort 10.96.121.169 <none> 80:30487/TCP,443:31117/TCP 21s #You can see that service maps ports 80 and 443 to ports 30487 and 3111 of the node, respectively (randomly mapped, or you can modify the yaml file to specify the port)
At this point, the domain name of www.lzj.com can be bound to port 30487/31111 of any node in the cluster.
The tests are as follows (the IP for domain name resolution can be any node IP in the k8s cluster):
So far, the initial demand has been fulfilled!
7) Create virtual host-based Ingress rules
If you need to make both www.lzj.com and www.zhj.com correspond to the services run by the pod container on the back end.The following configurations should be made:
[root@master ~]# vim ingress.yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test-ingress namespace: test-ns annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - host: www.lzj.com http: paths: - path: / backend: serviceName: httpd-svc servicePort: 80 - path: /tomcat backend: serviceName: tomcat-svc servicePort: 8080 - host: www.zhj.com #Just copy the svc service corresponding to the original domain name and change the domain name! http: paths: - path: / backend: serviceName: httpd-svc servicePort: 80 - path: /tomcat backend: serviceName: tomcat-svc servicePort: 8080 [root@master ~]# kubectl apply -f ingress.yaml
Access to both www.lzj.com and www.zhj.com can now be achieved by accessing the pages provided by the backend httpd (resolving domain name resolution issues yourself), as follows:
Summary of the process for Ingress-nginx resources, as shown in the following figure:
From the diagram, you can see that there are multiple pods on the back end, and the pod is associated with the service. The service is discovered by the Ingres rule and dynamically written into the ingress-nginx-controller container. Then, a port is created for the ingress-nginx-controller that the service maps to the cluster node for access by the client.
In a real production environment, the DaemonSet resource type must be used to create Ingress Controller to ensure high availability of Ingress Controller!
Configuring HTTPS
In the above operation, ingress-nginx is used to provide a unified entry for all pods in the backend, so there is a very serious question to consider, how to configure CA certificates for our pods to achieve HTTPS access?Configure CA directly in pod?How much repetitive action does that require?Moreover, pods are always created after being killed by kubelet.Of course, there are many solutions to these problems, such as configuring CA directly in the mirror, but this requires a lot of CA certificates.
In the above series of processes, the key point is the ingress rule. We only need to configure the CA certificate for the domain name in the yaml file of ingress, as long as the domain name can be accessed through HTTPS. As to how this domain name relates to the pod that provides services on the back end, this is the communication within the k8s cluster, and even using http to communicate, it is harmless and elegant.
The configuration is as follows:
For simplicity, the following configurations perform the following configurations in the above environment:
[root@node01 ~]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc" #Create CA Certificate [root@node01 ~]# ls | grep tls #Confirmation produced the following two files tls.crt tls.key [root@master ~]# kubectl create secret tls tls-secret --key=tls.key --cert tls.crt #Create secret resource object [root@master ~]# kubectl describe secrets tls-secret #View secret resource object details Name: tls-secret Namespace: default Labels: <none> Annotations: <none> Type: kubernetes.io/tls Data ==== tls.crt: 1143 bytes tls.key: 1704 bytes [root@master ~]# vim ingress.yaml #Modify Ingresss Resource Object apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test-ingress namespace: test-ns annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: tls: #Add the following to the original - hosts: - www.lzj.com - www.zhj.com secretName: tls-secret #Fill in the domain name and the name of the certificate to use rules: - host: www.lzj.com http: paths: - path: / backend: serviceName: httpd-svc servicePort: 80 - path: /tomcat backend: serviceName: tomcat-svc servicePort: 8080 - host: www.zhj.com http: paths: - path: / backend: serviceName: httpd-svc servicePort: 80 - path: /tomcat backend: serviceName: tomcat-svc servicePort: 8080 [root@master ~]# kubectl apply -f ingress.yaml [root@master ~]# kubectl describe ingresses. test-ingress -n test-ns #View details of Ingress-nginx Name: test-ingress Namespace: test-ns Address: 10.96.121.169 Default backend: default-http-backend:80 (<none>) TLS: #Verify that the certificate is bound to the corresponding domain name tls-secret terminates www.lzj.com,www.zhj.com Rules: Host Path Backends ---- ---- -------- www.lzj.com / httpd-svc:80 (10.244.1.9:80,10.244.2.8:80) /tomcat tomcat-svc:8080 (10.244.1.10:8080,10.244.2.9:8080) www.zhj.com / httpd-svc:80 (10.244.1.9:80,10.244.2.8:80) /tomcat tomcat-svc:8080 (10.244.1.10:8080,10.244.2.9:8080)
Access Test:
_________