web-dev-qa-db-fra.com

Comment exécuter une commande une fois dans Docker compose

Je travaille donc sur un fichier de composition de docker pour déployer mon serveur Web Go. Mon serveur utilise mongo. J'ai donc ajouté un conteneur de volumes de données et le service Mongo dans docker compose . Ensuite, j'ai écrit un fichier Docker afin de construire mon projet Go et de l'exécuter.

Cependant, il y a une autre étape à faire. Une fois mon projet compilé, je dois exécuter la commande suivante: ./my-project -setup

Cela ajoutera quelques informations nécessaires à la base de données, et les informations ne devront être ajoutées qu'une seule fois . Je ne peux cependant pas ajouter cette étape au fichier Docker (dans le processus de construction) car mongo doit déjà être démarré .

Alors, comment puis-je y parvenir? Même si je redémarre le serveur et que je lance à nouveau docker-compose up, je ne veux pas que cette commande soit exécutée à nouveau.

Docker me manque un peu de compréhension, car je ne comprends pas tout ce qui concerne les conteneurs de volumes de données (s'agit-il simplement de conteneurs arrêtés qui montent un volume?) . puis exécutez docker-compose up, quelles commandes seront exécutées? Va-t-il simplement démarrer le même conteneur qui était maintenant arrêté avec le CMD donné?

En tout cas, voici mon docker-compose.yml:

version: '2'
services:
  mongodata:
    image: mongo:latest
    volumes:
      - /data/db
    command: --break-mongo
  mongo:
    image: mongo:latest
    volumes_from:
      - mongodata
    ports:
      - "28001:27017"
    command: --smallfiles --rest --auth
  my_project:
    build: .
    ports:
      - "6060:8080"
    depends_on:
      - mongo
      - mongodata
    links:
      - mongo

Et voici mon Dockerfile pour construire mon image de projet:

FROM golang

ADD . /go/src/my_project
RUN cd /go/src/my_project && go get
RUN go install my_project
RUN my_project -setup
ENTRYPOINT /go/bin/my_project

EXPOSE 8080
15
Ivan

Je suggère d'ajouter un script entrypoint à votre conteneur; dans ce script de point d'entrée, vous pouvez vérifier si la base de données a été initialisée et, dans le cas contraire, effectuer les étapes requises.

Comme vous l'avez remarqué dans votre question, l'ordre dans lequel les services/conteneurs sont démarrés ne doit pas être pris pour acquis, il est donc possible que votre conteneur d'applications soit démarré avant le conteneur de base de données, le script doit donc en tenir compte. .

A titre d'exemple, jetez un coup d'œil à l'image officielle de WordPress, qui effectue une initialisation unique de la base de données dans son script entrypoint. Le script tente de se connecter à la base de données (et tente à nouveau si la base de données ne peut pas encore être contactée) et vérifie si une initialisation est nécessaire. https://github.com/docker-library/wordpress/blob/df190dc9c5752fd09317d836bd2dcd09ee379a5/Apache/docker-entrypoint.sh#L146-L171

REMARQUE

Je remarque que vous avez créé un "conteneur de données uniquement" auquel attacher votre volume. Depuis Docker 1.9, docker dispose d’une gestion des volumes, y compris des noms de volumes. De ce fait, vous n’avez plus besoin d’utiliser des conteneurs "données uniquement".

Vous pouvez supprimer le conteneur contenant uniquement des données de votre fichier de composition et modifier votre service Mongo pour qu’il ressemble à ceci;

  mongo:
    image: mongo:latest
    volumes:
      - mongodata:/data/db
    ports:
      - "28001:27017"
    command: --smallfiles --rest --auth

Cela devrait créer un nouveau volume, nommé mongodata s'il n'existe pas, ou réutiliser le volume existant avec ce nom. Vous pouvez répertorier tous les volumes à l'aide de docker volume ls et supprimer un volume avec docker volume rm <some-volume> si vous n'en avez plus besoin.

5
thaJeztah

Vous pouvez essayer d'utiliser ONBUILD instruction :

L'instruction ONBUILD ajoute à l'image une instruction de déclenchement à exécuter ultérieurement, lorsque l'image est utilisée comme base pour une autre construction. Le déclencheur sera exécuté dans le contexte de la construction en aval, comme s'il avait été inséré immédiatement après l'instruction FROM dans la Dockerfile en aval.

Toute instruction de construction peut être enregistrée en tant que déclencheur.

Ceci est utile si vous construisez une image qui servira de base pour créer d'autres images, par exemple un environnement de construction d'application ou un démon pouvant être personnalisé avec une configuration spécifique à l'utilisateur.

Par exemple, si votre image est un générateur d’application Python réutilisable, il faudra ajouter le code source de l’application dans un répertoire particulier et éventuellement appeler un script de construction after that. Vous ne pouvez pas simplement appeler ADD et RUN maintenant, car vous n’avez pas encore accès au code source de l’application, qui sera différent pour chaque construction d’application. Vous pouvez simplement fournir aux développeurs d’applications une variable Dockerfile à copier-coller dans leur application, mais c’est inefficace, source d’erreurs et difficile à mettre à jour car elle se mélange au code spécifique à l’application.

La solution consiste à utiliser ONBUILD pour enregistrer les instructions préalables à exécuter ultérieurement, au cours de la phase de construction suivante.

Voici comment ça fonctionne:

  1. Lorsqu'il rencontre une instruction ONBUILD, le générateur ajoute un déclencheur aux métadonnées de l'image en cours de construction. L'instruction n'affecte pas par ailleurs la construction actuelle.
  2. À la fin de la construction, une liste de tous les déclencheurs est stockée dans le manifeste de l'image, sous la clé OnBuild. Ils peuvent être inspectés avec la commande docker inspect.
  3. Plus tard, l'image peut être utilisée comme base pour une nouvelle construction, en utilisant l'instruction FROM. Dans le cadre du traitement de l'instruction FROM, le générateur en aval recherche les déclencheurs ONBUILD et les exécute dans le même ordre dans lequel ils ont été enregistrés. Si l'un des déclencheurs échoue, l'instruction FROM est abandonnée, ce qui entraîne l'échec de la construction. Si tous les déclencheurs réussissent, l'instruction FROM se termine et la construction se poursuit normalement.
  4. Les déclencheurs sont effacés de l'image finale après leur exécution. En d'autres termes, ils ne sont pas hérités des générations de «petits-enfants».
2
Petr Shevtsov

Votre application a besoin d'un état initial pour fonctionner. Cela signifie que vous devriez:

  1. Vérifier si l'état requis existe déjà
  2. Dépend de l'état initial du résultat de la première étape ou non

Vous pouvez écrire un programme pour vérifier l’état actuel de la base de données (ici, je vais utiliser le script bash mais ce peut être tout autre programme linguistique):

RUN if $(./check.sh); then my_project -setup; fi

Dans mon cas, si le script renvoie 0 (statut de sortie réussi), la commande setup sera appelée.

0
Cortwave