Appliquer Lexpage tous les jours rend votre poil plus soyeux et votre haleine plus fraîche.    —  Mythrandil

Discussions

Amazon Web Services / Heroku

Guybrush 8342 Bob
Reprise automatique du message précédent.
On en avait déjà parlé brièvement, mais est-ce que certains ici ont une expérience avec Docker ?

Je me suis tapé une large partie de leur documentation, et il est probable que je fasse mes premiers pas avec demain (j'ai un hexacore avec 32go de RAM qui me sert de serveur de test à l'unif, et le biologiste avec qui je travaille, qui est aussi un informaticien curieux, s'intéresse à Docker. C'est donc l'occasion de s'y mettre).

En particulier, une idée de la "difficulté" de migrer une infrastructure existante dans des containers ? Si mes essais s'avèrent concluants, je compte migrer Lexpage & co dans des containers... Mais j'ai encore un peu de mal à voir comment "tout doit être idéalement décomposé".

Notamment, sur le VPS, j'ai actuellement un Nginx, et 3 applications (enfin, 3 types d'applications) derrière : du Django (servi via Gunicorn en WSGI, via socket), du PHP (servi via FPM, je pense que c'est du wsgi aussi via socket) et du NodeJS (servi directement, Nginx ne sert que de proxy + fichiers statiques).

Est-ce qu'il vaut mieux :
- Un container par application, avec un Nginx "local" + un container "Nginx frontal" qui fait le dispatch ? Cela me permet d'avoir une application "auto-contenue" dans son container, mais nécessite un Nginx supplémentaire par application...
- Un container par application, avec un Nginx frontal dans un container, qui communique/redirige via socket (ou autre) avec les autres containers. Dans ce cas, le container "frontal" aura une connaissance plus complète des applications derrières (notamment pour servir les fichiers statiques). C'est une sorte de "clone mais sous container" de la configuration actuelle, mais cela signifie que mon frontal ne fait pas que du proxy, et qu'une partie de la "logique" de l'application (les fichiers statiques, typiquement, ainsi que l'upload, etc. etc.) ne se trouve pas dans le container de cette application. Vraiment, les fichiers statiques font un peu chier :-D

Et aussi, est-ce qu'il est préférable de :
- Charger une image, et dans le container, faire la configuration puis sauver tout ça sous forme d'image (en gros, ça devient mon "environnement" que je peux cloner) ou;
- Créer un Dockerfile sur base d'une image existante et scripter la configuration là-dedans, afin d'avoir le "minimum" de modifications dans l'image de base ?

Le premier cas est plus simple (en gros, une sorte de VM). Le deuxième me semble plus propre, car l'image de base est conservée. L'avantage est qu'il est facilement possible de mettre à jour l'image de base sans perdre la configuration. Au final, de toute façon, les deux approches fournissent exactement la même image ...


Ce message a été modifié 2 fois. Dernière modification : 11 février 2015 à 11:47 par Guybrush.

Fabe 607 Geek
GuybrushEt aussi, est-ce qu'il est préférable de :
- Charger une image, et dans le container, faire la configuration puis sauver tout ça sous forme d'image (en gros, ça devient mon "environnement" que je peux cloner) ou;
- Créer un Dockerfile sur base d'une image existante et scripter la configuration là-dedans, afin d'avoir le "minimum" de modifications dans l'image de base ?
Fais un Dockerfile, c'est toujours plus simple de maintenir et partager un script qu'une image. De plus, en clonant le projet, tout est à disposition pour créér et instancier l'image, pas besoin d'indiquer un registry à toi si ton image n'est pas sur le central ou de la partager autrement.

Dans ton cas et dans une optique de "KISS", si tes trois composants applicatifs ne forment qu'une seule et même application, j'aurais mis les trois composants dans le même conteneur.
Un conteneur par application n'est utile que si chaque application peut être déployée indépendamment des autres (dans une architecture orientée service par exemple).

Si les trois applis n'ont rien à voir entre elles à part le fait d'être hébergées au même endroit, un conteneur par appli est OK. Note que si PHP ne te sert que pour Piwik, il y a déjà pas mal de conteneur sur le Docker Hub Registry qu'il ne reste qu'à configurer, la bonne pratique serait de ne pas en faire un nouveau :)
Guybrush 8342 Bob
Ok :-) Oui, la partie PHP ne sert que pour Piwik :-D Pour les différents "composants", ils ne servent pas la même application. Je suppose que le container contenant Lexpage devrait se limiter à Django + Gunicorn, et ne pas aller plus loin, par exemple. Un autre container, frontal, servira Nginx. Reste à voir comment servir les fichiers statiques depuis le container frontal, pour des questions de performances. J'imagine qu'un volume partagé devrait faire l'affaire, mais je ne suis pas encore à l'aise avec tout ça.

D'ailleurs, niveau persistance en général, j'ai encore un peu de mal :
- Si je comprends bien, le contexte du container est peuplé sur base du répertoire local lors du lancement du container. On peut monter ce contexte n'importe où dans le container ? C'est du "symetric data-binding", je suppose ?
- J'ai lu qu'on pouvait aussi monter n'importe quel répertoire/fichier vers n'importe quel emplacement dans un container. C'est aussi dans "les deux sens" ?
- Cette histoire de volume, c'est pour pouvoir se créer un "pseudo filesystem" que l'on va pouvoir partager entre plusieurs containers ? Par exemple, créer un container-volume avec les fichiers statiques dans le container "Django+Gunicorn" et le partager avec le container frontal Nginx ?

Si j'ai bien compris, le système de fichiers local d'un container est perdu quand le container est "mis à jour" (pull/checkout de l'image) ? Dans ce cas, la seule façon de ne pas risquer de perdre ses données, si on a un container "database" par exemple, c'est de monter un volume ou un FS là ou la db va typiquement stocker ses données, ou alors la politique/bonne habitude consiste à se dire qu'on ne va pas faire un pull/checkout sur l'image ?

En gros, est-ce qu'il parait concevable (et prudent ?) que les données persistées le soient "uniquement dans l'image", ou alors il vaut mieux binder ça avec le FS de l'hôte ?
Fabe 607 Geek
Guybrush
En gros, est-ce qu'il parait concevable (et prudent ?) que les données persistées le soient "uniquement dans l'image", ou alors il vaut mieux binder ça avec le FS de l'hôte ?
Définitivement, créér un volume avec le FS de l'hôte. Un conteneur est volatile par définition.
Typiquement chez nous on a deux répertoires montés comme volumes /var/lib/mysql sur les conteneurs BDD et /var/www/<nom de l'app> sur les conteneurs applis.
Les volumes sont toujours en "two ways", à l'époque où Docker ne fonctionnait qu'au dessus de LXC, j'aurais affirmé avec une quasi certitude que c'était le même répertoire physique (lien symbolique ? autre type de référencement au niveau inode ?) mais je n'ai jamais cherché à savoir ce qu'il y avait sous le capot. En simplifiant, le FS d'un conteneur est juste un chroot du FS de l'hôte.

Par contre monter le même répertoire sur deux conteneurs, ça va marcher, mais je trouve ça louche comme besoin, ça ressemble quand même un peu à une seule appli :)
Guybrush 8342 Bob
J'y vois déjà plus clair (et notamment parce que je viens de me taper une bonne dizaine d'articles sur des blogs sur cette "problématique", qui apparemment est en général mal comprise par les nouveaux venus, ce que je peux confirmer dans mon cas :-D).

En fait, c'est la notion même de "volume" qui n'est pas toujours claire dans la doc. Je viens seulement de comprendre qu'un "espace de stockage" peut se monter de plusieurs façons :
- Soit via un simple -v /path/to/dir/ lors du run, et dans ce cas, le container aura son /path/to/dir qui va pointer implicitement vers le FS hôte, qqchose du genre /var/docker/volume/super_uuid_du_volume.
- Soit via -v /host/path:/target/path (ou l'inverse ? ^^) qui va rendre dispo /host/path de l'hôte dans le container, à l'emplacement /target/path.
- Soit via --volume-from container_name. Dans ce cas, si container_name était un container qui avait été lancé avec un -v (ou dont l'image a été créée avec un VOLUME comme paramètre), ces différents volumes (qui en réalité sont stockés sur l'hôte quelque part dans /var/docker/volume/super_uuid_du_volume) seront tous disponibles aussi dans le container nouvellement lancé.

Je ne sais pas si les volumes sont conservés quand tous les containers qui en font usage sont supprimés ou pas, mais il semble que le pattern classique consiste à créer un container "data-only" qui utilisera ce volume, comme ça on distingue clairement les données de l'app (via ce container data-only) et l'application (via son propre container). Cela permet aussi de partager les données facilement (il suffit de faire un --volume-from mon_container_data_only).

Je peux donc facilement migrer, par exemple, mon MariaDB sur le VPS dans un container :
- J'installe docker, j'installe une image contenant MariaDB.
- Je crée un container "data-only" avec un volume "/var/lib/mysql"
- Je copie le contenu de mon /var/lib/mysql de l'hôte dans /var/docker/volume/le_super_uuid_du_volume_associe_a_data_only/ --> on peut faire ça ? Quid du type de filesystem ? Des droits ? etc. ? Ou alors il faut monter temporairement /var/lib/mysql local vers un /tmp du container, faire la copie dans le container du contenu de /tmp vers /var/lib/mysql du container (le vrai volume, en gros) ?
- Je lance mon container mariadb en --volume-from data-only

Je suis dans le bon ? :-)


Ce message a été modifié 1 fois. Dernière modification : 11 février 2015 à 14:59 par Guybrush.

Guybrush 8342 Bob
Une question un peu naïve sur l'organisation des containers : si j'ai deux applications web A et B qui tournent derrière un Nginx. Quelle configuration adopter ?

1) Un container pour A, un container pour B, un container pour Nginx configuré pour servir A et B (fichiers statiques de A et B dans ce container).

2) Un container pour A, avec un Nginx. Un container pour B avec un Nginx et un container pour le Nginx frontal, configuré comme proxy pour le Nginx de A, et comme proxy pour le Nginx de B.

Je sais que Nginx a une très faible empreinte mémoire, je suppose donc que ça ne doit pas être un gros problème d'en booter plusieurs sur une même machine. En ayant un Nginx dans chaque container pour A et B, cela me permet de localement (dans A et dans B) gérer les fichiers statiques, et donc d'avoir un vrai container "auto-contenu" pour l'application A et pour l'application B.


3) Approche "vraiment micro-services" sur base de (1) : un container pour les données de A, un container pour les données de B, un container pour le WSGI de A avec volume data-A, un container pour le WSGI de B avec volume data-B, un container avec un Nginx frontal utilisant les volumes data-A et data-B pour servir les statiques.

4) Approche "vraiment micro-services" sur base de (2) : un container pour les données de A, un container pour les données de B, un container pour le WSGI de A avec volume data-A, un container pour le WSGI de B avec volume data-B, un container avec un Nginx pour A, un container avec un Nginx pour B, et enfin un container frontal.

Quelle est la granularité idéale à apporter aux containers ? J'ai cru comprendre "un container = une application", mais de nombreux exemples poussent la décomposition à l'extrême. Je vois mal ce que ça apporte réellement, si ce n'est le plaisir de factoriser au possible.

Je me renseigne sur Fig et les alternatives, mais est-ce qu'il y a des outils à la supervisord pour gérer le maintien de tout ça en mémoire ? Vu qu'on peut lancer un container en daemon, j'imagine que ça doit être possible, mais avec des dépendances parmi les containers, ça ne devient pas vite une horreur à gérer ? (Et là, j'imagine qu'on évite d'utiliser des trucs genre Fabric pour gérer le déploiement des containers, sinon on ne gagne pas grand chose, si ce n'est le coté "environnement virtuel", ce qui est déjà pas mal en soi).
pom 145 Padawan
Dans notre jargon chez nous, on parle de nœuds applicatifs. Une instance de tomcat, c'est un NA. Un apache, c'est un NA. Une base de donnée Oracle, aussi. Mais attention au piège, 2 webapps sur une même instance de tomcat ne font qu'un NA. Pour un apache avec PHP (ou python), ça ne fait qu'un nœud aussi. J'imagine qu'un répartiteur de charge serait aussi un NA à part entière. Et ce sont ces nœuds qui me semblent être désignés pour être des containers docker.

Ensuite, les containers de data c'est pour rendre les données persistantes, ce n'est pas pour le code (le code n'a pas besoin d'être persisté puisqu'il est censé être sous contrôle de source). Le code (ou les ressources statiques) ça devrait être dans des volumes que tu donnes en paramètres à ton container et pointant vers un répertoire physique de la machine hôte. Pour mon container tomcat, je vois bien lui mettre en paramètre le répertoire target de mon projet eclipse (qui construit via Maven un war).

Guybrush 8342 Bob
pomDans notre jargon chez nous, on parle de nœuds applicatifs. Une instance de tomcat, c'est un NA. Un apache, c'est un NA. Une base de donnée Oracle, aussi. Mais attention au piège, 2 webapps sur une même instance de tomcat ne font qu'un NA. Pour un apache avec PHP (ou python), ça ne fait qu'un nœud aussi. J'imagine qu'un répartiteur de charge serait aussi un NA à part entière. Et ce sont ces nœuds qui me semblent être désignés pour être des containers docker.
Ok. Je suppose que l'argument clé pour séparer tout ça, c'est le fait que seule une commande peut être "démonisée" dans le container pour que ce dernier soit maintenu. Par contre, j'ai encore du mal à voir si Docker doit être utilisé plutôt pour "virtualiser" l'environnement, tout en récupérant certaines "configurations par défaut" via les images disponibles publiquement, ou si l'usage est plutôt de pousser l'autre extrême, et de configurer un container de façon tellement spécifique qu'il n'y a pratiquement plus qu'à "cliquer sur un bouton" (on se comprend) pour que l'application contenue soit lancée. En fait, j'ai du mal à identifier quels sont les "paramètres" (dans le sens configuration) qu'il vaut mieux enregistrer dans son container, ou passer lors du lancement du container.

Par exemple, un mysql.conf, on le modifie dans le container et on commit le container sous forme d'image (pour pouvoir déployer cette image partout où on en a besoin), ou bien est-ce qu'on garde un container "mysql sans aucune configuration spécifique", et lors du lancement du container, on lui monte un mysql.conf à la volée ?

Les deux approches me semblent appréciables : la première permet d'avoir une image "toute prête", qu'il suffit de déployer. La seconde permet d'avoir une image prête, qui ne nécessite qu'un fichier de config spécifique à l'environnement dans lequel le container va être lancé.

Pour cet exemple, l'impact n'est pas important. Mais si je parle d'un serveur Nginx, par exemple, devant servir plusieurs applications à priori sans lien, ça l'est : dans le premier cas, je ne peux déployer l'image que sur le serveur de prod, sauf si je suis prêt à déployer toutes mes applications en dev alors que je n'en touche qu'une seule. Dans le second cas, par contre, il me faudra chipoter pas mal pour réussir à merger plusieurs configurations potentielles (bon, ok, le cas de Nginx n'est pas représentatif puisqu'on a plusieurs fichiers de conf distincts pour faire ça :-D).

D'où l'idée, vu la faible empreinte de Nginx, d'avoir un container "frontal" que je "configure à la main" (je me connecte dessus et je modifie le ng.conf en fonction de ce que je dois servir) et d'avoir, derrière, un container par application (quitte à avoir un autre nginx dans certains de ces containers, je ne crois pas que ça soit anormal de chaîner les nginx ^^).

Vraiment, mon gros problème avec Docker, c'est que je suis convaincu que c'est sympa d'avoir un peu de "virtualisation" des environnements, mais on te "vend" Docker comme étant aussi un truc où tu peux jouer avec des Lego pour assembler ton environnement final, et j'ai du mal à identifier ce qui constitue la "brique" (tu y as déjà répondu partiellement) et comment gérer la configuration de chaque brique, pour ne pas avoir à repartir à 0 à chaque fois (et ne pas avoir à gérer 30 fichiers de configuration pour chaque application et chaque environnement dans lequel le container va prendre place.

Par ex, pour Nginx, il est clair que je ne vais pas fixer un server_name à www.lexpage.net sur ma machine de test... (cela dit, si chaque application tourne dans un container avec son propre nginx, ce dernier peut simplement fixer le server_name à _ (tout) et c'est le container frontal qui s'occupera du dispatch. Et en développement, il me suffit juste de lancer le container spécifique à l'application).
pomEnsuite, les containers de data c'est pour rendre les données persistantes, ce n'est pas pour le code (le code n'a pas besoin d'être persisté puisqu'il est censé être sous contrôle de source). Le code (ou les ressources statiques) ça devrait être dans des volumes que tu donnes en paramètres à ton container et pointant vers un répertoire physique de la machine hôte. Pour mon container tomcat, je vois bien lui mettre en paramètre le répertoire target de mon projet eclipse (qui construit via Maven un war).
Ok, je pense avoir bien compris :-)

Il faudrait que je pense aussi à faire en sorte que mes applications ne nécessitent pas d'avoir les passwords hardcodés dans les fichiers de conf (par ex, sous NodeJS, les paramètres SMTP. Sous Django-Lexpage, c'est la db, le smtp et la secret_key). J'ai vu qu'une pratique courante consistait à placer ça dans des variables d'environnement. Mais qu'est-ce que ça change ? Parce que les variables d'environnement, on va les peupler au lancement du serveur via un fichier de conf ou un script... qui contiendra donc les passwords hardcodés, non ?

Si je comprends bien, l'objectif n'est pas d'éviter que ces passwords soient hardcodés "trop facilement" quelque part, mais plutôt de faire en sorte que si on bundle l'application quelque part (au hasard, un dépot git public), que les passwords de prod ne soient pas visibles, mais restent tout de même disponibles (en prod). Auquel cas, vous faites quoi pour "archiver/version-controler" votre configuration serveur ? Un git privé ?).
pom 145 Padawan
Je te conseille cette petite vidéo (même si ça ne répondra pas à tes questions précises). Le type est une rock star de l'admin et explique bien les intérêts du projet. Le truc qui tue de le vidéo, c'est . La vitesse de lancement des containers, c'est juste ouf.

Je comprends tes questions et ce que je ferai, c'est d'ajouter une personnalisation dans le docker file quand cette perso est très light, c'est à dire que ça ne mériterait pas de faire une image juste pour ça. Une perso, c'est l'ajout d'un user, la modification de droits, changer son shell, activer/désactiver des services, modifier l'encodage, etc.. Si tu veux ajouter plein de nouveaux rpm dans ce container, là il est peut être plus pertinent de faire une nouvelle image. Et encore, je viens de revoir la vidéo en 34', et en fait même pour lancer un apt-get update, docker est assez malin pour tout garder en cache quand tu adaptes dans un 2ème temps ton docker file. Donc même pour ajouter X rpms, ça (à l'air de) reste(r) très efficace. C'est long la 1ère fois qu'un dev récupère ton docker file et ensuite, tout est buildé sur son poste donc c'est très rapide.

Pour tout ce qui est password, url vers la base de données, etc.. c'est ce que j'appelle de la configuration externe. C'est un terme qu'on utilise chez nous et qui me semble pertinent. C'est pour résumer un type de conf modifiable par les exploitants. Elle s'oppose à la conf interne qui elle, est uniquement connue par les dev et qui ne doit jamais être modifiée. Par exemple, pour Hibernate, j'ai un fichier de conf interne qui tient tout le mapping hbm/java, mes requêtes hql,.. qui ne doit jamais être modifié, sinon ça buguera de partout. En revanche, ma conf externe permet de donner l'url de la base, d'activer ou désactiver ehcache, d'afficher le sql en debug, etc.. Cette partie là peut être modifiée tranquillement par l'exploitant (que ce soit pour la prod ou pour faire des tests particuliers en recette).

J'imagine qu'il faut que cette conf, soit un ensemble de fichier et que tu donnes à ta communauté un exemple de fichiers de config (mais sans les password, charge à tous les dev qui forkent ton projet de remplir pour eux le bon password, la bonne url de sgbd, etc..). Ensuite, tu peux filer ce répertoire de conf sous forme de volume ou bien de container data pour qu'il soit accessible aux N autres containers contenant des services. C'est une hypothèse, hein ;), je l'ai jamais fait. Mais c'est très souple donc on doit pouvoir utiliser les links pour qu'un même container soit connu de tous les autres et partager ainsi de la conf concernant toute ta plateforme et donc partagée à tous tes containers.


Ce message a été modifié 3 fois. Dernière modification : 11 février 2015 à 23:54 par pom.

Tchou 3555 Bob
Je viens de me fader la présentation. Ah ouais, je comprends 'achement mieux l'intérêt du merdier !

Faut que ça murisse, faut que je réfléchisse voir si je peux l'utiliser, mais à un moment, ma tête a explosé devant les possibilités que ça ouvre.
Sysson 1401 Spammeur
C'est vachement cool d'avoir autant de développeurs ici sur Lexpage, et vu que vous êtes emballés tant mieux. Je m'excuse par avance pour la passive aggressivité de mon message, mais j'aimerais des réponses honnêtes.

Perso je suis administrateur système et réseau, et j'utilise des containers en prod depuis des années avec LXC. J'ai très très peur de Docker et du merdier que ça va apporter et je n'ai absolument aucune envie de maintenir un truc aussi bancal sécuritairement. Sans compter le rêve du "ça tourne sur n'importe quel linux, oui oui tant que kernel > 3.8, osef de ta prod actuelle sous debian stable".

Donc s'il vous plait expliquez moi l'intérêt dans la vraie vie, car franchement je ne vois pas ce que ça apporte à du LXC pour de la prod. Pour du dev très clairement je comprend l'intérêt et l'engouement, mais pour packager et livrer... j'en ai des frissons tellement c'est criant de connerie.

Répondre

Vous devez être inscrit et identifié.