Experimenting with Ingress Controllers on Oracle Container Engine (OKE) — Part 1

Ali Mukadam
Oracle Developers
Published in
8 min readJul 3, 2019

In a previous post, I briefly mentioned creating a Kubernetes Ingress and IngressController but did not explain much about it. In this post, I’ll briefly explain what they are and then run an experiment with 4 popular Ingress Controllers on OKE.

Ingress and Ingress controllers

You can read more about them in this excellent post or HAProxy’s but I’ll give you a summary here. A Kubernetes Ingress is essentially a set of rules that handle external requests to access services in the Kubernetes cluster.

Think of the Ingress Controller as a router but with a bit of intelligence. Whenever a request is received, it routes the request according to rules such as a hostname or a URL path or a combination of both. The Ingress Controller listens to the Kubernetes API for Ingress resources and routes these requests to the pods according to these rules. Essentially, an Ingress Controller is a system that is able to do reverse proxying.

These rules are specified in an Ingress (see this post by Jay Gorrell for a more detailed explanation.

The controller obtain the endpoints from the service specified in the Ingress in the form of POD_IP: PORT_NUMBER.

kubectl get endpoints acme-website                                                                                                                         
NAME ENDPOINTS AGE
acme-website 10.244.0.9:80,10.244.1.16:80,10.244.2.3:80 25h

Let’s look at an example.

The diagram above illustrates 4 ingress rules:

  1. Website: which uses only the hostname rule and handles http://www.acme.com/
  2. Blog: which uses the hostname and the path rules and handles http://www.acme.com/blog
  3. Support: which also uses only the hostname rule, albeit a different hostname from the website and uses http://support.acme.com
  4. Default: This is to handle requests that do not have a matching rule

There are many Ingress Controllers and in the rest of this post, we will take some of them for a spin on OKE. This is not recommending one over the other. Like every software, you need to do your own evaluation. Sometimes, you might even end up having to use more than one.

The Ingress Controllers that we will be looking at are the following:

Deploying ACME website and blog

As we will be reusing the ACME website and blog to test each controller, let’s deploy them first.

Clone this repo and apply the ACME manifests:

$ git clone https://github.com/hyder/okesamples/
$ cd okesamples
$ kubectl apply -f ingresscontrollers/acme/

Verify that they have been correctly deployed. Get the list of pods:

kubectl get pods -o namepod/acme-blog-5b6cf84489-qrjsq                                                                                                                   
pod/acme-website-69596fd678-fzzvs

Use port-forwarding to access them to test they have been deployed properly:

kubectl port-forward acme-website-69596fd678-fzzvs 80:80

You should now be able to access the website in your browser at http://localhost/

ACME website
kubectl port-forward acme-blog-5b6cf84489-qrjsq 80:80

You should now be able to access the blog in your browser at http://localhost/

Blog site

Using nginx-ingress

nginx-ingress is an Ingress Controller based on the popular NGINX web server. It is open source, maintained by the kubernetes community, rich in features and also has a helm package. More importantly, it is well documented.

Installing it is quite straightforward and we will use the helm package that available.

helm install --name acmecontroller stable/nginx-ingress \
--set controller.name=acme \
--set defaultBackend.enabled=true \
--set defaultBackend.name=acmedefaultbackend \
--set rbac.create=true

Options such as the defaultBackend.enabled and rbac.create are already enabled by default. The reason I am showing them here is to also contrast the effort of doing this manually or let helm do the hard work for you.

Verify that the LoadBalancer (by default, the controller service type is LoadBalancer which you can override if you do not want to) has been created:

kubectl get svc -o wide                                                                                                                                                            
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
acmecontroller-nginx-ingress-acme LoadBalancer 10.96.63.247 129.146.155.105 80:31166/TCP,443:31952/TCP 2m41s app=nginx-ingress,component=acme,release=acmecontroller
acmecontroller-nginx-ingress-acmebackend ClusterIP 10.96.177.110 80/TCP 2m41s app=nginx-ingress,component=acmebackend,release=acmecontrolle
r
kubernetes ClusterIP 10.96.0.1 443/TCP 3d2h

Edit the ingresscontrollers/nginx/acme-website-ingress.yaml:

spec:
rules:
# replace www.acme.com with your FQDN
- host: www.acme.com

Edit the ingresscontrollers/nginx/acme-blog-ingress.yaml:

spec:
rules:
# replace www.acme.com with your FQDN
- host: www.acme.com/blog

Create the Ingress for the website:

kubectl apply -f ingresscontrollers/nginx/acme-website-ingress.yaml

Create the Ingress for the blog:

kubectl apply -f ingresscontrollers/nginx/acme-blog-ingress.yamlingress.extensions/rewrite created

Add the DNS record for your domain as explained in the previous post and you can now access the website at http://www.acme.com/ and the blog at http://www.acme.com/blog (replace acme.com with your domain) and you should now be able to access both the website and the blog.

There are many more configuration options for the nginx controller. You can view them here.

Let’s clean up all the nginx-related deployment for now but keep all the acme deployment and services:

kubectl delete -f ingresscontrollers/nginx/
helm delete --purge acmecontroller

Using HAProxy

haproxy-ingress is another Ingress Controller based on the popular HAProxy, the well-known HTTP/TCP Load Balancer. It is also open source, rich in features and also has a helm package.

As the haproxy-ingress chart is still in the incubator repository, we need to add the incubator repo first:

helm repo add incubator https://kubernetes-charts-incubator.storage.googleapis.com/

We can now use the helm chart to install it.

helm install --name haproxycontroller incubator/haproxy-ingress \
--set controller.name=haproxycontroller \
--set defaultBackend.enabled=true \
--set defaultBackend.name=haproxydefaultbackend \
--set rbac.create=true

Edit the ingresscontrollers/haproxy/acme-website-ingress.yaml:

spec:
rules:
# replace www.acme.com with your FQDN
- host: www.acme.com

Edit the ingresscontrollers/haproxy/acme-blog-ingress-2.yaml. This time, we want to use blog.acme.com to access the blog:

spec:
rules:
# replace www.acme.com with your FQDN
- host: blog.acme.com

Create the Ingress for the website:

kubectl apply -f ingresscontrollers/haproxy/acme-website-ingress.yaml

Create the Ingress for the blog:

kubectl apply -f ingresscontrollers/haproxy/acme-blog-ingress-2.yamlingress.extensions/acme-blog-ingress created

If you wish to deploy the blog under www.acme.com/blog, you can deploy using the acme-blog-ingress.yaml instead.

kubectl apply -f ingresscontrollers/haproxy/acme-blog-ingress.yaml

Since a new OCI Load Balancer will be created when we deployed the HAProxy controller, we need to add first update the DNS ‘A’ Record for the website. Get the IP Address of the Load Balancer as described previously:

kubectl get svc -o wide                                                                                                                                                            
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
haproxycontroller-haproxy-ingress-haproxycontroller LoadBalancer 10.96.68.165 129.146.148.61 80:32398/TCP,443:30754/TCP 38s app=haproxy-ingress,component=haproxycontroller,release=haproxycontroller
haproxycontroller-haproxy-ingress-haproxydefaultbackend ClusterIP 10.96.160.78 <none> 8080/TCP 38s app=haproxy-ingress,component=haproxydefaultbackend,release=haproxycontroller

Since we are also accessing the blog with a new host (blog.acme.com instead of www.acme.com/blog), we also need to add a new ‘A’ Record in OCI DNS for the blog:

Adding subdomain record

You can use the instructions explained in the previous post to do that . Remember to click on “Publish Changes” button for the DNS changes to be effective. You can now access the website at http://www.acme.com/ and the blog at http://blog.acme.com/ (replace acme.com with your domain).

Let’s clean up all the haproxy-related deployment for now but keep all the acme deployment and services:

kubectl delete -f ingresscontrollers/haproxy/
helm delete --purge haproxycontroller

Using Traefik

Traefik is a relatively newer (than HAProxy/Nginx) HTTP reverse proxy and load balancer that can also be used as an Ingress Controller. It is also open source, has a web UI, great documentation as well a helm package in the stable repo. Create a namespace for traefik:

kubectl create ns traefik

Install the Traefik controller using traefik’s helm package:

kubectl create ns traefikhelm install stable/traefik --namespace traefik \
--name traefikcontroller --set rbac.enabled=true \
--set kubernetes.ingressClass=traefik

We will discuss Ingress Class in Part 2.

Create the ingresses as before except this time use those in the traefik directory:

kubectl create -f ingresscontrollers/traefik/

Remember to change the hostnames in the yaml files and update the DNS records for the new LoadBalancer and you can then test.

Let’s clean up before testing our last Ingress Controller:

kubectl delete -f ingresscontrollers/traefik/
helm delete — purge traefikcontroller

Contour

The last controller we will test is Contour, an ingress controller based on Envoy. Contour does not have an official helm chart (although there is an unofficial one and a PR that has been submitted for the stable repo) yet so we will do the deployment manually.

Clone the contour git repo:

git clone https://github.com/heptio/contour.git
cd contour/examples/deployment-grpc-v2
kubectl apply -f .

Contour can be deployed using either Deployment or DaemonSet. Other than describing what happens with each deployment option, Contour’s documentation doesn’t explain why or when you would use one over the other. Instead, I found this in Traefik’s documentation which also offers similar options. In this example, we will use the deployment. If you use the default yamls, contour will be deployed in the heptio-contour namespace. In order to get the IP address of the Load Balancer, you therefore have to specify the namespace when retrieving it:

kubectl get -n heptio-contour service contour -o wideNAME      TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)                      AGE   SELECTOR                                                                                          
contour LoadBalancer 10.96.168.70 129.146.214.77 80:30082/TCP,443:31043/TCP 36s app=contour

Update the DNS ‘A’ Records as before (remember to change the hostnames) and then create the Ingresses.

kubectl create -f ingresscontrollers/contour/acme-website-ingress.yaml
kubectl create -f ingresscontrollers/contour/acme-blog-ingress.yaml

The website’s ingress will work fine. However, accessing the blog with http://www.acme.com/blog will not. To achieve this with Contour, you need to use Contour’s Ingress API (IngressRoute). My first IngressRoute looked like this:

apiVersion: contour.heptio.com/v1beta1
kind: IngressRoute
metadata:
name: acme-blog-ingress
labels:
app: acme-blog
spec:
virtualhost:
fqdn: www.acme.com
routes:
- match: /blog
services:
- name: acme-blog
port: 80

This did not work either. A bit of googling and I landed on a similar blog post which recommended to add prefixRewrite. Turned out that this was also documented but a bit further down the IngressRoute page. Let’s add this:

apiVersion: contour.heptio.com/v1beta1
kind: IngressRoute
metadata:
name: acme-blog-ingress
labels:
app: acme-blog
spec:
virtualhost:
fqdn: www.acme.com
routes:
- match: /blog
prefixRewrite: "/"
services:
- name: acme-blog
port: 80

Apply the IngressRoute again and this time you will be able to access the blog.

Let’s clean up once again for Part 2 where we will look at using multiple controllers concurrently.

kubectl delete -f ingresscontrollers/contour/
kubectl delete ns heptio-contour

Conclusion

The area of Ingress Controllers is experiencing a similar level of innovation as the Kubernetes networking. You can see those on Kubernetes Ingress Controller documentation.

The purpose of this post was to test a few of these Ingress Controllers and see how they would work with OKE so you don’t feel your choices are limited. In Part 2, we’ll look at how they can be customized as well as how they can work together if such a use case arises. I hope you find this useful.

Update:

My colleague Karthik Gaekwad suggested I add this link for those who need to chose: How to choose your Ingress Controller. It’s a concise and also very comprehensive list in terms of features and can help you narrow down your choice quickly.

Addendum:

Dissecting the HAProxy Kubernetes Ingress Controller

--

--