Skip to content

Instantly share code, notes, and snippets.

@ddtmachado
Created December 21, 2022 12:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ddtmachado/06b5988f9762c9ab243e92b170c1500d to your computer and use it in GitHub Desktop.
Save ddtmachado/06b5988f9762c9ab243e92b170c1500d to your computer and use it in GitHub Desktop.
Traefik v2 to v3 parallel CRD migration

For this test I used k3d with the following start options:

k3d cluster create \
    "trk" \
    --agents 2 \
    --port="80:80@loadbalancer" \
    --port="443:443@loadbalancer" \
    --k3s-arg="--disable=traefik@server:0" \
    --image "rancher/k3s:v1.20.15-k3s1-amd64"

Clone and build the CRD PR since its not merged yet, then import the built image into k3d

k3d image import --cluster trk traefik/traefik:latest

Create separate namespaces

kubectl create namespace traefik-v2
kubectl create namespace traefik-v3

Create the static configuration for each Traefik instance

kubectl apply -k configs -n traefik-v2
kubectl apply -k configs -n traefik-v3

Install both CRD versions

kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/${version}/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-${version}.yml

Deploy the stack

kubectl apply -f proxy-v2-and-v3.yaml

Create the dashboard and fallthrough rules

kubectl apply -f kubernetes/apps/dashboard-v2.yml   -n traefik-v2
kubectl apply -f kubernetes/apps/fallthrough.yml -n traefik-v2

At this point you should be able to access the dashboard of the Treaefik v2 instance while going through Traefik v3. Any application deployed with the old CRD API will be recognized and exposed in Traefik v2 but also acessible from v3 because of the fallthrough rule.

The easies way to validate that is to deploy a new dashboard CRD, this time with the new CRD API so it gets exposed in v3 and gets prioritized

kubectl apply -f kubernetes/apps/dashboard-v3.yml   -n traefik-v3

Now when accessing the dashboard you'll be presented with the v3 dashboard. The same principle can be applied for any exposed app, once you deploy the new CRD it will take precedence over any route with the same match on v2.

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: api
spec:
entryPoints:
- web
routes:
- match: Host(`traefik-dashboard.docker.localhost`)
kind: Rule
services:
- name: api@internal
kind: TraefikService
apiVersion: traefik.io/v1
kind: IngressRoute
metadata:
name: api
spec:
entryPoints:
- web
routes:
- kind: Rule
match: Host(`traefik-dashboard.docker.localhost`)
priority: 10
services:
- name: api@internal
kind: TraefikService
apiVersion: traefik.io/v1
kind: IngressRoute
metadata:
name: api
spec:
entryPoints:
- web
routes:
- kind: Rule
match: HostRegexp(`.+`)
priority: 1
services:
- name: traefik-v2
port: 80
# Saved into ./configs folder
configMapGenerator:
- name: traefik-config
files:
- static.yaml=static-config.yaml
generatorOptions:
disableNameSuffixHash: true
apiVersion: v1
kind: Service
metadata:
name: traefik-v2
namespace: traefik-v2
spec:
type: ClusterIP
ports:
- protocol: TCP
name: web
port: 80
- protocol: TCP
name: websecure
port: 443
selector:
app: traefik-v2
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: traefik-v2-cr
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- traefik.containo.us
resources:
- middlewares
- middlewaretcps
- ingressroutes
- traefikservices
- ingressroutetcps
- ingressrouteudps
- tlsoptions
- tlsstores
- serverstransports
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: traefik-v2-crb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-v2-cr
subjects:
- kind: ServiceAccount
name: traefik-v2-sa
namespace: traefik-v2
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-v2-sa
namespace: traefik-v2
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: traefik-v2
namespace: traefik-v2
labels:
app: traefik-v2
spec:
replicas: 1
selector:
matchLabels:
app: traefik-v2
template:
metadata:
labels:
app: traefik-v2
spec:
serviceAccountName: traefik-v2-sa
containers:
- name: traefik
image: traefik:v2.9
imagePullPolicy: IfNotPresent
args:
- "--configfile=/configs/static.yaml"
- "--log.level=DEBUG"
ports:
- name: web
containerPort: 80
- name: websecure
containerPort: 443
volumeMounts:
- name: "traefik-config"
mountPath: "/configs"
volumes:
- name: traefik-config
configMap:
name: traefik-config
---
###### V2 ######
apiVersion: v1
kind: Service
metadata:
name: traefik-v3
namespace: traefik-v3
spec:
type: LoadBalancer
ports:
- protocol: TCP
name: web
port: 80
- protocol: TCP
name: websecure
port: 443
selector:
app: traefik-v3
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: traefik-v3-cr
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- traefik.io
resources:
- middlewares
- middlewaretcps
- ingressroutes
- traefikservices
- ingressroutetcps
- ingressrouteudps
- tlsoptions
- tlsstores
- serverstransports
- serverstransporttcps
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: traefik-v3-crb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-v3-cr
subjects:
- kind: ServiceAccount
name: traefik-v3-sa
namespace: traefik-v3
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-v3-sa
namespace: traefik-v3
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: traefik-v3
namespace: traefik-v3
labels:
app: traefik-v3
spec:
replicas: 1
selector:
matchLabels:
app: traefik-v3
template:
metadata:
labels:
app: traefik-v3
spec:
serviceAccountName: traefik-v3-sa
containers:
- name: traefik
image: traefik/traefik:latest
imagePullPolicy: IfNotPresent
args:
- "--configfile=/configs/static.yaml"
- "--log.level=DEBUG"
ports:
- name: web
containerPort: 80
- name: websecure
containerPort: 443
volumeMounts:
- name: "traefik-config"
mountPath: "/configs"
volumes:
- name: traefik-config
configMap:
name: traefik-config
api:
dashboard: true
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
providers:
kubernetesCRD: {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment