Meilleures pratiques Kubernetes. Créer 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 vous pouvez créer une image d'un petit récipient sûr.
Grâce à Docker, la création d'images de conteneurs n'a jamais été aussi simple. Spécifiez l'image de base, ajoutez vos modifications et créez un conteneur.



Malgré le fait que cette technique soit idéale pour commencer, l'utilisation d'images de base par défaut peut conduire à un travail non sécurisé avec de grandes images pleines de vulnérabilités.

De plus, la plupart des images de Docker sont utilisées pour une image de base Debian ou Ubuntu, et bien que cela offre une excellente compatibilité et une adaptation 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 de l'application Go hello-world prend environ 700 mégaoctets, tandis que la taille de votre application elle-même n'est que de quelques mégaoctets.



Ainsi, toute cette charge supplémentaire est un gaspillage d'espace numérique et un excellent cache pour les vulnérabilités et les erreurs du système de sécurité. Examinons donc deux façons de réduire la taille d'une image de conteneur.

Le premier est l'utilisation d'images de base de petite taille, le second est l'utilisation du modèle de conception Builder Pattern. L'utilisation d'images de base plus petites est probablement le moyen le plus simple de réduire la taille de votre conteneur. Très probablement, votre langue ou la pile que vous utilisez fournit une image d'application originale qui est beaucoup plus petite que l'image par défaut. Jetons un coup d'œil à notre conteneur node.js.



Par défaut, dans Docker, la taille de l'image du noeud de base: 8 est de 670 Mo et la taille du noeud: 8 alpin n'est que de 65 Mo, soit 10 fois plus petite. L'utilisation de l'image de base alpine plus petite réduira considérablement la taille de votre conteneur. Alpine est une distribution Linux petite et légère qui est très populaire auprès des utilisateurs Docker car elle est compatible avec de nombreuses applications, tout en conservant la petite taille des conteneurs. Contrairement à l'image standard du «nœud» Docker, «nœud: alpin» supprime de nombreux fichiers et programmes utilitaires, ne laissant que ceux qui sont suffisants pour exécuter votre application.

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



Maintenant, contrairement à l'ancienne image onbuild, vous devez copier votre code dans le conteneur et installer toutes les dépendances. Dans le nouveau fichier Docker, le conteneur commence par l'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 démarre server.js.



Avec cette mise à jour, un conteneur est 10 fois plus petit. Si votre langage de programmation ou votre pile n'a pas la capacité de réduire l'image de base, utilisez Alpine Linux. Il offrira également la possibilité de gérer entièrement le contenu du conteneur. L'utilisation d'images de base de petite taille est un excellent moyen de créer rapidement de petits conteneurs. Mais vous pouvez obtenir une réduction encore plus importante en utilisant le modèle de générateur.



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 vraiment nécessaires pour exécuter le code. Cela signifie que vous pouvez retirer complètement ces outils du conteneur final. Vous pouvez utiliser le modèle Builder pour cela.



Le code est créé dans le premier conteneur et compilé. Ensuite, le code compilé est empaqueté dans le conteneur final sans les compilateurs et les outils nécessaires pour compiler ce code. Ignorons l'application Go à travers ce processus. Tout d'abord, nous passerons de l'image onbuild à Alpine Linux.



Dans le nouveau fichier Docker, le conteneur commence par l'image golang: alpine. Il crée ensuite un répertoire pour le code, le copie dans le code source, crée ce code source et lance 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. Extrayons donc le programme compilé et mettons-le dans notre propre conteneur.



Vous pouvez remarquer quelque chose d'étrange dans ce fichier Docker: il contient deux lignes FROM. La première section de 4 lignes ressemble exactement au fichier Docker précédent, sauf qu'elle utilise le mot clé AS pour nommer cette étape. Dans la section suivante, il y a une nouvelle ligne FROM qui vous permet de démarrer une nouvelle image, et au lieu de l'image golang: alpine, nous utiliserons Raw alpine comme image de base.

Raw Alpine Linux n'a pas de certificats SSL installés, ce qui entraînera l'échec de la plupart des appels API HTTPS, alors installons certains certificats racine CA.

Et maintenant le plus intéressant: pour copier le code compilé du premier conteneur vers le second, vous pouvez simplement utiliser la commande COPY située sur la 5ème ligne de la deuxième section. Il ne copiera qu'un seul fichier d'application et n'affectera pas les outils de l'utilitaire Go. Le nouveau fichier Docker en plusieurs étapes contiendra une image de conteneur de seulement 12 mégaoctets, tandis que l'image de conteneur d'origine était de 700 mégaoctets, et c'est une grande différence!
Ainsi, l'utilisation de petites images de base et de modèles de générateur est un excellent moyen de créer des conteneurs beaucoup plus petits sans beaucoup 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 ont-ils vraiment un avantage mesurable? Examinons deux aspects où les petits conteneurs sont extrêmement efficaces - performances et sécurité.

Pour évaluer l'augmentation des performances, tenez compte de la durée du processus de création d'un conteneur, de son insertion dans le registre (push), puis de sa récupération (pull). Vous pouvez voir qu'un petit conteneur a un avantage indéniable sur un plus grand conteneur.



Docker mettra en cache les couches, donc les builds suivants seront très rapides. Cependant, dans de nombreux systèmes CI utilisés pour créer et tester des conteneurs, les couches ne sont pas mises en cache, ce qui permet de gagner beaucoup de temps. Comme vous pouvez le voir, le temps de construction d'un grand conteneur, en fonction de la puissance de votre machine, est de 34 à 54 secondes, et lorsque vous utilisez un conteneur réduit avec le modèle Builder, de 23 à 28 secondes. Pour des opérations de ce type, les gains de productivité seront de 40 à 50%. Pensez donc combien de fois vous créez et testez votre code.

Une fois le conteneur construit, vous devez insérer son image (image de conteneur push) dans le registre des conteneurs afin d'utiliser Kubernetes dans votre cluster. Je recommande d'utiliser le registre des conteneurs Google.



En utilisant le Google Container Registry (GCR), vous ne payez que pour le stockage brut et le réseau, et il n'y a pas de frais de gestion de conteneur supplémentaires. Il est confidentiel, sécurisé et très rapide. GCR utilise de nombreuses astuces pour accélérer l'opération de traction. Comme vous pouvez le voir, l'insertion d'une image de conteneur Docker Container Image à l'aide de go: onbuild, en fonction des performances de l'ordinateur, prendra de 15 à 48 secondes, et la même opération avec un conteneur plus petit prendra de 14 à 16 secondes, et pour les machines moins efficaces, l'avantage de la vitesse de fonctionnement augmente de 3 fois. Pour les grandes machines, le temps est approximativement le même, car GCR utilise le cache global pour une base de données d'images commune, c'est-à-dire que vous n'avez pas du tout besoin de les télécharger. Dans un ordinateur à faible consommation, le processeur est un goulot d'étranglement,par conséquent, l'avantage d'utiliser de petits conteneurs ici est beaucoup plus tangible.

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



Comme vous pouvez le voir, 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 avec une machine productive - dans ce cas, le processus de construction et d'envoi de conteneurs à l'hôte est presque 2 fois plus rapide. De plus, chaque jour, vous bénéficiez de 120 minutes d'assemblage gratuites, ce qui dans la plupart des cas répond aux besoins de création de conteneurs.

Vient ensuite la mesure de performance la plus importante - la vitesse à laquelle vous récupérez ou téléchargez des conteneurs Pull. Et si vous ne vous souciez pas vraiment du temps passé sur l'opération de poussée, la durée du processus de traction affecte sérieusement les performances globales du système. Supposons que vous ayez un cluster de trois nœuds et que l'un d'eux se bloque. Si vous utilisez un système de gestion, tel que Google Kubernetes Engine, il remplacera automatiquement le nœud inactif par un nouveau. Cependant, ce nouveau nœud sera complètement vide et vous devrez y faire glisser tous vos conteneurs pour le faire fonctionner. Si l'opération d'extraction est suffisamment longue, alors tout ce temps, votre cluster fonctionnera avec des performances inférieures.

Il existe de nombreux cas où cela peut se produire: ajouter un nouveau nœud à un cluster, mettre à jour les nœuds ou même basculer vers un nouveau conteneur pour le déploiement. Ainsi, minimiser le temps d'extraction de traction devient un facteur clé. Il est incontestable qu'un petit conteneur se télécharge beaucoup plus rapidement qu'un grand. Si vous utilisez plusieurs conteneurs dans un cluster Kubernetes, le gain de temps peut être très important.



Jetez un œil à la comparaison: l'opération de traction lorsque vous travaillez avec de petits conteneurs prend 4 à 9 fois moins de temps en fonction de la puissance de la machine que la même opération avec go: onbuild. L'utilisation d'images de base courantes de petits conteneurs accélère considérablement le temps et la vitesse avec lesquels les nouveaux nœuds Kubernetes peuvent se déployer et se connecter.

Examinons la question de la sécurité. On pense que les petits conteneurs sont beaucoup plus sûrs que les grands conteneurs 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 pour détecter les vulnérabilités. Il y a quelques mois, j'ai créé des conteneurs onbuild et multi-stage, alors voyons s'il y a des vulnérabilités.



Le résultat est étonnant: seulement 3 vulnérabilités moyennes ont été trouvées dans un petit conteneur, et 16 vulnérabilités critiques et 376 autres vulnérabilités dans un grand. Si vous regardez le contenu d'un grand conteneur, vous pouvez 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. Donc, quand les gens parlent d'une grande surface d'attaques, cela signifie exactement cela.



La conclusion est évidente: créez de petits conteneurs car ils apportent de réels bénéfices dans les performances et la sécurité de votre système.

Meilleures pratiques Kubernetes. Organisation Kubernetes avec espace de noms


Un peu de publicité :)


Merci de rester avec nous. Aimez-vous nos articles? Vous voulez voir des matériaux plus intéressants? Soutenez-nous en passant une commande ou en recommandant à vos amis, le cloud VPS pour les développeurs à partir de 4,99 $ , un analogue unique de serveurs d'entrée de gamme que nous avons inventé pour vous: Toute la vérité sur VPS (KVM) E5-2697 v3 (6 cœurs) 10 Go DDR4 480 Go SSD 1 Gbit / s à partir de 19 $ ou comment diviser le serveur? (les options sont disponibles avec RAID1 et RAID10, jusqu'à 24 cœurs et jusqu'à 40 Go de DDR4).

Dell R730xd 2 fois moins cher au centre de données Equinix Tier IV à Amsterdam? Nous avons 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 sur la création d'un bâtiment d'infrastructure. classe c utilisant des serveurs Dell R730xd E5-2650 v4 coûtant 9 000 euros pour un sou?

All Articles