Ich möchte so etwas tun, wo ich mehrere Befehle nacheinander ausführen kann.
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
Um herauszufinden, verwenden Siebash -c
.
Beispiel:
command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
Gleiches Beispiel in Multilinien:
command: >
bash -c "python manage.py migrate
&& python manage.py runserver 0.0.0.0:8000"
Ich führe Vor-Start-Sachen wie Migrationen in einem separaten ephemeren Container aus (wie folgt (beachten Sie, dass die Erstellungsdatei die Version '2' hat)
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
Dies hilft, Dinge sauber und getrennt zu halten. Zwei Dinge zu beachten:
Sie müssen die korrekte Startreihenfolge sicherstellen (mithilfe von „changes_on“).
sie möchten mehrere Builds vermeiden, die durch die erste Markierung mit Build und Image erreicht werden. Sie können dann auf das Bild in anderen Containern verweisen
Ich empfehle die Verwendung von sh
im Gegensatz zu bash
, da sie auf den meisten Unix-basierten Bildern (Alpine usw.) leichter verfügbar ist.
Hier ist ein Beispiel 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"
Dadurch werden die folgenden Befehle der Reihe nach aufgerufen:
python manage.py wait_for_db
- warte, bis die Datenbank bereit istpython manage.py migrate
- Alle Migrationen ausführen python manage.py runserver 0.0.0.0:8000
- starte meinen EntwicklungsserverEine andere Idee:
Wenn Sie wie in diesem Fall den Container erstellen, platzieren Sie einfach ein Startskript und führen Sie dieses mit dem Befehl aus. Oder mounten Sie das Startskript als Volume.
Sie können hier einen Eingangspunkt verwenden. entrypoint in docker wird ausgeführt, bevor der Befehl ausgeführt wird, während der Befehl der Standardbefehl ist, der ausgeführt werden soll, wenn der Container gestartet wird .. Die meisten Anwendungen führen im Allgemeinen eine Einstellungsprozedur in der Entypoint-Datei aus, und zuletzt erlauben sie die Ausführung des Befehls.
eine Shell-Skriptdatei kann als docker-entrypoint.sh
(Name ist egal) mit folgendem Inhalt erstellt werden.
#!/bin/bash
python manage.py migrate
exec "[email protected]"
in der Datei docker-compose.yml verwenden Sie sie mit entrypoint: /docker-entrypoint.sh
und den Befehl register als command: python manage.py runserver 0.0.0.0:8000
P.S: Vergessen Sie nicht, docker-entrypoint.sh
zusammen mit Ihrem Code zu kopieren.
Das funktioniert bei mir:
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 versucht, Variablen vor dem Ausführen des Befehls zu dereferenzieren. Wenn Sie also möchten, dass bash mit Variablen umgeht, müssen Sie die Dollarzeichen umgehen, indem Sie sie verdoppeln ...
command:
- /bin/bash
- -c
- |
var=$$(echo 'foo')
echo $$var # prints foo
... sonst erhalten Sie eine Fehlermeldung:
Ungültiges Interpolationsformat für die Option "Befehl" im Dienst "Web":
Wenn Sie mehr als einen Daemon-Prozess ausführen müssen, gibt es in der Docker-Dokumentation einen Vorschlag, Supervisord in einem nicht getrennten Modus zu verwenden, damit alle Sub-Daemons im stdout ausgegeben werden.
Aus einer anderen SO - Frage habe ich herausgefunden, dass Sie die Ausgabe der untergeordneten Prozesse an die Standardausgabe umleiten können. Auf diese Weise können Sie alle Ausgaben sehen!
Verwenden Sie ein Tool wie beispielsweise Wait-For-It oder Dockerize . Dies sind kleine Wrapper-Skripts, die Sie in das Image Ihrer Anwendung einfügen können. Oder schreiben Sie Ihr eigenes Wrapper-Skript, um anwendungsspezifische Befehle auszuführen. gemäß: https://docs.docker.com/compose/startup-order/
* UPDATE *
Ich habe mir gedacht, dass der beste Weg, einige Befehle auszuführen, darin besteht, eine benutzerdefinierte Docker-Datei zu schreiben, die alles ausführt, was ich will, bevor die offizielle CMD aus dem Bild ausgeführt wird.
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)
Dies ist wahrscheinlich der sauberste Weg, dies zu tun.
* ALTER WEG *
Ich habe ein Shell-Skript mit meinen Befehlen erstellt. In diesem Fall wollte ich mongod
starten und mongoimport
ausführen, aber der Aufruf von mongod
hindert Sie daran, den Rest auszuführen.
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
Also gabelt das Mongo, macht Monogimport und tötet dann den abgespannten gespaltenen Mongo und startet ihn wieder, ohne ihn zu lösen. Sie sind sich nicht sicher, ob es einen Weg gibt, an einen gegabelten Prozess anzuhängen, aber das funktioniert.
Ich bin darauf gestoßen, als ich versuchte, meinen Jenkins-Container so einzurichten, dass er als Jenkins-Benutzer Docker-Container erstellt.
Ich musste die docker.sock-Datei in der Docker-Datei anfassen, da ich sie später in der Docker-Compose-Datei verlinke. Wenn ich es nicht zuerst berührte, existierte es noch nicht. Das hat bei mir funktioniert.
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