kustomize
est un outil conçu pour permettre aux utilisateurs de :
Personnaliser des fichiers YAML bruts et sans modèle à des fins multiples, en laissant le YAML d'origine intact et utilisable tel quel
Je n'invente rien, ce texte est tiré de la présentation de l'outil sur sa page GitHub 😂
Inclus directement dans Kubernetes depuis sa version 1.14, Kustomize
va donc nous permettre de customiser la configuration de nos déploiements en gardant une base commune. Par exemple nous allons pouvoir utiliser le même fichier de déploiement YAML
pour un environnement de développement et de production, en n'utilisatant Kustomize
pour définir les éléments propres à chaque environnement ! Top ?!
Tout ceci semble prometteur mais dans le concret ça donne quoi ? Un exemple ?
Pourquoi ?
Comment passer d'un environnement de développement à la production sans modifier de façon systématique tous mes fichiers YAML
de configuration ? Appliquez une configuration en fonction des environnements, tout en gardant une base commune m'aiderait tout simplement à maintenir plus facilement mes solutions !
Dans son utilisation la plus simple, kustomize
n'est tout simplement qu'un ensemble de ressources ( les fichiers YAML
qui définissent vos objets Kubernetes comme les déploiements, les services, etc.) et un ensemble d'instructions sur les modifications à apporter à ces ressources ( des patches ).
Nous pourrions comparer cette pratique à la façon dont make
utilise un fichier Makefile
pour effectuer une compilation. Kustomize utilise lui un fichier kustomization.yaml
afin de stocker les instructions qui vont modifier vos ressources.
Mais d'abord regardons un fichier kustomization.yaml
:
namePrefix: dev-
namespace: development
commonLabels:
environment: development
resources:
- deployment.yaml
- service.yaml
Voici une explication rapide de cet exemple :
- Le champ
namePrefix
va permettre de préfixer tous les noms de ressources définies avec la valeur que vous aurez pu définir. Dans notre cas, je vais préfixer tous mes noms avec "dev-". Par exemple un déploiement nommé traefik-deployment deviendra dev-traefik-deployement.
- L'instruction namespace est très intéressante, grâce à elle,
Kustomize
va ainsi créer nos éléments dans le namespace spécifié. Dans mon exemple : "development".
- Nous pouvons également spécifier un label pour toutes les ressources générées. Je vais ici mettre un label "environment" avec la valeur "development" pour chaque ressource.
- Enfin, je vais pouvoir appliquer des patches pour des ressources spécifiques que je vais préciser dans le champ : resources . Dans notre cas, les fichiers
deployment.yaml
etservice.yaml
.
Enfin Kustomize
nous offre principalement la possibilité de sur-charger une ressources avec de nouvelles valeurs. Et de ce fait, la patcher, avec des éléments précis d'un cas d'utilisation.
L'utilisation de variantes avec une base commune est appelée overlays. Voyons ensemble l'utilisation d'un cas concret d'overlays !
Overlays
Vous avez dû le remarquer, j'utilise beaucoup Traefik comme reverse-proxy !
Cet outil m'apporte une solution rapide et efficace pour gérer les nombreux conteneurs - web - que je mets en production et dont je maintiens également un environnement de développement, voir de staging.
Mais comment passer d'un environnement de développement à la production sans modifier de façon systématique mes fichiers YAML
de configuration ? Appliquez une configuration en fonction des environnements, tout en gardant une base commune m'aiderait tout simplement à maintenir plus facilement mes solutions !
Voici donc ce que j'envisage pour notre exemple :
- Une base Traefik, qui sera semblable à un environnement de développement :
- Uniquement du HTTP,
- API et Dashboard accessible sans sécurité.
2. Un environnement de production :
- Une redirection HTTP vers HTTPS,
- Dashboard et API désactivés.
Je pourrais bien évidement mettre bien plus d'options dans mon environnement de production, comme un middleware par défaut pour ajouter des en-têtes de sécurité par exemple, mais il s'agit là d'un exemple et je souhaite le conserver simple afin de garder ma configuration lisible et compréhensible pour tous !
Commençons immédiatement avec notre base !
Base
Tout d'abord voici l'arborescence des dossiers de mon projet :
.
├── base
├── development
└── production
Je ne présente pas encore chaque fichiers.
Votre base doit être commune à votre environnement de développement mais aussi de production. Il faut donc en extraire les éléments communs.
Déclarons donc déjà les éléments essentiels afin de lancer Traefik dans mon environnement Kubernetes.
🚩 Pour mes essais, j'utilise K3S que j'installe tout simplement avec la commande :
curl -sfL https://get.k3s.io | sh -s - --no-deploy=traefik
Je ne déploie pas Traefik car nous allons le faire avec Kustomize
🚩
Je vais reprendre une bonne partie de la configuration présente dans cet article :
Voici les fichiers que je vais utiliser pour déployer Traefik :
- Un fichier traefik-rbac.yaml pour les droits clusters/autorisations.
- traefik-service.yaml pour déclarer mon service.
- Un fichier traefik-configmap.yaml pour définir ma configuration statique.
- Enfin mon fichier de déploiement : traefik-deployment.yaml.
Je ne vais pas détailler le fichier RBAC, vous le trouverez ici.
Mon fichier de service que je vais utiliser pour la base :
apiVersion: v1
kind: Service
metadata:
name: traefik
spec:
ports:
- protocol: TCP
name: web
port: 80
type: LoadBalancer
selector:
app: traefik
Je ne déclare que les éléments communs à mon environnement de production et de développement. Je retire donc le HTTPS et le dashboard.
Mon fichier traefik-configmap.yaml :
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-config-static
namespace: default
labels:
app: traefik
data:
traefik.yml: |
entryPoints:
web:
address: :80
providers:
kubernetesCRD: {}
Enfin mon fichier de traefik-deployment :
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: default
name: traefik-ingress-controller
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
name: traefik
labels:
app: traefik
spec:
replicas: 1
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik-ingress-controller
containers:
- name: traefik
image: traefik:v2.2
imagePullPolicy: Always
volumeMounts:
- name: traefik-config-static
mountPath: /etc/traefik/
ports:
- name: web
containerPort: 80
volumes:
- name: traefik-config-static
configMap:
name: traefik-config-static
Je vais pouvoir utiliser Kustomize
en déclarant dans mon fichier kustomization.yaml
mes ressources :
resources:
- traefik-rbac.yaml
- traefik-configmap.yaml
- traefik-service.yaml
- traefik-deployment.yaml
Ma structure de projet ressemble maintenant à :
.
├── base
│ ├── kustomization.yaml
│ ├── traefik-configmap.yaml
│ ├── traefik-deployment.yaml
│ ├── traefik-rbac.yaml
│ └── traefik-service.yaml
├── development
└── production
Vous pouvez vérifier que tout fonctionne en appliquant vos fichiers :
$ kubectl apply -k ./
customresourcedefinition.apiextensions.k8s.io/ingressroutes.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/ingressroutetcps.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/ingressrouteudps.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/middlewares.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/tlsoptions.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/tlsstores.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/traefikservices.traefik.containo.us created
serviceaccount/traefik-ingress-controller created
clusterrole.rbac.authorization.k8s.io/traefik-ingress-controller created
clusterrolebinding.rbac.authorization.k8s.io/traefik-ingress-controller created
configmap/traefik-config-static created
service/traefik created
deployment.apps/traefik created
Vous pouvez supprimer les objets créés avec la commande :
$ kubectl delete -k ./
Nous allons pouvoir appliquer les modifications pour notre environnement de développement. Que nous manque t-il ?
- Le dashboard !
Développement
Pour déclarer l'utilisation du dashboard je dois :
- Le déclarer dans ma configuration statique :
api.insecure=true
- Déclarer le port dans mon service et dans mon container.
Je vais donc dans le dossier development
modifier mon fichier de configuration :
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-config-static
namespace: default
labels:
app: traefik
data:
traefik.yml: |
entryPoints:
web:
address: :80
api:
insecure: true
providers:
kubernetesCRD: {}
🚩 Oui je réécris mon fichier en grande partie, pour ne pas le faire, il faudrait tirer partie d'autres directives que je ne souhaite pas aborder ici 🚩
Enfin dans mon fichier de service :
apiVersion: v1
kind: Service
metadata:
name: traefik
spec:
ports:
- protocol: TCP
name: admin
port: 8080
type: LoadBalancer
selector:
app: traefik
Et le fichier de deployment :
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
name: traefik
labels:
app: traefik
spec:
replicas: 1
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
containers:
- name: traefik
ports:
- name: admin
containerPort: 8080
Par contre pour ces deux fichiers, je ne modifie, ou ajoute, que les éléments nécessaires !
Je vais pouvoir créer mon fichier kustomization.yaml
:
bases:
- ../base
patches:
- traefik-configmap.yaml
- traefik-deployment.yaml
- traefik-service.yaml
Vous pouvez maintenant lancer votre reverse-proxy de développement :
$ kubectl apply -k ./
Vérifier votre installation en accédant au dashboard :
Et mon environnement de production dans tout ça ?!
Rien de plus simple !
Production
On repart donc de notre base et on modifie la configuration pour effectuer une redirection HTTP vers HTTPS :
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-config-static
namespace: default
labels:
app: traefik
data:
traefik.yml: |
entryPoints:
web:
address: :80
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: :443
http:
tls:
certResolver: myresolver
accessLog: {}
providers:
kubernetesCRD: {}
certificatesResolvers:
myresolver:
acme:
email: "[email protected]"
storage: "/letsencrypt/acme.json"
tlsChallenge: {}
J'en profite pour ajouter les accessLog
et bien sûr retirer l'accès au dashboard.
Mon fichier pour la déclaration du service :
apiVersion: v1
kind: Service
metadata:
name: traefik
spec:
ports:
- protocol: TCP
name: websecure
port: 443
type: LoadBalancer
selector:
app: traefik
Et enfin le déploiement :
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
name: traefik
labels:
app: traefik
spec:
replicas: 1
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
containers:
- name: traefik
ports:
- name: websecure
containerPort: 443
🚩 Oui oui il manque quelques petites choses, mais j'ai supprimé quelques elements afin de gagner en lisibilité de l'article. J'ajouterai ces éléments par la suite sur GitHub : Exemple, aucun volume pour les certificats LE 🚩
Le fichier kustomization
ressemble très fortement à celui de développement :
bases:
- ../base
patches:
- traefik-configmap.yaml
- traefik-deployment.yaml
- traefik-service.yaml
Voici enfin à quoi ressemble ma structure de projet une fois terminée :
.
├── base
│ ├── kustomization.yaml
│ ├── traefik-configmap.yaml
│ ├── traefik-deployment.yaml
│ ├── traefik-rbac.yaml
│ └── traefik-service.yaml
├── development
│ ├── kustomization.yaml
│ ├── traefik-configmap.yaml
│ ├── traefik-deployment.yaml
│ └── traefik-service.yaml
└── production
│ ├── kustomization.yaml
│ ├── traefik-configmap.yaml
│ ├── traefik-deployment.yaml
└── └── traefik-service.yaml
Il ne reste plus qu'à essayer tout ça :
🚩 Je n'ai pas utilisé de Prefix dans cet exemple, ne lancez pas la production et le développement en même temps, sinon vous allez avoir quelques erreurs ! 🚩
$ kubectl apply -k ./
En vous rendant sur http://monip/ vous devriez être automatiquement redirigé vers le https.
Vous pouvez bien sûr déployer une image comme containous/whoami
pour valider le bon fonctionnement !
Nous avons donc pu voir ensemble comment utiliser `Kustomize` et le mettre en pratique avec la création de deux environnements pour Traefik.
Il est bien évidement possible d'ajouter plus d'éléments à la production. Comme par exemple l'ouverture du Dashboard avec des restrictions IP ou accès par mot de passe, ajouter des middlewares, utiliser un KV store uniquement en production, etc. Les possibilités sont multiples et vont dépendre de votre couche applicative !
L'intérêt de Kustomize
ne s'arrête bien sûr pas ici ! Il est par exemple possible de l'utiliser lors d'un changement configuration ( une surcharge de paramètre par exemple ). Vous pourrez ainsi réaliser cette modification sans altérer votre configuration de base.
Et cela sera encore plus intéressant si vous travaillez en équipe sur votre infrastructure. Chacun pourra patcher son environnement et proposer sur un dépôt les modifications par exemple mais en gardant votre base commune !
Et vous ! Est-ce que vous envisagez d'utiliser Kustomize
prochainement ?!
En tout cas n'hésitez pas à m'apporter des remarques ou des commentaires sur Twitter ! C'est toujours un plaisir d'avoir des retours !