I have a single-node Kubernetes cluster, but I also run docker workloads on it, and wanted to use traefik for both.
Sure, I could run two separated instances but it would be a waste.
Traefik is a versatile reverse proxy, and has many different backend for Configuration Discovery, such as Docker labels, KubernetesIngress, Nomad…
graph TB
Traefik-->pid1(local process)
Traefik-->pid2(local process)
subgraph Kubernetes
pod1
pod2
end
Traefik-->pod1(Pod)
Traefik-->pod2(Pod)
subgraph Docker
container1
container2
end
Traefik-->container1(container)
Traefik-->container2(container)
example deployment with multiple targets
Targets
I want my Traefik to proxy traffic and handle TLS termination for the following types of services:
- standalone Docker containers
- Kubernetes pods
- regular Linux processes
Because everything runs on a single machine, a lot of the network setup can be ignored. Traefik must be able to reach the IP adresses of the Docker containers and the Kubernetes pods.
Installation
I wanted to run Traefik with systemd, but since Traefik does not provide Debian packages, you need to install the binary by hand and setup a service file.
Setup Traefik as a systemd Service (.kg-bookmark-container)
This post uses TOML configuration, but the result is the same
Setup
Traefik will need to access the Docker socket and the Kubernetes API.
And everything else will be configured in Traefik dynamic files
Instead of using the credentials in you kubeconfig, you should create a ServiceAccount so that Traefik can access the Kubernets API without root access.
Fortunately the work of identifying the correct permissions has been done by the Traefik team in their Helm chart
Because Traefik runs outside of Kubernetes, its ServiceAccount token will expire. You can issue tokens with no expiration by manually creating an empty Secret.
Configure Service Accounts for Pods
I use the following configuration in kubernetes:
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-account
namespace: kube-public
---
apiVersion: v1
kind: Secret
metadata:
annotations:
kubernetes.io/service-account.name: traefik-account
name: traefik-token
namespace: kube-public
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: traefik-role
rules:
- apiGroups:
- ""
resources:
- services
- secrets
- nodes
verbs:
- get
- list
- watch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: traefik-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-role
subjects:
- kind: ServiceAccount
name: traefik-account
namespace: kube-public
Once this is created, you need to extract some informations: get the ServiceAccount token and CA using the following commands
kubectl --namespace kube-public get secret traefik-token \
--output jsonpath='{.data.token}' \
| base64 --decode # → the token
kubectl --namespace kube-public get secret traefik-token \
--output jsonpath="{['data']['ca\.crt']}"\
| base64 --decode > your-CA.pem # → the CA
And for the endpoint and CA, get it from your kubeconfig.
You can check you got the correct endpoint with curl --cacert your-CA.pem https://your-endpoint:6443
If the api-server certificate does not match the hostname/IP of the endpoint, then you can skip certificate verification with kubectl --insecure-skip-tls-verify=false ....
Beware, this exposes you to man-in-the-middle attacks !
And now for the Traefik main config:
providers:
kubernetesIngress:
endpoint: https://your-endpoint:6443 # your endpoint
token: 'your-token'
certAuthFilePath: 'path/to/your-CA.pem'
ingressEndpoint:
ip: your-traefik-ip # optional
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
file:
directory: "traefik/conf.d"
watch: true
api: {}
ping:
entryPoint: "ping"
entryPoints:
ping:
address: ":8082"
reusePort: true
web:
address: ":80"
reusePort: true
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
reusePort: true
http3: {}
http:
tls: {}
defaultEntryPoints:
- websecure
File configuration
The File provider will dynamically reload Traefik state as the files change.