Ingress-nginx deployment use for Kubernetes

Keywords: Nginx Tomcat Kubernetes Docker

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:





_________

Posted by phertzog on Sat, 22 Feb 2020 09:47:47 -0800