Je veux faire quelque chose comme ceci où je peux exécuter plusieurs commandes dans l'ordre.
db:
image: postgres
web:
build: .
command: python manage.py migrate
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db
Pour le comprendre, utilisezbash -c
.
Exemple:
command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
Même exemple en multilignes:
command: >
bash -c "python manage.py migrate
&& python manage.py runserver 0.0.0.0:8000"
J'exécute des tâches de pré-démarrage telles que les migrations dans un conteneur éphémère distinct, par exemple (remarque, le fichier de composition doit être de type "2"):
db:
image: postgres
web:
image: app
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db
depends_on:
- migration
migration:
build: .
image: app
command: python manage.py migrate
volumes:
- .:/code
links:
- db
depends_on:
- db
Cela aide les choses à rester propres et séparées. Deux choses à considérer:
Vous devez vous assurer que la séquence de démarrage est correcte (en utilisant depend_on).
vous voulez éviter les versions multiples, ce qui est obtenu en la marquant du premier coup en utilisant build et image; vous pouvez vous référer à l'image dans d'autres conteneurs alors
Je recommande d'utiliser sh
plutôt que bash
car il est plus facilement disponible sur la plupart des images à base d'unix (Alpine, etc.).
Voici un exemple docker-compose.yml
:
version: '3'
services:
app:
build:
context: .
command: >
sh -c "python manage.py wait_for_db &&
python manage.py migrate &&
python manage.py runserver 0.0.0.0:8000"
Cela appellera les commandes suivantes dans l’ordre:
python manage.py wait_for_db
- attend que la base de données soit prêtepython manage.py migrate
- exécuter toutes les migrations python manage.py runserver 0.0.0.0:8000
- démarrer mon serveur de développementUne autre idée:
Si, comme dans ce cas, vous construisez le conteneur, placez-y simplement un script de démarrage et exécutez-le avec la commande. Ou montez le script de démarrage en tant que volume.
Vous pouvez utiliser entrypoint ici. entrypoint in docker est exécuté avant la commande while commande est la commande par défaut à exécuter au démarrage du conteneur . Ainsi, la plupart des applications portent généralement la procédure d'installation dans un fichier entrypoint et autorisent l'exécution de la dernière commande.
créer un fichier de script shell peut être en tant que docker-entrypoint.sh
(le nom importe peu) avec le contenu suivant.
#!/bin/bash
python manage.py migrate
exec "$@"
dans le fichier docker-compose.yml, utilisez-le avec entrypoint: /docker-entrypoint.sh
et enregistrez la commande en tant que command: python manage.py runserver 0.0.0.0:8000
P.S: n'oubliez pas de copier docker-entrypoint.sh
avec votre code.
Cela fonctionne pour moi:
version: '3.1'
services:
db:
image: postgres
web:
build: .
command:
- /bin/bash
- -c
- |
python manage.py migrate
python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db
docker-compose essaie de déréférencer les variables avant en exécutant la commande. Si vous voulez que bash gère les variables, vous devrez échapper aux signes dollar en les doublant ...
command:
- /bin/bash
- -c
- |
var=$$(echo 'foo')
echo $$var # prints foo
... sinon vous aurez une erreur:
Format d'interpolation non valide pour l'option "commande" du service "web":
Si vous devez exécuter plusieurs processus démons, une suggestion de dans la documentation de Docker consiste à utiliser Supervisord en mode détaché afin que tous les sous-démons soient exportés vers la sortie standard.
À partir d'une autre question SO, j'ai découvert que vous pouvez rediriger la sortie des processus enfants vers la sortie standard. De cette façon, vous pouvez voir tout le résultat!
Utilisez un outil tel que wait-for-it ou dockerize . Il s’agit de petits scripts de wrapper que vous pouvez inclure dans l’image de votre application. Ou écrivez votre propre script d'encapsulation pour exécuter des commandes plus spécifiques à l'application. selon: https://docs.docker.com/compose/startup-order/
* METTRE À JOUR *
J'ai pensé que la meilleure façon d'exécuter des commandes est d'écrire un fichier Docker personnalisé qui fait tout ce que je veux avant que le CMD officiel ne soit exécuté à partir de l'image.
docker-compose.yaml:
version: '3'
# Can be used as an alternative to VBox/Vagrant
services:
mongo:
container_name: mongo
# image: mongo:3.2.12
build:
context: .
dockerfile: deploy/local/Dockerfile.mongo
ports:
- "27017:27017"
volumes:
- ../.data/mongodb:/data/db
Dockerfile.mongo:
FROM mongo:3.2.12
RUN mkdir -p /fixtures
COPY ./fixtures /fixtures
RUN (mongod --fork --syslog && \
mongoimport --db wcm-local --collection clients --file /fixtures/clients.json && \
mongoimport --db wcm-local --collection configs --file /fixtures/configs.json && \
mongoimport --db wcm-local --collection content --file /fixtures/content.json && \
mongoimport --db wcm-local --collection licenses --file /fixtures/licenses.json && \
mongoimport --db wcm-local --collection lists --file /fixtures/lists.json && \
mongoimport --db wcm-local --collection properties --file /fixtures/properties.json && \
mongoimport --db wcm-local --collection videos --file /fixtures/videos.json)
C'est probablement la manière la plus propre de le faire.
* VIEILLE VOIE *
J'ai créé un script shell avec mes commandes. Dans ce cas, je voulais démarrer mongod
et exécuter mongoimport
mais appeler mongod
vous empêche de lancer le reste.
docker-compose.yaml :
version: '3'
services:
mongo:
container_name: mongo
image: mongo:3.2.12
ports:
- "27017:27017"
volumes:
- ./fixtures:/fixtures
- ./deploy:/deploy
- ../.data/mongodb:/data/db
command: sh /deploy/local/start_mongod.sh
start_mongod.sh :
mongod --fork --syslog && \
mongoimport --db wcm-local --collection clients --file /fixtures/clients.json && \
mongoimport --db wcm-local --collection configs --file /fixtures/configs.json && \
mongoimport --db wcm-local --collection content --file /fixtures/content.json && \
mongoimport --db wcm-local --collection licenses --file /fixtures/licenses.json && \
mongoimport --db wcm-local --collection lists --file /fixtures/lists.json && \
mongoimport --db wcm-local --collection properties --file /fixtures/properties.json && \
mongoimport --db wcm-local --collection videos --file /fixtures/videos.json && \
pkill -f mongod && \
sleep 2 && \
mongod
Donc, cette fourche mongo fait monogimport puis tue le mongo fourchu qui est détaché et le redémarre sans se détacher. Vous ne savez pas s'il existe un moyen de vous connecter à un processus forké, mais cela fonctionne.
Je me suis heurté à cela en essayant de configurer mon conteneur Jenkins pour construire des conteneurs Docker en tant qu'utilisateur jenkins.
Je devais toucher le fichier docker.sock dans le fichier Docker car je le lierai plus tard dans le fichier docker-compose. À moins que je ne l'aie touché en premier, cela n'existait pas encore. Cela a fonctionné pour moi.
Dockerfile:
USER root
RUN apt-get update && \
apt-get -y install apt-transport-https \
ca-certificates \
curl \
software-properties-common && \
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release;
echo "$ID")/gpg > /tmp/dkey; apt-key add /tmp/dkey && \
add-apt-repository \
"deb [Arch=AMD64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
$(lsb_release -cs) \
stable" && \
apt-get update && \
apt-get -y install docker-ce
RUN groupmod -g 492 docker && \
usermod -aG docker jenkins && \
touch /var/run/docker.sock && \
chmod 777 /var/run/docker.sock
USER Jenkins
docker-compose.yml:
version: '3.3'
services:
jenkins_pipeline:
build: .
ports:
- "8083:8083"
- "50083:50080"
volumes:
- /root/pipeline/jenkins/mount_point_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock