Utilizzando Docker-Compose, come eseguire più comandi


500

Voglio fare qualcosa del genere in cui posso eseguire più comandi in ordine.

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

Risposte:


861

Capito, usa bash -c.

Esempio:

command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"

Stesso esempio in multiline:

command: >
    bash -c "python manage.py migrate
    && python manage.py runserver 0.0.0.0:8000"

O:

command: bash -c "
    python manage.py migrate
    && python manage.py runserver 0.0.0.0:8000
  "

6
@Pedram Assicurati di utilizzare un'immagine su cui sia installato bash. Alcune immagini potrebbero anche richiedere un percorso diretto per bash, ad esempio/bin/bash
codemaven,

6
Se non è installato bash puoi provare sh -c "tuo comando"
Chaoste

Assicurati di racchiudere i tuoi comandi tra virgolette quando passi a bash e ho dovuto scivolare un "sleep 5" per assicurarmi che il db fosse attivo, ma ha funzionato per me.
scambio

74
In realtà le immagini basate su Alpine sembrano non avere bash installato - fai come @Chaoste consiglia e usa shinvece:[sh, -c, "cd /usr/src/app && npm start"]
Florian Loch

1
Può anche usare solo ashsu alpini :)
Jonathan

160

Eseguo cose pre-avvio come le migrazioni in un contenitore temporaneo separato, in questo modo (nota, il file di composizione deve essere di tipo '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

Questo aiuta a mantenere le cose pulite e separate. Due cose da considerare:

  1. Devi assicurarti la sequenza di avvio corretta (usando depend_on)

  2. vuoi evitare build multiple ottenute taggandolo la prima volta usando build e image; allora puoi fare riferimento all'immagine in altri contenitori


2
Questa mi sembra l'opzione migliore e vorrei usarla. Puoi elaborare la tua configurazione di tagging per evitare più build? Preferirei evitare passaggi extra, quindi se questo ha bisogno di alcuni, potrei andare bash -csopra.
Stavros Korokithakis,

3
Nello yaml sopra, la compilazione e la codifica avvengono nella sezione migrazione. Non è davvero ovvio a prima vista, ma la finestra mobile-componi lo contrassegna quando specifichi la proprietà AND dell'immagine - per cui la proprietà image specifica il tag per quella build. Che può quindi essere usato successivamente senza innescare una nuova build (se guardi il web, vedi che non ha build ma solo una proprietà di immagine). Ecco alcuni ulteriori dettagli docs.docker.com/compose/compose-file )
Bjoern Stiel,

26
Sebbene mi piaccia l'idea, il problema è che dipende_on assicura solo che si avviino in quell'ordine, non che siano pronti in quell'ordine. wait-for-it.sh potrebbe essere la soluzione di cui alcune persone hanno bisogno.
scambio

2
Questo è assolutamente corretto e un po 'un peccato che la composizione docker non supporti alcun controllo fine come l'attesa dell'uscita di un contenitore o l'avvio dell'ascolto su una porta. Ma sì, uno script personalizzato risolve questo, buon punto!
Bjoern Stiel,

1
Questa risposta fornisce informazioni errate e potenzialmente distruttive sul funzionamento di depend_on.
antonagestam,

96

Mi consiglia di utilizzare shal contrario di bashquanto è più facilmente disponibili sulla maggior parte delle immagini Sulla base Unix (alpino, ecc).

Ecco un esempio 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"

Questo chiamerà i seguenti comandi in ordine:

  • python manage.py wait_for_db - attendere che il db sia pronto
  • python manage.py migrate - eseguire eventuali migrazioni
  • python manage.py runserver 0.0.0.0:8000 - avvia il mio server di sviluppo

2
Personalmente questa è la mia soluzione preferita e più pulita.
BugHunterUK,

1
Anche il mio. Come sottolineato da @LondonAppDev, bash non è disponibile per impostazione predefinita in tutti i contenitori per l'ottimizzazione dello spazio (ad esempio, la maggior parte dei contenitori costruiti su Alpine Linux)
ewilan

2
Ho dovuto sfuggire al multiline && con un \
Andre Van Zuydam il

@AndreVanZuydam hmmm è strano, non ho avuto bisogno di farlo. Ti sei circondato di citazioni? Che sapore di docker stai eseguendo?
LondonAppDev,

2
@oligofren la >viene utilizzato per avviare un input multi-linea (vedi stackoverflow.com/a/3790497/2220370 )
LondonAppDev

40

Questo funziona per me:

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 prova a dereferenziare le variabili prima di eseguire il comando, quindi se vuoi che bash gestisca le variabili dovrai sfuggire ai segni del dollaro raddoppiandoli ...

    command:
      - /bin/bash
      - -c
      - |
        var=$$(echo 'foo')
        echo $$var # prints foo

... altrimenti visualizzerai un errore:

Formato di interpolazione non valido per l'opzione "comando" nel servizio "web":


Ciao amico. Ho riscontrato un problema: `` '' argomenti non riconosciuti: / bin / bash -c python3 /usr/local/airflow/__init__.py -C Local -T Windows `` `il comando nel mio docker-compose.yml è: comando: - / bin / bash - -c - | python3 /usr/local/airflow/__init__.py -C $ {Client} -T $ {Tipi} Sai come risolverlo? Aggiungo client e tipi nel mio file .env.
Newt,

Ecco un documento per te: docs.docker.com/compose/compose-file/#variable-substitution Penso che ciò che sta accadendo sia che il tuo file .env colloca tali variabili nell'ambiente container, ma docker-compose sta cercando nel tuo ambiente shell . Prova invece $${Types}e $${Client}. Penso che questo impedirà alla composizione docker di interpretare quelle variabili e di cercare i loro valori in qualunque shell da cui invochi la composizione docker, il che significa che sono ancora in giro per bash per dereferirle ( dopo che la finestra mobile ha elaborato il tuo .envfile).
MatrixManAtYrService

Grazie per il tuo commento. Ho fatto quello che hai detto in effetti. Quindi ho ricevuto $ (Client) nelle informazioni sull'errore. Ho cambiato il modo di leggere le variabili di ambiente per usare os.getenv in Python, il che è più semplice. Grazie comunque.
Newt

23

Puoi usare entrypoint qui. entrypoint nella finestra mobile viene eseguito prima del comando mentre command è il comando predefinito che deve essere eseguito all'avvio del contenitore. Quindi la maggior parte delle applicazioni generalmente porta la procedura di installazione nel file entrypoint e nell'ultima consente l'esecuzione del comando.

fare un file di script shell può essere come docker-entrypoint.sh(il nome non ha importanza) con i seguenti contenuti in esso.

#!/bin/bash
python manage.py migrate
exec "$@"

nel file docker-compose.yml usalo con entrypoint: /docker-entrypoint.she registra il comando come command: python manage.py runserver 0.0.0.0:8000 PS: non dimenticare di copiare docker-entrypoint.shinsieme al tuo codice.


Si noti che questo verrà eseguito anche quando lo faidocker-compose run service-name ....
thisismydesign

18

Un'altra idea:

Se, come in questo caso, si crea il contenitore, inserire semplicemente uno script di avvio al suo interno ed eseguirlo con il comando. Oppure monta lo script di avvio come volume.


Sì, alla fine ho creato uno script run.sh: #!/bin/bash \n python manage.py migrate \n python manage.py runserver 0.0.0.0:8000(brutto oneline)
fero

9

* AGGIORNARE *

Ho pensato che il modo migliore per eseguire alcuni comandi fosse scrivere un Dockerfile personalizzato che fa tutto ciò che voglio prima che il CMD ufficiale venga eseguito dall'immagine.

finestra mobile-compose.yaml:

version: '3'

# Can be used as an alternative to VBox/Vagrant
services:

  mongo:
    container_name: mongo
    image: mongo
    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)

Questo è probabilmente il modo più pulito per farlo.

* VECCHIO MODO *

Ho creato uno script di shell con i miei comandi. In questo caso, volevo iniziare mongoded eseguire, mongoimportma chiamare mongodti impedisce di eseguire il resto.

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

Quindi questo biforcuta mongo, fa il monogimport e quindi uccide il mongo biforcuto che è staccato e lo riavvia senza staccarsi. Non sono sicuro se esiste un modo per collegarsi a un processo biforcato ma questo funziona.

NOTA: se si desidera caricare rigorosamente alcuni dati db iniziali, questo è il modo per farlo:

mongo_import.sh

#!/bin/bash
# Import from fixtures

# Used in build and docker-compose mongo (different dirs)
DIRECTORY=../deploy/local/mongo_fixtures
if [[ -d "/fixtures" ]]; then
    DIRECTORY=/fixtures
fi
echo ${DIRECTORY}

mongoimport --db wcm-local --collection clients --file ${DIRECTORY}/clients.json && \
mongoimport --db wcm-local --collection configs --file ${DIRECTORY}/configs.json && \
mongoimport --db wcm-local --collection content --file ${DIRECTORY}/content.json && \
mongoimport --db wcm-local --collection licenses --file ${DIRECTORY}/licenses.json && \
mongoimport --db wcm-local --collection lists --file ${DIRECTORY}/lists.json && \
mongoimport --db wcm-local --collection properties --file ${DIRECTORY}/properties.json && \
mongoimport --db wcm-local --collection videos --file ${DIRECTORY}/videos.json

I file mongo_fixtures / *. json sono stati creati tramite il comando mongoexport.

finestra mobile-compose.yaml

version: '3'

services:
  mongo:
    container_name: mongo
    image: mongo:3.2.12
    ports:
      - "27017:27017"
    volumes:
      - mongo-data:/data/db:cached
      - ./deploy/local/mongo_fixtures:/fixtures
      - ./deploy/local/mongo_import.sh:/docker-entrypoint-initdb.d/mongo_import.sh


volumes:
  mongo-data:
    driver: local

5

Se è necessario eseguire più di un processo daemon, nella documentazione Docker è presente un suggerimento per utilizzare Supervisord in modalità non staccata, in modo che tutti i sotto-demoni vengano inviati allo stdout.

Da un'altra domanda SO, ho scoperto che puoi reindirizzare l'output dei processi figlio sullo stdout. In questo modo puoi vedere tutto l'output!


Ripensandoci, questa risposta sembra più adatta all'esecuzione di più comandi in parallelo anziché in serie.
Tim Tisdall,



0

Mi sono imbattuto in questo mentre cercavo di configurare il mio contenitore jenkins per costruire contenitori docker come utente jenkins.

Avevo bisogno di toccare il file docker.sock nel file Docker mentre lo collego in seguito nel file comporre docker. A meno che non lo toccassi per primo, non esisteva ancora. Questo ha funzionato per me.

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

finestra mobile-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

Questa sembra la risposta a una domanda diversa.
Kenorb,

-7

prova a usare ";" per separare i comandi se ci sono due verioni, ad es

command: "sleep 20; echo 'a'"

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.