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.
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: traefik-ingress-controller
namespace: kube-system
labels:
k8s-app: traefik-ingress-lb
spec:
replicas: 1
selector:
matchLabels:
k8s-app: traefik-ingress-lb
template:
metadata:
labels:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
spec:
terminationGracePeriodSeconds: 60
containers:
- image: traefik
name: traefik-ingress-lb
resources:
limits:
cpu: 200m
memory: 30Mi
requests:
cpu: 100m
memory: 20Mi
ports:
- containerPort: 80
hostPort: 80
- containerPort: 8080
args:
- --web
- --kubernetes
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
:
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:
$kubectl --namespace=kube-system get pods
NAME READY STATUS RESTARTS AGE
kube-addon-manager-minikubevm 1/1 Running 0 4h
kubernetes-dashboard-s8krj 1/1 Running 0 4h
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 thekube-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.
curl $(minikube ip)
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.
apiVersion: v1
kind: Service
metadata:
name: traefik-web-ui
namespace: kube-system
spec:
selector:
k8s-app: traefik-ingress-lb
ports:
- port: 80
targetPort: 8080
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: traefik-web-ui
namespace: kube-system
spec:
rules:
- host: traefik-ui.local
http:
paths:
- backend:
serviceName: traefik-web-ui
servicePort: 80
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
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.
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: stilton
labels:
app: cheese
cheese: stilton
spec:
replicas: 2
selector:
matchLabels:
app: cheese
task: stilton
template:
metadata:
labels:
app: cheese
task: stilton
version: v0.0.1
spec:
containers:
- name: cheese
image: errm/cheese:stilton
resources:
requests:
cpu: 100m
memory: 50Mi
limits:
cpu: 100m
memory: 50Mi
ports:
- containerPort: 80
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: cheddar
labels:
app: cheese
cheese: cheddar
spec:
replicas: 2
selector:
matchLabels:
app: cheese
task: cheddar
template:
metadata:
labels:
app: cheese
task: cheddar
version: v0.0.1
spec:
containers:
- name: cheese
image: errm/cheese:cheddar
resources:
requests:
cpu: 100m
memory: 50Mi
limits:
cpu: 100m
memory: 50Mi
ports:
- containerPort: 80
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: wensleydale
labels:
app: cheese
cheese: wensleydale
spec:
replicas: 2
selector:
matchLabels:
app: cheese
task: wensleydale
template:
metadata:
labels:
app: cheese
task: wensleydale
version: v0.0.1
spec:
containers:
- name: cheese
image: errm/cheese:wensleydale
resources:
requests:
cpu: 100m
memory: 50Mi
limits:
cpu: 100m
memory: 50Mi
ports:
- containerPort: 80
examples/k8s/cheese-deployments.yaml
kubectl apply -f examples/k8s/cheese-deployments.yaml
Next we need to setup a service for each of the cheese pods.
---
apiVersion: v1
kind: Service
metadata:
name: stilton
spec:
ports:
- name: http
targetPort: 80
port: 80
selector:
app: cheese
task: stilton
---
apiVersion: v1
kind: Service
metadata:
name: cheddar
spec:
ports:
- name: http
targetPort: 80
port: 80
selector:
app: cheese
task: cheddar
---
apiVersion: v1
kind: Service
metadata:
name: wensleydale
annotations:
traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5"
spec:
ports:
- name: http
targetPort: 80
port: 80
selector:
app: cheese
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
kubectl apply -f examples/k8s/cheese-services.yaml
Now we can submit an ingress for the cheese websites.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cheese
spec:
rules:
- host: stilton.local
http:
paths:
- path: /
backend:
serviceName: stilton
servicePort: http
- host: cheddar.local
http:
paths:
- path: /
backend:
serviceName: cheddar
servicePort: http
- host: wensleydale.local
http:
paths:
- path: /
backend:
serviceName: wensleydale
servicePort: http
examples/k8s/cheese-ingress.yaml
Notice that we list each hostname, and add a backend service.
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.
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.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cheeses
annotations:
traefik.frontend.rule.type: pathprefixstrip
spec:
rules:
- host: cheeses.local
http:
paths:
- path: /stilton
backend:
serviceName: stilton
servicePort: http
- path: /cheddar
backend:
serviceName: cheddar
servicePort: http
- path: /wensleydale
backend:
serviceName: wensleydale
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.
kubectl apply -f examples/k8s/cheeses-ingress.yaml
echo "$(minikube ip) cheeses.local" | sudo tee -a /etc/hosts
You should now be able to visit the websites in your browser.