Bonnes pratiques Kubernetes. Création de petits conteneurs

Bonnes pratiques Kubernetes. Création de petits conteneurs

La première étape du déploiement sur Kubernetes consiste à placer votre application dans un conteneur. Dans cette série, nous verrons comment créer une petite image de conteneur sécurisée.
Grâce à Docker, créer des images de conteneurs n'a jamais été aussi simple. Spécifiez une image de base, ajoutez vos modifications et créez un conteneur.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Bien que cette technique soit idéale pour débuter, l’utilisation d’images de base par défaut peut conduire à un travail dangereux avec de grandes images pleines de vulnérabilités.

De plus, la plupart des images de Docker utilisent Debian ou Ubuntu pour l'image de base, et bien que cela offre une excellente compatibilité et une personnalisation facile (un fichier Docker ne prend que deux lignes de code), les images de base peuvent ajouter des centaines de mégaoctets de charge supplémentaire à votre conteneur. Par exemple, un simple fichier node.js pour une application Go « hello-world » fait environ 700 mégaoctets, alors que votre application réelle ne fait que quelques mégaoctets.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Toute cette charge de travail supplémentaire est donc un gaspillage d’espace numérique et une excellente cachette pour les vulnérabilités et les bugs de sécurité. Examinons donc deux façons de réduire la taille d'une image de conteneur.

La première est l’utilisation de petites images de base, la seconde est l’utilisation du Builder Pattern. Utiliser des images de base plus petites est probablement le moyen le plus simple de réduire la taille de votre conteneur. Très probablement, le langage ou la pile que vous utilisez fournit une image d'application originale beaucoup plus petite que l'image par défaut. Jetons un coup d'œil à notre conteneur node.js.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Par défaut dans Docker, la taille de l'image de base node:8 est de 670 Mo et la taille de l'image node: 8-alpine n'est que de 65 Mo, soit 10 fois plus petite. En utilisant l'image de base Alpine plus petite, vous réduirez considérablement la taille de votre conteneur. Alpine est une distribution Linux petite et légère qui est très populaire parmi les utilisateurs de Docker car elle est compatible avec de nombreuses applications tout en gardant les conteneurs petits. Contrairement à l'image "node" standard de Docker, "node:alpine" supprime de nombreux fichiers et programmes de service, ne laissant que ceux qui sont suffisants pour exécuter votre application.

Pour passer à une image de base plus petite, mettez simplement à jour le Dockerfile pour commencer à travailler avec la nouvelle image de base :

Bonnes pratiques Kubernetes. Création de petits conteneurs

Désormais, contrairement à l'ancienne image onbuild, vous devez copier votre code dans le conteneur et installer toutes les dépendances. Dans un nouveau Dockerfile, le conteneur commence par une image node:alpine, puis crée un répertoire pour le code, installe les dépendances à l'aide du gestionnaire de packages NPM et enfin exécute server.js.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Cette mise à niveau aboutit à un conteneur 10 fois plus petit. Si votre langage de programmation ou votre pile ne dispose pas de fonctionnalité de réduction d'image de base, utilisez Alpine Linux. Il offrira également la possibilité de gérer entièrement le contenu du conteneur. L’utilisation de petites images de base est un excellent moyen de créer rapidement de petits conteneurs. Mais une réduction encore plus importante peut être obtenue en utilisant le modèle Builder.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Dans les langages interprétés, le code source est d’abord transmis à l’interpréteur puis directement exécuté. Dans les langages compilés, le code source est d'abord converti en code compilé. Cependant, la compilation utilise souvent des outils qui ne sont pas réellement nécessaires à l'exécution du code. Cela signifie que vous pouvez supprimer complètement ces outils du conteneur final. Vous pouvez utiliser Builder Pattern pour cela.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Le code est créé dans le premier conteneur et compilé. Le code compilé est ensuite regroupé dans un conteneur final sans les compilateurs ni les outils nécessaires pour compiler ce code. Exécutons une application Go via ce processus. Tout d’abord, nous allons passer de l’image onbuild à Alpine Linux.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Dans le nouveau Dockerfile, le conteneur commence par une image golang:alpine. Il crée ensuite un répertoire pour le code, le copie dans le code source, construit ce code source et exécute l'application. Ce conteneur est beaucoup plus petit que le conteneur onbuild, mais il contient toujours le compilateur et d'autres outils Go dont nous n'avons pas vraiment besoin. Alors extrayons simplement le programme compilé et mettons-le dans son propre conteneur.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Vous remarquerez peut-être quelque chose d'étrange dans ce fichier Docker : il contient deux lignes FROM. La première section de 4 lignes ressemble exactement au Dockerfile précédent, sauf qu'elle utilise le mot-clé AS pour nommer cette étape. La section suivante contient une nouvelle ligne FROM pour démarrer une nouvelle image, où au lieu de l'image golang:alpine, nous utiliserons Raw alpine comme image de base.

Raw Alpine Linux n'a aucun certificat SSL installé, ce qui entraînera l'échec de la plupart des appels d'API via HTTPS, installons donc des certificats d'autorité de certification racine.

Vient maintenant la partie amusante : pour copier le code compilé du premier conteneur vers le second, vous pouvez simplement utiliser la commande COPY située à la ligne 5 de la deuxième section. Cela ne copiera qu'un seul fichier d'application et n'affectera pas les outils utilitaires Go. Le nouveau fichier Docker en plusieurs étapes contiendra une image de conteneur d'une taille de seulement 12 mégaoctets, par rapport à l'image de conteneur d'origine qui faisait 700 mégaoctets, ce qui est une grande différence !
Ainsi, l’utilisation de petites images de base et de Builder Pattern constitue un excellent moyen de créer des conteneurs beaucoup plus petits sans trop de travail.
Il est possible qu'en fonction de la pile d'applications, il existe des moyens supplémentaires de réduire la taille de l'image et du conteneur, mais les petits conteneurs présentent-ils vraiment un avantage mesurable ? Examinons deux domaines dans lesquels les petits conteneurs sont extrêmement efficaces : les performances et la sécurité.

Pour évaluer l'augmentation des performances, considérez la durée du processus de création d'un conteneur, de son insertion dans le registre (push), puis de sa récupération à partir de là (pull). Vous pouvez constater qu’un conteneur plus petit présente un net avantage par rapport à un conteneur plus grand.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Docker mettra en cache les couches afin que les versions ultérieures soient très rapides. Cependant, de nombreux systèmes CI utilisés pour créer et tester des conteneurs ne mettent pas de couches en cache, ce qui permet un gain de temps considérable. Comme vous pouvez le constater, le temps de construction d'un grand conteneur, en fonction de la puissance de votre machine, est de 34 à 54 secondes, et lors de l'utilisation d'un conteneur réduit à l'aide du Builder Pattern - de 23 à 28 secondes. Pour des opérations de ce type, l'augmentation de la productivité sera de 40 à 50 %. Pensez donc simplement au nombre de fois que vous créez et testez votre code.

Une fois le conteneur créé, vous devez transférer son image (image du conteneur push) dans le registre des conteneurs afin de pouvoir ensuite l'utiliser dans votre cluster Kubernetes. Je recommande d'utiliser Google Container Registry.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Avec Google Container Registry (GCR), vous ne payez que pour le stockage brut et la mise en réseau, et il n'y a aucun frais de gestion de conteneurs supplémentaires. C'est privé, sécurisé et très rapide. GCR utilise de nombreuses astuces pour accélérer l’opération d’extraction. Comme vous pouvez le constater, l'insertion d'un conteneur Docker Container Image à l'aide de go:onbuild prendra de 15 à 48 secondes, selon les performances de l'ordinateur, et la même opération avec un conteneur plus petit prendra de 14 à 16 secondes, et pour des machines moins productives. l'avantage en termes de vitesse de fonctionnement augmente de 3 fois. Pour les machines plus grandes, le temps est à peu près le même, puisque GCR utilise un cache global pour une base de données d'images partagée, ce qui signifie que vous n'avez pas du tout besoin de les charger. Dans un ordinateur à faible consommation, le processeur constitue le goulot d'étranglement, l'avantage d'utiliser de petits conteneurs est donc bien plus important ici.

Si vous utilisez GCR, je vous recommande fortement d'utiliser Google Container Builder (GCB) dans le cadre de votre système de build.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Comme vous pouvez le constater, son utilisation vous permet d'obtenir de bien meilleurs résultats en réduisant la durée de l'opération Build+Push que même une machine productive - dans ce cas, le processus de construction et d'envoi de conteneurs à l'hôte est accéléré de près de 2 fois. . De plus, vous bénéficiez de 120 minutes de construction gratuites chaque jour, ce qui couvre vos besoins en matière de création de conteneurs dans la plupart des cas.

Vient ensuite la mesure de performance la plus importante : la vitesse de récupération ou de téléchargement des conteneurs Pull. Et si vous ne vous souciez pas beaucoup du temps consacré à une opération push, la durée du processus pull a un impact sérieux sur les performances globales du système. Disons que vous disposez d'un cluster de trois nœuds et que l'un d'eux échoue. Si vous utilisez un système de gestion tel que Google Kubernetes Engine, il remplacera automatiquement le nœud mort par un nouveau. Cependant, ce nouveau nœud sera complètement vide et vous devrez y glisser tous vos conteneurs pour qu'il commence à fonctionner. Si l'opération d'extraction prend suffisamment de temps, votre cluster fonctionnera tout le temps avec des performances inférieures.

Il existe de nombreux cas où cela peut se produire : ajout d'un nouveau nœud à un cluster, mise à niveau de nœuds ou même passage à un nouveau conteneur pour le déploiement. Ainsi, minimiser le temps d’extraction par traction devient un facteur clé. Il est indéniable qu’un petit conteneur télécharge beaucoup plus rapidement qu’un grand. Si vous exécutez plusieurs conteneurs dans un cluster Kubernetes, le gain de temps peut être important.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Jetez un œil à cette comparaison : une opération pull sur de petits conteneurs prend 4 à 9 fois moins de temps, selon la puissance de la machine, que la même opération utilisant go:onbuild. L’utilisation d’images de base de conteneurs partagées et de petite taille accélère considérablement le temps et la vitesse auxquels les nouveaux nœuds Kubernetes peuvent être déployés et mis en ligne.

Examinons la question de la sécurité. Les conteneurs plus petits sont considérés comme beaucoup plus sûrs que les plus grands car ils ont une surface d'attaque plus petite. Est ce que c'est vraiment? L'une des fonctionnalités les plus utiles de Google Container Registry est la possibilité d'analyser automatiquement vos conteneurs à la recherche de vulnérabilités. Il y a quelques mois, j'ai créé des conteneurs onbuild et multistage, voyons donc s'il existe des vulnérabilités.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Le résultat est étonnant : seules 3 vulnérabilités moyennes ont été détectées dans un petit conteneur, et 16 vulnérabilités critiques et 376 autres ont été trouvées dans un grand conteneur. Si nous regardons le contenu d'un grand conteneur, nous pouvons voir que la plupart des problèmes de sécurité n'ont rien à voir avec notre application, mais sont liés à des programmes que nous n'utilisons même pas. Ainsi, lorsque les gens parlent d’une grande surface d’attaque, c’est ce qu’ils veulent dire.

Bonnes pratiques Kubernetes. Création de petits conteneurs

Le point à retenir est clair : construisez de petits conteneurs car ils offrent de réels avantages en termes de performances et de sécurité à votre système.

Bonnes pratiques Kubernetes. Organisation de Kubernetes avec espace de noms

Quelques publicités 🙂

Merci de rester avec nous. Vous aimez nos articles ? Vous voulez voir du contenu plus intéressant ? Soutenez-nous en passant une commande ou en recommandant à vos amis, cloud VPS pour les développeurs à partir de 4.99 $, un analogue unique des serveurs d'entrée de gamme, que nous avons inventé pour vous : Toute la vérité sur le VPS (KVM) E5-2697 v3 (6 Cores) 10Go DDR4 480Go SSD 1Gbps à partir de 19$ ou comment partager un serveur ? (disponible avec RAID1 et RAID10, jusqu'à 24 cœurs et jusqu'à 40 Go de DDR4).

Dell R730xd 2 fois moins cher dans le centre de données Equinix Tier IV à Amsterdam ? Ici seulement 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV à partir de 199$ aux Pays-Bas! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - à partir de 99$ ! En savoir plus Comment construire une infrastructure corp. classe avec l'utilisation de serveurs Dell R730xd E5-2650 v4 qui valent 9000 XNUMX euros pour un sou ?

Source: habr.com

Ajouter un commentaire