Cover image taken from traefik docs
What is Traefik
Traefik is a leading modern reverse proxy and load balancer that makes deploying microservices easy. Traefik integrates with your existing infrastructure components and configures itself automatically and dynamically.
Some of the features are
Learn more on Traefik
- Routing & load balancing
- Security
- Dynamic Configuration
- Observability
Traefik also supports multiple providers & orchestrators, and today I will be talking about Kubernetes.
Why Traefik
Most cloud providers will provision Load Balancer if you use Ingress. Most of the time the Load Balancer are packed with features, and at the same time high price tag, or some restriction that we can't modify. If that is your use case, you could install other Ingress, for example Traefik.
Get started with Traefik
Image take from Traefik docs
Traefik is the only container that accessible from outside, in other words, it is the entrypoint of your services, possible with multiple domains, with only single IP address
Installation
I will walk through the demo on Google Cloud (GKE and Google DNS) with terraform.
The source code can be found at cncf-demo
If you wish to follow along, make sure you have Google Cloud project created, and download service account with appropriate IAM roles assigned, to be used with terraform.
Traefik can be configured to use an ACME provider (like Let's Encrypt) for automatic certificate generation. So we need to attach Persistence Disk to Kubernetes pods, to persist the certificate configuration. Additional configuration can be view at values.yaml.
git clone https://github.com/WLun001/cncf-demo
cd terraform/gke-traefik
terraform init
# it will provision GKE cluster
# and install traefik with helm
terraform apply
optionally you can create terraform.tfvars
to store variables for terraform
Get Traefik resouces
Once terraform process is completed, you can view the deployment on GKE dashboard or via kubectl
Make sure kubectl
is authenticated to access your cluster
$ kubectl get deploy,svc -n traefik -L=app.kubernetes.io/instance: traefik
NAME READY UP-TO-DATE AVAILABLE AGE INSTANCE:
deployment.apps/traefik 1/1 1 1 2d17h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE INSTANCE:
service/traefik LoadBalancer 10.3.247.160 SOME_EXTERNAL_IP 80:32757/TCP,443:30535/TCP 2d17h
You should be able to access Traefik on the external IP on port 80
Create sample apps
Let's create some sample apps, to be routed by Traefik
cd kubernetes
kubectl apply -f whoami.yaml -f hello-world.yaml
Create Traefik routes
create a new file call myroutes.yaml
add the following
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: myingressroute
namespace: default
spec:
entryPoints:
- web
routes:
- match: PathPrefix(`/`)
kind: Rule
services:
- name: hello-world-service
port: 80
- match: PathPrefix(`/whoami`)
kind: Rule
services:
- name: whoami
port: 80
- match: (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
kind: Rule
services:
- name: api@internal
kind: TraefikService
apply the routes
kubectl apply -f myroutes.yaml
Now you should able to access the following routes
/
- it will printhello world
/whoami
- it will print some information fromwhoami
/dashboard/
- Traefik dashboard
Bind Traefik routes with custom domain
Add the external IP to your DNS providers,
and edit the following for myroutes.yaml
, replace traefik.example.com
with your domain
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: myingressroute
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`traefik.example.com`) && PathPrefix(`/`)
kind: Rule
services:
- name: hello-world-service
port: 80
- match: Host(`traefik.example.com`) && PathPrefix(`/whoami`)
kind: Rule
services:
- name: whoami
port: 80
- match: Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
kind: Rule
services:
- name: api@internal
kind: TraefikService
apply the routes
kubectl apply -f myroutes.yaml
After a few minutes, wait for DNS update, you can only access the service via domain, can't access via external IP anymore.
Automatic HTTPS
Traefik support automatic https generation with multiple providers, more on docs. I will walk through Google DNS as DNS provider, the flow would be similar.
The default ACME support does not give high availability. If you have multiple replicas of Traefik, it will request multiple certificates, for example Let's Encrypt, and eventually hit the rate limit. To learn more about high availability auto TLS, Read next ๐๐ป achieve high availability auto TLS with cert manager
- Create service account for with
DNS Administrator
role assigned - Download the service account
- Create kubernetes secret with the service account
kubectl create secret generic google-dns-sa \
--from-file=key.json=your-service-account.json -n traefik
Edit Traefik deployment yaml
This can be done through helm charts, or edit the file manually with kubectl edit or kubectl patch
note that this example we using let's encrypt staging server,
- Let's Encrypt production server:
https://acme-v02.api.letsencrypt.org/directory
- Let's Encrypt staging server:
https://acme-staging-v02.api.letsencrypt.org/directory
Using Helm charts
add the following to existing values.yaml
, complete yaml file can be found on values.yaml
additionalArguments:
- "--certificatesResolvers.myresolver.acme.dnsChallenge.provider=gcloud"
- "--certificatesresolvers.myresolver.acme.email=youremail@email.com"
- "--certificatesresolvers.myresolver.acme.storage=/data/acme.json"
# Please note that this is the staging Let's Encrypt server.
# Once you get things working, you should remove that whole line altogether.
# if you dont persistence enabled
- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
env:
- name: GCE_PROJECT
value: YOUR_PROJECT_ID
- name: GCE_SERVICE_ACCOUNT_FILE
value: /var/secret/google/key.json
- name: GOOGLE_APPLICATION_CREDENTIALS
value: /var/secret/google/key.json
volumes:
- name: google-dns-sa
mountPath: /var/secret/google
type: secret
Using kubectl edit
or kubectl patch
The follow yaml file highlights the changes required, complete yaml file can be view at example-traefik.yaml
apiVersion: apps/v1
kind: Deployment
....
spec:
template:
spec:
containers:
args:
...
- --certificatesResolvers.myresolver.acme.dnsChallenge.provider=gcloud
- --certificatesresolvers.myresolver.acme.email=youremail@email.com
- --certificatesresolvers.myresolver.acme.storage=/data/acme.json
# Please note that this is the staging Let's Encrypt server.
# Once you get things working, you should remove that whole line altogether.
- --certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
env:
- name: GCE_PROJECT
value: YOUR_PROJECT_ID
- name: GCE_SERVICE_ACCOUNT_FILE
value: /var/secret/google/key.json
- name: GOOGLE_APPLICATION_CREDENTIALS
value: /var/secret/google/key.json
....
volumeMounts:
...
- mountPath: /var/secret/google
name: google-credentials-volume
...
volumes:
...
- name: google-credentials-volume
secret:
secretName: google-dns-sa
Add https routes
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: myingressroute-secure
namespace: default
spec:
entryPoints:
- websecure
routes:
- match: Host(`traefik.example.com`) && PathPrefix(`/`)
kind: Rule
services:
- name: hello-world-service
port: 80
- match: Host(`traefik.example.com`) && PathPrefix(`/whoami`)
kind: Rule
services:
- name: whoami
port: 80
- match: Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
tls:
certResolver: myresolver
domains:
- main: "*.example.com"
apply the routes
kubectl apply -f myroutes.yaml
If you need to see the error log , if there is any, can check with kubectl
. If any error with https generation, it will be visible here.
kubectl logs -f deployment/traefik -n traefik
Wait a few minutes, you should see the cert provision successfully.
If you are using staging server, the root cert will be from Fake LE Intermediate X1
.
I am using production server, so the browser showing the certificate is verify. Browser will complain not secure for staging server.
Multiple domains
you can add more domains by adding config to routes
array on yaml, and match by domain
routes:
- match: Host(`domain1.com`) && PathPrefix(`/`)
kind: Rule
services:
- name: hello-world-service
port: 80
- match: Host(`domain2.com`) && PathPrefix(`/whoami`)
kind: Rule
services:
- name: whoami
port: 80
HTTPS redirect
Traefik provides middleware feature, one of the use case is https redierct
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: redirect-https
spec:
redirectScheme:
scheme: https
add to the service
- match: Host(`example.com`) && PathPrefix(`/`)
kind: Rule
services:
- name: whoami
port: 80
middlewares:
- name: redirect-https
if you open your domain, it should auto redirect to https
Complete working example of IngressRoute can be found ingress-route.yaml
Clean up
All cloud resources cost money, make sure you clean up after experiment.
cd terraform/gke-traefik
terraform destroy
That's all for today, if you have any idea, feel free to comment below.
The source code can be found at cncf-demo
Read next ๐๐ป achieve high availability auto TLS with cert manager