Skip to content

Kubernetes – Trucs et astuces

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.

Résultat de recherche d'images pour "git"

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.

Résultat de recherche d'images pour "helm logo"

Une charte Helm classique est composé de :

  • Charts.yaml pour le nom, le tag et la version de votre application
  • templates/ 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.

Résultat de recherche d'images pour "ingress k8s"

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.

Résultat de recherche d'images pour "rbac k8s"

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.

Screenshot

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.

Published inDevOpsKubernetesLinux

Be First to Comment

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Proudly hosted with Open-sources Softwares.