Make your Kubernetes services accessible outside the cluster using DNS names and well-known ports

This guide is about how to set up a basic web application called echoheaders in our Kubernetes cluster and making it accessible to the outside world by a DNS address on the well known http/80 port.

 Fig. 1: Ingress example setup

Ingress rules will help us make this possible, but to make them work we will need an ingress controller to handle the requests and manage the rules.

 Fig. 2: Ingress request handling

Working with ingress rules will help you make services available to other clients outside your Kubernetes cluster.

Prerequisites

  • Working Kubernetes Cluster
  • DNS Cluster Services

This guide is based on my All in One Kubernetes Cluster with kubeadm which will need an additional RBAC policy. From this policy you will have to use following resources in your setup:

  • namespace
    • nginx-ingress
  • serviceaccount
    • nginx-ingress-serviceaccount

user@computer$ kubectl create -f https://raw.githubusercontent.com/nevetS/ingress/master/examples/rbac/nginx/nginx-ingress-controller-rbac.yml

As RBAC isn’t our focus in this guide, we won’t dive deeper into RBAC policies.

Step 1 – Setup Ingress Capabilities

We begin by enabling our Kubernetes cluster to handle ingress rules.

 Fig. 3: Ingress Controller and http Default Backend

We set up the service which makes our ingress controller available outside the Kubernetes cluster. In our case to be able to use well-known ports like http/80 we will make use of the externalIPs directive.

nginx-ingress-service.yml
apiVersion: v1
kind: Service
metadata:
name: nginx-ingress
namespace: nginx-ingress
spec:
externalIPs:
– 192.168.0.217
ports:
– port: 80
name: http
selector:
k8s-app: nginx-ingress-lb

user@computer$ kubectl create -f nginx-ingress-service.yml

Next let’s create the ingress controller which will handle all incoming request from this service and manage the corresponding ingress rules. We tell the controller to use the service default-http-backend in the name space nginx-ingress-controller to use as the default route when the request doesn’t match with an ingress rule.

nginx-ingress-deployment.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: nginx-ingress
spec:
replicas: 2
template:
metadata:
labels:
k8s-app: nginx-ingress-lb
spec:
serviceAccountName: nginx-ingress-serviceaccount
containers:
– name: nginx-ingress-controller
image: gcr.io/google_containers/nginx-ingress-controller:0.8.3
args:
– /nginx-ingress-controller
– –default-backend-service=nginx-ingress/default-http-backend
env:
– name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
– name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
– containerPort: 80

user@computer$ kubectl create -f nginx-ingress-deployment.yml

Next step is to set up our missing default http backend so that our ingress controller can redirect non-matching requests to the service.

default-backend.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: default-http-backend
labels:
k8s-app: default-http-backend
namespace: nginx-ingress
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: default-http-backend
spec:
terminationGracePeriodSeconds: 60
containers:
– name: default-http-backend
image: gcr.io/google_containers/defaultbackend:1.3
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
ports:
– containerPort: 8080
resources:
limits:
cpu: 10m
memory: 20Mi
requests:
cpu: 10m
memory: 20Mi

apiVersion: v1
kind: Service
metadata:
name: default-http-backend
namespace: nginx-ingress
labels:
k8s-app: default-http-backend
spec:
ports:
– port: 80
targetPort: 8080
selector:
k8s-app: default-http-backend

user@computer$ kubectl create -f default-backend.yaml

We made our Kubernetes cluster ready for handling and managing external http traffic by setting up the core components ingress service, ingress controller pod and the default http backend service and pod. Now we are ready to work with ingress rules.

Step 2 – Add Ingress Rules And Set Up Basic Application

We now will need to tell the ingress controller what to do with the incoming requests. That’s where ingress rules come into play.

 Fig. 4: Ingress rule pointing to echoheaders deployment

We first set up an ingress rule that will redirect http traffic to the destination host echoheaders.powerodit.ch to the service echoheaders-x.

ingress-echoheader.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echoheader
spec:
rules:
– host: echoheader.powerodit.ch
http:
paths:
– path: /
backend:
serviceName: echoheaders-x
servicePort: 80

$kubectl create -f ingress-echoheader.yaml

Now we need the corresponding service and pod with the web application to be reached by this ingress rule. We will make use of echoheaders app which shows us basic request information to the pod.

deployment-echo-header.yaml
apiVersion: extensions/v1beta1
apiVersion: v1
kind: Service
metadata:
name: echoheaders-x
labels:
app: echoheaders-x
spec:
ports:
– port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: echoheaders

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: echoheaders
spec:
replicas: 1
template:
metadata:
labels:
app: echoheaders
spec:
containers:
– name: echoheaders
image: gcr.io/google_containers/echoserver:1.8
ports:
– containerPort: 8080

user@computer$ kubectl create -f deployment-echo-header.yaml

Great we set up our ingress rule to redirect http traffic to our deployed echoheaders application. Now let’s see if it all works

Step 3 – Test Ingress Setup

For our setup you will need to adjust your hosts file to point the subdomain echoheader.powerodit.ch to your all in one kubeadm clusters external IP.

In my case this is

/etc/hosts
192.168.0.217         echoheader.powerodit.ch

Now let’s open our browser and call the subdomain we just configured. You should see a page with plain text information about our request.

 Fig. 5: Echoheaders response

But wait, there is more. Remember our default http backend when no request is matched! Let’s just request a web page with the IP address of your all in one kubeadm cluster and we get the default http backend answering, as the request didn’t match any ingress rule inside our cluster.

 Fig. 6: Http default backend response

Our basic tests to see if our ingress setup is working were successful.

Conclusion

We have successfully set up a basic ingress controller which handles requests and manages ingress rules and implemented a basic ingress rule example.

From here on you could also try setting up our basic WordPress example from Kubernetes Patterns: Stateful Applications.