You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 10 Next »

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 a new node to the cluster, 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

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]

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 obtain

Roles of nodes
# Note the "ROLES" column
$ kubectl get node
NAME                     STATUS   ROLES     AGE     VERSION
mycentos-0.novalocal     Ready    master    70d     v1.19.1
mycentos-1.novalocal     Ready    worker    69d     v1.19.1
mycentos-2.novalocal     Ready    worker    69d     v1.19.1
mycentos-ing.novalocal   Ready    ingress   4d19h   v1.19.1

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 start with the installation procedure. Here we will use the Nginx Ingress Controller guide as a reference. For more information, we recommend that you consult the official guide (an installation with Heml is also available on the same site).

We perform a download from GitHub of the folder containing the necessary for the installation of the input controller and, once finished, we move on to its entirety

GitHub repo
$ git clone https://github.com/nginxinc/kubernetes-ingress/
$ cd kubernetes-ingress/deployments
$ git checkout v1.8.1

Before continuing, 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 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 node

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 node between the quotes

As for the other file, let's add these lines in the specification

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.

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

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)

Ingress Controller Pod
# Note that the Pod is present on the "ingress" node and has its own 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)

Directory complete-example
$ ls
cafe-ingress.yaml  cafe-secret.yaml  cafe.yaml  dashboard.png  README.md
$ kubectl apply -f cafe.yaml

At this point we check that the Pods and the associated services have been created

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

cafe-ingress.yaml
apiVersion: extensions/v1beta1
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
        backend:
          serviceName: tea-svc      # Enter the service name
          servicePort: 80           # Enter the port number on which the service is listening
      - path: /coffee               # Use cafe.example.com/coffee to target "coffee" services
        backend:
          serviceName: coffee-svc   # Enter the service name
          servicePort: 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.

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)

/etc/hosts

131.154.97.164 cafe.example.com

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

cafe.example.com
Server address: 10.10.94.71:8080               # IP:port 
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.

Configuring TLS certificate

If you pay attention to the address bar, you will notice the message "your connection to this site is not secure". Our goal is to secure the connection. This will show itself visually with the appearance of the small padlock in the address bar. 

First, we need to get the certificate for our site (cafe.example.com), which will come in handy shortly. We then create a new Kubernetes component, called Secret. To create it we use the cafe-secret.yaml file, which we had previously set aside, replacing the keys already present with those obtained from the certificate (in the next sub-paragraph there is a little insight into this aspect).

cafe-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: cafe-secret
  namespace: nginx-ingress   # Warning! The namespace of the Secret and of the ingress resource must match
type: kubernetes.io/tls
data:
  tls.crt: <new_base64_encoded_cert>
  tls.key: <new_base64_encoded_key>

Once you have entered the two keys, we are ready to create the resource

Create Secret
$ kubectl apply -f cafe-secret.yaml
secret/cafe-secret created
$ kubectl get secret -n nginx-ingress
NAME            TYPE                  DATA   AGE
cafe-secret     kubernetes.io/tls     2      2m8s

Now we need to de-comment the lines in cafe-ingress.yaml, related to the TLS protocol, and perform a replace of the component. Returning to the browser we should note that now "the connection is protected", as evidenced by the appearance of the padlock next to the address bar.

Learn more about the tls.crt and tls.key keys

You may have noticed the particular wording "base64_encoded" inside the cafe-secret.yaml. In fact, it is necessary to insert the keys with a certain coding. We take our two keys, obtained with the certificate, and apply the following command

Convert "x509 format base64 decoded" to "x509 format base64 encoded"
$ base64 -w 0 cafe.example.com.pem
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUhDakNDQlBLZ0F3SUJBZ0lRR0J6emlZVDR0V3BpT...
$ base64 -w 0 cafe.example.com.key
LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBdjFyQzdvWVh3YU5yc...

We just have to paste the output of the .pem file into the tls.crt field and the output of the .key file into the tls.key field.

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

Unistall Ingress Controller
$ 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
  • No labels