Kubernetes Ingress Controller

This guide explains how to use Træfɪk as an Ingress controller in a Kubernetes cluster. If you are not familiar with Ingresses in Kubernetes you might want to read the Kubernetes user guide

The config files used in this guide can be found in the examples directory

Prerequisites

  • A working Kubernetes cluster. If you want to follow along with this guide, you should setup minikube on your machine, as it is the quickest way to get a local Kubernetes cluster setup for experimentation and development.

  • The kubectl binary should be installed on your workstation.

Deploy Træfɪk

We are going to deploy Træfɪk with a Deployment, as this will allow you to easily roll out config changes or update the image.

  1. kind: Deployment
  2. apiVersion: extensions/v1beta1
  3. metadata:
  4. name: traefik-ingress-controller
  5. namespace: kube-system
  6. labels:
  7. k8s-app: traefik-ingress-lb
  8. spec:
  9. replicas: 1
  10. selector:
  11. matchLabels:
  12. k8s-app: traefik-ingress-lb
  13. template:
  14. metadata:
  15. labels:
  16. k8s-app: traefik-ingress-lb
  17. name: traefik-ingress-lb
  18. spec:
  19. terminationGracePeriodSeconds: 60
  20. containers:
  21. - image: traefik
  22. name: traefik-ingress-lb
  23. resources:
  24. limits:
  25. cpu: 200m
  26. memory: 30Mi
  27. requests:
  28. cpu: 100m
  29. memory: 20Mi
  30. ports:
  31. - containerPort: 80
  32. hostPort: 80
  33. - containerPort: 8080
  34. args:
  35. - --web
  36. - --kubernetes

examples/k8s/traefik.yaml

notice that we binding port 80 on the Træfɪk container to port 80 on the host. With a multi node cluster we might expose Træfɪk with a NodePort or LoadBalancer service and run more than 1 replica of Træfɪk for high availability.

To deploy Træfɪk to your cluster start by submitting the deployment to the cluster with kubectl:

  1. kubectl apply -f examples/k8s/traefik.yaml

Check the deployment

Now lets check if our deployment was successful.

Start by listing the pods in the kube-system namespace:

  1. $kubectl --namespace=kube-system get pods
  2. NAME READY STATUS RESTARTS AGE
  3. kube-addon-manager-minikubevm 1/1 Running 0 4h
  4. kubernetes-dashboard-s8krj 1/1 Running 0 4h
  5. traefik-ingress-controller-678226159-eqseo 1/1 Running 0 7m

You should see that after submitting the Deployment to Kubernetes it has launched a pod, and it is now running. It might take a few moments for kubernetes to pull the Træfɪk image and start the container.

You could also check the deployment with the Kubernetes dashboard, run minikube dashboard to open it in your browser, then choose the kube-system namespace from the menu at the top right of the screen.

You should now be able to access Træfɪk on port 80 of your minikube instance.

  1. curl $(minikube ip)
  2. 404 page not found
We expect to see a 404 response here as we haven't yet given Træfɪk any configuration.

Submitting An Ingress to the cluster.

Lets start by creating a Service and an Ingress that will expose the Træfɪk Web UI.

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: traefik-web-ui
  5. namespace: kube-system
  6. spec:
  7. selector:
  8. k8s-app: traefik-ingress-lb
  9. ports:
  10. - port: 80
  11. targetPort: 8080
  12. ---
  13. apiVersion: extensions/v1beta1
  14. kind: Ingress
  15. metadata:
  16. name: traefik-web-ui
  17. namespace: kube-system
  18. spec:
  19. rules:
  20. - host: traefik-ui.local
  21. http:
  22. paths:
  23. - backend:
  24. serviceName: traefik-web-ui
  25. servicePort: 80

examples/k8s/ui.yaml

  1. kubectl apply -f examples/k8s/ui.yaml

Now lets setup an entry in our /etc/hosts file to route traefik-ui.local to our cluster.

In production you would want to set up real dns entries. You can get the ip address of your minikube instance by running minikube ip
  1. echo "$(minikube ip) traefik-ui.local" | sudo tee -a /etc/hosts

We should now be able to visit traefik-ui.local in the browser and view the Træfɪk Web UI.

Name based routing

In this example we are going to setup websites for 3 of the United Kingdoms best loved cheeses, Cheddar, Stilton and Wensleydale.

First lets start by launching the 3 pods for the cheese websites.

  1. ---
  2. kind: Deployment
  3. apiVersion: extensions/v1beta1
  4. metadata:
  5. name: stilton
  6. labels:
  7. app: cheese
  8. cheese: stilton
  9. spec:
  10. replicas: 2
  11. selector:
  12. matchLabels:
  13. app: cheese
  14. task: stilton
  15. template:
  16. metadata:
  17. labels:
  18. app: cheese
  19. task: stilton
  20. version: v0.0.1
  21. spec:
  22. containers:
  23. - name: cheese
  24. image: errm/cheese:stilton
  25. resources:
  26. requests:
  27. cpu: 100m
  28. memory: 50Mi
  29. limits:
  30. cpu: 100m
  31. memory: 50Mi
  32. ports:
  33. - containerPort: 80
  34. ---
  35. kind: Deployment
  36. apiVersion: extensions/v1beta1
  37. metadata:
  38. name: cheddar
  39. labels:
  40. app: cheese
  41. cheese: cheddar
  42. spec:
  43. replicas: 2
  44. selector:
  45. matchLabels:
  46. app: cheese
  47. task: cheddar
  48. template:
  49. metadata:
  50. labels:
  51. app: cheese
  52. task: cheddar
  53. version: v0.0.1
  54. spec:
  55. containers:
  56. - name: cheese
  57. image: errm/cheese:cheddar
  58. resources:
  59. requests:
  60. cpu: 100m
  61. memory: 50Mi
  62. limits:
  63. cpu: 100m
  64. memory: 50Mi
  65. ports:
  66. - containerPort: 80
  67. ---
  68. kind: Deployment
  69. apiVersion: extensions/v1beta1
  70. metadata:
  71. name: wensleydale
  72. labels:
  73. app: cheese
  74. cheese: wensleydale
  75. spec:
  76. replicas: 2
  77. selector:
  78. matchLabels:
  79. app: cheese
  80. task: wensleydale
  81. template:
  82. metadata:
  83. labels:
  84. app: cheese
  85. task: wensleydale
  86. version: v0.0.1
  87. spec:
  88. containers:
  89. - name: cheese
  90. image: errm/cheese:wensleydale
  91. resources:
  92. requests:
  93. cpu: 100m
  94. memory: 50Mi
  95. limits:
  96. cpu: 100m
  97. memory: 50Mi
  98. ports:
  99. - containerPort: 80

examples/k8s/cheese-deployments.yaml

  1. kubectl apply -f examples/k8s/cheese-deployments.yaml

Next we need to setup a service for each of the cheese pods.

  1. ---
  2. apiVersion: v1
  3. kind: Service
  4. metadata:
  5. name: stilton
  6. spec:
  7. ports:
  8. - name: http
  9. targetPort: 80
  10. port: 80
  11. selector:
  12. app: cheese
  13. task: stilton
  14. ---
  15. apiVersion: v1
  16. kind: Service
  17. metadata:
  18. name: cheddar
  19. spec:
  20. ports:
  21. - name: http
  22. targetPort: 80
  23. port: 80
  24. selector:
  25. app: cheese
  26. task: cheddar
  27. ---
  28. apiVersion: v1
  29. kind: Service
  30. metadata:
  31. name: wensleydale
  32. annotations:
  33. traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5"
  34. spec:
  35. ports:
  36. - name: http
  37. targetPort: 80
  38. port: 80
  39. selector:
  40. app: cheese
  41. task: wensleydale
Notice that we also set a circuit breaker expression for one of the backends by setting the traefik.backend.circuitbreaker annotation on the service.

examples/k8s/cheese-services.yaml

  1. kubectl apply -f examples/k8s/cheese-services.yaml

Now we can submit an ingress for the cheese websites.

  1. apiVersion: extensions/v1beta1
  2. kind: Ingress
  3. metadata:
  4. name: cheese
  5. spec:
  6. rules:
  7. - host: stilton.local
  8. http:
  9. paths:
  10. - path: /
  11. backend:
  12. serviceName: stilton
  13. servicePort: http
  14. - host: cheddar.local
  15. http:
  16. paths:
  17. - path: /
  18. backend:
  19. serviceName: cheddar
  20. servicePort: http
  21. - host: wensleydale.local
  22. http:
  23. paths:
  24. - path: /
  25. backend:
  26. serviceName: wensleydale
  27. servicePort: http

examples/k8s/cheese-ingress.yaml

Notice that we list each hostname, and add a backend service.
  1. kubectl apply -f examples/k8s/cheese-ingress.yaml

Now visit the Træfɪk dashboard and you should see a frontend for each host. Along with a backend listing for each service with a Server set up for each pod.

If you edit your /etc/hosts again you should be able to access the cheese websites in your browser.

  1. echo "$(minikube ip) stilton.local cheddar.local wensleydale.local" | sudo tee -a /etc/hosts

Path based routing

Now lets suppose that our fictional client has decided that while they are super happy about our cheesy web design, when they asked for 3 websites they had not really bargained on having to buy 3 domain names.

No problem, we say, why don't we reconfigure the sites to host all 3 under one domain.

  1. apiVersion: extensions/v1beta1
  2. kind: Ingress
  3. metadata:
  4. name: cheeses
  5. annotations:
  6. traefik.frontend.rule.type: pathprefixstrip
  7. spec:
  8. rules:
  9. - host: cheeses.local
  10. http:
  11. paths:
  12. - path: /stilton
  13. backend:
  14. serviceName: stilton
  15. servicePort: http
  16. - path: /cheddar
  17. backend:
  18. serviceName: cheddar
  19. servicePort: http
  20. - path: /wensleydale
  21. backend:
  22. serviceName: wensleydale
  23. servicePort: http

examples/k8s/cheeses-ingress.yaml

Notice that we are configuring Træfɪk to strip the prefix from the url path with the traefik.frontend.rule.type annotation so that we can use the containers from the previous example without modification.
  1. kubectl apply -f examples/k8s/cheeses-ingress.yaml
  1. echo "$(minikube ip) cheeses.local" | sudo tee -a /etc/hosts

You should now be able to visit the websites in your browser.