My Journey to Kubernetes onto Bare Metal — Part 7: Traefik
Integrate a reverse proxy with previous tools.
Now comes the next phase of this journey: Configuring a reverse proxy. The reverse proxy I chose is Traefik v2.2. I am assuming that if you are reading this guide then you have a certain amount of knowledge already of what a reverse proxy is and if you need this guide at all. I am going to show you what I did to get Traefik working with my external and internal services.
Create Namespace
---
apiVersion: v1
kind: Namespace
metadata:
name: traefik
Apply RBAC
piVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: ingressroutes.traefik.containo.us
namespace: traefik
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRoute
plural: ingressroutes
singular: ingressroute
scope: Namespaced---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: ingressroutetcps.traefik.containo.us
namespace: traefik
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRouteTCP
plural: ingressroutetcps
singular: ingressroutetcp
scope: Namespaced---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: ingressrouteudps.traefik.containo.us
namespace: traefik
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRouteUDP
plural: ingressrouteudps
singular: ingressrouteudp
scope: Namespaced---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: middlewares.traefik.containo.us
namespace: traefik
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: Middleware
plural: middlewares
singular: middleware
scope: Namespaced---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: tlsoptions.traefik.containo.us
namespace: traefik
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: TLSOption
plural: tlsoptions
singular: tlsoption
scope: Namespaced---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: tlsstores.traefik.containo.us
namespace: traefik
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: TLSStore
plural: tlsstores
singular: tlsstore
scope: Namespaced---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: traefikservices.traefik.containo.us
namespace: traefik
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: TraefikService
plural: traefikservices
singular: traefikservice
scope: Namespaced
Persistent Storage
I wanted to store some persistent data so I created this PV Claim:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: acme-storage-claim
namespace: traefik
#annotations:
# volume.beta.kubernetes.io/storage-class: "nfs-client"
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
storageClassName: nfs-client
Create Services
Notice that the “annotations” for the Service “traefik” is using the metallb address pool “public”, so it will be assigned a public-facing IP address.
--
apiVersion: v1
kind: Service
metadata:
name: traefik
namespace: traefik
annotations:
metallb.universe.tf/address-pool: publicspec:
type: LoadBalancer
ports:
- protocol: TCP
name: web
port: 80
- protocol: TCP
name: websecure
port: 443
#- protocol: TCP
# name: gitlab-ssh
# port: 22
selector:
app: traefik---
apiVersion: v1
kind: Service
metadata:
name: traefik-dashboard
namespace: traefik
annotations:
prometheus.io/scrape: 'true'spec:
type: ClusterIP
ports:
- protocol: TCP
name: admin
port: 8080
selector:
app: traefik
Create Redirection Middleware
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: redirect-http
namespace: traefik
spec:
redirectScheme:
scheme: https
permanent: true
Deploy Traefik
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: traefik
namespace: traefik
labels:
app: traefik
spec:
replicas: 1
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik-ingress-controller
volumes:
- name: acme-storage-volume
persistentVolumeClaim:
claimName: acme-storage-claim
containers:
- name: traefik
image: traefik:v2.2
ports:
- name: web
containerPort: 80
- name: websecure
containerPort: 443
- name: admin
containerPort: 8080
- name: metrics
containerPort: 8082
#- name: gitlab-ssh
# containerPort: 22
volumeMounts:
- name: acme-storage-volume
mountPath: /acme
subPath: ""
args:
- --api.insecure=true
- --api.dashboard=true
- --accesslog
- --metrics.prometheus=true
- --metrics.prometheus.addEntryPointsLabels=true
- --metrics.prometheus.addServicesLabels=true
- --entryPoints.metrics.address=:8082
- --metrics.prometheus.entryPoint=metrics
- --entrypoints.web.Address=:80
- --entrypoints.websecure.Address=:443
- --entrypoints.websecure.http.tls=true
- --entrypoints.plex-pms.Address=:32400
- --entrypoints.gitlab-ssh.Address=:22/tcp
- --log.level=DEBUG
- --ping
- --providers.kubernetescrd=true
- --providers.kubernetesIngress=true
Please note that a kubernetes ingress class is automatically created and called “traefik”. This will come in handy later when I show you how to leverage it.
Optional: Metric Service
---
apiVersion: v1
kind: Service
metadata:
name: traefik-metrics
namespace: traefik
spec:
type: ClusterIP
ports:
- protocol: TCP
name: admin
port: 8082
selector:
app: traefik
Create Access to Traefik
After you have applied all of the settings above you should have a running instance of Traefik. Your next problem will be how to access the dashboard. Since I have an external and internal network I am going to show you how to access it both ways.
Internal Access
In my home network I have a Windows Domain controller with the DNS service installed. These are the steps I took for internal access:
- Create an internal Service that will point to Traefik:
---
apiVersion: v1
kind: Service
metadata:
name: traefik-internal
namespace: traefik
annotations:
metallb.universe.tf/address-pool: private
spec:
type: LoadBalancer
ports:
- protocol: TCP
name: web
port: 80
- protocol: TCP
name: websecure
port: 443
selector:
app: traefik
This will create a LoadBalancer which will allocate an IP address from metallb’s private address pool. In my case the IP assigned will be 192.168.86.220
2. Within my homelab DNS Server, manually create a DNS record for 192.168.86.220 for a record named “traefik”. The fully-qualified name will become “traefik.macross.com”.
3) Now using your local browser try the URL for your DNS record. So I will try the URL http://traefik.macross.com/
SUCCESS!
External Access
Please note that you really DO NOT want to expose your Traefik dashboard to the public, but if you are adamant then this is how you would go about it.
Below create a temp service called “dashboard-external-dns” which sits in a perpetual state of being created but is never completed. That’s fine by me since it auto-magically creates a DNS record at my DNS provider (Google DNS) for “traefik.macrossplusinc.com” and assign the IP address to “1.2.3.4”. Which, if course, you will replace with your own public IP address.
Next, create the Ingress object so it will route traffic from the publicly exposed IP address to the Traefik dashboard service called “traefik-dashboard”, which was created above in this guide.
---
# This will create a DNS record automatically
kind: Service
apiVersion: v1
metadata:
name: dashboard-external-dns
namespace: traefik
annotations:
external-dns.alpha.kubernetes.io/hostname: traefik.macrossplusinc.com
spec:
type: ExternalName
externalName: 1.2.3.4---
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: dashboard-ingress
namespace: traefik
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
#, websecure
#traefik.ingress.kubernetes.io/router.middlewares: traefik-redirect-http@kubernetescrd
#cert-manager.io/cluster-issuer: le-clusterissuer-prod-httpspec:
#tls:
#- hosts:
# - traefik.macrossplusinc.com
# secretName: traefik.macrossplusinc.com-tls
rules:
#- host: traefik.macrossplusinc.com
http:
paths:
- path: /
backend:
serviceName: traefik-dashboard
servicePort: 8080
Informational: I have left the comments which will enable HTTPS by creating a TLS certificate using the Cert-Manager service that was setup in a previous guide. After a short while you should be able to access your Traefik dashboard externally from anywhere publicly accessible.
Metric Service
To allow your Metric Service to gather data from Traefik I created this service which is exposed internally only. It will allow a connection route from your personal metric gathering tool (ex: Prometheus) to Traefik’s metric data.
---
apiVersion: v1
kind: Service
metadata:
name: traefik-metrics
namespace: traefik
spec:
type: ClusterIP
ports:
- protocol: TCP
name: admin
port: 8082
selector:
app: traefik
Next: Exposing an application using everything we have learned here.