Let's now add an important element to our cluster, in order to get closer and closer to creating an HA cluster.
What is Ingress?
In Kubernetes, an Ingress is a object that allows access to your Kubernetes services from outside the cluster. The ingress is made up of 2 parts: the kubernetes component that deals with directing external traffic to internal services is called the ingress controller, which obeys the rules present in the ingress resources. So, you configure access by creating a collection of rules, written in a file, that define which inbound connections reach which services. Without the use of the ingress, all the cluster services, to which one wishes to access from the outside, must be exposed to the internet. The advantage of the ingress consists, in fact, in exposing a single access point externally, which will take care of routing the traffic within the cluster.
Ingress installation
Prerequisites
First we added assign a new node label to the a cluster node, which will take care of routing incoming requests to the appropriate services. This node will receive requests from the internet, so it must have a FIP. So, we created a new VM (Launch and manage instances) with a low-medium flavor, as it should only act as an ingress, and joined it to cluster (Building the cluster). We then assigned to the node, through a label, the "role" of ingress with the command
| Code Block |
|---|
| language | bash |
|---|
| title | Insert label |
|---|
|
# Enter the node name and label. The optional "--overwrite" flag is used in case the value is already present
$ kubectl label node <node_name> kubernetes.io/role=<label_value> [--overwrite]
# Alternatively, you can edit the label directly in a text editor
$ kubectl edit node <node_name> |
The addition of the label will be used later, to indicate on which node to install the input controller Pod. The same operation can also be performed on the other nodes, in order to obtainassigning the role of worker
| Code Block |
|---|
| language | bash |
|---|
| title | Roles of nodes |
|---|
|
# Note the "ROLES" column
$ kubectl get node
NAME STATUS ROLES AGE VERSION
mycentos-0.novalocal Ready master 70d v1.1920.15
mycentos-1.novalocal Ready worker 69d v1.1920.15
mycentos-2.novalocal Ready worker 69d v1.1920.15
mycentos-ing3.novalocal Ready ingress 4d19h v1.1920.15 |
Ingress Controller
As said previously, you must have an Ingress controller to satisfy an Ingress. Only creating an Ingress resource has no effect. There are several input controllers, here we will use one of the most used. Let's go, therefore, on the installation guide of We will use the Nginx Ingress Controller for Kubernetes guide as a reference. For more information, we recommend that you consult the official guide (an installation with Heml is Helm is also available on the same site).
We clone a GitHub repository on the master, downloading the folder containing the necessary for the installation of the input controller. Once finished, we move inside
| Code Block |
|---|
| language | bash |
|---|
| title | GitHub repo |
|---|
|
$ git clone https://github.com/nginxinc/kubernetes-ingress/
$ cd kubernetes-ingress/deployments
$ git checkout v1.11.3 |
Before continuing with step 2 of the guide, let's stop for a moment, because we need to make some small changes to the files in the folder we just cloned from the GitHub repo. The The files in question are located here:
/kubernetes-ingress/deployments/common/nginx-config.yaml/kubernetes-ingress/deployments/deployment/nginx-ingress.yaml
In the first file you only need to add the following line, which explains the FIP of the new ingress node
| Code Block |
|---|
| language | yml |
|---|
| title | nginx-config.yaml |
|---|
|
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-config
namespace: nginx-ingress
data:
.
.
.
external-status-address: "<FIP_Node>" #----- Insert the FIP of the ingress node between the quotes |
As for the other file, let's add these lines in the specification
| Code Block |
|---|
| language | yml |
|---|
| title | nginx-ingress.yaml (1) |
|---|
|
spec:
.
.
.
spec:
hostNetwork: true #----- Thanks to this instruction the controller Pod will have the same IP as the node
nodeSelector: #----- The Pod will be created inside the node
kubernetes.io/role: ingress #----- with the role "ingress" |
and uncomment the lines, present at the end of the file, indicated below (commented by default). This last change will come in handy when we create the ingress resource component.
| Code Block |
|---|
| language | yml |
|---|
| title | nginx-ingress.yaml (2) |
|---|
|
args:
- -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
- -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret
#- -v=3 # Enables extensive logging. Useful for troubleshooting.
- -report-ingress-status #----- Uncommented
#- -external-service=nginx-ingress
#- -enable-prometheus-metrics
#- -global-configuration=$(POD_NAMESPACE)/nginx-configuration
- -enable-leader-election #----- Uncommented
#- -enable-custom-resources |
With these changes made, we can continue with the installation procedure
| Code Block |
|---|
| language | bash |
|---|
| title | Install Ingress Controller |
|---|
|
$ kubectl apply -f common/ns-and-sa.yaml
$ kubectl apply -f rbac/rbac.yaml
$ kubectl apply -f common/nginx-config.yaml
$ kubectl apply -f common/default-server-secret.yaml
$ kubectl apply -f deployment/nginx-ingress.yaml |
At the end, if all went well, we should get the input controller Pod (note that the default namespace is nginx-ingress)
| Code Block |
|---|
| language | bash |
|---|
| title | Ingress Controller Pod |
|---|
|
# Note that the Pod is present on the "ingress" node and has its own private IP
$ kubectl get pod -n nginx-ingress -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-ingress-68d7b4bfdd-mw479 1/1 Running 0 20h 192.168.100.13 mycentos-ing.novalocal |
Ingress resource
We now present the ingress resource through a complete example, present in the directory downloaded from GitHub (/kubernetes-ingress/examples/complete-example). Let's move inside the complete-example directory and run the commands (we set aside the cafe-secret.yaml file for now)
| Code Block |
|---|
| language | bash |
|---|
| title | Directory complete-example |
|---|
|
$ ls
cafe-ingress.yaml cafe-secret.yaml cafe.yaml dashboard.png README.md
$ kubectl apply -f cafe.yaml -n nginx-ingress |
At this point we check that the Pods and the associated services have been created
| Code Block |
|---|
| language | bash |
|---|
| title | Cafe Pod&Service |
|---|
|
# Two coffee pods and three tea pods have been created, as required within the "cafe.yaml" file
$ kubectl get pod -n nginx-ingress -o wide
NAME READY STATUS RESTARTS AGE IP NODE
coffee-5f56ff9788-7fv8t 1/1 Running 0 20h 10.10.231.197 mycentos-1.novalocal
coffee-5f56ff9788-l5l9h 1/1 Running 0 20h 10.10.94.70 mycentos-2.novalocal
tea-69c99ff568-68bnr 1/1 Running 0 20h 10.10.94.71 mycentos-2.novalocal
tea-69c99ff568-k457k 1/1 Running 0 20h 10.10.231.198 mycentos-1.novalocal
tea-69c99ff568-pb9wc 1/1 Running 0 20h 10.10.231.199 mycentos-1.novalocal
$ kubectl get svc -n nginx-ingress
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
coffee-svc ClusterIP 10.107.81.22 <none> 80/TCP 20h
tea-svc ClusterIP 10.110.106.241 <none> 80/TCP 20h |
Finally, we create the input resource with the usual command kubectl apply -f <file.yaml>, even if it is better to take a look at the contents of the .yaml file first.
| Info |
|---|
| title | Type of ingress resource |
|---|
|
What we present here (one host with multiple path) is only one of the 2 ways in which incoming requests can be routed to the services present in the cluster. The other modality, present in the following sub-chapter, makes use of sub-domains to manage incoming requests. |
| Code Block |
|---|
| language | yml |
|---|
| title | cafe-ingress.yaml (multiple path) |
|---|
|
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cafe-ingress
spec:
# tls: # Let's ignore
# - hosts: # and comment
# - cafe.example.com # these lines
# secretName: cafe-secret # for the moment
rules:
- host: cafe.example.com
http:
paths:
- path: /tea # Use cafe.example.com/tea to target "tea" services
pathType: Prefix
backend:
service:
name: tea-svc # Enter the service name
port:
number: 80 # Enter the port number on which the service is listening
- path: /coffee # Use cafe.example.com/coffee to target "coffee" services
pathType: Prefix
backend:
service:
name: coffee-svc # Enter the service name
port:
number: 80 # Enter the port number on which the service is listening |
We verify that the ingress resource has been created correctly. The uncommented lines of the nginx-ingress.yaml file are used to make the FIP appear in the ADDRESS column.
| Code Block |
|---|
| language | bash |
|---|
| title | Ingress resource |
|---|
|
# In the ADDRESS column there is the FIP of the ingress node
$ kubectl get ing -n nginx-ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
cafe-ingress <none> cafe.example.com 131.154.97.164 80, 443 20h |
Let's move to the browser
We prove that everything works by moving to the browser. Since the cafe.example.com site is not registered on a DNS, we have to insert a line in the /etc/hosts file of our local machine (example on Windows the full path is C:\Windows\System32\drivers\etc\hosts)
| Panel |
|---|
|
131.154.97.164 cafe.example.com # Insert FIP of the node and the host |
If we now enter cafe.example.com/tea or cafe.example.com/coffee in the address bar of our browser, we should get, respectively, a web page with the following info
| Panel |
|---|
|
Server address: 10.10.94.71:8080 # "IP:port" of the invoked pod
Server name: tea-69c99ff568-68bnr # Name of the invoked pod
Date: 23/Sep/2020:13:20:22 +0000 # Current date and time
URI: /tea
Request ID: c2c8de16a55223239bdedee5abe4a8a4 -------------------------------------------- Server address: 10.10.94.70:8080 Server name: coffee-5f56ff9788-l5l9h Date: 23/Sep/2020:13:07:09 +0000 URI: /coffee Request ID: babe3fa35d62d2dc0efa6d60a58214e3 |
These two web pages, while very simple, assure us that the addressing mechanism works correctly. Of course, if you don't enter any path (/tea or /coffee) after the host, you will get the message "404 Not Found". This happens because we have not associated any service in our ingress resource in the "homepage" of the host (i.e. the "- path: /" is not configured).
Uninstall the Ingress Controller
All the components created in this guide share the nginx-ingress namespace, so if we want to remove everything in one go, just type
| Code Block |
|---|
| language | bash |
|---|
| title | Unistall Ingress Controller |
|---|
| collapse | true |
|---|
|
$ kubectl delete namespace nginx-ingress
namespace "nginx-ingress" deleted
# Moreover, to delete the ClusterRole and ClusterRoleBinding
$ kubectl delete clusterrole nginx-ingress
clusterrole.rbac.authorization.k8s.io "nginx-ingress" deleted
$ kubectl delete clusterrolebinding nginx-ingress
clusterrolebinding.rbac.authorization.k8s.io "nginx-ingress" deleted |