Compose: Existe-t-il un moyen de retarder le démarrage du conteneur pour prendre en charge les services dépendants avec un temps de démarrage plus long

Créé le 5 août 2014  ·  314Commentaires  ·  Source: docker/compose

J'ai un conteneur MySQL qui prend un peu de temps à démarrer car il doit importer des données.

J'ai un conteneur Alfresco qui dépend du conteneur MySQL.

Pour le moment, lorsque j'utilise fig, le service Alfresco à l'intérieur du conteneur Alfresco échoue lorsqu'il tente de se connecter au conteneur MySQL ... apparemment parce que le service MySQL n'est pas encore à l'écoute.

Existe-t-il un moyen de gérer ce type de problème dans la Fig?

Commentaire le plus utile

Ouais, je serais intéressé par quelque chose comme ça - destiné à publier à ce sujet plus tôt.

Le plus petit modèle d'impact auquel je puisse penser qui corrigerait ce cas d'utilisation pour nous serait le suivant:

Ajoutez "wait" comme nouvelle clé dans fig.yml, avec une sémantique de valeur similaire à link. Docker traiterait cela comme une condition préalable et attendrait que ce conteneur soit sorti avant de continuer.

Donc, mon fichier docker ressemblerait à quelque chose comme:

db:
  image: tutum/mysql:5.6

initdb:
  build: /path/to/db
  link:
    - db:db
  command: /usr/local/bin/init_db

app:
  link:
    - db:db
  wait:
    - initdb

Lors de l'exécution de l'application, il démarrera tous les conteneurs de liens, puis exécutera le conteneur d'attente et ne progressera vers le conteneur d'application réel qu'une fois le conteneur d'attente (initdb) terminé. initdb exécuterait un script qui attend que la base de données soit disponible, puis exécute toutes les initialisations / migrations / quoi que ce soit, puis se ferme.

Ce sont mes pensées, de toute façon.

Tous les 314 commentaires

Au travail, nous enveloppons nos services dépendants dans un script qui vérifie si le lien est encore actif. Je sais qu'un de mes collègues serait également intéressé par ça! Personnellement, je pense que c'est une préoccupation au niveau du conteneur d'attendre que les services soient disponibles, mais je me trompe peut-être :)

Nous faisons la même chose avec l'emballage. Vous pouvez voir un exemple ici: https://github.com/dominionenterprises/tol-api-php/blob/master/tests/provisioning/set-env.sh

Il serait pratique d'avoir un script de point d'entrée qui boucle sur tous les liens et attend qu'ils fonctionnent avant de lancer la commande qui lui est passée.

Cela devrait être intégré à Docker lui-même, mais la solution est un moyen de s'en sortir. Un conteneur ne doit pas être considéré comme démarré tant que le lien qu'il expose ne s'est pas ouvert.

@bfirsh c'est plus que ce que j'imaginais, mais ce serait excellent.

Un conteneur ne doit pas être considéré comme démarré tant que le lien qu'il expose ne s'est pas ouvert.

Je pense que c'est exactement ce dont les gens ont besoin.

Pour l'instant, j'utiliserai une variante sur https://github.com/aanand/docker-wait

Ouais, je serais intéressé par quelque chose comme ça - destiné à publier à ce sujet plus tôt.

Le plus petit modèle d'impact auquel je puisse penser qui corrigerait ce cas d'utilisation pour nous serait le suivant:

Ajoutez "wait" comme nouvelle clé dans fig.yml, avec une sémantique de valeur similaire à link. Docker traiterait cela comme une condition préalable et attendrait que ce conteneur soit sorti avant de continuer.

Donc, mon fichier docker ressemblerait à quelque chose comme:

db:
  image: tutum/mysql:5.6

initdb:
  build: /path/to/db
  link:
    - db:db
  command: /usr/local/bin/init_db

app:
  link:
    - db:db
  wait:
    - initdb

Lors de l'exécution de l'application, il démarrera tous les conteneurs de liens, puis exécutera le conteneur d'attente et ne progressera vers le conteneur d'application réel qu'une fois le conteneur d'attente (initdb) terminé. initdb exécuterait un script qui attend que la base de données soit disponible, puis exécute toutes les initialisations / migrations / quoi que ce soit, puis se ferme.

Ce sont mes pensées, de toute façon.

(révisé, voir ci-dessous)

+1 ici aussi. Ce n'est pas très attrayant de devoir faire cela dans les commandes elles-mêmes.

+1 aussi. Je viens de rencontrer ce problème. Excellent outil, rend ma vie tellement plus facile!

+1 serait génial d'avoir ça.

+1 également. Récemment rencontré le même ensemble de problèmes

+1 également. une déclaration de dockerguys?

J'écris des scripts wrapper en tant que points d'entrée à synchroniser pour le moment, je ne sais pas s'il est judicieux d'avoir un mécanisme sur la figure si vous avez d'autres cibles pour vos conteneurs qui exécutent l'orchestration d'une manière différente. Cela me semble très spécifique à l'application, en tant que tel, la responsabilité des conteneurs effectuant le travail.

Après réflexion et expérimentations, je suis plutôt d'accord avec cela.

En tant que telle application que je construis a fondamentalement une
waitfor (hôte, port) fonction qui me permet d'attendre les services de l'application
dépend de (détecté via l'environnement ou explicitement
configuration via les options cli).

à votre santé
James

James Mills / prologique

E: [email protected]
W: prologic.shortcircuit.net.au

Le vendredi 22 août 2014 à 18 h 34, Mark Stuart [email protected]
a écrit:

J'écris des scripts wrapper comme points d'entrée à synchroniser pour le moment,
Je ne sais pas s'il est judicieux d'avoir un mécanisme sur la figure si vous avez d'autres cibles pour
vos conteneurs qui exécutent l'orchestration d'une manière différente. Semble très
application qui m'est propre en tant que telle la responsabilité des conteneurs
faire le travail.

-
Répondez directement à cet e-mail ou affichez-le sur GitHub
https://github.com/docker/fig/issues/374#issuecomment -53036154.

Oui, certains "dépendent de" de base nécessaires ici ...
Donc, si vous avez 20 conteneurs, vous ne voudrez simplement pas courir fig et tout commence par le bon ordre ...
Cependant, il a également une option de délai d'expiration ou d'autres mécanismes de détection des pannes

Un autre +1 ici. Postgres prend plus de temps que Django pour démarrer, donc la base de données n'est pas là pour la commande de migration sans piratage.

@ahknight intéressant, pourquoi la migration fonctionne-t-elle pendant run ?

Vous ne souhaitez pas exécuter la migration pendant la phase build ? De cette façon, vous pouvez démarrer de nouvelles images beaucoup plus rapidement.

Il existe un script de démarrage plus volumineux pour l'application en question, hélas. Pour l'instant, nous faisons d'abord un travail non DB, en utilisant nc -w 1 dans une boucle pour attendre la DB, puis en effectuant des actions DB. Ça marche, mais ça me fait me sentir sale (euh).

J'ai eu beaucoup de succès en faisant ce travail pendant la phase fig build . J'en ai un exemple avec un projet django (encore un travail en cours): https://github.com/dnephin/readthedocs.org/blob/fig-demo/dockerfiles/database/Dockerfile#L21

Pas besoin d'interroger pour le démarrage. Bien que j'ai fait quelque chose de similaire avec mysql, où j'ai dû interroger le démarrage parce que le script mysqld init ne le faisait pas déjà. Ce script d'initialisation postgres semble être bien meilleur.

Voici ce que je pensais:

En utilisant l'idée de docker / docker # 7445, nous pourrions implémenter cet attribut "wait_for_helth_check" dans la fig?
Ce serait donc un problème, pas un problème avec Docker?

y a-t-il de toute façon de faire vérifier l'état tcp sur le conteneur lié, si oui, je pense que c'est la voie à suivre. =)

@dnephin pouvez-vous expliquer un peu plus ce que vous faites dans Dockerfiles pour vous aider?
La phase de construction n'est-elle pas incapable d'influencer l'exécution?

@docteurklein je peux. J'ai corrigé le lien ci-dessus (https://github.com/dnephin/readthedocs.org/blob/fig-demo/dockerfiles/database/Dockerfile#L21)

L'idée est que vous effectuez toutes les opérations de "configuration" plus lentes pendant la construction, pour ne pas avoir à attendre quoi que ce soit pendant le démarrage du conteneur. Dans le cas d'une base de données ou d'un index de recherche, vous devez:

  1. démarrer le service
  2. créer les utilisateurs, les bases de données, les tables et les données des appareils
  3. arrêter le service

le tout en une seule étape de construction. Plus tard, lorsque vous fig up le conteneur de base de données, il est prêt à fonctionner immédiatement, et vous pouvez également profiter du cache de construction du docker pour ces opérations plus lentes.

agréable! Merci :)

@dnephin gentil, n'y avait pas pensé.

+1 Ceci est absolument nécessaire.
Un horrible piratage de délai serait suffisant dans la plupart des cas, mais une solution _real_ serait la bienvenue.

Pourriez-vous donner un exemple de pourquoi / quand c'est nécessaire?

Dans mon cas d'utilisation, j'ai un serveur Elasticsearch, puis un serveur d'applications qui se connecte à Elasticsearch. Elasticsearch prend quelques secondes à démarrer, donc je ne peux pas simplement faire un fig up -d car le serveur d'applications échouera immédiatement lors de la connexion au serveur Elasticsearch.

Supposons qu'un conteneur démarre MySQL et que l'autre démarre une application qui a besoin de MySQL et que l'autre application démarre plus rapidement. Nous avons des échecs transitoires fig up cause de cela.

crane a un moyen de contourner ce problème en vous permettant de créer des groupes qui peuvent être démarrés individuellement. Vous pouvez donc démarrer le groupe MySQL, attendre 5 secondes, puis démarrer les autres éléments qui en dépendent.
Fonctionne à petite échelle, mais pas une vraie solution.

@oskarhane ne sait pas si cette "attente de 5 secondes" aide, dans certains cas, il faudra peut-être attendre plus (ou je ne peux pas être sûr que cela ne durera pas plus de 5 secondes) ... ce n'est pas très sûr de comptez sur le temps d'attente.
De plus, vous devriez faire cela manuellement en attendant et en chargeant l'autre groupe, et c'est un peu boiteux, fig devrait le faire pour vous = /

@oskarhane , @dacort , @ddossot : gardez à l'esprit que, dans le monde réel, les choses se bloquent et redémarrent, les connexions réseau vont et viennent, etc. résilient aux échecs de connexion. De cette façon, ils fonctionneront correctement partout.

Vous avez raison, mais jusqu'à ce que nous corrigions toutes les applications préexistantes pour faire des choses comme récupérer gracieusement de l'absence de leurs ressources critiques (comme DB) au démarrage (ce qui est une grande chose ™ mais malheureusement rarement pris en charge par les frameworks), nous devrions utiliser fig start pour démarrer un conteneur individuel dans un certain ordre, avec des retards, au lieu de fig up .

Je peux voir un script shell venir contrôler fig pour contrôler le docker: wink:

Je suis d'accord avec le fait que cela ne soit pas intégré à la figure, mais quelques conseils sur les meilleures pratiques pour attendre la préparation seraient bien

J'ai vu dans un code lié à un commentaire précédent que cela était fait:

while ! exec 6<>/dev/tcp/${MONGO_1_PORT_27017_TCP_ADDR}/${MONGO_1_PORT_27017_TCP_PORT}; do
    echo "$(date) - still trying to connect to mongo at ${TESTING_MONGO_URL}"
    sleep 1
done

Dans mon cas, il n'y a pas /dev/tcp chemin

J'ai trouvé à la place cette méthode qui semble fonctionner correctement:

until nc -z postgres 5432; do
    echo "$(date) - waiting for postgres..."
    sleep 1
done

Cela semble fonctionner mais je n'en sais pas assez sur de telles choses pour savoir si c'est robuste ... est-ce que quelqu'un sait s'il y a une condition de concurrence possible entre le port montrant jusqu'à nc et le serveur postgres _really_ capable d'accepter commandes?

Je serais plus heureux s'il était possible d'inverser le chèque - au lieu d'interroger les conteneurs dépendants, est-il possible d'envoyer un signal du conteneur cible (c'est-à-dire du serveur postgres) à toutes les personnes à charge?

C'est peut-être une idée idiote, quelqu'un a des pensées?

Les liens

est-ce que quelqu'un sait s'il y a une condition de concurrence possible entre le port montrant à nc et le serveur postgres vraiment capable d'accepter des commandes?

Il n'y a aucun moyen de savoir dans le cas général - cela pourrait être vrai pour postgres, cela pourrait être faux pour d'autres services - ce qui est un autre argument pour ne pas le faire dans la Fig.

@aanand J'ai essayé d'utiliser votre approche d'image docker / wait mais je ne suis pas sûr de ce qui se passe. Donc, fondamentalement, j'ai ce conteneur "Orientdb" auquel de nombreux autres conteneurs d'applications NodeJS sont liés. Ce conteneur orientdb prend un certain temps pour commencer à écouter sur le port TCP et cela fait que les autres conteneurs obtiennent l'erreur «Connexion refusée».

J'espérais qu'en liant le conteneur d'attente à Orientdb je ne verrai pas cette erreur. Mais malheureusement, je reçois toujours au hasard. Voici ma configuration (Docker version 1.4.1, fig 1.0.1 sur une Ubuntu 14.04 Box):

orientdb:
    build: ./Docker/orientdb
    ports:
        -   "2424:2424"
        -   "2480:2480"
wait:
    build: ./Docker/wait
    links:
        - orientdb:orientdb
....
core:
    build:  ./Docker/core
    ports:
        -   "3000:3000"
    links:
        -   orientdb:orientdb
        -   nsqd:nsqd

Toute aide est appréciée. Merci.

@mindnuts l'image wait est plus une démonstration; il ne convient pas pour une utilisation dans un fig.yml . Vous devez utiliser la même technique (interrogation répétée) dans votre conteneur core pour attendre que le conteneur orientdb démarre avant de lancer le processus principal.

+1 vient de commencer à tomber sur ce problème alors que je tire des images personnalisées plutôt que de les construire dans le fig.yml. L'application de nœud échoue car mongodb n'est pas encore prête ...

Je viens de passer des heures à déboguer les raisons pour lesquelles MySQL était accessible lors du démarrage manuel de WordPress avec Docker, et pourquoi il était hors ligne en commençant par Fig. pas encore en mesure de se connecter à MySQL.

J'ai ajouté mon propre entrypoint.sh surchargé qui attend 5 secondes avant d'exécuter le vrai entrypoint.sh. Mais il s'agit clairement d'un cas d'utilisation qui nécessite une solution générale, s'il est supposé être facile de lancer une combinaison de conteneurs MySQL + WordPress avec Docker / Fig.

donc le WordPress entrypoint.sh meurt ne pouvant pas encore se connecter à MySQL.

Je pense que c'est un problème avec le conteneur WordPress.

Alors que j'étais initialement fan de cette idée, après avoir lu https://github.com/docker/docker/issues/7445#issuecomment -56391294, je pense qu'une telle fonctionnalité serait la mauvaise approche et encourage en fait les mauvaises pratiques.

Il semble y avoir deux cas que ce problème vise à résoudre:

Un service de dépendance doit être disponible pour effectuer une initialisation.

Toute initialisation de conteneur doit vraiment être effectuée pendant build . De cette façon, il est mis en cache et le travail n'a pas besoin d'être répété par chaque utilisateur de l'image.

Un service de dépendance doit être disponible pour qu'une connexion puisse être ouverte

L'application doit vraiment être résiliente aux échecs de connexion et réessayer la connexion.

Je suppose que la racine du problème est qu'il n'y a pas de règles de base quant à la responsabilité d'attendre que les services soient prêts. Mais même s'il y en avait, je pense qu'il est un peu irréaliste de s'attendre à ce que les développeurs ajoutent une nouvelle tentative de connexion à la base de données à chaque script d'initialisation. De tels scripts sont souvent nécessaires pour préparer des volumes de données vides qui viennent d'être montés (par exemple, créer la base de données).

Le problème serait en fait beaucoup moins gênant si Fig ne redémarrait pas toujours les conteneurs liés (c'est-à-dire le serveur de base de données) lors du redémarrage du conteneur d'application. Je ne sais pas vraiment pourquoi il fait ça.

Le problème serait en fait beaucoup moins gênant si Fig ne redémarrait pas toujours les conteneurs liés (c'est-à-dire le serveur de base de données) lors du redémarrage du conteneur d'application. Je ne sais pas vraiment pourquoi il fait ça.

En fait, il ne se contente pas de restaurer les conteneurs, mais de les détruire et de les recréer, car c'est le moyen le plus simple de s'assurer que les modifications apportées à fig.yml sont prises en compte. Nous devrions éventuellement implémenter une solution plus intelligente qui puisse comparer la "configuration actuelle" avec la "configuration souhaitée" et ne recréer que ce qui a changé.

Pour revenir au problème d'origine, je ne pense vraiment pas qu'il soit irréaliste de s'attendre à ce que les conteneurs aient une logique de nouvelle tentative de connexion - c'est fondamental pour concevoir un système distribué qui fonctionne. Si différents scripts doivent le partager, il doit être pris en compte dans un exécutable (ou un module spécifique au langage si vous n'utilisez pas le shell), afin que chaque script puisse simplement invoquer waitfor db en haut.

@kennu qu'en est-il de --no-recreate ? / cc @aanand

@aanand je voulais dire le commentaire irréaliste du point de vue du Docker Hub est déjà plein d'images publiées qui ne gèrent probablement pas les tentatives de connexion dans leurs scripts d'initialisation, et que ce serait une entreprise assez difficile de faire en sorte que tout le monde l'ajoute. Mais je suppose que cela pourrait être fait si Docker Inc publiait une sorte de directives / exigences officielles.

Personnellement, je préfère garder les conteneurs / images simples et laisser le système sous-jacent se soucier de la résolution des dépendances. En fait, la politique de redémarrage de Docker peut déjà tout résoudre (si le conteneur d'application ne parvient pas à se connecter à la base de données, il redémarrera et réessayera jusqu'à ce que la base de données soit disponible).

Mais s'appuyer sur la politique de redémarrage signifie qu'elle devrait être activée par défaut, sinon les gens passent des heures à déboguer le problème (comme je viens de le faire). Par exemple, Kubernetes utilise par défaut RestartPolicyAlways pour les pods.

des progrès à ce sujet? Je voudrais faire écho au fait qu'il n'est pas raisonnable de s'attendre à ce que toutes les images de docker changent et que toute la communauté implémente des pratiques de relance de connexion. Fig est un outil d'orchestration Docker et le problème réside dans l'ordre dans lequel il fait les choses, donc le changement doit être effectué dans Fig, pas dans Docker ou dans la communauté.

s'attendre à ce que toutes les images du docker changent et que l'ensemble de la communauté implémente des pratiques de nouvelle tentative de connexion n'est pas raisonnable

Ce n'est pas qu'une application doive avoir besoin de réessayer à cause de docker ou fig. Les applications doivent être résilientes aux connexions interrompues car le réseau n'est pas fiable . Toute application doit déjà être construite de cette façon.

Personnellement, je n'ai pas eu à implémenter de nouvelles tentatives dans aucun de mes conteneurs, et je n'ai pas non plus eu besoin de délai ou d'attente au démarrage. Je pense que la plupart des cas de ce problème entrent dans ces deux catégories (mon utilisation de "réessayer" n'est probablement pas géniale ici, je voulais dire davantage que cela rétablirait une connexion si la connexion était fermée, pas nécessairement interroger pendant une période en essayant plusieurs fois).

Si vous vous assurez que toute l'initialisation se produit pendant la phase de «construction» et que les connexions sont rétablies à la prochaine demande, vous n'aurez pas besoin de réessayer (ou d'attendre le démarrage des autres conteneurs). Si les connexions sont ouvertes paresseusement (lors de la première demande), au lieu de le faire avec impatience (au démarrage), je suppose que vous n'aurez pas besoin de réessayer du tout.

le problème réside dans l'ordre [fig] fait les choses

Je ne vois aucune mention de cela dans cette discussion jusqu'à présent. Fig commande le démarrage en fonction des liens spécifiés dans la configuration, il doit donc toujours démarrer les conteneurs dans le bon ordre. Pouvez-vous fournir un cas de test où la commande est incorrecte?

Je suis d'accord avec @dnephin ici. Bien sûr, ce serait pratique si compose / fig pouvait faire de la magie et vérifier la disponibilité des services, cependant, quel serait le comportement attendu si un service ne répond pas? Cela dépend vraiment des exigences de votre application / pile. Dans certains cas, la pile entière doit être détruite et remplacée par une nouvelle, dans d'autres cas, une pile de basculement doit être utilisée. De nombreux autres scénarios peuvent être envisagés.

Compose / Fig ne peut pas prendre ces décisions, et les services de surveillance devraient être la responsabilité des applications exécutées à l'intérieur du conteneur.

Je voudrais suggérer que @dnephin a simplement eu de la chance. Si vous branchez deux processus en parallèle, dont l'un se connectera à un port que l'autre écoutera, vous introduisez essentiellement une condition de concurrence; une loterie pour voir quel processus s'initialise le plus rapidement.

Je voudrais également répéter l'exemple d'initialisation de WordPress: il exécute un script shell de démarrage qui crée une nouvelle base de données si le conteneur MySQL ne l'a pas encore (cela ne peut pas être fait lors de la construction de l'image Docker, car elle dépend du volume de données monté en externe). Un tel script devient beaucoup plus complexe s'il doit distinguer les erreurs de base de données génériques des erreurs «la base de données n'est pas encore prête» et implémenter une logique de nouvelle tentative raisonnable dans le script shell. Je considère qu'il est très probable que l'auteur de l'image ne testera jamais réellement le script de démarrage par rapport à ladite condition de concurrence.

Néanmoins, la politique de redémarrage intégrée de Docker fournit une solution de contournement pour cela, si vous êtes prêt à accepter que les conteneurs ne démarrent pas sporadiquement et impriment régulièrement des erreurs dans les journaux. (Et si vous vous souvenez de l'activer.)

Personnellement, je ferais que Things Just Work, en faisant en sorte que Fig détecte automatiquement quels ports de conteneur sont exposés à un conteneur lié, leur envoie un ping avant de démarrer le conteneur lié (avec un délai d'attente raisonnable), et fournit finalement un paramètre de configuration pour remplacer / désactiver cette fonctionnalité.

cela ne peut pas être fait lors de la création de l'image Docker, car elle dépend du volume de données monté en externe

Vrai. Une approche ici consiste à démarrer uniquement le conteneur de base de données une fois (si nécessaire, avec un point d'entrée / commande différent), pour initialiser la base de données, ou utiliser un conteneur de données uniquement pour la base de données, créé à partir de la même image que le conteneur de base de données lui-même.

Un tel script devient beaucoup plus complexe s'il doit distinguer les erreurs de base de données génériques des erreurs "la base de données n'est pas encore prête"

Compose / Fig rencontrera le même problème là-bas; Comment vérifier si MySQL fonctionne et _accepter_ les connexions? (et PostgreSQL, et (_insérez votre service ici_)). De plus, _où_ le "ping" doit-il être exécuté? Dans le conteneur que vous démarrez, de l'hôte?

Pour autant que je sache, l'image officielle de WordPress inclut une vérification pour voir si MySQL accepte les connexions dans le docker-entrypoint.sh

@thaJeztah "Ajouter une logique de relance simple en PHP pour les erreurs de connexion MySQL" créé par tianon il y a 2 jours - Nice. :-) Qui sait, peut-être que cela deviendra une approche standard après tout, mais j'ai encore des doutes, en particulier sur ce type d'implémentation de nouvelles tentatives ayant été testé par tous les auteurs d'images.

À propos du ping du port - je ne peux pas dire à la légère quelle serait l'implémentation optimale. Je suppose que peut-être une simple vérification de connexion à partir d'un conteneur lié temporaire et une nouvelle tentative tout en obtenant ECONNREFUSED. Tout ce qui résout 80% (ou peut-être 99%) des problèmes, afin que les utilisateurs n'aient pas à les résoudre par eux-mêmes encore et encore à chaque fois.

@kennu Ah! Merci, je ne savais pas qu'il venait d'être ajouté récemment, je viens de vérifier le script maintenant à cause de cette discussion.

Pour être clair, je comprends les problèmes que vous rencontrez, mais je ne suis pas sûr que Compose / Fig puisse les résoudre d'une manière propre qui fonctionne pour tout le monde (et de manière fiable). Je comprends que de nombreuses images sur le registre n'ont pas de "sauvegardes" en place pour gérer ces problèmes, mais je doute qu'il soit de la responsabilité de Compose / Fig de résoudre ce problème.

Ayant dit ce qui précède; Je pense que ce serait une bonne chose de documenter cela dans la section des meilleures pratiques Dockerfile .

Les gens doivent en être informés et quelques exemples doivent être ajoutés pour illustrer comment gérer les «pannes» de service. Y compris un lien vers l'article WikiPedia que @dnephin a mentionné (et éventuellement d'autres sources) pour référence.

J'ai rencontré le même problème et j'aime cette idée de @kennu

Personally, I would make Things Just Work, by making Fig autodetect which container ports are exposed to a linked container, ping them before starting the linked container (with a sane timeout), and ultimately provide a configuration setting to override/disable this functionality.

Je pense que cela résoudrait de nombreux cas d'utilisation typiques, comme pour moi lorsque je dépends du conteneur officiel

Je suis d'accord avec @soupdiver. J'ai également des problèmes avec un conteneur mongo, et bien que je le fasse fonctionner avec un script start.sh, le script n'est pas très dynamique et ajoute un autre fichier que je dois conserver dans mon repo (je voudrais juste avoir un Dockerfile et docker-compose.yml dans mon référentiel de nœuds). Ce serait bien s'il y avait un moyen de le faire fonctionner, mais je pense que quelque chose de simple comme une minuterie d'attente ne le coupera pas dans la plupart des cas.

Le ping de l'OMI n'est pas suffisant, car la connexion réseau de base peut être disponible, mais le service lui-même n'est toujours pas prêt.
C'est le cas de l'image MySQL par exemple, utiliser curl ou telnet pour la vérification de la connexion sur les ports exposés serait plus sûr, même si je ne sais pas si cela suffirait. Mais la plupart des conteneurs n'ont pas ces outils installés par défaut.

Docker ou fig pourrait-il gérer ces contrôles?

Docker ou fig pourrait-il gérer ces contrôles?

En bref: _no_. Pour diverses raisons;

  • Effectuer un "ping" à partir d'un conteneur signifierait exécuter un deuxième processus. Fig / Compose ne peut pas démarrer automatiquement un tel processus, et je ne pense pas que vous voudriez que Fig / Compose modifie votre conteneur en _installant_ un logiciel (tel que curl ou telnet).
  • (Comme je l'ai mentionné dans un commentaire précédent), chaque service nécessite une manière différente de vérifier s'il accepte les connexions / est prêt à être utilisé. Certains services peuvent avoir besoin d'informations d'identification ou de certificats pour _établir_ une connexion. Fig / Compose ne peut pas automatiquement inventer comment faire cela.

et je ne pense pas que vous voudriez que Fig / Compose modifie votre conteneur en y installant un logiciel (tel que curl ou telnet).

Non, bien sûr que non.

Fig / Compose ne peut pas automatiquement inventer comment faire cela.

Ne pas inventer. Je pensais plus à une instruction pour fig ou docker, comment le vérifier, par exemple.

web:
    image: nginx
    link: db
db:
   is_available: "curl DB_TCP_ADDR:DB_TCP_PORT"

La commande telnet serait exécutée sur l'hôte docker, pas dans le conteneur.
Mais je pense juste fort, je sais que ce n'est pas la solution parfaite. Mais la manière actuelle d'utiliser des scripts de vérification personnalisés pour les conteneurs pourrait être améliorée.

La commande telnet serait exécutée sur l'hôte docker, pas dans le conteneur.

Ensuite, curl ou <name a tool that's needed> devrait être installé sur l'hôte. Cela pourrait même avoir d'énormes problèmes de sécurité (par exemple, quelqu'un veut être drôle et utilise is_available: "rm -rf /" ). En dehors de cela, le fait de pouvoir accéder à la base de données depuis _host_ ne garantit pas qu'elle soit également accessible depuis l'intérieur du conteneur.

Mais je pense juste fort, ...

Je sais et je l'apprécie. Pensez simplement qu'il n'y a pas de moyen fiable d'automatiser cela, ou que cela servirait la plupart des cas d'utilisation. Dans de nombreux cas, vous vous retrouverez avec quelque chose de complexe (prenez, par exemple, l'exemple curl ; combien de temps doit-il essayer de se connecter? Réessayer?). Une telle complexité est préférable de se déplacer à l'intérieur du conteneur, ce qui serait également utile si le conteneur était démarré avec Docker, et non avec Fig / Compose.

@thaJeztah Je suis totalement d'accord avec vous. Et il est très probable qu'il n'y aura pas de solution à 100%.

Je vais répéter une suggestion que j'ai faite plus tôt: il me suffirait de dire dans le fig.yml «attendre que ce conteneur se termine avant d'exécuter cet autre conteneur».

Cela me permettrait de créer un conteneur qui sait attendre toutes ses dépendances - vérifier les ports, initialiser les bases de données, peu importe - et exigerait que fig en sache le moins possible.

Je le verrais configuré comme quelque chose comme:

"" "
application:
liens:
- db: db
prérequis:
- runthisfirst

runthisfirst:
liens:
- db: db
"" "

runthisfirst a un lien qui signifie que la base de données démarre afin de pouvoir vérifier l'accès. l'application ne fonctionnera qu'une fois runthisfirst terminé (points bonus si runthisfirst doit se terminer avec succès).

Est-ce faisable comme réponse?

KJL

Le 10 février 2015, à 05:28, Tobias Munk [email protected] a écrit:

@thaJeztah https://github.com/thaJeztah Je suis totalement d'accord avec vous. Et il est très probable qu'il n'y aura pas de solution à 100%.

-
Répondez directement à cet e-mail ou consultez-le sur GitHub https://github.com/docker/fig/issues/374#issuecomment -73561930.

Je viens d'essayer de migrer mes lanceurs de script shell et j'ai rencontré ce problème. Ce serait bien d'ajouter simplement une simple clé de veille / attente qui ne fait que dormir pendant ce nombre de secondes avant de lancer le prochain conteneur.

db:
  image: tutum/mysql:5.6
  sleep: 10
app:
  link:
    - db:db

Je n'aime vraiment pas ça pour plusieurs raisons.

a) Je pense que c'est le mauvais endroit pour ça
b) Combien de temps dormez-vous?
c) Que faire si le délai d'attente n'est pas assez long?

Mis à part les problèmes évidents, je ne pense vraiment pas
l'infrastructure doit se soucier de ce que l'application
est et vice versa. L'application IHMO doit être écrite pour être
plus tolérante et / ou plus intelligente sur ses propres exigences.

Cela étant dit, les applications existantes et les applications héritées
aura besoin de quelque chose - mais cela devrait probablement être plus long
les lignes de:

a docker-compose.yml :

db:
  image: tutum/mysql:5.6
app:
  wait: db
  link:
    - db:db

wait attend que les services «exposés» sur db deviennent disponibles.

Le problème est de savoir comment déterminer cela?

Dans les cas les plus simples, vous attendez de pouvoir ouvrir avec succès
une connexion tcp ou udp aux services exposés.

Cela pourrait être excessif pour ce problème, mais ce serait une bonne solution si docker fournissait un système de déclenchement d'événements où vous pourriez lancer un déclencheur à partir d'un conteneur qui entraînait une sorte de rappel dans un autre conteneur. Dans le cas d'attendre d'importer des données dans une base de données MySQL avant de démarrer un autre service, il ne suffit pas de surveiller si le port était disponible.

Le fait qu'un script de point d'entrée définisse une alerte à Docker depuis l'intérieur du conteneur (définissez une variable d'environnement prédéfinie par exemple) qui a déclenché un événement dans un autre conteneur (peut-être en définissant la même variable d'environnement synchronisée) permettrait aux scripts des deux côtés de savoir quand certains les tâches sont terminées.

Bien sûr, nous pourrions configurer notre propre serveur socket ou d'autres moyens, mais c'est fastidieux de résoudre un problème d'orchestration de conteneur.

@aanand j'ai _ presque_ quelque chose qui fonctionne en utilisant votre approche d'attente comme point de départ. Cependant, il se passe autre chose entre l' exécution de docker-compose et l' exécution de docker où le premier semble se bloquer tandis que le second fonctionne un charme.

exemple docker-compose.yml:

db:
  image: postgres
  ports:
    - "5432"
es:
  image: dockerfile/elasticsearch
  ports:
    - "9200"
wait:
  image: n3llyb0y/wait
  environment:
    PORTS: "5432 9200"
  links:
    - es
    - db

puis en utilisant ...

docker-compose run wait

mais cela ne doit pas être. Les services liés démarrent et il semble que nous sommes sur le point d'attendre seulement qu'il s'étouffe (au moins dans mon environnement de virtualbox. J'arrive à la boucle nc et nous obtenons un seul point alors ... rien).

Cependant, avec les services liés en cours d'exécution, je peux utiliser cette méthode (qui est essentiellement ce que j'ai fait pour nos builds CI)

docker run -e PORTS="5432 9200" --links service_db_1:wait1 --links service_es_1:wait2 n3llyb0y/wait

Il semble que docker-compose run devrait fonctionner de la même manière. La différence est que lorsque vous utilisez docker-compose run avec l'indicateur de détachement -d vous n'obtenez aucun avantage d'attente en tant qu'arrière-plan du conteneur d'attente et je pense (à ce moment-là) que ne pas utiliser l'indicateur provoque l'attente pour s'étouffer avec les autres services non fondés. Je vais regarder de plus près

Après quelques essais et erreurs, il semble que l'approche ci-dessus fonctionne! C'est juste que la base busybox n'a pas d'utilitaire netcat qui fonctionne très bien. Ma version modifiée de l'utilitaire @aanand wait fonctionne avec docker-compose 1.1.0 lorsque vous utilisez docker-compose run <util label> au lieu de docker-compose up . Exemple d'utilisation dans le lien.

Je ne sais pas s'il peut gérer les situations de chaînage selon la question d'origine. Probablement pas.

Laissez-moi savoir ce que vous pensez.

C'est une question très intéressante. Je pense que ce serait vraiment intéressant d'avoir un moyen pour qu'un conteneur attende qu'un autre soit prêt. Mais comme tout le monde le dit, que signifie prêt? Dans mon cas, j'ai un conteneur pour MySQL, un autre qui gère ses sauvegardes et est également en charge d'importer une base de données initiale, puis les conteneurs pour chaque application qui ont besoin de la base de données. Il est évident qu'attendre que les ports soient exposés ne suffit pas. Tout d'abord, le conteneur mysql doit être démarré, puis le reste doit attendre que le service mysql soit prêt à être utilisé, pas avant. Pour obtenir cela, j'ai dû implémenter un script simple à exécuter au redémarrage qui utilise la fonctionnalité docker exec . Fondamentalement, le pseudo-code serait comme:

run mysql
waitUntil "docker exec -t mysql mysql -u root -prootpass database -e \"show tables\""
run mysql-backup
waitUntil "docker exec -t mysql mysql -u root -prootpass database -e \"describe my_table\""
run web1
waitUntil "dexec web1 curl localhost:9000 | grep '<h1>Home</h1>'"
run web2
waitUntil "dexec web2 curl localhost:9000 | grep '<h1>Home</h1>'"
run nginx

Où la fonction waitUntil a une boucle avec un timeout qui évalue la commande docker exec … et vérifie si le code de sortie est 0.

Avec cela, j'assure que chaque conteneur attend que ses dépendances soient prêtes à être utilisées.

Je pense donc que cela pourrait être une option à intégrer dans l'utilitaire de composition. Peut-être quelque chose comme ça, où wait_until déclare une liste d'autres dépendances (conteneurs) et attend chacune jusqu'à ce qu'ils répondent ok à la commande correspondante (ou peut-être avec un modèle optionnel ou une regex pour vérifier si le résultat correspond à quelque chose que vous attendez, même si l'utilisation de la commande grep pourrait suffire).

mysql:
  image: mysql
  ...
mysql-backup:
  links:
   - mysql
  wait_until:
   - mysql: mysql -u root -prootpass database -e "show tables"
  ...
web1:
  links:
   - mysql
  wait_until:
   - mysql: mysql -u root -prootpass database -e "describe my_table"
  ...
web2:
  links:
   - mysql
  wait_until:
   - mysql: mysql -u root -prootpass database -e "describe my_table"
  ...
nginx:
  links:
   - web1
   - web2
  wait_until:
   - web1: curl localhost:9000 | grep '<h1>Home</h1>'
   - web2: curl localhost:9000 | grep '<h1>Home</h1>'
  ...

Quel n'est pas un simple eait pour le port comme ça?
http://docs.azk.io/en/azkfilejs/wait.html#

@robsonpeixoto : Attendre le port n'est pas suffisant pour de nombreux cas d'utilisation. Par exemple, disons que vous amorcez une base de données avec des données lors de la création et que vous ne voulez pas que le serveur Web démarre et s'y connecte tant que l'opération de données n'est pas terminée. Le port sera ouvert tout le temps pour ne pas empêcher le serveur Web de démarrer.

Quelque chose comme WaitCondition d'AWS CloudFormation serait bien. http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-waitcondition.html

+1 J'ai le même problème lors de l'utilisation de Docker pour tester mes applications Rails qui dépendent de MySQL

+1 J'ai aussi ce problème. J'aime l'idée @adrianhurt , où vous fournissez réellement la condition à évaluer pour déterminer si l'attente est terminée. De cette façon, vous avez toujours un joli yml déclaratif, et vous n'avez pas besoin d'avoir une définition arbitraire de «prêt».

+1

J'ai cet onglet ouvert depuis un moment: http://crosbymichael.com/docker-events.html ... semble pertinent

+1

+1 pour un délai d'expiration simple

+1 pour une condition prête

+1

Je résous cela de manière très fiable au niveau de l'application depuis un certain temps, comme cela a été recommandé dans ce fil.

Juste pour vous donner une idée de la façon dont cela peut être implémenté pour MySQL + PHP, voici mon code.

De igorw / retry :)

Puisque le réseau est fiable, les choses devraient toujours fonctionner. Ai-je raison? Pour les cas où ce n'est pas le cas, il y a une nouvelle tentative.

+1

@ schmunk42 Bon truc - j'aime que ce soit un bon exemple à la fois d'établir la connexion et d'effectuer une opération de configuration de base de données idempotente.

Cela pourrait être bon de créer un (quelques) exemple (s) de base à inclure dans la documentation, pour différents cas, par exemple NodeJS, Ruby, PHP.

+1, au moins devrait fournir des options pour ajouter un délai avant que le conteneur ne démarre correctement.

+1

Comment résoudre les problèmes lorsque vous essayez de connecter des services qui ne sont pas votre code.
Par exemple, si a le service Service et la base InfluxDB données Services nécessite InfluxDB et le InfluxDB a un démarrage lent.

Comment docker-compose peut-il attendre InfluxDB ?

Si le code est à moi, je peux le résoudre en réessayant. Mais pour la troisième application, je ne peux pas changer le code.

@robsonpeixoto il y a quelques exemples dans ce ticket avec netcat ou des moyens similaires. Vous pouvez consulter mon exemple MySQL dans un autre ticket: https://github.com/docker/docker/issues/7445#issuecomment -101523662

C'est la raison pour laquelle je pense que chaque conteneur devrait avoir la possibilité facultative d'indiquer sa propre disponibilité. Pour une base de données, par exemple, je veux attendre que le service soit complètement prêt, pas lorsque le processus est créé. Je résous cela avec des contrôles personnalisés avec docker exec et en vérifiant si cela peut résoudre une requête simple, par exemple.

Un indicateur facultatif pour docker run pour indiquer qu'une commande de vérification interne serait génial pour le lier ultérieurement à partir d'un autre conteneur en utilisant un indicateur spécial pour le lien.

Quelque chose comme:

$ sudo docker run -d --name db training/postgres --readiness-check /bin/sh -c "is_ready.sh"
$ sudo docker run -d -P --name web --link db:db --wait-for-readiness db training/webapp python app.py

is_ready.sh est un simple test booléen qui est en charge de la décision du moment où le conteneur est considéré comme prêt.

+1

@ schmunk42 belle citation!

+1

+1

+1

+1

+1

+1

+1

+1

+1

En fait, j'ai changé d'avis à ce sujet, donc -1

Il est plus logique que votre conteneur vérifie si le service tiers est disponible, et cela se fait facilement avec un petit script wrapper bash qui utilise nc par exemple.

S'appuyer sur un retard est tentant, mais c'est une mauvaise solution car:

  • Votre conteneur attendra toujours X secondes avant d'être prêt.
  • X secondes peuvent ne pas être suffisantes dans certains cas (par exemple, E / S ou CPU lourdes sur l'hôte), donc votre conteneur n'est toujours pas sécurisé.
  • Aucune stratégie d'échec.

Il est préférable de se fier à l'écriture d'un script bash wrapper car:

  • Votre conteneur est prêt dès que possible.
  • Vous pouvez implémenter n'importe quelle stratégie d'échec, par exemple essayer 10 fois puis échouer, essayer pour toujours, etc. Vous pouvez même implémenter le délai vous-même en dormant avant d'essayer!

En lisant ce fil, je ne vois pas que personne ne mentionne de secrets. J'essaie d'utiliser un conteneur de données uniquement qui demande des secrets une fois qu'il est exécuté. Le problème que j'ai: si mes secrets prennent trop de temps à transmettre / déchiffrer, mon conteneur dépendant échoue car les données qu'il attend ne sont pas là. Je ne peux pas vraiment utiliser la méthode "bien mettre tout dans le conteneur avant de l'exécuter" car ce sont des secrets.

Je sais qu'il existe une certaine ambiguïté autour des conteneurs de données uniquement dans compose en raison du contexte du code de retour, mais y a-t-il une meilleure façon de le faire?

De même, changer d'avis à ce sujet, -1. L'approche de @dnephin est tout à fait correcte. Si votre _application_ dépend d'un _service_, l'application elle-même devrait être capable de gérer l'indisponibilité de ce service de manière gracieuse (par exemple, rétablir une connexion). Cela ne devrait pas être un script wrapper bash ou une logique dans Compose ou Docker, c'est la responsabilité de l'application elle-même. Tout ce qui n'est pas au niveau de l'application ne fonctionnera également qu'à l'initialisation; si ce service tombe en panne, un script wrapper ou quelque chose ne sera pas exécuté.

Maintenant, si nous pouvions amener les développeurs d'applications / bibliothèques / frameworks à réaliser et à supporter cette responsabilité, ce serait fantastique.

Difficile à faire étant donné que les approches que vous adopteriez impliqueraient le chargement latéral d'autres démons, ce qui n'est pas recommandé. Pour mon exemple où j'ai une application rails qui tente de se connecter à une base de données MySQL alors qu'une autre application rails est en train de migrer et de semer la base de données au démarrage initial, pour que je fasse savoir à l'application rails de ne pas essayer d'utiliser la base de données, je voudrais non plus doivent modifier la bibliothèque ActiveRecord (cela ne se produira pas) ou exécuter un script qui vérifie en permanence si la base de données a été migrée et amorcée. Mais comment savoir avec certitude sans savoir quelles données sont censées s'y trouver et / ou avoir un script qui s'exécute sur le système qui amorce la base de données pour informer le reste de s'y connecter.

Peut-être que la solution évidente me manque, mais votre réponse "les développeurs devraient être capables de gérer cela dans leur propre code" échoue lorsque vous utilisez des bibliothèques prêtes à l'emploi et que vous n'êtes pas "censé" charger des démons dans un contenant.

@mattwallington Je ne sais même pas comment Compose apporterait une solution à cette situation ...
C'est aussi terriblement spécifique, ce qui rendrait encore plus difficile l'invention de Compose. Je lirais quelques- @dnephin ci-dessus sur l'initialisation / la migration / l'amorçage car cela pourrait vous aider.

Je pense que vous avez manqué le point de ma dernière ligne, de nombreuses bibliothèques prêtes à l'emploi ne fonctionnent pas avec précision car elles n'ont pas été construites de manière résiliente. Il n'existe pas de solution magique capable de résoudre tout cela que Compose peut simplement implémenter.

Compris. Ma suggestion plus tôt qui fonctionnerait pour beaucoup de ces cas d'utilisation est d'avoir une variable d'environnement partagée entre les conteneurs. Un côté pourrait se verrouiller sur l'interrogation de la variable et l'autre pourrait effectuer l'action puis définir la variable.

+1 @mattwallington idée de la variable d'environnement partagée entre les conteneurs

Je vous remercie. C'est simple (au niveau du produit. Je n'ai aucune idée de ce que cela prendrait du côté développement car je n'ai pas regardé le code) mais cela résoudrait beaucoup de ces problèmes et probablement beaucoup d'autres car ce n'est pas spécifique ce problème.

Mais comment savoir avec certitude sans savoir quelles données sont censées s'y trouver et / ou avoir un script qui s'exécute sur le système qui amorce la base de données pour informer le reste de s'y connecter.

@mattwallington : vérifiez le numéro de migration dans la table de schéma. Si le nombre est correct, vous savez que la migration a été exécutée.

Cela ne devrait pas être un script wrapper bash ou une logique dans Compose ou Docker, c'est la responsabilité de l'application elle-même. Tout ce qui n'est pas au niveau de l'application ne fonctionnera également qu'à l'initialisation; si ce service tombe en panne, un script wrapper ou quelque chose ne sera pas exécuté.

@ agilgur5 : oui je suis d'accord que cela serait géré par l'application, mais un script bash est une solution simple pour gérer les applications qui ne sont pas codées de cette façon, par exemple en redémarrant l'application lorsque le service n'est pas disponible.

Des arguments peuvent être avancés toute la journée sur ce qui devrait ou pourrait être fait au niveau de l'application, mais plutôt que de s'attendre à ce que chaque application sur le marché gère cela et devienne géniale en matière de récupération automatique (peu probable) pourquoi sommes-nous si contre l'ajout de fonctionnalités qui peuvent résoudre ce problème pour les applications s'exécutant dans docker indépendamment de la façon dont les applications tierces sont écrites ou de ce qu'elles DEVRAIENT faire mais ne le feront pas. C'est ce sur quoi nous contrôlons. Résolvons le problème plutôt que de décider qui devrait être celui qui le résoudra puisque nous n'avons aucun contrôle sur cela.

Je suis d'accord avec @mattwallington. Vous pouvez exiger cet effort supplémentaire pour l'auto-récupération au niveau de l'application de la part de chaque développeur de chaque image de conteneur, mais un grand pourcentage d'entre eux sera forcément trop ignorant ou tout simplement trop occupé pour l'implémenter et le tester avec soin. Le résultat final sera que certains conteneurs savent comment s'auto-récupérer alors que beaucoup ne le font pas. Et en tant qu'utilisateur, vous serez sans outils pour gérer ceux qui ne le font pas.

Une idée qui m'est venue à l'esprit: au lieu de résoudre le problème en retardant le démarrage du conteneur, Compose pourrait essayer de récupérer le conteneur défaillant.

Quelque chose comme recover: auto redémarrerait le conteneur défaillant 5 fois en 2, 4, 8, 16 et 32 ​​secondes, puis abandonnerait complètement.

Quelqu'un at-il pensé à la notion de conteneur de dépendance de conteneur?

Par exemple:

`` #! yml
db:
image: mysql

attendre:
liens:
- db
volumes:
- /var/lib/docker.sock:/docker.sock
- $ {PWD} /docker-compose.yml:/docker-compose.yml
commande: docker-compose up -d app

application:
image: myuser / myapp
liens:
- db
''

L'idée de base ici est que vous _solvez_ le problème des conteneurs qui ne disposent pas de mécanismes d'auto-récupération en créant un service réutilisable dédié qui pourrait être publié sur le Docker Hub que tout le monde peut ensuite simplement injecter dans leur composition.

Je serais même prêt à prototyper un tel service / conteneur / image et à laisser les autres jouer avec cela pour voir comment cela se passe ...

@prologic Le problème avec une dépendance est le suivant: comment s'assurer que le service auquel vous souhaitez parler fonctionne réellement?

Votre conteneur db peut répondre à un ping mais effectue un nettoyage / initialisation avant le lancement de la base de données avant qu'elle ne soit réellement disponible pour les commandes mysql / psql .

Ce test peut-il être défini de manière configurable et / ou fourni dans un script à un service de type waitfor réutilisable?

À mon humble avis, c'est un problème très courant et chacun a ses propres exigences spécifiques. Comme indiqué précédemment dans ce numéro, je pense que docker pourrait (et devrait) fournir un moyen pour un conteneur de spécifier une commande simple pour vérifier sa propre disponibilité. De toute évidence, en tant que développeurs, nous devrions avoir à indiquer spécifiquement comment vérifier la disponibilité de chaque conteneur.

Un indicateur facultatif pour l'exécution de docker pour indiquer une commande de vérification interne serait idéal pour le lier ultérieurement à partir d'un autre conteneur en utilisant un indicateur spécial pour le lien.

Quelque chose comme:

$ sudo docker run -d --name db training/postgres --readiness-check /bin/sh -c "is_ready.sh"
$ sudo docker run -d -P --name web --link db:db --wait-for-readiness db training/webapp python 

Où is_ready.sh est un simple test booléen qui est en charge de la décision du moment où le conteneur est considéré comme prêt.

Il peut également s'agir d'une commande permettant à un conteneur de vérifier manuellement sa disponibilité.

Où is_ready.sh est un simple test booléen qui est en charge de la décision du moment où le conteneur est considéré comme prêt.

ce qui signifie que chaque développeur doit préparer ses images / conteneurs pour inclure _quelque chose_ qui peut être utilisé pour vérifier si le conteneur est prêt.

Ce qui nous ramène à la case 1 .; les développeurs sont responsables de rendre leurs conteneurs résilients aux temps de panne de service / de démarrage, car ils sont les seuls à pouvoir dire «ce que» cela signifie pour leur situation?

Ou je néglige quelque chose ici?

Je suis d'accord. La responsabilité incombe au développeur / conteneur / service

Le jeudi 30 juillet 2015, Sebastiaan van Stijn [email protected]
a écrit:

Où is_ready.sh est un simple test booléen qui est en charge de la
décision du moment où le conteneur est considéré comme prêt.

ce qui signifie que chaque développeur doit préparer ses images / conteneurs pour
inclure _quelque chose_ qui peut être utilisé pour vérifier si le conteneur est
prêt.

Ce qui nous ramène à la case 1 .; les développeurs sont responsables de
rendre leurs conteneurs résilients aux interruptions de service / temps de démarrage, car
sont-ils les seuls à pouvoir dire «ce que» cela signifie pour leur situation?

Ou je néglige quelque chose ici?

-
Répondez directement à cet e-mail ou affichez-le sur GitHub
https://github.com/docker/compose/issues/374#issuecomment -126278215.

James Mills / prologique

E: [email protected]
W: prologic.shortcircuit.net.au

Oui bien sûr. Pour moi, le seul qui sait vraiment quand un conteneur est prêt est le propre conteneur. Docker ne peut rien savoir du contenu d'un conteneur. C'est une boîte noire. La seule chose qu'il pourrait faire est de demander au conteneur (avec une action personnalisée spécifiée lorsque vous souhaitez exécuter, comme je l'ai proposé, ou tout autre moyen courant de le tester). Et évidemment, le développeur est le seul à savoir ce dont il a besoin et le contenu de cette boîte noire.

Oui c'est vrai!

Le jeudi 30 juillet 2015, adrianhurt [email protected] a écrit:

Oui bien sûr. Pour moi, le seul qui sait vraiment quand un conteneur est
prêt est le propre conteneur. Docker ne peut rien savoir du contenu de
un contenant. C'est une boîte noire. La seule chose qu'il pourrait faire est de demander au
conteneur (avec une action personnalisée spécifiée lorsque vous souhaitez exécuter, comme je
proposé, ou tout autre moyen courant de le tester). Et évidemment le développeur
est le seul à savoir ce dont il a besoin et le contenu de cette boîte noire.

-
Répondez directement à cet e-mail ou affichez-le sur GitHub
https://github.com/docker/compose/issues/374#issuecomment -126285056.

James Mills / prologique

E: [email protected]
W: prologic.shortcircuit.net.au

OK - pour le bien de tous les logiciels en cours de développement ou hérités qui ne peuvent pas gérer les pannes de réseau, supposons que nous voulions résoudre ce problème après tout. Je ne dis pas que nous le faisons, je veux juste avoir une idée de la syntaxe, de la sémantique et de la complexité.

L'ensemble minimal d'exigences semble être:

  • Je veux que Compose attende de démarrer un service jusqu'à ce qu'un autre service soit "prêt".
  • Je veux définir «prêt» comme «accepte les connexions TCP sur le port X», ou autre chose.

Supposons également que les vérifications de l'état ne seront pas intégrées à Docker pendant un certain temps.

Je me demande si cela pourrait être résolu dans le cas général en permettant _attendre la sortie des conteneurs d'un autre service_. Vous pouvez alors rédiger votre bilan de santé comme un simple service supplémentaire.

web:
  image: mywebapp
  links: ["db"]
  wait_for: ["db_wait"]

db_wait:
  image: netcat
  links: ["db"]
  command: sh -c "while ! nc -w 1 -z db 5432; do sleep 1; done"

db:
  image: postgres

Si vous souhaitez une sorte de vérification de l'état personnalisée, définissez-la dans le service "wait". Ici, db_wait ne sortira qu'une fois que mytable existe dans la base mydb données

db_wait:
  image: postgres
  links: ["db"]
  command: sh -c "while ! psql --host db --dbname mydb -c "\d mytable"; do sleep 1; done"

Si vous avez un script de préparation de base de données à exécuter en premier, vous pouvez en faire la chose à attendre:

web:
  image: mywebapp
  links: ["db"]
  wait_for: ["prepare_db"]

prepare_db:
  image: prepare_db
  links: ["db"]
  command: ./prepare.sh

db:
  image: postgres

Le premier cas (attendre que le conteneur accepte les connexions TCP) peut être assez courant pour valoir la peine d'être pris en charge par défaut.

web:
  image: mywebapp
  links: ["db"]
  wait_for_tcp: ["db:5432"]

db:
  image: postgres

Il y a une implication cachée dans tout cela: docker-compose up -d devrait être bloqué pendant que le service de vérification de l'état ou de préparation intermédiaire est en cours d'exécution, afin qu'il puisse démarrer le (s) service (s) consommateur une fois terminé.

Oui. Cependant, à mon avis, docker lui-même devrait fournir un moyen de déterminer quand un conteneur est prêt, puis compose pourrait le gérer. Nous pourrions alors soulever un nouveau problème directement dans docker. Pour moi, cela pourrait être quelque chose comme:

web:
  image: mywebapp
  links: ["db"]
  wait_for: ["db"]

db:
  image: postgres
  ready_when: sh -c "while ! psql --host db --dbname mydb -c "\d mytable"; do sleep 1; done"

Ensuite, il n'est pas nécessaire de créer de nouveaux services comme solution de contournement

D'accord. Donnez la flexibilité au développeur. La suspension du conteneur peut également ne pas être ce que le développeur a besoin de ce conteneur pendant qu'il attend. Peut-être qu'il y a une partie de son propre init qui doit se produire, mais attendez ensuite que la base de données soit prête pour les connexions. Donc, s'il s'agit d'une simple variable d'environnement partagée, cela permet au développeur de l'utiliser comme il le souhaite.

Comment une variable d'environnement partagée serait-elle mise à jour? Pour autant que je sache, vous ne pouvez pas modifier l'ensemble de variables d'environnement d'un processus une fois qu'il a démarré.

Vous pouvez les changer par exemple dans une session bash, mais ils ne seront pas propagés dans toutes les autres couches.

Pour ce faire, la modification doit être validée et le conteneur redémarré. C'est assez inutile dans ce scénario.

De plus, même si la variable pouvait changer, le processus dans le conteneur aurait besoin de savoir pour l'interroger, ce qui en fait une non-solution pour le logiciel hérité auquel cette fonctionnalité est apparemment destinée.

Étant donné que nous ne parlons en réalité que de la résolution de ce problème pour les conteneurs hérités dans les environnements de développement, je pense qu'il pourrait être résolu comme un outil qui se trouve au-dessus de compose docker-compose ps -s (liste des services dans l'ordre des dépendances, # 1077).

Avec ces deux commandes, un outil pourrait être écrit qui fait quelque chose comme ceci:

  1. Exécutez docker-compose ps -s pour obtenir la liste des noms de services dans l'ordre des dépendances
  2. Exécutez docker-compose up -d --no-recreate <first service from the list>
  3. Exécutez la commande «healthcheck» pour ce service jusqu'à ce qu'il soit sain ou qu'il atteigne le délai d'expiration. Cela peut être une requête HTTP ou un appel docker exec
  4. Répétez 2 et 3 pour chaque service de la liste
  5. Exécutez docker-compose logs (ou pas si -d est passé)

De cette façon, la configuration "healthcheck" et "wait for" peut être externe pour composer, mais je ne pense pas que le développeur soit obligé de fournir quoi que ce soit au-dessus de ce qui serait requis si elle était implémentée dans le cadre de compose lui-même.

Une raison pour laquelle cela ne fonctionnerait pas?

Je suis content que nous ayons limité la portée aux anciens conteneurs, c'est beaucoup plus raisonnable: +1:

@dnephin Je pense que c'est génial du point de vue immédiat qu'il est flexible et que Compose n'a pas besoin d'avoir un support intégré pour les conteneurs hérités, mais je vois un problème immédiat similaire à ce que @mattwallington a décrit, et si les autres conteneurs peuvent exécuter certaines choses (par exemple init) avant de vous connecter à ce service? Le blocage sur ce conteneur _works_, mais n'est pas idéal (cela étant dit, je ne suis pas sûr qu'il existe une solution idéale pour un conteneur hérité). Cela résoudrait au moins mon problème, maintenant je dois trouver ce billet!

+1

pour pouvoir spécifier des dépendances dans les fichiers docker-compose ...

... ne pas utiliser de liens (car ils sont incompatibles avec net = host). J'aurais pensé que c'était le travail ou du moins le souci d'un outil de gestion multi-conteneurs de savoir dans quel ordre les choses devraient démarrer, un peu comme marionnette a son propre arbre de dépendances, mais parfois l'utilisateur sait mieux et peut passer outre. En lisant tout ce qui précède, il me semble que la seule difficulté est de décider quand un conteneur est "up" afin que le prochain conteneur de la chaîne de dépendances puisse être démarré. Cela pourrait être exactement le même mécanisme que le mécanisme de liaison (pour le moment) - tout vaut mieux que rien. Plus tard, la clarification de "remplir une dépendance" pourrait être spécifiée par le fichier docker-compose, par exemple - cette dépendance il importe que le conteneur soit en cours d'exécution

depends_on:
  container: foo
  requires: running

ou cette dépendance, il importe que les ports TCP des conteneurs écoutent.

depends_on:
  container: foo
  requires: listening

Dire que c'est le travail d'un outil ou d'un script externe au sommet de docker-compose revient à dire que docker-compose n'a aucun intérêt ni aucune responsabilité réelle pour l'orchestration de l'exécution de 2 conteneurs ou plus sur la même machine. Alors quel est son but?

J'aurais pensé que c'était le travail ou du moins le souci d'un outil de gestion multi-conteneurs de savoir dans quel ordre les choses devraient démarrer

Non pas forcément. Pour les raisons déjà exposées à plusieurs reprises dans ce fil, je pense qu'il n'y a que deux excuses pour confier ce travail à un outil de gestion de conteneurs:

  1. Vous exécutez des images de conteneurs standard qui ne résistent pas à l'indisponibilité des services en amont dont elles dépendent, et pour des raisons techniques ou commerciales, vous ne pouvez pas les modifier ou les étendre.
  2. Vous exécutez un logiciel uniquement dans un environnement de développement, pas dans un environnement de production, et vous avez mieux à consacrer du temps à la mise en œuvre de la résilience.

Cependant, si vous avez le contrôle sur votre logiciel et que vous prévoyez de le déployer en production, vous ne pouvez pas espérer compter sur un outil externe qui ne fait que démarrer les choses dans le bon ordre, même si vous avez soigneusement défini vos conditions de préparation. Ce n'est pas une solution au problème fondamental, et votre système tombera en cas de problème de réseau. Au mieux, vous devrez redémarrer automatiquement tous vos conteneurs frontend Web à chaque fois que cela se produit, et je ne vois pas cela comme un temps d'arrêt acceptable pour quiconque.

Convenez avec vous qu'un logiciel bien écrit résoudra les pannes de réseau. Je pense que nous convenons tous les deux que tous les logiciels ne sont pas bien écrits et que les développeurs ne pensent pas toujours à tous les cas d'utilisation possibles.

Peut-être que je veux exécuter un conteneur de clients exécutant une JVM et un autre outil de surveillance pour y attacher, à la fois dans l'espace de noms PID hôte afin que l'un puisse surveiller l'autre et je ne suis pris en charge et autorisé à exécuter un tel outil avec l'image autorisée du fournisseur . Si l'outil de surveillance surveille les machines virtuelles Java existantes, il importe dans quel ordre elles démarrent (évidemment). Il y a probablement des centaines de cas d'utilisation où l'ordre compte, certains impliquant des réseaux (mysql, elasticsearch, des clusters de découverte de services ont tous été mentionnés), mais certains impliquant d'autres choses qui peuvent être partagées en utilisant efficacement les différents espaces de noms.

Je suis donc tout à fait d'accord avec le cas d'utilisation (1), car dans certaines circonstances, vous ne pouvez tout simplement pas changer un conteneur

Mais aussi dès qu'un outil se préoccupe de tout multiple, il se heurte immédiatement à la commande. Si la commande est importante et que la seule façon de garantir une commande est d'écrire un script bash autour de docker-compose pour commencer quelque chose, puis quelque chose d'autre, docker-compose pourrait aussi bien ne pas exister dans la chaîne, à part le fait JSON / YAML est plus joli que les arguments cmdline.

IMHO En fin de compte, un outil est utile ou non pour un tas de cas d'utilisation. Docker-compose est clairement utile pour les démarrages non ordonnés de plusieurs conteneurs sur le même hôte. Si suffisamment de personnes et suffisamment de cas d'utilisation concernent la commande et qu'un outil ne les aborde pas, les gens iront simplement ailleurs pour ces cas d'utilisation, ce qui est dommage.

Quoi qu'il en soit, je vois que je ne fais que reformuler d'anciens arguments, alors je vais maintenant m'écarter de ce fil ..

C'est le même argument qui est énoncé à travers des milliers de threads sur tant de sujets de développement différents "Si tout le code était écrit correctement par tout le monde, il n'y aurait pas besoin de ce genre de chose, alors ne le faisons pas". Cela revient à dire: si tous les peuples du monde arrêtaient de brûler des combustibles fossiles ou d’utiliser l’électricité, nous pourrions régler les problèmes que nous causons à notre planète. Vous avez raison. Si toutes les applications faisaient ce qu'elles devraient, nous ne serions pas là pour en parler. Mais nous vivons sur terre. Un endroit qui avait des imperfections massives avec une espèce d'êtres qui ont tendance à devoir apprendre les choses à la dure. Les mêmes personnes qui ne font décoller les entreprises que parce qu'elles créent un "produit minimum viable" afin de prier pour qu'elles atteignent le prochain cycle de financement ou le prochain client qui pourrait un jour leur permettre de créer la version qu'elles souhaiteraient pouvoir .

Le monde n'est pas et ne sera jamais parfait et nous ne pouvons donc faire que ce que nous avons sous notre propre contrôle. Et dans ce cas, la seule chose que j'ai sous mon contrôle est d'essayer de vous convaincre tous (c'est-à-dire les gens qui développent l'outil que j'aime absolument et que j'utiliserais comme un fou s'il n'avait que cette fonctionnalité) pour le construire une façon de gérer les logiciels qui existent dans le monde dans lequel nous vivons. Pas celui dans lequel nous aurions souhaité vivre.

Le 31 juillet 2015 à 3 h 42, Aanand Prasad [email protected] a écrit:

J'aurais pensé que c'était le travail ou du moins le souci d'un outil de gestion multi-conteneurs de savoir dans quel ordre les choses devraient démarrer

Non pas forcément. Pour les raisons déjà exposées à plusieurs reprises dans ce fil, je pense qu'il n'y a que deux excuses pour confier ce travail à un outil de gestion de conteneurs:

Vous exécutez des images de conteneurs standard qui ne résistent pas à l'indisponibilité des services en amont dont elles dépendent, et pour des raisons techniques ou commerciales, vous ne pouvez pas les modifier ou les étendre.

Vous exécutez un logiciel uniquement dans un environnement de développement, pas dans un environnement de production, et vous avez mieux à consacrer du temps à la mise en œuvre de la résilience.

Cependant, si vous avez le contrôle sur votre logiciel et que vous prévoyez de le déployer en production, vous ne pouvez pas espérer compter sur un outil externe qui ne fait que démarrer les choses dans le bon ordre, même si vous avez soigneusement défini vos conditions de préparation. Ce n'est pas une solution au problème fondamental, et votre système tombera en cas de problème de réseau. Au mieux, vous devrez redémarrer automatiquement tous vos conteneurs frontend Web à chaque fois que cela se produit, et je ne vois pas cela comme un temps d'arrêt acceptable pour quiconque.

-
Répondez directement à cet e-mail ou affichez-le sur GitHub.

+1 @aanand. Ce n'est pas quelque chose que vous allez pouvoir limiter. La fonctionnalité, si elle est réalisée, doit être quelque chose sur laquelle les gens peuvent compter. Ils codent pour une infrastructure «durable» depuis longtemps et il faut beaucoup de temps pour convertir les masses. Ils _will_ utiliseront ceci pendant un long moment à venir.

Je voudrais répéter que nous n'avons pas exclu la mise en œuvre de quelque chose pour atténuer le problème des dépendances de synchronisation de démarrage entre les conteneurs - j'ai esquissé une solution possible hier, dans ce fil même .

Mais je veux que nous soyons sur la même longueur d'onde concernant à qui cette fonctionnalité est destinée, quels problèmes elle résoudra, quels problèmes elle ne résoudra pas et dans quelle mesure elle peut être invoquée. C'est ce que j'essaie de ressentir.

De plus, étant donné les multiples définitions de la disponibilité ("le conteneur a démarré" vs "le conteneur accepte les connexions TCP" vs "les passes de vérification de l'état personnalisées"), et la complexité différente de la mise en œuvre de chacun d'eux, je souhaite obtenir un comparatif idée du nombre de personnes qui bénéficieraient d'un soutien prêt à l'emploi pour chacune.

Une technique courante de synchronisation des services est quelque chose comme un «registre de services» utilisant etcd ou similaire. Que diriez-vous d'un wait_for_service:

web:
  image: mywebapp
  links: ["db"]
  wait_for_service:
    type: etcd (or consul, or zk)    -- or use swarm type notation
    addr: http://my.etcd.com/
    path: postgres.service

db:
  image: postgres

compose ne sait pas si le service est vraiment prêt, mais il peut rechercher les données dans le registre et démarrer le conteneur dépendant en fonction de cela. Il est de la responsabilité des services (comme postgres) de publier leur disponibilité dans le registre.Pour les applications héritées, une sorte de script d'encapsulation le ferait: démarrer l'application, surveiller la mise en ligne du port, puis publier dans le registre.

Salut @aanand.

J'en discutais aujourd'hui avec @bfirsh sur les twitters car c'est quelque chose que j'ai rencontré.

Plus précisément, lors de la création d'un système distribué à partir de nombreux petits composants dockerisés, j'ai trouvé le besoin d'avoir des tests d'intégration qui ont lancé toutes les applications d'interface principales et leurs dépendances, puis j'ai exécuté divers tests avant de tout démolir à nouveau.

Cela a conduit aux problèmes de Riak, par exemple, qui prennent un certain temps pour démarrer par rapport à à peu près tout ce qui l'utilise.

Je ne serais pas particulièrement opposé à ce que vous disiez tous "les conteneurs démarrent de manière asynchrone, traitez-y", mais concevoir autour de chaque service en exposant un bilan de santé cohérent contiendrait au moins le "traitement" d'une implémentation par service plutôt que d'avoir du code pour gérer les nouvelles tentatives de connexion dans chaque application qui repose sur le service.

Les services définissant leur propre bilan de santé sont également utiles à des fins de surveillance.

@elliotcm D'accord sur les deux points.

Pour tester notre CI, nous avons créé un petit utilitaire qui peut être utilisé dans un conteneur Docker pour attendre que les services liés soient prêts. Il trouve automatiquement tous les services TCP liés à partir de leurs variables d'environnement et essaie à plusieurs reprises et simultanément d'établir des connexions TCP jusqu'à ce qu'il réussisse ou expire.

Nous avons également écrit un article de blog décrivant pourquoi nous l'avons construit et comment nous l'utilisons .

@meeee qui a l'air vraiment sympa et utile! Pouvez-vous nous montrer des exemples de la façon dont il est lancé; en particulier en utilisation avec un docker-compose?

J'ai eu un cas plus délicat aujourd'hui, où je commençais un conteneur mysql pour la première fois. Le conteneur s'amorce lors de sa première exécution et redémarre le démon de base de données lorsqu'il est configuré. Cela a provoqué le déclenchement prématuré de mes contrôles de disponibilité des ports et des conteneurs dépendants ont démarré mais n'ont pas réussi à se connecter. C'était dans un environnement CI, où nous voulons que les choses soient entièrement configurées à partir de zéro.

J'ai très envie de composer pour prendre en charge une sorte de comportement d'attente / vérification, mais il existe des cas trompeusement délicats. Je suis heureux de participer aux discussions.

@prologic Tout ce que vous avez à faire est d'exécuter la commande waitforservices dans un conteneur Docker en fonction d'autres services / conteneurs avant d'exécuter votre application ou vos tests. Il trouve tous les services liés et s'exécute jusqu'à ce qu'il puisse s'y connecter ou qu'un certain temps se soit écoulé (60 secondes par défaut). Exécutez simplement tout le code qui dépend d'autres services après la fermeture du binaire (vous voudrez peut-être vérifier l'état de sortie).

@pugnascotia Votre serveur de base de données pourrait écouter sur localhost uniquement pendant le démarrage - vous devrez exposer une sorte d'indicateur si le conteneur est prêt de toute façon. Nous n'utilisons pas MySQL, mais waitforservices fonctionne parfaitement avec l' image officielle postgres .

@aanand Postgres est un excellent exemple à choisir, car attendre que le port TCP s'ouvre n'est pas suffisant - si vous faites cela dans ce type de scénario (docker), vous serez parfois frappé par une erreur comme FATAL: the database system is starting up. si votre autre conteneur se connecte trop rapidement après l'ouverture de la connexion TCP. Donc, psql semble nécessaire si vous voulez être sûr que postgres est prêt - j'utilise select version() mais il y a peut-être une alternative plus légère.

Il existe un plugin docker Maven particulier qui a une implémentation d'attente intéressante. Pour le moment, j'utilise un wrapper bash pour démarrer chaque service, ce qui va plutôt à l'encontre de l'intérêt d'utiliser compose.

En utilisant ceci comme solution de contournement (pas sûr que ce soit à l'épreuve des balles):

db:
  image: postgres:9.3
  ports:
    - "5432:5432"
createdbs:
  image: postgres:9.3
  links:
    - db
  command: >
    /bin/bash -c "
      while ! psql --host=db --username=postgres; do sleep 1; done;
      psql --host=db --username=postgres -c 'CREATE DATABASE \"somedatabase\";';
    "

J'utilise des méthodes similaires à @olalonde. Lorsque j'utilise des guillemets simples pour la commande qui est exécutée après /bin/bash -c , je peux également utiliser des variables d'environnement qui sont réutilisées à partir de liens lorsque d'autres applications afin que je puisse utiliser les noms d'utilisateur et les mots de passe sans avoir à les maintenir en deux des endroits. Cela fonctionne bien dans les situations où j'ai un service, tel qu'une API, qui a besoin d'une base de données pour être en place, et que les données appropriées soient amorcées en exécutant une requête vérifiant si une table ou un enregistrement spécifique existe. Cela signifie également que j'ai besoin d'une sorte de client installé dans le conteneur pour interroger correctement la base de données, mais cela fonctionne.

+1 Je suis vraiment intéressé par cette fonctionnalité

+1 aux dépendances. Je conviens qu'en principe, l'architecture doit être suffisamment robuste pour prendre en charge toute commande de démarrage. MAIS, souvent, cela n'est pas pratique.

On a l'impression que le recul de cette fonctionnalité vient du fait que d'autres essaient de dicter l'architecture de loin; là où ils n’ont vraiment pas le droit de le faire. Cette fonctionnalité permettrait de travailler autour de refactors chronophages; avec peu de valeur à long terme. (Refactoring dans un souci de refactoring).

Oui, j'ai dit "contourner"; et je me sens sale. Mais composer pour moi, c'est vraiment permettre aux autres d'être productifs. Cette configuration simple permet cela.

Si cette fonctionnalité existait dans le toolest, je pourrais résoudre mon problème en une minute et passer à l'ajout de valeur réelle. Au lieu de cela, je me cogne la tête contre un mur en essayant de contourner les problèmes de commande de démarrage avec des dépendances externes.

@beardface , et tout le monde: quelle fonctionnalité, en particulier, vous permettrait de poursuivre le développement de votre application?

  1. La possibilité de spécifier que le service A doit attendre le démarrage du service B? (qui, gardez à l'esprit, ne résoudra toujours pas la condition de concurrence lorsqu'un conteneur a démarré mais n'est pas prêt à accepter les connexions)
  2. La possibilité de spécifier qu'un service A doit attendre pour démarrer jusqu'à ce que le service B accepte les connexions? (qui, gardez à l'esprit, ne résoudra toujours pas la condition de concurrence quand un conteneur écoute mais n'a pas fini l'initialisation - par exemple un conteneur postgres créant une base de données au démarrage, pour utiliser l'exemple de
  3. La possibilité de définir une vérification de l'état du service B et de spécifier que le service A doit attendre pour démarrer jusqu'à ce que la vérification de l'état du service B réussisse?

@aanand Le numéro 3 est mon vote. Cela donne au développeur la possibilité de choisir la logique de vérification de l'état au lieu de se fier à nouveau au service pour décider du moment. Pour ce cas d'utilisation particulier, une plus grande liberté de développeur est meilleure. Impossible d'anticiper tous les types d'applications qui seront installées dans des conteneurs.

+3

Ce serait bien d'avoir quelques contrôles de santé de base inclus, cependant. Quelque chose comme _http 200 ok sur le port 80_ est si courant que cela en vaut la peine.

Ce serait bien d'avoir un numéro 3 "piles incluses" (alors oserais-je dire tout ce qui précède?)

Ie capacité intégrée pour "le conteneur est en place", "le fichier est présent" et "le port est ouvert" type d'attente et ensuite un moyen de laisser les gens définir leurs propres contrôles de "couche d'application".

3 obtient mon vote

3 est un plus général 2 est un plus général 1. Tout le monde préférera 3, mais 2 ou 1 suffiront pour certains.

Votez pour 3

Évidemment, la 3ème option. Il y a des tas de cas uniquement dans cette discussion. Les 1ère et 2ème options seraient donc formidables et beaucoup de gens seraient heureux, mais la question resterait ouverte.

Votez pour 3

Votez pour 3

Votez pour 3. Intéressé par le test bêta aussi.

Votez pour 3.

Votez pour 3. Intéressé par le test bêta aussi.

Votez pour 3

3

Merci tout le monde. Vous pouvez arrêter de voter maintenant - je pense que le message est clair.

Je serais intéressé par les commentaires sur la conception que j'ai proposée dans https://github.com/docker/compose/issues/374#issuecomment -126312313 - toutes les propositions de conception alternatives, ainsi que des discussions sur leurs forces / faiblesses.

La méthode de commodité wait_for_tcp serait utile, mais je ne vois pas comment il est plus facile d'avoir un conteneur séparé pour faire la vérification de l'état que de le faire dans le même conteneur que celui décrit par @olalonde et @mbentley ci-dessus .

Qu'en est-il de faire quelque chose comme ce que fait Alexec dans le docker-maven-plugin? Il a explicitement conçu sa configuration pour être similaire à docker-compse / fig et jusqu'à présent, cela a très bien fonctionné pour mes projets.

healthChecks:
  pings:
     # check this URL for 200 OK
     - https://localhost:8446/info
     # check another URL with non-default time out, with a pattern, and non checking SSL certificates
     - url: https://localhost:8446/info
       timeout: 60000
       pattern: pattern that must be in the body of the return value
       sslVerify: false
  logPatterns:
     - pattern that must be in log file
     - pattern: another pattern with non-default timeout
       timeout: 30000

Source: https://github.com/alexec/docker-maven-plugin/blob/master/USAGE.md

Vérifier que la connexion TCP n'est pas suffisante pour savoir que la base de données est démarrée. Je pense qu'il vaut mieux avoir une commande qui vérifie la santé de la base de données.

@ceagan Comme ça. Les commandes personnalisées seraient également utiles. par exemple

healthChecks:
  custom:
    # retry this command until it returns success exit code
    - cmd: psql --host=localhost --username=postgres
      sleep: 1s

Je pense aussi que checks serait mieux que healthChecks car il n'est pas nécessaire de se souvenir de la convention de cas. Cela peut aussi être utile d'avoir wait (combien de secondes attendre avant de commencer à exécuter des vérifications de santé), attempts (combien de fois la santé doit être vérifiée avant d'abandonner), retire (combien de secondes attendre avant d'abandonner complètement) les paramètres.

cela va dans le sens où le cadre du marathon l'a résolu. dépendances de base et vérifications de santé . comme il est très populaire pour démarrer des conteneurs docker, il vaut la peine de vérifier ses options (délais d'expiration, intervalle, codes de réponse, etc.) pour les adopter pour la composition.

Idem ici, option 3.

+1

+1

+1

Je vais m'en tenir à un script d'attente personnalisé, cependant, ce serait très bien.

+1

+1

Les options 3-healthChecks sonne bien.

+1

+1

+1

+3.
Pour ajouter d'autres réflexions à la discussion, les choix proposés par @aanand disent vraiment: l'état des conteneurs est de la responsabilité de docker, pas de docker-compose. Docker-compose pourrait implémenter tous ces cas d'utilisation de manière propre et élégante, si docker fournissait des informations d'état. Mais ce n'est pas le cas de Docker. Il semble s'en tenir à la vision de conteneurs immédiats et sans état, qui se lancent si rapidement que ces types de problèmes de synchronisation sont sans importance.
Dans mon cas, je poursuis l'idée de pouvoir choisir la meilleure architecture pour mes services, pour chaque cas. Par exemple, je voudrais parfois plusieurs instances MariaDB, chacune desservant une seule application. D'autres fois, je voudrais une seule instance MariaDB, servant plusieurs applications. Je ne veux pas que Docker me dise ce qui est le mieux ou ce que je devrais faire à la place. Docker semble toujours avoir ce genre de tentations;).
Je pense que la meilleure solution est de convaincre Docker de laisser les conteneurs déclarer des métadonnées arbitraires sur eux-mêmes, et d'utiliser cette fonctionnalité pour permettre à docker-compose de savoir si un conteneur est considéré comme "prêt" afin que d'autres puissent compter sur eux.
En ce qui concerne l’approche des «applications simples db-multiples», j'aimerais une définition telle que:

db:
  image: postgres:9.3
  ports:
    - "5432:5432"
app1:
  image: wordpress
  links:
    - db [WP]
app2:
  image: ghost
  links:
    - db [GST]

Docker Compose lancera "db" et posera des questions sur ses métadonnées (pertinentes pour Docker Compose). À partir du fichier yml, il sait que "app1" s'attend à ce que "db" soit "wordpress ready" (ce qui signifie non seulement accepter les connexions, mais aussi avec les objets requis).

Je n'ai pas de solution simple pour résoudre cette situation. Je le fais actuellement manuellement, en deux étapes: une image personnalisée postgresql-bootstrap, dans laquelle je crée la base de données et l'utilisateur de la base de données pour y accéder; et une image personnalisée liquibase-postgresql, pour générer les objets de base de données à partir des DDL fournis par (ou extraits) du conteneur Wordpress. Ce n'est qu'alors que je peux lancer "app1".
Cela m'oblige à séparer les conteneurs en groupes «infrastructure» et «applications», si les conteneurs «infrastructure» servent des applications différentes.

Docker Compose veut être aussi apatride que Docker lui-même. Je ne sais pas si c'est possible si ça veut être vraiment utile.

+1 pour l'option 3

+1

+1 pour l'option 3.

+1 pour l'option 3

+1 pour l'option 3

Ce problème existe depuis un certain temps, quelle est la solution?

@ bweston92 Je pense que le statut est que @aanand a proposé une solution plus tôt dans ce fil et cherche

toute proposition de conception alternative, ainsi que des discussions sur leurs forces / faiblesses.

Personnellement, je pense que la solution proposée par

Mon cas d'utilisation est juste pour les tests. Mes tests échoueront s'ils démarrent avant la création de la base de données, j'ai donc changé leur commande en bash -c "sleep 2; python manage.py test --keepdb" , comme ceci:

db:
    image: postgres:9.5
test:
    build: .
    command: bash -c "sleep 2; python manage.py test --keepdb"
    volumes:
        - ./test_project:/app
    links:
        - db
        - selenium
    environment:
        - EXTERNAL_TEST_SERVER=http://testserver:8000/
        - SELENIUM_HOST=http://selenium:4444/wd/hub
selenium:
    image: selenium/standalone-chrome:2.48.2
    links:
        - testserver
testserver:
    build: .
    command: bash -c "sleep 5; python manage.py testserver 8000 --static"
    volumes:
        - ./test_project:/app
    ports:
      - "8000:8000"
    links:
        - db

afin que je puisse exécuter docker-compose run test sans commencer la base de données et attendre.

Il est difficile de dire quel problème de nos jours est le "bon" endroit pour voter pour une nouvelle fonctionnalité de composition de docker qui permet de déclarer des dépendances explicites, mais considérez mon vote comme fort. Avec la nouvelle fonctionnalité de mise en réseau de Docker 1.9 et la dépréciation imminente des liens de conteneur en sa faveur, il n'y a plus de moyen idéal de s'assurer que le conteneur A démarre avant le conteneur B - car si vous utilisez le réseau défini par l'utilisateur de Docker 1.9, vous pouvez ne spécifie plus de liens de conteneur. C'est ... cassé.

Je suis d'accord. Existe-t-il un calendrier pour obtenir l'option 3? Ce serait formidable que cela soit accéléré.

Il convient de noter que l'ordre des dépendances ne résout pas réellement ce problème. Ce problème s'applique également aux liens. Dans de nombreux cas, un conteneur démarre assez rapidement pour que vous ne remarquiez pas le problème, mais le problème est toujours là.

Ce qui est nécessaire pour résoudre ce problème est une vérification de l'état des applications. Un contrôle de santé est essentiellement une boucle qui retentit une opération jusqu'à ce que l'opération soit réussie ou qu'un délai d'expiration soit atteint. Dans le cas d'un service HTTP, cela peut faire des requêtes http jusqu'à ce que vous obteniez un code 2xx. Pour une base de données, il peut s'agir de la connexion et de la sélection dans une table.

Dans tous les cas, il est spécifique à l'application, il doit donc être défini par le développeur. Si nous devions implémenter l'option 3 de https://github.com/docker/compose/issues/374#issuecomment -135090543, vous auriez toujours besoin d'implémenter cette logique de vérification de l'état.

Cela a déjà été mentionné à quelques reprises dans ce numéro (https://github.com/docker/compose/issues/374#issuecomment-53036154, https://github.com/docker/compose/issues/374#issuecomment-71342299 ), mais pour réitérer, vous pouvez résoudre ce problème dès aujourd'hui en rendant votre application résiliente à l'échec en réessayant une connexion. Vous devez le faire de toute façon pour n'importe quel système de production.

Il s'avère que la fonctionnalité permettant de rendre votre application résiliente aux échecs est en fait la même logique qu'un contrôle de santé. Donc, dans tous les cas, vous devez toujours implémenter la même logique. La seule différence serait de l'inclure. Pour le moment, vous pouvez l'inclure dans votre application ou dans un script de point d'entrée. Avec la modification proposée, vous pourrez la définir dans le fichier Compose. Dans tous les cas, vous devez toujours implémenter un bilan de santé pour chaque service.

Y a-t-il un avantage significatif à l'inclure dans le fichier Compose au lieu du script de point d'entrée? C'est peut-être encore à débattre.

Le gros inconvénient de le placer dans le fichier Compose est qu'il ralentit considérablement up .

Avec le nouveau réseau, nous pouvons faire en sorte que up se produise en parallèle (comme nous le faisons pour stop, rm et scale). Chaque conteneur peut démarrer en même temps, effectuer une initialisation, puis attendre que ses dépendances soient disponibles pour continuer. Cela rend le démarrage d'un environnement très rapide.

Si Compose doit attendre la fin d'une vérification de l'état, le démarrage est en fait séquentiel. Le démarrage du conteneur et l'initialisation de l'application ne se font pas en parallèle et tout est plus lent.

La plupart des applications auront des contrôles de santé en raison de derrière LB, surveillés en externe, etc. Pour en ouvrir un nouveau n'est pas difficile. Donc, si compose le prend en charge, c'est un choix que les gens peuvent utiliser. Ce n'est pas obligatoire. Dans le monde réel, les gens doivent faire face à une variété d'applications et cette notion selon laquelle toutes les applications peuvent soudainement être rendues intelligentes est irréaliste et peu pratique. Et la logique du wrapper dans le point d'entrée est tout simplement moche. Je pense qu'il y a eu suffisamment de demande dans la communauté pour une fonctionnalité et, comme vous le voyez, l'option 3 a obtenu beaucoup de votes.

Envoyé de mon iPhone

Le 18 novembre 2015, à 11 h 01, Daniel Nephin [email protected] a écrit:

Il convient de noter que l'ordre des dépendances ne résout pas réellement ce problème. Ce problème s'applique également aux liens. Dans de nombreux cas, un conteneur démarre assez rapidement pour que vous ne remarquiez pas le problème, mais le problème est toujours là.

Ce qui est nécessaire pour résoudre ce problème est une vérification de l'état des applications. Un contrôle de santé est essentiellement une boucle qui retentit une opération jusqu'à ce que l'opération soit réussie ou qu'un délai d'expiration soit atteint. Dans le cas d'un service HTTP, cela peut faire des requêtes http jusqu'à ce que vous obteniez un code 2xx. Pour une base de données, il peut s'agir de la connexion et de la sélection dans une table.

Dans tous les cas, il est spécifique à l'application, il doit donc être défini par le développeur. Si nous devions implémenter l'option 3 à partir de # 374 (commentaire), vous auriez toujours besoin d'implémenter cette logique de vérification de l'état.

Cela a déjà été mentionné à quelques reprises dans ce numéro (# 374 (commentaire), # 374 (commentaire)), mais pour réitérer, vous pouvez résoudre ce problème aujourd'hui en rendant votre application résiliente à l'échec en réessayant une connexion. Vous devez le faire de toute façon pour n'importe quel système de production.

Il s'avère que la fonctionnalité permettant de rendre votre application résiliente aux échecs est en fait la même logique qu'un contrôle de santé. Donc, dans tous les cas, vous devez toujours implémenter la même logique. La seule différence serait de l'inclure. Pour le moment, vous pouvez l'inclure dans votre application ou dans un script de point d'entrée. Avec la modification proposée, vous pourrez la définir dans le fichier Compose. Dans tous les cas, vous devez toujours implémenter un bilan de santé pour chaque service.

Y a-t-il un avantage significatif à l'inclure dans le fichier Compose au lieu du script de point d'entrée? C'est peut-être encore à débattre.

Le gros inconvénient de le mettre dans le fichier Compose est qu'il ralentit considérablement.

Avec le nouveau réseau, nous pouvons faire en sorte que cela se produise en parallèle (comme nous le faisons pour stop, rm et scale). Chaque conteneur peut démarrer en même temps, effectuer une initialisation, puis attendre que ses dépendances soient disponibles pour continuer. Cela rend le démarrage d'un environnement très rapide.

Si Compose doit attendre la fin d'une vérification de l'état, le démarrage est en fait séquentiel. Le démarrage du conteneur et l'initialisation de l'application ne se font pas en parallèle et tout est plus lent.

-
Répondez directement à cet e-mail ou affichez-le sur GitHub.

@dnephin Le résultat final est que vous avez les mêmes scripts wrapper pour chaque service. Mon point est qu'il y a des choses qui sont si courantes (comme HTTP 200 sur 80 et 443 ou TCP sur 5432) que c'est une bonne idée de les expédier avec compose.

Bien sûr, ce serait cool de résoudre tout cela au niveau de l'application, mais en réalité, vous n'aurez le contrôle que sur votre propre application et pas sur toutes les autres pièces mobiles comme la base de données, le cache ou la file d'attente de massage.

Je suis d'accord avec @mbdas et @jayfk , et je vais simplement ajouter: si la résistance à cela est que même avec les spécifications de dépendance et l'ordre résultant du démarrage du conteneur, il y aura des échecs, puis l'utilisation de liens de conteneurs et de volumes-de à L'ordre de démarrage du conteneur de contrôle n'aurait jamais dû se produire - tout ce que nous demandons, c'est que maintenant que le nouveau modèle de réseau signifie que les liens sont obsolètes (et que le nouveau modèle de réseau ne peut littéralement pas coexister avec les liens), le même démarrage -Ordre la fonctionnalité que les liens ont permis de nous être rendus d'une manière ou d'une autre. Bien sûr, tous les cas d'échec qui auraient pu se produire avec la commande de conteneurs basée sur les liens peuvent toujours se produire avec le nouveau modèle de réseau et les dépendances de conteneur, mais nous avons tous appris à vivre avec cela.

@delfuego : pouvez-vous expliquer comment les liens sont obsolètes, et surtout par quoi ils sont remplacés? un lien vers des documents / exemples suffit

@Silex https://docs.docker.com/compose/networking. est-ce que tu veux dire?

@ h17liner : oui c'est intéressant! Merci

Bien que je sois d' accord avec @dnephin ,

Cela a déjà été mentionné à quelques reprises dans ce numéro, mais pour réitérer, vous pouvez résoudre ce problème aujourd'hui en rendant votre application résiliente à l'échec en réessayant une connexion. Vous devez le faire de toute façon pour n'importe quel système de production.

Je ne vois pas cela comme faisant quelque chose comme exécuter des tests. Si je teste simplement si un modèle s'enregistre correctement dans l'application Django, je ne sais pas à quel point il est judicieux d'ajouter de la résilience à la connexion à la base de données.

@delfuego Je pense que vous étiez au bon endroit à l'origine (# 686) pour ce problème. Ce problème ne concerne pas la commande, il s'agit d'un retard artificiel au démarrage (lorsqu'une commande existe déjà). Bien que ces choses soient liées, ce sont des problèmes distincts.

Je ne suis pas d'accord avec les liens non pris en charge dans les réseaux de ponts créés par l'utilisateur et documentés comme étant obsolètes en général, il n'y a pas de commande. Ainsi, l'option 3 s'occupe à la fois de la commande et du moment de début du problème.

Envoyé de mon iPhone

Le 19 novembre 2015, à 8h14, Daniel Nephin [email protected] a écrit:

@delfuego Je pense que vous étiez au bon endroit à l'origine (# 686) pour ce problème. Ce problème ne concerne pas la commande, il s'agit d'un retard artificiel au démarrage (lorsqu'une commande existe déjà). Bien que ces choses soient liées, ce sont des problèmes distincts.

-
Répondez directement à cet e-mail ou affichez-le sur GitHub.

J'aimerais proposer l'option 4 (certains diront que c'est en fait une variation de 3)
Le conteneur n'est pas prêt tant que toutes les commandes de démarrage ne sont pas terminées avec 0 code de sortie. Doit être possible de définir ces commandes de démarrage dans un fichier yml pour chaque conteneur. Ces commandes sont exécutées comme vous le feriez avec "docker exec" contre un conteneur en cours d'exécution. Pensez aux méthodes setUp () et tearDown () dans les tests unitaires classiques. Oui, nous pourrions également avoir des commandes "shutdown".
De toute évidence, le prochain conteneur de la hiérarchie n'est pas lancé tant que tous les conteneurs dont il dépend ne sont pas prêts.
PS Merci pour l'excellente DockerCon.Eu 2015

Une directive HEALTHCHECK est beaucoup plus flexible (c'est-à-dire qu'elle peut être utilisée ultérieurement) et utile. La configuration doit être effectuée dans le script CMD ou (mieux encore) ENTRYPOINT , démontage en gérant les signaux de processus.

Je pense que le nœud du problème ici est que les gens veulent une seule commande docker-compose up pour faire apparaître une pile et que tout fonctionne comme par magie.

Sur la base de tous les commentaires, il existe clairement de nombreuses solutions pour différents cas d'utilisation, mais pas de «taille unique».

Vous pouvez exécuter des tâches "d'initialisation" assez facilement en exécutant plusieurs commandes docker-compose - et je pense que cette approche est l'approche la plus générique et la plus flexible.

Par exemple, j'exécute un playbook Ansible dans un conteneur "agent" avec une seule tâche qui attend que le conteneur my database (MySQL) s'exécute sur le port 3306. Ce conteneur "agent" est lié au conteneur my "db" donc automatiquement le démarre lorsque ce qui suit est exécuté:

$ docker-compose run --rm agent
Creating db_1

PLAY [Probe Host] *************************************************************

TASK: [Set facts] *************************************************************
ok: [localhost]

TASK: [Message] ***************************************************************
ok: [localhost] => {
    "msg": "Probing db:3306 with delay=0s and timeout=180s"
}

TASK: [Waiting for host to respond...] ****************************************
ok: [localhost -> 127.0.0.1]

PLAY RECAP ********************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0

Après quoi je peux exécuter docker-compose up sachant que le conteneur db est pleinement opérationnel.

Voici un simple fichier docker-compose.yml qui prend en charge ceci:

...
...
db:
  image: mysql
  hostname: db
  expose:
    - "3306"
  environment:
    MYSQL_DATABASE: xxx
    MYSQL_USER: xxx
    MYSQL_PASSWORD: xxx
    MYSQL_ROOT_PASSWORD: xxx

agent:
  image: cloudhotspot/ansible
  links:
    - db
  volumes:
    - ../../ansible/probe:/ansible
  environment:
    PROBE_HOST: "db"
    PROBE_PORT: "3306"

Le conteneur "agent" exécute un playbook nommé site.yml dans le volume monté /ansible qui est illustré ci-dessous:

- name: Probe Host
  hosts: localhost
  connection: local
  gather_facts: no
  tasks: 
    - name: Set facts
      set_fact: 
        probe_host: "{{ lookup('env','PROBE_HOST') }}"
        probe_port: "{{ lookup('env','PROBE_PORT') }}"
        probe_delay: "{{ lookup('env','PROBE_DELAY') | default(0, true) }}"
        probe_timeout: "{{ lookup('env','PROBE_TIMEOUT') | default (180, true) }}"
    - name: Message
      debug: msg="Probing {{ probe_host }}:{{ probe_port }} with delay={{ probe_delay }}s and timeout={{ probe_timeout}}s"
    - name: Waiting for host to respond...
      local_action: >
        wait_for host={{ probe_host }}
        port={{ probe_port }}
        delay={{ probe_delay }}
        timeout={{ probe_timeout }}
      sudo: false

Une solution à l'objectif unique docker-compose up pourrait être d'introduire une fonctionnalité de "workflow" pour docker compose et d'inclure un fichier de spécification de workflow facultatif qui permet des scénarios d'orchestration plus complexes et contrôlés en spécifiant une ou plusieurs commandes docker-compose comme "tâches" à exécuter:

# The default workflow, specified tasks will be run before docker-compose up
# The "up" task is implicit and automatically invoked for the default workflow
# The "up" task is explicit for custom workflows as some workflows may not want docker-compose up
default:
  tasks:
    - run --rm agent
    - up

# Custom workflows that can be invoked via a new docker-compose command option
# This example:
# 1. Runs agent container that waits until database container is up on port 3306
# 2. Runs Django database migrations from app container
# 3. Runs Django collect static task from app container
# 4. Runs test container that runs acceptance tests against linked app container
# Does not execute a docker-compose up afterwards

test:
  tasks:
    - run --rm agent 
    - run --rm app manage.py migrate
    - run --rm app manage.py collectstatic --noinput
    - run --rm test

Aujourd'hui, j'obtiens ce qui précède en utilisant des Makefiles, qui fournissent une capacité d'ordre supérieur à définir mes propres flux de travail pour différents scénarios.

Ce serait formidable si une fonctionnalité de "workflow" ou similaire pouvait être introduite dans docker compose, ce qui fournirait une solution très générique et flexible à ce problème particulier et bien d'autres.

D'accord, le problème est que les gens s'attendent à ce que docker-compose soit suffisant pour les déploiements de production. Personnellement, je pense que cela prendra du temps avant que cela ne devienne réalisable et Helm semble être beaucoup plus proche de cet objectif.

@olalonde , bien sûr, nous aimerions composer pour être prêt pour la production ... mais nous prendrons en charge des fonctionnalités importantes et existantes qui, compte tenu de la dépréciation des liens de conteneurs, vont disparaître à moins qu'elles ne soient répliquées au nouvel utilisateur -modèle de réseaux-créés. (Encore une fois, peut-être que cette demande n'est pas parfaitement alignée avec ce problème spécifique - je ne sais toujours pas si la simple commande de démarrage du conteneur "appartient" ici ou dans le numéro 686 ...)

Avec une directive HEALTCHECK Docker, la fonctionnalité depends_on peut soit attendre le démarrage du conteneur (pas de contrôle de santé) ou le script de contrôle de santé pour se terminer avec succès (code de sortie 0 ). Ceci est aussi flexible que possible (vous pouvez définir une logique arbitraire) et maintient la logique de contrôle de santé à sa place (dans le conteneur qui est vérifié).

@delfuego même pour le développement et les tests, cette fonctionnalité serait utile. Personnellement, je veux pouvoir faire docker-compose run test et le faire fonctionner sans avoir à mettre en place les services au préalable et à attendre manuellement. Bien que cela soit possible, cela rend juste un peu plus pénible de démarrer avec le projet et ajoute d'autres façons dont les tests peuvent échouer.

+1

Je pense que la résolution nécessite une voie médiane - composer ne pourra jamais rendre compte de toutes les différentes façons dont les applications peuvent être considérées comme disponibles ou non. L'idée d'un bilan de santé aura différentes significations pour différentes personnes, et peut ne pas être aussi simple que «est-ce que ça marche ou pas». En production, vous pouvez supprimer un conteneur s'il présentait des temps de réponse anormalement longs, même s'il passait des contrôles HTTP.

Je pense donc que le support de base des réponses HTTP, des ports ouverts, des fichiers créés ou des lignes de journal émises devrait être suffisant pour le développement. Tout ce qui est plus avancé que cela devient presque immédiatement spécifique à l'application. J'aime aussi l'idée d'encourager les développeurs à rendre les différentes parties de leurs piles d'applications plus robustes.

@pugnascotia merci, c'est un commentaire constructif et une approche raisonnable ("le meilleur des deux mondes"?)

Les solutions actuellement discutées ne semblent pas réellement résoudre le problème _ signalé à l'origine_ qui est beaucoup plus simple ... qui n'attend PAS qu'un service soit disponible, mais d'attendre qu'un service quitte.

J'ai un cas d'utilisation où j'ai deux conteneurs qui exposent les mêmes ports. Le premier fonctionne pendant 15 à 60 secondes, puis se termine. Ensuite, le deuxième service devrait démarrer. Il n'y a aucun moyen (évident?) De faire cela dans compose aujourd'hui car il détectera le conflit de port et sortira; même pas «redémarrer: toujours» est une solution.

Oui, Compose n'est pas conçu pour ce cas d'utilisation. Compose se concentre sur les environnements d'exécution, pas sur la création de pipelines. Je ne pense pas que ce soit le sujet du problème initialement signalé.

Il y a eu quelques demandes de fonctionnalités plus orientées build, mais je ne pense pas qu'elles aient un sens pour la composition. Les deux fonctions sont très différentes et essayer de les faire rentrer dans le même format de configuration est susceptible de conduire à beaucoup de confusions et à une mauvaise expérience utilisateur.

@ewindisch votre cas d'utilisation peut être généralisé à l'exécution d'une chaîne de travaux par lots. Compose est utile dans ce cas (bien qu'il n'ait pas été conçu pour cela) car il maintient les dépendances entre les services - par exemple, ces chaînes. Mais il ne gère pas le séquençage et à mon humble avis, il ne devrait pas parce que Compose est à l'extérieur des conteneurs et n'a aucune idée de ce qu'un processus à l'intérieur d'un conteneur va faire.

Cette partie de la documentation de Compose couvre la question de savoir pourquoi Compose n'a pas cette capacité:

https://docs.docker.com/compose/faq/#how -do-i-get-compose-to-wait-for-my-database-to-be-ready-before-start-my-application

Cependant, ces pages ne mentionnent pas du tout le problème:

https://docs.docker.com/compose/django/
https://docs.docker.com/compose/rails/
https://docs.docker.com/compose/wordpress/

À tout le moins, ces pages devraient inclure une confirmation que Compose n'attendra pas qu'un conteneur de base de données soit prêt. Ils pourraient également inclure des exemples de moyens de gérer ce problème.

@ewindisch En fait, c'est exactement ce que je proposais dans https://github.com/docker/compose/issues/374#issuecomment -126312313 - avec l'hypothèse que la résolution de _that_ problème donne également aux utilisateurs les outils pour résoudre le problème de commande de démarrage ( sinon le problème de la résilience à plus long terme).

Je suis toujours intéressé à explorer cet espace de solution, si quelqu'un d'autre l'est.

Je suis.

Moi aussi.

+1

+3

+1

+1 pour la mise en œuvre de la solution https://github.com/docker/compose/issues/374#issuecomment -126312313.

Un vote massivement positif!
Actuellement, cela affecte l'utilisation d'outils qui s'exécutent dans le conteneur, mais qui reposent sur des événements de docker (par exemple, jwilder / nginx-proxy). La façon dont je le fais est simplement de docker-composer manuellement l'auditeur et d'exécuter ensuite tous les autres conteneurs (ce qui gâche toute la beauté de docker-compose up en tant que point d'entrée unique).

@meetmatt avez-vous essayé d'exécuter jwilder / nginx-proxy par la suite? L'ordre de départ ne devrait pas avoir d'importance pour cela, il récupérera les conteneurs existants (en cours d'exécution) au démarrage

+1

+1

J'aimerais vraiment voir une solution transparente basée sur les canaux. Fondamentalement, comme libchan. De cette façon, si j'interroge une base de données, la demande est mise en mémoire tampon jusqu'à ce que la base de données soit prête.

Je ne pense vraiment pas que l'ordre de chargement soit une solution suffisante dans les systèmes distribués. Que se passe-t-il si, par exemple, vous devez redémarrer votre base de données mais que d'autres services risquent de se bloquer en conséquence? Une vraie solution gérerait également ce cas d'utilisation.

Comptez sur moi, car la prévisibilité du pipeline d'exécution est un élément clé de ce que nous faisons au travail. +1

+1

J'ai dû louper quelque chose.

Pourquoi personne ne préconise l'ajout d'un "attendre jusqu'à" dans le docker run (le moteur docker lui-même). Dans tous les cas auxquels je pense, le conteneur dépendant sait quand il est "prêt" mais docker ne respecte pas cela.

Dans le cas d'origine (mysql chargeant un grand ensemble de données et en plein air), le conteneur mysql peut renvoyer ou signaler quand il est prêt et le conteneur en plein air ne démarrerait pas avant.

Je voudrais exécuter une logique arbitraire et signaler à docker quand je suis prêt comme décidé par moi (par exemple quand un certain message dans le journal apparaît -> signal CONTAINER_UP).

net: "container:[name or id]" pourquoi ne pas commander les startups de mes conteneurs? J'ai dû abandonner links car il sera obsolète et je veux que toute la pile utilise le réseau net: "host" . Malheureusement, cela n'est pas autorisé avec links . Existe-t-il un autre moyen de modifier l'ordre de démarrage des conteneurs ou dois-je partager des volumes inutiles entre eux?

Mettre à jour:

Je viens de faire la commande avec des volumes inutiles au lieu de links :

base:
  build: ./base
  net: "host"
  volumes:
    - /root/lemp_base
phpmyadmin:
  build: ./phpmyadmin
  net: "host"
  volumes_from:
    - base
  volumes:
    - /root/lemp_phpmyadmin
ffmpeg:
  build: ./ffmpeg
  net: "host"
  volumes_from:
    - phpmyadmin
  volumes:
    - /root/lemp_ffmpeg
mariadb:
  build: ./mariadb
  net: "host"
  volumes_from:
    - ffmpeg
  volumes:
    - /root/lemp_mariadb
php:
  build: ./php
  net: "host"
  volumes_from:
    - mariadb
  volumes:
    - /root/lemp_php
nginx:
  build: ./nginx
  net: "host"
  volumes_from:
    - php
  volumes:
    - /root/lemp_nginx

(J'ai effacé d'autres volumes partagés de la pile et une autre information comme container_name, les ports pour avoir l'air simple.)

Si je veux utiliser avec net: "container:base , j'ai un message d'erreur sur la commande docker-compose build .

ERROR: Service "mariadb" is trying to use the network of "lemp_base", which is not the name of a service or container.

Ce que je n'aime pas dans cette solution, c'est que tous les autres conteneurs auront les fichiers du serveur Web dans le dossier /var/www partir de base .

ÉDITER:
Pour une raison quelconque, cette pile supprime tout le dossier /var/www au démarrage.

Mon humble avis est que tout mécanisme aboutissant à la connaissance de la dépendance entre conteneurs par Docker Compose va à l'encontre de la séparation des préoccupations. Docker Compose est responsable de l'exécution des conteneurs A et B. Les conteneurs A et B sont responsables de leur propre service. Si B dépend de A pour fonctionner correctement, il est de la responsabilité de B d'attendre que A soit en état de fonctionnement. Comme cela a été dit dans la discussion, cela peut être fait par timeout, réessayer ou autre, mais c'est le problème de B, pas de Docker Compose ni A. Le SoC est d'une importance primordiale pour l'indépendance du service et une mise à l'échelle appropriée.

Y a-t-il du travail sur votre idée 3 @aanand ? Il serait bon de savoir s'il y a des progrès, cela sonnait comme un début prometteur qui aiderait quelques cas d'utilisation très courants même si ce n'est pas une solution parfaite

+1

+1

Peut-être que je me trompe, mais args: buildno: peut commander les conteneurs en docker-compose.yml version 2?

J'ai tendance à convenir qu'il s'agit d'une préoccupation qui n'appartient pas à Compose. @jwilder est excellente Dockerize tout le soutien obtenu à attendre pour les conteneurs à charge et vous pouvez spécifier le protocole / port que vous attendez sur. Je suggérerais que cela convienne à la plupart des cas d'utilisation décrits ici:

api:
  build: .
  ports:
   - "8000:80"
  expose:
  - "80"

test:
  build: test
  command: dockerize -wait http://api:80 -wait tcp://db:5432 somecommand -some arg -another arg2
  links:
    - api:api

Idéalement, nous utilisons l'API Docker Events pour détecter automatiquement cela, mais cela signifierait que chaque conteneur aurait également besoin d'accéder au runtime Docker, ce qui n'est probablement pas faisable / ce que nous voudrions.

Je pense que l'attente doit se faire en dehors de composer. Dans mon développement, je vais utiliser un hybride de ce que @mefellows a suggéré et des pages d'état de timercheck.io . J'ai quelque chose qui me donnera exactement ce dont j'ai besoin sans avoir à utiliser RabbitMQ ou quelque chose de similaire.

Nous utilisons un point d'entrée de script shell qui attend l'ouverture du port, avec un timeout de 15 secondes:

#!/usr/bin/env bash

# wait for db to come up before starting tests, as shown in https://github.com/docker/compose/issues/374#issuecomment-126312313
# uses bash instead of netcat, because netcat is less likely to be installed
# strategy from http://superuser.com/a/806331/98716
set -e

echoerr() { echo "$@" 1>&2; }

echoerr wait-for-db: waiting for db:5432

timeout 15 bash <<EOT
while ! (echo > /dev/tcp/db/5432) >/dev/null 2>&1;
    do sleep 1;
done;
EOT
RESULT=$?

if [ $RESULT -eq 0 ]; then
  # sleep another second for so that we don't get a "the database system is starting up" error
  sleep 1
  echoerr wait-for-db: done
else
  echoerr wait-for-db: timeout out after 15 seconds waiting for db:5432
fi

exec "$@"

Cela devrait être résolu par le prochain (et apparemment imminent avec la mise à jour de la documentation) depend_on , ouais?

Nan. depends_on commande uniquement. Pour retarder réellement le démarrage d'un autre conteneur, il faudrait un moyen de détecter quand un processus a fini de s'initialiser.

Ah, merci pour la clarification. =)

J'ai écrit un utilitaire de ligne de commande purement bash appelé wait-for-it qui peut être inclus dans les déploiements de docker pour aider à synchroniser les déploiements de services.

Pour moi, ce n'est pas une bonne idée de coder en dur une collection arbitraire de «contrôles de disponibilité». Il existe de nombreuses situations spécifiques à un type de déploiement et vous ne pourrez jamais toutes les couvrir. À titre d'exemple, dans mon application multi-conteneurs, je dois attendre qu'un certain message de journal apparaisse dans un certain fichier journal - ce n'est qu'alors que le service de conteneur sera prêt.
Au lieu de cela, ce qu'il faut, c'est un SPI que je peux implémenter. Si Docker fournit des exemples d'implémentations pour les cas d'utilisation les plus fréquents (par exemple connexion TCP), c'est très bien. Mais il doit y avoir un moyen pour moi de brancher ma propre fonctionnalité et que Docker l'appelle.
Docker Compose est à peu près inutile pour moi dans son ensemble, si je ne peux pas faire fonctionner mes conteneurs de manière fiable. Un «SPI de préparation du service de conteneur» stable et uniforme est donc nécessaire. Et «prêt» ne devrait pas être un booléen, car il y a peut-être plus de niveaux de préparation (comme: «maintenant vous pouvez lire» et «maintenant vous pouvez écrire»).

@realulim Bonne rédaction. Je suis entièrement d'accord avec l'idée de nous laisser définir ce que signifie l'état "prêt" d'un service via des plugins. Je pense aussi que c'est une bonne idée d'avoir une valeur par défaut pour le plugin qui vérifie uniquement qu'un service écoute une connexion http / tcp. Cela couvrirait la majorité des cas sur place.

C'est ce que je suis venu avec, dans le fichier entrypoint;

until netcat -z -w 2 database 5432; do sleep 1; done
# do the job here, database host on port 5432 accepts connections

@kulbida ,
Je fais quelque chose de très similaire avec MySQL. "base de données" dans ce cas est un lien dans un fichier de composition.

if [[ "$APP_ENV" == "local" ]]; then
    while ! mysqladmin ping -h database --silent; do
        sleep 1
    done
    # Load in the schema or whatever else is needed here.
fi

Il y a eu des commentaires dans ce fil qui prétendent que l'ordre de démarrage n'est qu'un sous-ensemble de la récupération d'erreur au niveau de l'application, que votre application devrait de toute façon gérer. Je voudrais donner un exemple pour illustrer les cas où cela n’est pas toujours le cas. Considérez si certains services dépendent d'une base de données en cluster, et chaque fois qu'un quorum est perdu en raison d'un plantage, etc., vous ne voulez pas réessayer automatiquement à partir de l'application. Cela peut être le cas, par exemple, si la récupération de la base de données nécessite des étapes manuelles et que vous avez besoin que les services restent sans ambiguïté jusqu'à ce que ces étapes soient effectuées.

Maintenant, la logique de gestion des erreurs de l'application peut être assez différente de la logique de démarrage:

  • Si la base de données est en panne parce que nous ne faisons que démarrer, attendez qu'elle soit disponible.
  • Si la base de données est en panne parce qu'elle s'est plantée, enregistrez une erreur critique et mourez.

Ce n'est peut-être pas le scénario le plus courant, mais vous voyez parfois ce modèle. Dans ce cas, le clustering est utilisé pour résoudre le problème «le réseau n'est pas fiable» dans le cas général, ce qui change certaines des attentes autour desquelles les conditions d'erreur doivent être retentées dans l'application. Les plantages de cluster peuvent être assez rares et leur redémarrage automatique peut être suffisamment risqué pour que le redémarrage manuel des services soit préférable à une nouvelle tentative dans l'application. Je soupçonne qu'il existe également d'autres scénarios qui pourraient remettre en question les hypothèses sur le moment de réessayer.

Plus généralement, je prétends que la commande de démarrage et la gestion des erreurs ne sont pas toujours équivalentes et qu'il est approprié pour un framework de fournir des fonctionnalités (facultatives) pour gérer la commande de démarrage. Je me demande si cela appartient à docker-engine, plutôt que de composer. Cela peut être nécessaire à tout moment du démarrage de docker, que Compose soit ou non utilisé.

Une discussion commence sur le repo du moteur docker dans la proposition https://github.com/docker/docker/issues/21142 pour ajouter la prise en charge de la vérification de l'état. Une fois ce support disponible, Compose pourra fournir un moyen de le configurer et de l'utiliser pour un démarrage différé.

Que diriez-vous d'utiliser le système de fichiers pour vérifier l'existence d'un fichier?

ready_on: /tmp/this_container_is_up_and_ready

De cette façon, c'est au développeur du conteneur de décider quand les choses sont en cours, mais compose peut attendre que le conteneur se déclare prêt. C'est une convention explicite, mais qui pourrait être facilement ajoutée en tant que couche supplémentaire aux images qui n'ont pas ce comportement.

La prise en charge intégrée des bilans de santé sera bonne; en attendant, voici le hack que j'ai fait travailler dans ma configuration locale de docker-compose:

    nginx:
        image: nginx:latest
        command: /bin/bash -c "sleep 2 && echo starting && nginx -g 'daemon off;'"
        ...

(En production, mon application effectue un proxy vers quelques serveurs en amont déjà en cours d'exécution à l'aide de proxy_pass ; dans le développement et le test locaux, je démarre les instances docker de ceux-ci, et nginx doit attendre un peu pour qu'ils démarrent, sinon il se bloque et meurt. La chose daemon off garde nginx dans un seul processus, sinon docker arrêtera le conteneur dès que le processus parent génère son enfant démon.)

Juste pour ajouter mes deux cents, si vous utilisez l'outil de construction ANT, il est livré avec un support intégré pour retarder l'exécution jusqu'à ce qu'un certain socket soit ouvert.

Notre serveur Jenkins CI fait tourner les conteneurs de projet avec Docker Compose, puis exécute ANT à partir du conteneur principal, comme ceci:

docker-compose up -d
docker exec -it projectx-fpm-jenkins ant -f /var/www/projectX/build.xml

Il s'agit de l'élément de configuration pertinent du fichier docker-compose.yml. Notez que, comme discuté ci-dessus, faire dépendre fpm de mysql n'est pas suffisant pour garantir que le service MySQL sera prêt quand il sera réellement nécessaire.

version: '2'
services:
  nginx:
    build: ./docker/nginx
    depends_on:
      - fpm
  fpm:
    build: ./docker/fpm
    depends_on:
      - mysql
  mysql:
    image: mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=projectx
      - MYSQL_DATABASE=projectx

Mais vous pouvez l'attendre pendant la tâche ANT:

<!-- other targets... -->

<target name="setup db">
    <!-- wait until the 3306 TCP port in the "mysql" host is open -->
    <waitfor>
        <socket server="mysql" port="3306"/>
    </waitfor>

    <exec executable="php">
        <arg value="${consoledir}/console"/>
        <arg value="doctrine:database:create"/>
        <arg value="--no-interaction"/>
    </exec>
</target>

@kulbida Cela a fait l'affaire, merci. Quelque chose d'un peu plus rapide:

while ! nc -w 1 -z db 5432; do sleep 0.1; done

_depends_on_ peut résoudre le problème.
À partir de la documentation de docker-compose .
Dépendance express entre les services, ce qui a deux effets:

  1. docker-compose up démarrera les services dans l'ordre des dépendances. Dans l'exemple suivant, db et redis seront démarrés avant web.
  2. docker-compose up SERVICE inclura automatiquement les dépendances de SERVICE. Dans l'exemple suivant, docker-compose up web créera et démarrera également db et redis.

version 2'
prestations de service:
la toile:
construire: .
dépend de:
- db
- redis
redis:
image: redis
db:
image: postgres

@alexch : lors d'un test de performance côté client (micro-service acheminé via nginx +). Test nginx dockérisé - une baisse de la charge de très hauts à un minimum proche de zéro se répétait toutes les 1-2 minutes Finalement, j'ai décidé d'aller avec Nginx non dockerisé fonctionnant en tant que VM (juste à cause de l'énorme différence de performances), peut-être un problème de plugin de pilote réseau / libNetwork.

@syamsathyan depends_on ne semble pas aider.

@skorokithakis , @kulbida c'est une bonne solution. Malheureusement, netcat n'est disponible par défaut dans aucun des services dont j'ai besoin pour me connecter à ma base de données (y compris postgres ). Connaissez-vous une méthode alternative?

@nottrobin J'ai peur que non, je viens de l'installer à mon image: /

@nottrobin mon équipe travaille là-dessus, vous le fera savoir dans un jour ou deux!

Pour ceux qui ont récemment eu une bash, il existe une solution sans netcat (inspirée de: http://stackoverflow.com/a/19866239/1581069):

while ! timeout 1 bash -c 'cat < /dev/null > /dev/tcp/db/5432'; do sleep 0.1; done

ou version moins verbeuse:

while ! timeout 1 bash -c 'cat < /dev/null > /dev/tcp/db/5432' >/dev/null 2>/dev/null; do sleep 0.1; done

@typekpb qui fonctionne parfaitement. Merci!

Maintenant que le support HEALTHCHECK est fusionné en amont selon https://github.com/docker/docker/pull/23218 - cela peut être considéré pour déterminer quand un conteneur est sain avant de commencer le suivant dans la commande. La moitié du puzzle est résolue :)

Maintenant que le support HEALTHCHECK est fusionné en amont selon le docker / docker # 23218 - cela peut être pris en compte pour déterminer quand un conteneur est sain avant de commencer le suivant dans la commande. La moitié du puzzle est résolue :)

Cela semble bon. Comment l'implémenter sur docker-compose.yml ?

Cela semble bon. Comment l'implémenter sur docker-compose.yml?

L'autre pièce du puzzle consistera à surveiller la composition de docker pour les conteneurs sains et à utiliser quelque chose comme la syntaxe depend_on mentionnée plus haut dans ce numéro. Il faudra des correctifs pour docker-compose pour que les choses fonctionnent.

Notez également que la fonctionnalité de vérification de l'état de Docker n'est actuellement pas publiée, il faudra donc probablement s'aligner sur un cycle de publication de Docker / Docker Compose.

J'ai écrit une bibliothèque js qui a une méthode .waitForPort() . Tout comme cela a été mentionné précédemment, cela pourrait ne pas fonctionner pour toutes les situations, mais pourrait très bien fonctionner pour la majorité des cas d'utilisation.
Voir mon blog .

La fusion HEALTHCHECK est une excellente nouvelle.

En attendant, ce document décrit le problème et quelques solutions.

@pablofmorales Non, car depends_on vérifie simplement que le conteneur est actif .

Certains démons ont besoin de plus de temps pour s'amorcer et commencer à écouter leurs ports et adresses assignés, notamment MySQL.

Je pense toujours qu'une déclaration "READY_ON" est toujours la meilleure dans l'ensemble. Cela laisse la décision de savoir quand quelque chose est prêt pour le conteneur lui-même, quelle que soit l'image, il est explicite dans l'activation et la fonctionnalité de chemin de ressource (dans le conteneur) dans l'API Docker Remote garantit des modifications minimales nécessaires.

Le comportement du moment où un conteneur est "up" est le seul effet que cela devrait avoir. Il ne sera signalé comme "up" que lorsque le fichier READY_ON existe.

Je pense que c'est 90% du comportement dont tout le monde parle. Je pense que "healthcheck" ici est confondu comme 2 événements différents, mais en essayant de le cramponner en un seul. L'un est «prêt» pour une chaîne d'événements lors de la mise en route d'une infrastructure, l'autre est «santé» afin que l'infrastructure puisse être maintenue.

"prêt" est un endroit tout à fait approprié pour que docker aide. Quant à la «santé», c'est tellement varié en termes de systèmes, je pense que c'est au conteneur de s'en occuper.

Pour une meilleure alternative à la vérification de l'état, vous voudrez peut-être examiner quelque chose comme containerpilot qui couvre non seulement la santé, mais aussi la découverte et la surveillance des services. https://github.com/joyent/containerpilot

Oui, c'est une distinction précise et importante. Cependant, comment les conteneurs vont-ils écrire ce fichier sans que les images ne deviennent beaucoup plus compliquées? Il me semble que cela nécessiterait un script wrapper pour chaque conteneur qui souhaite l'utiliser.

De toute façon, vous devrez lancer un script pour initialiser l'instance ... la dernière chose que le script doit faire est de toucher un fichier. Pour moi, cela semble beaucoup plus facile que d'essayer d'exécuter un exécutable sur une machine distante pour faire une vérification de l'état. Au moins avec un fichier tactile, il peut être regardé, etc. entièrement via l'API de manière passive sans avoir besoin d'entrer dans le contexte du conteneur.

Je suis d'accord, mais de nombreux conteneurs n'utilisent pas de script, ils installent simplement un service comme Postgres ou Redis et le laissent démarrer sans le regarder.

Dans mon cas, j'utilise Kong API Gateway

Avant d'exécuter le conteneur kong, je vérifie simplement si Cassandra travaille avec ce script

while true; do
    CHECK=`kong-database/check`
    if [[ $CHECK =~ "system.dateof" ]]; then
        break
    fi
    sleep 1;
done

le fichier de chèque contient ceci

#!/bin/bash
docker cp cassandra-checker kong-database:/root/
docker exec -i kong-database cqlsh -f /root/cassandra-checker

cassandra-checker est juste une simple requête

SELECT dateof(now()) FROM system.local ;

Bien sûr, mais l'alternative est un contrôle de santé, qui nécessite un script que vous devrez de toute façon écrire, donc il n'y a pas de différence de frais généraux. C'est aussi un opt-in explicite, ce qui signifie que vous déclarez que vous voulez ce comportement. Quant à quelque chose qui n'exécute pas de script, vous pouvez toujours avoir une vérification de chemin ready_on pour un fichier pid ou une socket unix; qui ne nécessiterait pas de script.

C'est vrai, tu as raison.

Vérifier l'existence d'un fichier peut convenir dans de nombreux cas, mais forcer les conteneurs à utiliser un script de démarrage alors qu'ils n'en auraient pas besoin autrement est une nuisance. Pourquoi ne peut-il pas également y avoir de contrôles pour d'autres conditions très simples? Il serait particulièrement utile d'attendre que le processus écoute sur un port tcp particulier.

Cette idée est opt-in, donc il n'y a rien de forcé. En fait, vous êtes explicite en disant à quoi il faut s'attendre.

Une écoute de port TCP peut ne pas être suffisante pour dire quand un conteneur a été initialisé car il peut y avoir un tas de données de configuration à exécuter. Enfer, si vous vous connectez trop rapidement à un conteneur postgres, même via TCP, vous obtiendrez une erreur indiquant que la base de données n'est pas encore prête.

Si je vous comprends bien, c'est "opt-in, sinon vous ne pouvez pas utiliser cette fonctionnalité". Ergo, si j'ai besoin de cette fonctionnalité et que mon application n'utilise pas de fichier pid, je suis obligé d'utiliser un script de démarrage.

Pour MySQL (le cas de l'OP), une fois qu'il écoute, il est prêt. Ils se donnent beaucoup de mal pour s'assurer que c'est vrai, probablement pour des cas comme celui-ci. Mon avis est qu'il existe probablement une courte liste de conditions qui pourraient être énumérées de telle sorte que vous puissiez «opter» pour configurer une vérification prête contre l'une de ces conditions. Je ne vois aucune raison que cela doive être fait d'une seule et unique manière.

Pour mysql, une fois qu'il écoute, il n'est pas prêt. Dans le cas simple d'un nœud, il sera prêt, mais si vous avez plus d'un nœud, il ne sera certainement pas encore prêt. Je comprends ce que vous entendez par «une et une seule manière», mais je pense qu'en tant qu'abstraction de base, c'est tout simplement parfait. Je le vois plutôt comme un endroit où vous pouvez appliquer l'outillage que vous voulez. Heck, votre script pourrait même communiquer avec des services externes et leur demander de vérifier le conteneur, auquel cas vos services externes pourraient indiquer à votre agent de conteneur d'écrire le fichier. Flexibilité ftw.

Si vous essayez quelque chose dans cette liste de "conditions", il y aura TOUJOURS un cas où cela ne fonctionnera pas. Cependant, toucher un fichier fonctionnera toujours, car l'image sait quand elle pense qu'elle est prête (oh, je dois attendre sur d'autres hôtes, j'ai besoin que les fichiers soient téléchargés, je dois m'assurer que $ external_service est également disponible, je passe correctement, mais pour une raison quelconque, je n'ai pas les autorisations appropriées sur la base de données, pourquoi cette image est-elle en lecture seule ... etc. etc.

Ces sortes de scripts existent déjà partout ... bon sang, il était déjà nécessaire d'écrire ces scripts parce que nous n'avions jamais eu de fonctionnalités comme celle-ci auparavant. Donc, laisser tomber un script comme celui-ci est minime, car il est probable qu'un script existe déjà.

Un autre cas probable est que vous auriez quelque chose comme chef ou ansible exécuté contre cet hôte, puis écrivez le fichier.

S'il s'agit d'une vérification côté Docker, alors quelque chose comme;

UPCHECK --port=7474 --interval=0.5s --response="Please log in"

Pour mémoire, je pense que la solution de fichiers a beaucoup de mérite, mais elle introduit également de la complexité.
80% du temps, vérifier la réponse tcp fonctionnerait très bien.

eh bien ... je suppose:

UPCHECK --file=/tmp/container_is_ready --interval=0.5s --timeout=2m

C'est juste la même chose.

Je travaille actuellement sur une réimplémentation de docker-compose qui ajoute des fonctionnalités pour attendre des conditions spécifiques. Il utilise libcompose (donc je n'ai pas à reconstruire l'interaction docker) et ajoute un tas de commandes de configuration pour cela. Découvrez-le ici: https://github.com/dansteen/controlled-compose

Notez que le code est terminé, mais j'attends que quelques problèmes en amont soient résolus avant que cela puisse être vraiment utilisé.

Goss peut être utilisé comme un shim assez flexible pour retarder le démarrage du conteneur, j'ai écrit un article de blog expliquant comment cela peut être accompli avec une modification mineure de votre image ici:

Kubernetes a le concept d' init-containers Je me demande si compose / swarm bénéficierait d'un concept similaire.

+1

Je pense qu'il vaut mieux laisser le service que vous exposez sur un conteneur décider s'il est ou non prêt ou capable d'exposer son service.

Par exemple, une application PHP peut dépendre de la connexion de MySQL. Donc sur le ENTRYPOINT de PHP Container, j'ai écrit quelque chose comme ça.

#!/bin/bash
cat << EOF > /tmp/wait_for_mysql.php
<?php
\$connected = false;
while(!\$connected) {
    try{
        \$dbh = new pdo( 
            'mysql:host=mysql:3306;dbname=db_name', 'db_user', 'db_pass',
            array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
        );
        \$connected = true;
    }
    catch(PDOException \$ex){
        error_log("Could not connect to MySQL");
        error_log(\$ex->getMessage());
        error_log("Waiting for MySQL Connection.");
        sleep(5);
    }
}
EOF
php /tmp/wait_for_mysql.php
# Rest of entry point bootstrapping

De cette façon, je peux ajouter n'importe quelle logique pour m'assurer que les dépendances du service que j'expose, c'est-à-dire php, ont été résolues.

Nabin Nepal schrieb:

Je pense qu'il vaut mieux laisser le service que vous exposez sur un conteneur décider s'il est ou non prêt ou capable d'exposer son service.

Vous pouvez bien sûr coder en dur ce comportement dans chaque conteneur qui utilise votre
Conteneur MySql. Mais si quelque chose dans votre service MySql change, vous êtes
changer tous les conteneurs dépendants, sans parler du codage répétitif
nécessaire dans chacun. Ce n'est pas SEC, il n'y a pas de contrat stable et donc
conduisent à des systèmes fragiles.

Du point de vue de l'artisanat logiciel, il devrait y avoir une sorte de
"Container Readiness SPI", que le développeur du conteneur peut implémenter. Sur
de l'autre côté, il devrait y avoir une "API de préparation du conteneur", qui
les services peuvent dépendre.

Ulrich

@realulim J'accepte que tout changement dans le conteneur MySQL doit être répliqué ou propagé à tous les conteneurs affectés ou liés.

Cependant, si la modification concerne des paramètres tels que DB_HOST, DB_NAME, DB_USER et DB_PASSWORD. Ceux-ci peuvent être passés en tant que ARG (argument) et être partagés par tous les conteneurs associés. Si vous utilisez le fichier docker-compose.yml , le changement se produit sur un seul fichier.

Et tout à fait d'accord que le fait d'avoir une API pour vérifier l'état de préparation du conteneur est le véritable moyen de résoudre ce problème, mais je crois toujours que le service exposé serait un meilleur candidat pour le déclarer.

une solution until nc -z localhost 27017; do echo Waiting for MongoDB; sleep 1; done contournement

@ piotr-s-brainhub D'après les commentaires ci-dessus, il est mentionné qu'avoir un port ouvert ne signifie pas que le service est prêt.

Pouvons-nous avoir une condition facultative de disponibilité qui peut être déclenchée par les journaux, l'ouverture du port ou le retard? Quelque chose comme:

ready_when:
  in_logs: `MySQL init process done`
  ports_open:
  - 3306

Je viens de réaliser qu'attendre que les conteneurs de dépendances soient prêts peut être facilement implémenté avec des outils comme ansible. Quelqu'un a-t-il utilisé cette approche? Pouvez-vous facilement remplacer docker-compose par ansible / chef / puppet? Un projet sur github démontrant cette approche?

Remarque: je comprends l'importance d'écrire un service robuste qui peut fonctionner même lorsque ses dépendances ne sont pas disponibles pour le moment. Ce n'est pas la question.

J'ai résolu cela de nos jours avec un outil que j'ai écrit: https://github.com/betalo-sweden/await

Il peut attendre qu'une liste donnée de ressources soit disponible et continuer ce que vous voulez continuer, soit en passant à la commande suivante implicitement, soit en l'appelant explicitement.

@djui , que fait

@derekmahar Il interroge. Il a un délai d'expiration par défaut de 60 secondes. Chaque fois qu'il ne peut pas voir la ressource, il réessayera simplement à intervalles de 1 seconde. Actuellement, il ne fait pas de détection de ressources simultanées, donc c'est séquentiel, mais cela s'est avéré être assez bon et peut être corrigé.

Je l'utilise dans le scénario suivant:

Je lance une infrastructure docker-compose, puis j'exécute un pilote de test d'intégration. Le service de pilote ne démarre que lorsque tous les composants de l'infrastructure sont disponibles, en utilisant await; alors wait appelle finalement la commande run du pilote.

Voici un moyen de le faire avec la nouvelle directive Docker HEALTHCHECK utilisant make:

https://gist.github.com/mixja/1ed1314525ba4a04807303dad229f2e1

[MISE À JOUR: mise à jour de l'essentiel pour gérer si le conteneur se termine avec un code d'erreur, car Docker 1.12 signale un peu stupidement l' état de Healthcheck sur le conteneur arrêté comme "commençant"]

Merci @mixja , belle solution.

@mixja , belle solution! C'est exactement la fonctionnalité que je m'attendrais à sortir de la boîte. Mais maintenant, la question est de savoir si vous démarrez vos conteneurs manuellement, pourquoi avez-vous besoin de docker-compose?

Pour les tests, j'utilise https://github.com/avast/docker-compose-gradle-plugin et il utilise également Docker healthcheck - plus de pauses artificielles, des constructions plus rapides.

@korya - Docker compose n'est pas vraiment un outil d'orchestration - c'est plutôt un outil de spécification et de gestion d'environnement. J'utilise Make pour fournir une orchestration de style procédural sur Docker Compose et Docker (et d'autres outils si nécessaire). La combinaison de Make, Docker et Docker Compose est très puissante et vous pouvez réaliser de nombreux scénarios différents avec ces blocs de construction.

@mixja eh bien, vous avez peut-être raison. Mais comme beaucoup de personnes l'ont souligné dans ce fil, une fonctionnalité d'orchestration est très nécessaire dans les environnements de test, et quand il y a docker-compose dans votre boîte à outils, il est très tentant d'exiger ce type de fonctionnalité de docker-compose.

En effet, selon la documentation "Compose est un outil pour définir et exécuter des applications Docker multi-conteneurs". Bien qu'il ne dise pas que compose est un outil d'orchestration, je pense que du point de vue de l'utilisateur (moi-même par exemple), il est naturel d'attendre d'un "outil de définition et d'exécution d'applications Docker multi-conteneurs" pour prendre en charge la gestion de base des dépendances entre les conteneurs gérés hors de la boîte.

Je ne dis pas que l'outil doit le soutenir. Tout ce que je dis, c'est qu'il est très naturel de s'y attendre. Sinon, tout le monde doit trouver ses moyens super intelligents de le faire. En fait, nous utilisons un script bash faisant quelque chose de similaire à ce que fait votre makefile.

@mixja @korya Je voudrais améliorer mon outil en attente et je voudrais vous demander des commentaires sur ce que les versions Makefile fournissent qui est manquant / plus pratique / permettant plus de await .

Il semble que la version healthcheck + make semble être une vue "globale", aucun conteneur ne connaît l'état global (mais le makefile le fait) et await est une vue "locale", chaque conteneur activé sait (seulement) ce qu'il doit savoir, similaire à depends_on ou links . De plus, vous préférez expédier le conteneur avec les outils requis pour le contrôle de santé (qui est parfois la valeur par défaut, par exemple mysqlshow ) et sinon, laissez le Dockerfile intact. De plus, vous semblez utiliser docker-compose non plus principalement pour la composition, mais principalement pour la configuration flexible (par exemple docker-compose up -d mysql devrait être équivalent à docker run -d -e ... -v ... -p ... mysql ).

Salut @djui - c'est probablement un point de vue philosophique, mais je pense que toute la prémisse du HEALTHCHECK est de promouvoir le bon comportement - c'est-à-dire qu'un conteneur peut fournir un moyen d'établir la santé du conteneur, sans aucune dépendance externe.

Cela ne nuit en aucun cas à la valeur d'avoir quelque chose d'externe pour vérifier la connectivité, mais j'exécuterais généralement une suite de tests d'acceptation pour couvrir cela car vous voulez vérifier la connectivité et bien plus encore (c'est-à-dire la fonctionnalité de l'application). Bien sûr, vous ne pouvez généralement pas exécuter ce niveau de test tant qu'un environnement complet n'a pas été établi et que la portée de votre outil await et d'autres approches que j'ai utilisées dans le passé (Playbooks Ansible enveloppés dans un agent container) se concentre vraiment sur l'orchestration correcte de la configuration de l'environnement (pas l'objectif final des tests d'acceptation) et jusqu'à présent, c'était vraiment la seule approche disponible dans un monde Docker.

Avec Docker 1.12, nous avons maintenant un moyen d'introspecter l'environnement Docker et la possibilité d'utiliser des constructions bien établies (c'est-à-dire des mécanismes bash / shell) pour "attendre" un certain état, bien sûr tant que nos conteneurs ont défini leurs propres contrôles de santé . Je vois plus d'intérêt à tirer parti des capacités natives de la plate-forme et à encourager les propriétaires de conteneurs à définir leurs propres bilans de santé, plutôt que de s'appuyer sur l'approche externe historique (j'ai commencé mon processus de candidature, ce n'est plus mon problème) que nous avons dû recourir à.

Comme analogie connexe, considérons AWS CloudFormation et le concept d'autoscaling de groupes et d'orchestration de mises à jour progressives. Comment CloudFormation sait-il si une nouvelle instance est "saine" prête à fonctionner et si nous pouvons tuer une ancienne instance et lancer une autre nouvelle instance? Écrivons-nous un contrôle de santé externe ou comptons-nous sur l'instance elle-même pour signaler la santé? La réponse est la dernière, cela signifie que le propriétaire de l'instance peut définir tous les critères de succès requis pour son instance, puis signaler au système d'orchestration global (c'est-à-dire CloudFormation) que l'instance est "saine".

En ce qui concerne vos commentaires sur Docker Compose, c'est un outil qui peut fournir les deux aspects que vous mentionnez. La partie docker-compose.yml est la spécification d'environnement de composition d'état souhaitée, tandis que les diverses commandes docker-compose permettent d'interagir avec l'environnement de plusieurs façons. Pour l'instant, nous avons besoin d'outils d'orchestration externes car fondamentalement docker-compose n'effectue pas assez bien la gestion des dépendances entre les services. Au fur docker-compose mesure que docker-compose up sera plus réaliste, en supposant que nous serons en mesure de spécifier par exemple un service doit être marqué avant il est considéré comme «up», ce qui signifie alors que nos services dépendants attendent effectivement que la dépendance soit saine.

@mixja Merci pour l'explication détaillée. je pense

Je vois plus de valeur à tirer parti des capacités natives de la plate-forme

est un bon / le point principal. Attendez simplement que Docker Compose tire parti des vérifications de santé de manière native, soit dans depend_on, soit dans une nouvelle clé, attendez. Il suffit de se demander si devrait / ira même un peu plus loin que cela et réduira fondamentalement les conteneurs liés si, par exemple, --abort-on-container-exit est défini et qu'un contrôle de santé pendant l'exécution définit le libellé de contrôle de santé sur _unhealthy_.

Solution de contournement temporaire possible pour ceux d'entre vous qui recherchent des fonctionnalités delay pour exécuter des tests:

J'ai deux fichiers docker-compose yml. L'un est pour les tests et l'autre pour le développement. La différence est simplement d'avoir sut conteneur docker-compose.test.yml . sut conteneur s'exécute pytest . Mon objectif était d'exécuter le test docker-compose et si la commande pytest dans le conteneur sut échoue, ne lancez pas le développement docker-compose . Voici ce que j'ai trouvé:

# launch test docker-compose; note: I'm starting it with -p argument
docker-compose -f docker-compose.test.yml -p ci up --build -d
# simply get ID of sut container
tests_container_id=$(docker-compose -f docker-compose.test.yml -p ci ps -q sut)
# wait for sut container to finish (pytest will return 0 if all tests passed)
docker wait $tests_container_id
# get exit code of sut container
tests_status=$(docker-compose -f docker-compose.test.yml -p ci ps -q sut | xargs docker inspect -f '{{ .State.ExitCode  }}' | grep -v 0 | wc -l | tr -d ' ')
# print logs if tests didn't pass and return exit code
if [ $tests_status = "1" ] ; then
    docker-compose -f docker-compose.test.yml -p ci logs sut
    return 1
else
    return 0
fi

Vous pouvez maintenant utiliser le code ci-dessus dans n'importe quelle fonction de votre choix (la mienne s'appelle test ) et faire comme ça:

test
test_result=$?
if [[ $test_result -eq 0 ]] ; then
    docker-compose -f docker-compose.yml up --build -d
fi

Fonctionne bien pour moi mais j'ai toujours hâte de voir docker-compose prendre en charge ce genre de choses en natif :)

+1

Peut-être que les choses considérées en dehors du noyau de docker-compose pourraient être prises en charge en autorisant les plugins? Semblable à la demande # 1341, il semble qu'il existe des fonctionnalités supplémentaires que certains trouveraient utiles mais qui ne correspondent pas nécessairement entièrement à la vision actuelle. Peut-être que la prise en charge d'un système de plugin tel que proposé par # 3905 fournirait un moyen de permettre à la composition de se concentrer sur un ensemble de fonctionnalités de base et si ce n'est pas le cas, ceux qui le souhaitent pour leur cas d'utilisation particulier pourraient écrire un plugin pour gérer l'exécution de up différemment?

Ce serait bien de pouvoir avoir docker-compose comme point d'entrée de tous les projets que nous avons localement autour de la configuration d'environnement de docker, plutôt que d'avoir besoin d'ajouter un script devant tous pour agir comme point d'entrée par défaut au lieu de les personnes ayant besoin de se rappeler d'exécuter le script pour les cas étranges.

Voici un moyen de le faire avec healthcheck et docker-compose 2.1+ :

version: "2.1"
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
    healthcheck:
      test: mysqladmin -uroot -ppassword ping
      interval: 2s
      timeout: 5s
      retries: 30
  web:
    image: nginx:latest # your image
    depends_on:
      db:
        condition: service_healthy

Ici, docker-compose up démarrera le conteneur Web uniquement une fois que le conteneur de base de données sera considéré comme sain.

Désolé si cela a déjà été mentionné, mais je ne pense pas qu'une solution complète ait été publiée.

Voici un moyen pour PostgreSQL.

Merci @Silex 👍

version: '2.1'
services:
  db:
    image: postgres:9.6.1
    healthcheck:
      test: "pg_isready -h localhost -p 5432 -q -U postgres"
      interval: 3s
      timeout: 5s
      retries: 5

@Silex malheureusement avec la version "3" et ce format:

    image: nginx:latest # your image
    depends_on:
      db:
        condition: service_healthy

Je reçois ERROR: The Compose file './docker-compose.yml' is invalid because: depends_on contains an invalid type, it should be an array

2.1 continue de le prendre en charge et ne sera pas obsolète. 3.x est principalement pour le mode Swarm Services (non local).

  From: Vlad Filippov <[email protected]>

À: docker / compose [email protected]
Cc: mbdas [email protected] ; Mentionnez [email protected]
Envoyé: mercredi 8 mars 2017 11 h 45
Objet: Re: [docker / compose] Existe-t-il un moyen de retarder le démarrage du conteneur pour prendre en charge les services dépendants avec un temps de démarrage plus long (# 374)

@Silex malheureusement avec la version "3" et ce format: image: nginx: dernière # votre image
dépend de:
db:
condition: service_healthy
J'obtiens une ERREUR: le fichier de composition './docker-compose.yml' n'est pas valide car: services.auth.depends_on contient un type invalide, il devrait s'agir d'un tableau—
Vous recevez cela parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub ou désactivez le fil de discussion.

2.1 continue de le prendre en charge et ne sera pas obsolète. 3.x est principalement pour le mode Swarm Services (non local).

Merci!

@vladikoff : plus d'informations sur la version 3 sur https://github.com/docker/compose/issues/4305

Fondamentalement, il ne sera pas pris en charge, vous devez rendre vos conteneurs tolérants aux pannes au lieu de compter sur docker-compose.

Je crois que cela peut être fermé maintenant.

Malheureusement, la condition n'est plus prise en

website:
    depends_on:
      - 'postgres'
    build: .
    ports:
      - '3000'
    volumes:
      - '.:/news_app'
      - 'bundle_data:/bundle'
    entrypoint: ./wait-for-postgres.sh postgres 5432

  postgres:
    image: 'postgres:9.6.2'
    ports:
      - '5432'

wait-for-postgres.sh:

#!/bin/sh

postgres_host=$1
postgres_port=$2
shift 2
cmd="$@"

# wait for the postgres docker to be running
while ! pg_isready -h $postgres_host -p $postgres_port -q -U postgres; do
  >&2 echo "Postgres is unavailable - sleeping"
  sleep 1
done

>&2 echo "Postgres is up - executing command"

# run the command
exec $cmd

Le point d'entrée personnalisé @ slava-nikulin est une pratique courante, c'est presque le seul moyen (natif de docker) de définir et de vérifier toutes les conditions dont vous avez besoin avant de lancer votre application dans un conteneur.

La vérité est qu'il y a eu beaucoup de débats et je pense que le support 2.x du support conditionnel pour intégrer nativement avec les bilans de santé et ordonner la startup était un support indispensable. Docker ne prend pas en charge le pod local de conteneurs de manière native et quand il le fera, il devra à nouveau prendre en charge quelque chose de similaire, tout comme kubernetes par exemple fournit la sémantique.

Docker 3.x est une série pour apporter le support swarm dans la composition et donc un tas d'options a été abandonné en gardant à l'esprit la nature distribuée.

2.x series préserve les fonctionnalités de composition / topologie locale d'origine.

Docker doit comprendre comment fusionner ces 2 versions, car forcer l'essaim à composer en réduisant l'ensemble de fonctionnalités de composition n'est pas une direction bienvenue.

Le 10 mai 2017, à 20h15, Slava Nikulin [email protected] a écrit:

Malheureusement, la condition n'est plus prise en charge dans la v3. Voici la solution de contournement que j'ai trouvée:

site Internet:
dépend de:
- 'postgres'
construire: .
ports:
- «3000»
volumes:
- '.: / news_app'
- 'bundle_data: / bundle'
point d'entrée: ./wait-for-postgres.sh postgres 5432

postgres:
image: ' postgres: 9.6.2 '
ports:
- «5432»
wait-for-postgres.sh:

! / bin / sh

postgres_host = 1 $
postgres_port = 2 $
cmd = "$ @"

attendez que le docker postgres soit en cours d'exécution

tandis que ! pg_isready -h $ postgres_host -p $ postgres_port -q -U postgres; faire

& 2 echo "Postgres est indisponible - en veille"
dormir 1
terminé

& 2 echo "Postgres est actif - commande en cours d'exécution"

exécuter la commande

exec $ cmd
-
Vous recevez cela parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub ou désactivez le fil de discussion.

J'ai pu faire quelque chose comme ça
// start.sh

#!/bin/sh
set -eu

docker volume create --name=gql-sync
echo "Building docker containers"
docker-compose build
echo "Running tests inside docker container"
docker-compose up -d pubsub
docker-compose up -d mongo
docker-compose up -d botms
docker-compose up -d events
docker-compose up -d identity
docker-compose up -d importer
docker-compose run status
docker-compose run testing

exit $?

// status.sh

#!/bin/sh

set -eu pipefail

echo "Attempting to connect to bots"
until $(nc -zv botms 3000); do
    printf '.'
    sleep 5
done
echo "Attempting to connect to events"
until $(nc -zv events 3000); do
    printf '.'
    sleep 5
done
echo "Attempting to connect to identity"
until $(nc -zv identity 3000); do
    printf '.'
    sleep 5
done
echo "Attempting to connect to importer"
until $(nc -zv importer 8080); do
    printf '.'
    sleep 5
done
echo "Was able to connect to all"

exit 0

// dans mon fichier de composition de docker

  status:
    image: yikaus/alpine-bash
    volumes:
      - "./internals/scripts:/scripts"
    command: "sh /scripts/status.sh"
    depends_on:
      - "mongo"
      - "importer"
      - "events"
      - "identity"
      - "botms"

J'ai un problème similaire mais un peu différent. Je dois attendre que MongoDB démarre et initialise un jeu de répliques.
Je fais toute la procédure dans docker. c.-à-d. création et jeu de répliques d'authentification. Mais j'ai un autre script python dans lequel je dois me connecter au nœud principal du jeu de répliques. J'obtiens une erreur là-bas.

docker-compose.txt
Dockerfile.txt
et dans le script python, j'essaye de faire quelque chose comme ça
for x in range(1, 4): client = MongoClient(host='node' + str(x), port=27017, username='admin', password='password') if client.is_primary: print('the client.address is: ' + str(client.address)) print(dbName) print(collectionName) break

Ai-je du mal à le faire, quelqu'un a une idée?

@patrickml Si je n'utilise pas docker compose, comment puis-je le faire avec Dockerfile?
J'ai besoin de 'cqlsh' pour exécuter mon build_all.cql. Cependant, 'cqlsh' n'est pas prêt ... il faut attendre 60 secondes pour être prêt.

chat Dockerfile

FROM store / datastax / dse- serveur: 5.1.8

Racine UTILISATEUR

Exécuter la mise à jour apt-get
EXÉCUTER apt-get install -y vim

AJOUTER db-scripts-2.1.33.2-RFT-01.tar / docker / cms /
COPIER entrypoint.sh /entrypoint.sh

WORKDIR /docker/cms/db-scripts-2.1.33.2/
RUN cqlsh -f build_all.cql

UTILISATEUR dse

=============

Étape 8/9: RUN cqlsh -f build_all.cql
---> Fonctionnement dans 08c8a854ebf4
Erreur de connexion: ('Impossible de se connecter à un serveur', {'127.0.0.1': erreur (111, "Tentative de connexion à [('127.0.0.1', 9042)]. Dernière erreur: Connexion refusée")})
La commande '/ bin / sh -c cqlsh -f build_all.cql' a renvoyé un code différent de zéro: 1

Requiert = var-lib-libvirt.mount var-lib-libvirt-images-ram.mount

Cette page vous a été utile?
0 / 5 - 0 notes