Après un long moment d’inactivité, me revoilà avec un article apportant quelques astuces découvertes depuis mon utilisation intensive de Kubernetes en production dans mon entreprise et à mes recherches sur le sujet.
1. Conserver vos ressources dans un git
L’installation de Kubernetes génère la création et la gestion de beaucoup de fichiers yaml. Que ce soit pour configurer votre DNS interne (CoreDNS), déployer votre Ingress-controller ou ajouter des addons à votre cluster, on se retrouve avec des centaines de lignes de yaml.
Je vous suggère d’ouvrir un dépôt Git privé afin d’y stocker vos ressources yaml que vous utiliserez comme source de référence pour votre cluster. Chaque modification y sera versionnée et si vous êtes plusieurs à administrer le cluster, cela sera d’autant plus transparent.
Cette gestion vous impose cependant de modifier vos yaml dans votre dépôt et de les envoyer vers Kubernetes avec kubectl apply -f fichier.yml
au lieu d’éditer vos ressources avec kubectl edit ressource
.
Vous pouvez également organiser votre dépôt par namespace avec des dossiers pour kube-system, nginx-ingress, etc.
2. Déployer avec Helm
Helm est décrit comme un gestionnaire de paquet pour Kubernetes. Il permet d’empaqueter vos ressources yaml pour votre application, en les variabilisant afin de permettre de facilement la distribuer et la redéployer.
Une charte Helm classique est composé de :
Charts.yaml
pour le nom, le tag et la version de votre applicationtemplates/
est le dossier dans lequel vous placez tous vos fichiers yaml (deployments, services, ingresses…)values.yaml
est un fichier de clé-valeur en yaml où l’on place les variables qu’on veut remplacer dans nos fichiers yaml de templates.
Par exemple, avec ce fichier values.yaml
:
global:
dbName: test
dbPassword: xahc5Ceej2keekoo
On peut réutiliser ses variables dans templates/mysql-deployment.yaml
:
apiVersion: v1
kind: Deployment
apiVersion: apps/v1
metadata:
name: mysql
labels:
k8s-app: mysql
spec:
replicas: 1
selector:
matchLabels:
k8s-app: mysql
template:
metadata:
labels:
k8s-app: mysql
spec:
containers:
- image: mysql:latest
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: {{ .Values.global.dbPassword }}
- name: MYSQL_DATABASE
value: {{ .Values.global.dbName }}
Pour installer notre propre charte Helm :
helm install --name=my-chart /chart-folder
Si vous changez un paramètre dans votre chart (template ou values), vous pouvez mettre à jour votre charte dans votre cluster (manuellement ou en CI/CD) avec la commande :
helm upgrade my-chart /chart-folder
Je vous suggère donc de créer des chartes Helm perso pour vos applications et les stocker dans votre dépôt Git afin de packager et variabiliser le déploiement de votre app. Cela vous permet ainsi de faciliter son installation dans plusieurs clusters ou environnements.
3. Exposer avec des Ingresses
Il y a plein de façon d’exposer un service dans Kubernetes. Si vous n’utilisez pas un cluster tout-en-un hébergé dans le cloud (Google, Aws, etc.) Vous ne pourrez pas utiliser le type de service LoadBalancer
car personne ne vous fournira automatiquement une adresse IP publique.
La meilleure façon, pour moi, dans un cluster custom de production est d’utiliser un Ingress Controller
comme Nginx-ingress
et de l’exposer publiquement avec un service avec une ExternalIP
ou avec un controller comme MetalLB
qui vous fournira un service type LoadBalancer
avec une IP dédiée.
Pour utiliser ExternalIP, vous devez router une adresse vers vos workers Kubernetes et ensuite créer un service comme ceci :
apiVersion: v1
kind: Service
metadata:
labels:
svc: nginx-ingress
name: nginx-ingress
spec:
clusterIP: 10.32.35.129
externalIPs:
- 192.51.100.1
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
svc: nginx-ingress
type: ClusterIP
Si je route l’IP 192.51.100.1
vers mes nodes k8s, des règles IPTables (crées par kube-proxy) vont « catcher » le traffic vers cette IP et l’envoyer vers mon service « nginx-ingress » port 80.
4. Utiliser TLS au maximum
Pour sécuriser les communications internes au cluster, il peut être intéressant d’utiliser TLS de bout en bout dans les applications que vous déployez.
Un premier point serait d’exposer le service de votre pod avec du TLS. Donc si vous avez un service HTTP dans votre container, pourquoi pas ajouter des certificats et forcer les communications en HTTPS.
Le second point serait d’exposer ce service HTTPS avec une Ingress intégrant également des certificats TLS, cela permet de faire du HTTPS de votre Ingress-Controller à vos pods.
Pour cela il va falloir créer un secret avec kubectl :
kubectl -n default create secret tls pod1-tls --key privkey.pem --cert fullchain.pem
Vous pouvez désormais créer une ressource ingress avec certificat TLS :
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: pod1
namespace: default
annotations:
nginx.org/ssl-services: "pod1"
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- pod1.example.com
secretName: pod1-tls
rules:
- host: pod1.example.com
http:
paths:
- path: /
backend:
serviceName: pod1
servicePort: 443
Comme vous le voyez, le service pod1
est exposé en HTTPS de bout en bout.
Il est également important d’utiliser TLS au maximum dans les communications internes ou entre éléments du cluster. Par exemple on peut configurer Helm pour n’être joint qu’avec chiffrement TLS.
5. Suivre les logs de vos pods
Pour déboguer une application composée de plusieurs micro-services, il est parfois nécessaire de lancer plusieurs commandes kubectl logs -f afin de suivre les logs de plusieurs pods.
Pour régler ce problème, un script shell nommé kubetail permet de suivre les logs d’un namespace, d’un deployement (plusieurs pods) ou d’autres ressources.
Pour l’installer,
wget https://raw.githubusercontent.com/johanhaleby/kubetail/master/kubetail
chmod +x kubetail && mv kubetail /usr/local/bin
Imaginez que vous avez un deployment nginx
scallé à 10 pods. Pour suivre les logs de ces 10 pods simultanément, on peut utiliser cette commande :
kubetail nginx -n my-namespace
6. Nettoyer votre cluster
Faire du déploiement en continu sur Kubernetes est super, mais cela créer beaucoup de résidus d’images Docker, qui, si l’on ne fait rien grossit sur le file-system de vos workers.
Une bonne pratique, pour éviter d’impacter l’hôte Linux en cas de remplissage, est de séparer la partition Docker du reste du système (par défaut, /var/lib/docker
).
Un second point serait d’automatiser le nettoyage de vos workers avec des crons, un gestionnaire de configuration ou une meilleure approche, Kubelet directement.
Une dernière chose qui peut grossir dans votre cluster, c’est le nombre de ReplicasSets généré par les mises à jours de vos Deployments. À chaque changement d’image ou de variable, Kubernetes créer un nouveau ReplicasSet pour cette configuration. Pour régler cela et limiter la taille maximum, on peut utiliser .spec.revisionHistoryLimit
dans la configuration de notre Deployment.
Si vous utilisez Helm en production, vous devez constater que à chaque mise à jour de votre charte, Helm vous créer un ConfigMap qui correspond à la définition de votre Release en cour.
Si votre application connait beaucoup de déploiements, on peut vite se retrouver avec des centaines de ConfigMaps
. Pour limiter cela, on peut limiter la quantité de ressources :
helm init --history-max 50
7. NetworkPolicies avec Calico
Calico
est un outil qui se présente comme Secure networking for the cloud native era
.
Il est compatible avec Kubernetes et ajoute plein de fonctionnalités utiles :
- Règles de networking fines
- Réseau routé entre les workers
- BGP avec vos routeurs pour désactiver le NAT (si besoin)
- IPv6 pour vos Pods
- Gestion de plusieurs IPPools
Si vous avez un cluster Kubernetes avec Calico, vous pouvez restreindre les communications vers et hors des pods d’un namespace avec une unique ressource :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Si vous créez un pod et un service Nginx dans le namespace default. Personne ne peut le joindre à cause de la ressource default-deny.
Si vous voulez y autoriser l’accès, il faudra définir une NetworkPolicy
comme ceci :
kind: NetworkPolicy
apiVersion: extensions/v1beta1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
run: nginx
ingress:
- from:
- podSelector:
matchLabels: {}
Avec ces ressources, vous pouvez définir clairement quel pod peut parler à quel pod. Si vous souhaitez installer Calico dans votre cluster, je vous laisse jeter un coup d’œil à la documentation.
8. Utiliser RBAC
RBAC (Roles based authentification control) est le meilleur moyen de contrôler qui accède à quoi dans votre cluster.
Pour activer RBAC, vous devez rajouter un paramètre dans votre API server :
--authorization-mode=RBAC
Avec RBAC d’activé, si vous souhaitez avoir des utilisateurs admins, il faut les mettre dans le group system:masters
.
Pour par exemple, créer un utilisateur developer
restreint dans le namespace dev
, vous allez devoir créer un Role
et un RoleBinding
:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: dev
name: role-developer
rules:
- apiGroups: ["*"] # "" indicates the core API group
resources: ["*"]
verbs: ["*"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: rolebinding-developer
namespace: dev
subjects:
- kind: User
name: developer
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: role-developer
apiGroup: rbac.authorization.k8s.io
RBAC vous permet ainsi de définir finement les droits de vos utilisateurs dans Kubernetes. Pour aller plus loin, je vous invite à regarder la documentation officielle.
9. Interaction avec le cluster
Il y a beaucoup de moyens d’interagir avec un cluster Kubernetes. Le plus commun est bien sûr kubectl ou le dashboard de Kubernetes, mais il en existe d’autres qui peuvent vous faciliter la vie.
I- k9s
k9s est un outil en ncurses qui s’exécute dans votre terminal et permet d’administrer votre cluster de manière dynamique en ayant rapidement accès aux logs (l), à la description (d) ou à la suppression d’une ressource (Ctrl+d).
2- ViKube
ViKube est un plugin pour l’éditeur de texte (et pas que !) qui permet d’interagir avec votre cluster depuis votre éditeur préféré.
Vous pourrez décrire, afficher les logs, supprimer et bien plus depuis votre Vim !
3- Zsh prompt
zsh-kubectl-prompt permet d’afficher le context et le namespace de Kubernetes configuré dans votre shell. Ce plugin pour Zsh (des équivalents pour bash doivent exister) permet par exemple de ne pas supprimer le namespace kube-system dans son cluster de production par erreur.
4- Cabin
Cabin est une application mobile pour Kubernetes (et surement la plus aboutie). Elle permet de se connecter à plusieurs clusters, d’afficher tout les types de ressources ainsi que les décrire et les administrer (par exemple, scaller un deployment).
Disponible sur iOS et Android, cette app vous permet de scaller votre appli à 1000 replicas depuis le métro à l’instant même ou votre Startup passe au journal de 20h.
5- Kubernetic
Kubernetic est une application graphique (Windows, Mac et Linux) permettant d’administrer votre cluster Kubernetes. Très simple d’utilisation, il peut être un vrai plus pour débuter sur l’administration de cluster.
Attention, Kubernetic ne semble pas être un outil open-source.
Be First to Comment