Le blog tech de Nicolas Steinmetz (Time Series, IoT, Web, Ops, Data)
Pour faire suite au billet sur le déploiement de Traefik sous la forme d’un DaemonSet chez OVH, j’ai profité de la sortie en mode beta des Load Balancers pour revoir ma copie :
Par simplicité, je n’ai toujours qu’une node en plus du master fourni par OVH. Cela m’évite la problématique du stockage distribué des certificats. Cela fera l’objet d’un autre billet.
Créons le namespace traefik :
# Create namespace
kubectl create ns traefik
# Change context to this namespace so that all commands are by default run for this namespace
# see https://github.com/ahmetb/kubectx
kubens traefik
Commençons par traefik/rbac.yml
- le fichier défini le compte de service (Service Account
), le rôle au niveau du cluster (Cluster Role
) et la liaison entre le rôle et le compte de service (Cluster Role Binding
)
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-ingress-controller
namespace: traefik
---
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
---
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: traefik
Ensuite, pour Traefik, j’ai besoin d’un fichier traefik.toml
avec la configuration que je mets à disposition sous la forme d’une ConfigMap
dans un fichier traefik/traefik-toml-configmap.yml
:
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-conf
data:
traefik.toml: |
defaultEntryPoints = ["http", "https"]
logLevel = "INFO"
insecureSkipVerify = true
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[entryPoints.api]
address = ":8080"
[acme]
email = "contact@cerenit.fr"
storage = "/acme/acme.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"
[api]
entryPoint = "api"
dashboard = true
debug = false
[kubernetes]
Le dashboard est à protéger par une authentification pour éviter tout accès non souhaité. Je l’ai supprimé de la configuration par simplicité.
Ensuite, pour stocker mes certificats, il me faut un volume que je défini via le fichier traefik/traefik-certificates-pvc.yml
:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: traefik-certificates
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 1Gi
storageClassName: cinder-classic
1 Go pour des certificats, c’est clairement trop mais il n’est pas possible pour le moment d’avoir un stockage plus réduit.
Je peux donc enfin déployer Traefik via le fichier traefik/traefik-deployment.yml
:
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: traefik-ingress-controller
labels:
k8s-app: traefik-ingress-lb
spec:
replicas: 1
selector:
matchLabels:
k8s-app: traefik-ingress-lb
template:
metadata:
labels:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 60
containers:
- image: traefik:1.7.7
name: traefik-ingress-lb
volumeMounts:
- mountPath: /config
name: traefik-config
- mountPath: /acme
name: certificates
ports:
- name: http
containerPort: 80
- name: admin
containerPort: 8080
- name: secure
containerPort: 443
args:
- --configfile=/config/traefik.toml
volumes:
- name: traefik-config
configMap:
name: traefik-conf
- name: certificates
persistentVolumeClaim:
claimName: traefik-certificates
Nous déployons donc :
Pour permettre au cluster d’accéder aux différents ports, il faut définir un service via le fichier traefik-service-clusterip.yml
:
---
kind: Service
apiVersion: v1
metadata:
name: traefik-ingress-service-clusterip
spec:
selector:
k8s-app: traefik-ingress-lb
ports:
- protocol: TCP
port: 80
name: web
- protocol: TCP
port: 8080
name: admin
- protocol: TCP
port: 443
name: secure
type: ClusterIP
Et pour avoir un accès de l’extérieur, il faut instancier un load-balancer via le fichier traefik/traefik-service-loadbalancer.yml
kind: Service
apiVersion: v1
metadata:
name: traefik-ingress-service-lb
spec:
selector:
k8s-app: traefik-ingress-lb
ports:
- protocol: TCP
port: 80
name: web
- protocol: TCP
port: 443
name: secure
type: LoadBalancer
Pour donner l’accès au dashboard via une url sécurisée par un certificat Let’s Encrypt, il faut déclarer un Ingress, dans le fichier traefik/traefik-api-ingress.yml
:
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: traefik-web-ui
spec:
rules:
- host: traefik.k8s.cerenit.fr
http:
paths:
- path: /
backend:
serviceName: traefik-ingress-service
servicePort: admin
Il ne nous reste plus qu’à faire :
# Create k8s ressources for traefik
kubectl create -f traefik/
# Watch service to get IPs
kubectl get svc -w
Une fois votre IP obtenue, il suffit de faire pointer votre entrée DNS vers cette IP ou de tester via :
curl -H "Host: traefik.k8s.cerenit.fr" https://xxx.xxx.xxx.xxx/
Pour l’obtention du certificat Let’s Encrypt, il faut que votre enregistrement DNS soit à jour préalablement. Sinon vous aurez un certificat autosigné par Traefik en attendant.
Dès lors, vous pouvez accéder au dashboard de Traefik via l’url définie. Pour donner accès à d’autres sites, il faut déclarer d’autres ingress sur le même modèle et le tour est joué.
Comparativement au dernier tutoriel :
Il reste encore le problème des stockage des certificats à résoudre pour passer à un contexte multi-nodes. Ce sera l’objet d’un prochain billet avec idéalement l’intégration de Traefik avec cert-manager (plutôt que de devoir déployer une base clé/valeur comme etcd ou consul pour y stocker les infos de traefik).
N’hésitez pas à me faire part de vos retours.
Sortant de la formation Déployer ses applications avec Kubernetes animée par Jérome Petazzoni - slides - j’ai voulu mettre en oeuvre différents enseignements. OVH proposant un service kubernetes managé en version beta basé sur une infrastructure Openstack, j’en ai profité pour jouer un peu avec.
En parcourant la documentation disponible et le canal gitter, on note que :
NodePort
pour accéder aux applications.J’ai voulu donc voir comment déployer Traefik sur mon cluster qui ne contient qu’une seule node pour me facilier la gestion des volumes. En effet, la classe de stockage “cinder” ne supporte pas un accès depuis plusieurs nodes (ReadOnlyMany
ou mieux ReadWriteMany
) mais seulement depuis une node (ReadWriteOnce
).
C’est donc clairement sous-optimal comme configuration mais ça permet de se faire la main à un prix raisonnable et sans trop se casser la tête. Dans le cadre d’un vrai déploiement, il faudrait trouver une solution de stockage plus intéressante pour les données de traefik (en l’occurence les certificats).
L’idée est donc de déployer Traefik sous la forme d’un DaemonSet et de mapper les ports 80/443 de chaque node du cluster.
Pour se faire, Traefik founi un exemple de DaemonSet que j’ai largement repris.
Commençons par traefik/rbac.yml
- le fichier défini le compte de service (Service Account
), le rôle au niveau du cluster (Cluster Role
) et la liaison entre le rôle et le compte de service (Cluster Role Binding
)
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-ingress-controller
namespace: kube-system
---
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
---
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: kube-system
Ensuite, pour Traefik, j’ai besoin d’un fichier traefik.toml
avec la configuration que je mets à disposition sous la forme d’une ConfigMap
dans un fichier traefik/traefik-toml-configmap.yml
:
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-conf
namespace: kube-system
data:
traefik.toml: |
defaultEntryPoints = ["http", "https"]
insecureSkipVerify = true
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[entryPoints.api]
address = ":8080"
[acme]
email = "contact@cerenit.fr"
storage = "/acme/acme.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"
[api]
entryPoint = "api"
dashboard = true
debug = false
Le dashboard est à protéger par une authentification pour éviter tout accès non souhaité. Je l’ai supprimé de la configuration par simplicité.
Ensuite, pour stocker mes certificats, il me faut un volume que je défini via le fichier traefik/traefik-certificates-pvc.yml
:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: traefik-certificates
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 1Gi
storageClassName: cinder-classic
1 Go pour des certificats, c’est clairement trop mais il n’est pas possible pour le moment d’avoir un stockage plus réduit.
Je peux donc enfin déployer Traefik via le fichier traefik/traefik-ds.yml
:
---
kind: DaemonSet
apiVersion: extensions/v1beta1
metadata:
name: traefik-ingress-controller
namespace: kube-system
labels:
k8s-app: traefik-ingress-lb
spec:
template:
metadata:
labels:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
spec:
hostNetwork: true
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 60
containers:
- image: traefik
name: traefik-ingress-lb
volumeMounts:
- mountPath: /config
name: traefik-config
- mountPath: /acme
name: certificates
ports:
- name: http
containerPort: 80
hostPort: 80
- name: https
containerPort: 443
hostPort: 443
- name: admin
containerPort: 8080
hostPort: 8080
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
args:
- --kubernetes
- --logLevel=INFO
- --configfile=/config/traefik.toml
volumes:
- name: traefik-config
configMap:
name: traefik-conf
- name: certificates
persistentVolumeClaim:
claimName: traefik-certificates
---
kind: Service
apiVersion: v1
metadata:
name: traefik-ingress-service
namespace: kube-system
spec:
selector:
k8s-app: traefik-ingress-lb
ports:
- protocol: TCP
port: 80
name: web
- protocol: TCP
port: 8080
name: admin
- protocol: TCP
port: 443
name: https
Nous déployons donc :
A partir de ce moment là, vous avez accès au dashboard via http://<node ip>:8080/
Pour améliorer un peu les choses, nous pouvons vouloir donner accès au dashboard via une url et sécurisé par un certificat Let’s Encrypt.
Pour se faire, il faut déclarer un Ingress, dans le fichier traefik/traefik-api-ingress.yml
:
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: traefik-web-ui
namespace: kube-system
spec:
rules:
- host: traefik.k8s.cerenit.fr
http:
paths:
- path: /
backend:
serviceName: traefik-ingress-service
servicePort: admin
Il ne nous reste plus qu’à faire :
kubectl create -f traefik/
ingress.extensions/traefik-web-ui created
persistentvolumeclaim/traefik-certificates created
daemonset.extensions/traefik-ingress-controller created
service/traefik-ingress-service created
serviceaccount/traefik-ingress-controller created
clusterrole.rbac.authorization.k8s.io/traefik-ingress-controller created
clusterrolebinding.rbac.authorization.k8s.io/traefik-ingress-controller created
Dès lors, vous pouvez accéder au dashboard de Traefik via l’url définie.
Nous arrivons au bout de ce tutoriel permettant de jouer rapidement avec Traefik sous la forme d’un DaemonSet. Le contenu est criticable et améliorable par bien des aspects :
N’hésitez pas à me faire part de vos retours.
Il ne me reste plus qu’à vous souhaiter de bonnes fêtes de fin d’année et à vous retrouver l’année prochaine pour de nouvelles aventures.
python == python2
pour le motif de ne pas se tirer une balle dans le pied et qu’il y a alternatives --set python /usr/bin/python3
pour ça.Feature-Policy
indique au navigateur les fonctionnalités nécessaires pour le bon fonctionnement du site et désactiver les autres.