How to Install Traefik as an Ingress Controller in Kubernetes

Hi everyone. Today I want to show how to install traefik as an Ingress Controller in your own on-premise kubernetes cluster.

Traefik can run in Kubernetes in 2 modes:

  1. kubernetesingress - it watches the standard objects with kind: Ingress and builds routes based on them
  2. kubernetescrd - to describe routes, you have to create kind: IngressRoute objects. This approach is more flexible, but if you ever switch to another Ingress Controller, you will have to rewrite your Ingress rules completely. Besides, from the kubernetes point of view, this kind of deployment is not an Ingress Controller, but that doesn't matter much to us. What matters is that we get the same result.

We will deploy both. On top of that, we'll also hook up Let's Encrypt.

Here is the plan: we'll put a label on one of the cluster nodes and use it in a nodeSelector to pick the node where our daemonset will run. This daemonset will run with hostNetwork: true so that we can open ports 80 and 443. The dedicated node won't be directly reachable from the internet; only ports 80 and 443 will be "forwarded" to it.

So, let's label our node:

kubectl label nodes k8s-us1804-a traefik=true

Describe all the resources traefik needs:

# All resources definition must be declared
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: ingressroutes.traefik.containo.us

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: middlewares.traefik.containo.us

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: ingressroutetcps.traefik.containo.us

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

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: tlsoptions.traefik.containo.us

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

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

spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: TraefikService
    plural: traefikservices
    singular: traefikservice
  scope: Namespaced

Grant permissions to the service account:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: traefik-ingress-controller

rules:
  - apiGroups:
      - ""
    resources:
      - services
      - endpoints
      - secrets
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses/status
    verbs:
      - update
  - apiGroups:
      - traefik.containo.us
    resources:
      - middlewares
      - ingressroutes
      - traefikservices
      - ingressroutetcps
      - ingressrouteudps
      - tlsoptions
      - tlsstores
    verbs:
      - get
      - list
      - watch

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: traefik-ingress-controller

roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: traefik-ingress-controller
subjects:
  - kind: ServiceAccount
    name: traefik-ingress-controller
    namespace: default

And start our traefik:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: traefik-ingress-controller
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: traefikconfig
data:
  traefik.yaml: |-
    api:
      dashboard: true
    entryPoints:
      web:
        address: ":80"
        forwardedHeaders:
          insecure: true
      websecure:
        address: ":443"
        forwardedHeaders:
          insecure: true
    providers:
      kubernetesingress: {}
      kubernetescrd: {}
    certificatesResolvers:
      letsencrypt:
        acme:
          email: vitaliy@leschenko.by
          storage: /acme/acme.json
          caserver: https://acme-v02.api.letsencrypt.org/directory
          httpChallenge:
            entryPoint: web
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: traefik
  labels:
    app: traefik
spec:
  selector:
    matchLabels:
      app: traefik
  template:
    metadata:
      labels:
        app: traefik
    spec:
      hostNetwork: true
      serviceAccountName: traefik-ingress-controller
      nodeSelector:
        kubernetes.io/os: linux
        traefik: "true"
      volumes:
        - name: acme
          hostPath:
            path: /acme
        - name: config
          configMap:
            name: traefikconfig
      containers:
        - name: traefik
          image: traefik:v2.2
          volumeMounts:
            - name: acme
              mountPath: /acme
            - name: config
              mountPath: /traefik
          args:
            - --configFile=/traefik/traefik.yaml
            - --log.level=DEBUG
          ports:
            - name: web
              containerPort: 80
            - name: https
              containerPort: 443
            - name: admin
              containerPort: 8080

As a bonus, let's create a rule for traefik's own dashboard:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`traefik.vitaliy.org`)
    kind: Rule
    services:
    - name: api@internal
      kind: TraefikService
    middlewares:
      - name: auth
  tls:
    certResolver: letsencrypt
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: auth
spec:
  basicAuth:
    secret: authsecret
---
# A file containing test/test and test2/test2
apiVersion: v1
kind: Secret
metadata:
  name: authsecret
  namespace: default
data:
  users: |2
    dGVzdDokYXByMSRINnVza2trVyRJZ1hMUDZld1RyU3VCa1RycUU4d2ovCnRlc3QyOiRhcHIxJGQ5
    aHI5SEJCJDRIeHdnVWlyM0hQNEVzZ2dQL1FObzAK

That's it. In a few seconds you can open https://traefik.vitaliy.org.

Only registered users can leave a comment.

Sign in or register to leave a comment.