Services & Ingress

A Pod is not meant to be accessed publicly, instead the communication through Services and Ingresses. We will define both in this exercise, to illustrate the capabilities of both resource types.

Create a Service

Search the Kubernetes documentation for Service, you will find an exhaustive documentation of the Service resource. Within that document, find the section on Publishing Services (ServiceTypes) and read about the difference between ClusterIP and NodePort.

In a nutshell, ClusterIP is the default and is all that you need to understand if you use Kubernetes properly. However, a NodePort service is easier to understand, so we start with a NodePort example. Copy the previous simple-pod.yml example to a new file service.yml and append NodePort example.

# service.yml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
    - port: 1234
      targetPort: 80

Apply this configuration. Kubernetes will find both resources in the file and create them in the cluster.

$ kubectl apply -f service.yml
pod/nginx created
service/my-service created

The remaining challenge is to find how to access the service through the node port. You have to do two things, find the port that has been automatically been selected and find the IP of the node.

$ kubectl get services
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
my-service   NodePort    10.100.239.117   <none>        1234:32629/TCP   22m
...
$ kubectl get nodes -o wide
NAME       STATUS   ROLES           AGE    VERSION   INTERNAL-IP    EXTERNAL-IP   ...
minikube   Ready    control-plane   158m   v1.26.3   192.168.49.2   <none>        ...

From this output, you can see that the relevant IP and port of the node is 192.168.49.2:32629.

Due to the virtualization setup of Minikube, this address is not accessible from your local machine though and a tunnel is required. Minikube can help you with this, you can ask it to list all configured services and to create such a tunnel for a service.

$ minikube service list
|----------------------|------------------------------------|--------------|-----|
|      NAMESPACE       |                NAME                | TARGET PORT  | URL |
|----------------------|------------------------------------|--------------|-----|
...
| default              | my-service                         |         1234 |     |
...
|----------------------|------------------------------------|--------------|-----|
$ minikube service my-service --url
http://127.0.0.1:50461

The command is blocking, as long as it is running, you can open the URL in your browser and you will see the nginx status page. You can abort the tunneling with Ctrl+C.

If the networking setup sounds very complex and confusing, do not despair. In addition to what has been covered in the lecture, the local setup with Minikube adds one more virtualization layer around everything. You do not have to understand every networking detail, however, we strongly recommend to get at least a grasp of the basics. This will help you immensely when debugging issues later.

In a normal setup, in which your computer is in the same network as all Kubernetes nodes, no tunnel is required and you can directly access node ports.

If you are really desperate, you can use the Virtual Box driver for Minikube. This makes it possible to access nodes directly, however, the tradeoff is that you must install Virtual Box.

Create an Ingress

It is discouraged to operate services on NodePorts as this limits the flexibility of the setup. Instead, a deployment should only use internal services and expose them by making use of an Ingress. This allows to define complex routing rules, like matching services based on the domain or the path that has been used in a request. In this step, we will create such an Ingress.

Make sure that you have enable an ingress controller before (minikube addons enable ingress).

Search again in the Kubernetes docs for information about Ingress resources. You will be able to find some screenshots from the lecture in this article. The article introduces several Types of Ingress examples. We recommend you to skim the simple fanout to understand how powerful an Ingress is. For this exercise, however, we will use the example of an Ingress backed by a single Service.

We will copy this config snippet and extend our previous example. Copy your service.yml to a file called ingress.yml and append the Ingress example to the end. As a notable difference to before, we have removed the NodePort from the service, which makes it default to the ClusterIP type.

# ingress.yml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: nginx
  ports:
    - port: 1234
      targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  defaultBackend:
    service:
      name: my-service
      port:
        number: 1234

Please note that the port that is defined in the Ingress is the port of the Service. An Ingress itself does not have a port, the relevant port is determined by the Ingress Controller.

Once you have applied the ingress.yml , you can ask Minikube again for the available services. You will see that my-service is no longer accessible, the only available ports are from the Ingress.

$ minikube service list
|----------------------|------------------------------------|--------------|-----|
|      NAMESPACE       |                NAME                | TARGET PORT  | URL |
|----------------------|------------------------------------|--------------|-----|
...
| default              | my-service                         | No node port |     |
| ingress-nginx        | ingress-nginx-controller           | http/80      |     |
|                      |                                    | https/443    |     |
...
|----------------------|------------------------------------|--------------|-----|

Due to the limitations of the Minikube virtualization through the Docker network, we still need to create a tunnel to access the Ingress. You can execute minikube tunnel to open the ingress ports on localhost. As ports 80 and 443 are priviledged, you will need to give Minikube root permissions for this to work. Afterwards, you can open localhost to see the nginx status page without any node port.

To finish the exercise, delete the resources from the cluster (kubectl delete -f ingress.yml).


Last modified on Jun 27, 2023 at 21:59.