Traefik in actions. The Cloud Native Edge Router
Cover image taken from traefik docs
Table of contents generated with markdown-toc
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
I have been using Google Kubernetes Engine (GKE) for awhile, and default Ingress for GKE is GCE Ingress, which uses Google Cloud Load Balancer under the hood. GCE Ingress is great, it is global service, has optional configuration for dashboard, logging, CDN, Anti DDOS (Cloud Armor), managed certificate and etc. But it lacks of essential features such as basic auth, https redirect, and required kubernetes service type set to NodePort
to works. Furthermore, it could incur high cost. It will charge on the following:
- it needs one static IP per Ingress, any unused IP address will be charge hourly.
- Cloud Load Balancer
- CDN, DDOS protection if any
- Network egress
The cost will multiply if you have multiple ingresses running.
With all the reason above, I decide to try out other Ingress, and here comes 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 zone-printer.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: zone-printer-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 print the cluster zone, if you are on GKE/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: zone-printer-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.
- 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: zone-printer-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`) && PathPrefix(`/`)
kind: Rule
services:
- name: zone-printer-service
port: 80
- match: Host(`domain2`) && 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
The source code can be view at cncf-demo. That's all for today, if you have any idea, feel free to comment below.
No Comments Yet