Menggunakan Docker-Compose, cara menjalankan beberapa perintah

500

Saya ingin melakukan sesuatu seperti ini di mana saya dapat menjalankan beberapa perintah secara berurutan.

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
RustyShackleford
sumber

Jawaban:

861

Mencari tahu, gunakan bash -c.

Contoh:

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

Contoh yang sama di multiline:

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

Atau:

command: bash -c "
    python manage.py migrate
    && python manage.py runserver 0.0.0.0:8000
  "
RustyShackleford
sumber
6
@Pedram Pastikan Anda menggunakan gambar yang sebenarnya telah menginstal bash. Beberapa gambar mungkin juga memerlukan jalur langsung ke bash misalnya/bin/bash
codemaven
6
Jika tidak ada bash yang dipasang, Anda dapat mencoba sh -c "your command"
Chaoste
Pastikan Anda membungkus perintah Anda dalam tanda kutip ketika memberikan bash dan saya harus memasukkan "sleep 5" untuk memastikan db sudah habis, tetapi itu berhasil untuk saya.
traday
74
Gambar berbasis Alpine sebenarnya tampaknya tidak memiliki bash yang diinstal - lakukan seperti @Chaoste merekomendasikan dan menggunakan shsebagai gantinya:[sh, -c, "cd /usr/src/app && npm start"]
Florian Loch
1
Bisa juga menggunakan hanya ashdi alpine :)
Jonathan
160

Saya menjalankan hal-hal pra-mulai seperti migrasi dalam wadah singkat yang terpisah, seperti itu (catatan, file penulisan harus bertipe versi '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

Ini membantu menjaga kebersihan dan terpisah. Dua hal yang perlu dipertimbangkan:

  1. Anda harus memastikan urutan startup yang benar (menggunakan depend_on)

  2. Anda ingin menghindari beberapa build yang dicapai dengan memberi tag pada putaran pertama kali menggunakan build dan gambar; Anda dapat merujuk gambar di wadah lain itu

Bjoern Stiel
sumber
2
Ini sepertinya pilihan terbaik bagi saya, dan saya ingin menggunakannya. Bisakah Anda menguraikan pengaturan penandaan untuk menghindari beberapa build? Saya lebih suka untuk menghindari langkah-langkah tambahan, jadi jika ini perlu beberapa, saya mungkin pergi dengan di bash -catas.
Stavros Korokithakis
3
Di yaml di atas, build dan penandaan terjadi di bagian migrasi. Ini tidak benar-benar jelas pada pandangan pertama, tetapi membuat tag buruh pelabuhan saat Anda menentukan properti build DAN image - di mana properti gambar menentukan tag untuk build itu. Itu kemudian dapat digunakan selanjutnya tanpa memicu membangun baru (jika Anda melihat web, Anda melihatnya tidak memiliki membangun tetapi hanya properti gambar). Berikut ini beberapa detail lainnya docs.docker.com/compose/compose-file )
Bjoern Stiel
26
Meskipun saya menyukai gagasan ini, masalahnya adalah depend_on hanya memastikan mereka memulai dalam urutan itu, bukan bahwa mereka siap dalam urutan itu. wait-for-it.sh mungkin solusi yang dibutuhkan sebagian orang.
Traday
2
Itu benar-benar benar dan sedikit memalukan bahwa komposisi buruh pelabuhan tidak mendukung kontrol berbutir halus seperti menunggu wadah untuk keluar atau mulai mendengarkan pada port. Tapi ya, skrip khusus tidak menyelesaikan ini, bagus!
Bjoern Stiel
1
Jawaban ini memberikan informasi yang salah dan berpotensi merusak tentang bagaimana depend_on bekerja.
antonagestam
96

Saya sarankan menggunakan shsebagai kebalikan dari bashkarena lebih mudah tersedia pada sebagian besar gambar berbasis unix (alpine, dll).

Berikut ini sebuah contoh 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"

Ini akan memanggil perintah berikut secara berurutan:

  • python manage.py wait_for_db - tunggu db siap
  • python manage.py migrate - jalankan migrasi apa pun
  • python manage.py runserver 0.0.0.0:8000 - mulai server pengembangan saya
LondonAppDev
sumber
2
Secara pribadi ini adalah solusi favorit saya, dan terbersih.
BugHunterUK
1
Milik saya juga. Seperti yang ditunjukkan oleh @LondonAppDev, bash tidak tersedia secara default di semua kontainer untuk mengoptimalkan ruang (mis., Kebanyakan kontainer dibangun di atas Alpine Linux)
ewilan
2
Saya harus melarikan diri dari multiline && dengan \
Andre Van Zuydam
@AndreVanZuydam hmmm itu aneh, saya tidak perlu melakukan itu. Apakah Anda dikelilingi dengan tanda kutip? Apa rasa buruh pelabuhan yang Anda jalankan?
LondonAppDev
2
@oligofren the >digunakan untuk memulai input multi-line (lihat stackoverflow.com/a/3790497/2220370 )
LondonAppDev
40

Ini bekerja untuk saya:

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 mencoba melakukan dereferensi variabel sebelum menjalankan perintah, jadi jika Anda ingin bash untuk menangani variabel, Anda harus lolos dari tanda dolar dengan menggandakannya ...

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

... kalau tidak Anda akan mendapatkan kesalahan:

Format interpolasi tidak valid untuk opsi "perintah" di layanan "web":

MatrixManAtYrService
sumber
Hai teman Saya menemukan masalah: `` `argumen yang tidak dikenal: / bin / bash -c python3 /usr/local/airflow/__init__.py -C Lokal -T Windows` `` perintah di docker-compose.yml saya adalah: command: - / bin / bash - -c - | python3 /usr/local/airflow/__init__.py -C $ {Client} -T $ {Types} Apakah Anda tahu cara memperbaikinya? Saya menambahkan Klien dan Jenis dalam file .env saya.
Newt
Inilah dokumen untuk Anda: docs.docker.com/compose/compose-file/#variable-substitution Saya pikir yang terjadi adalah file .env Anda menempatkan variabel-variabel tersebut di lingkungan wadah, tetapi komposisi buruh pelabuhan sedang mencari di lingkungan shell Anda . Coba saja $${Types}dan $${Client}. Saya pikir ini akan mencegah pembuat galangan dari menafsirkan variabel-variabel tersebut dan mencari nilai-nilai mereka di shell apa pun yang Anda gunakan dari pembuat galangan, yang akan berarti bahwa mereka masih ada untuk bash untuk mereferensikan mereka ( setelah buruh pelabuhan memproses .envfile Anda ).
MatrixManAtYrService
Terima kasih atas komentar Anda. Sebenarnya saya melakukan apa yang Anda katakan. Jadi saya mendapat $ (Klien) dalam informasi kesalahan. Saya mengubah cara membaca variabel lingkungan untuk menggunakan os.getenv dengan python, yang lebih mudah. Bagaimanapun, terima kasih.
Newt
23

Anda dapat menggunakan titik masuk di sini. entrypoint di docker dieksekusi sebelum perintah sedangkan perintah adalah perintah default yang harus dijalankan ketika kontainer mulai. Jadi sebagian besar aplikasi umumnya menjalankan prosedur pengaturan dalam file entrypoint dan pada akhirnya mereka mengizinkan perintah untuk dijalankan.

membuat file skrip shell mungkin sebagai docker-entrypoint.sh(nama tidak masalah) dengan konten berikut di dalamnya.

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

dalam file docker-compose.yml gunakan dengan entrypoint: /docker-entrypoint.shdan daftarkan perintah sebagai command: python manage.py runserver 0.0.0.0:8000 PS: jangan lupa menyalin docker-entrypoint.shbersama dengan kode Anda.

Harshad Yeola
sumber
Perhatikan bahwa ini akan dieksekusi juga ketika Anda melakukannyadocker-compose run service-name ....
thisismydesign
18

Ide lain:

Jika, seperti dalam kasus ini, Anda membangun wadah hanya tempat skrip startup di dalamnya dan jalankan ini dengan perintah. Atau pasang skrip startup sebagai volume.

rweng
sumber
Ya, pada akhirnya saya membuat skrip run.sh: #!/bin/bash \n python manage.py migrate \n python manage.py runserver 0.0.0.0:8000(onlin jelek)
fero
9

* PEMBARUAN *

Saya pikir cara terbaik untuk menjalankan beberapa perintah adalah dengan menulis Dockerfile kustom yang melakukan semua yang saya inginkan sebelum CMD resmi dijalankan dari gambar.

docker-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)

Ini mungkin cara paling bersih untuk melakukannya.

* CARA LAMA *

Saya membuat skrip shell dengan perintah saya. Dalam hal ini saya ingin memulai mongod, dan menjalankan mongoimporttetapi memanggil mongodblok Anda dari menjalankan sisanya.

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

Jadi ini garpu mongo, melakukan monogimport dan kemudian membunuh mongo bercabang yang terlepas, dan memulai lagi tanpa melepaskan. Tidak yakin apakah ada cara untuk melampirkan proses bercabang tapi ini berhasil.

CATATAN: Jika Anda benar-benar ingin memuat beberapa data db awal, ini adalah cara untuk melakukannya:

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

file mongo_fixtures / *. json dibuat melalui perintah mongoexport.

docker-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
radtek
sumber
5

Jika Anda perlu menjalankan lebih dari satu proses daemon, ada saran dalam dokumentasi Docker untuk menggunakan Supervisord dalam mode un-detached sehingga semua sub-daemon akan menghasilkan keluaran ke stdout.

Dari pertanyaan SO lainnya, saya menemukan Anda dapat mengarahkan output proses anak ke stdout. Dengan begitu Anda bisa melihat semua output!

Tim Tisdall
sumber
Melihat ini lagi, jawaban ini tampaknya lebih cocok untuk menjalankan beberapa perintah secara paralel daripada seri.
Tim Tisdall
1

Gunakan alat seperti menunggu atau meroserisasi . Ini adalah skrip pembungkus kecil yang dapat Anda sertakan dalam gambar aplikasi Anda. Atau tulis skrip pembungkus Anda sendiri untuk melakukan perintah aplikasi yang lebih spesifik. menurut: https://docs.docker.com/compose/startup-order/

Eran
sumber
0

Saya berlari ke ini ketika mencoba untuk mengatur wadah jenkins saya untuk membangun wadah buruh pelabuhan sebagai pengguna jenkins.

Saya perlu menyentuh file docker.sock di Dockerfile ketika saya menautkannya nanti di file menulis-docker. Kecuali saya menyentuhnya terlebih dahulu, itu belum ada. Ini berhasil untuk saya.

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
Jason Anderson
sumber
Ini sepertinya jawaban untuk pertanyaan yang berbeda.
kenorb
-7

coba gunakan ";" untuk memisahkan perintah jika Anda berada di verions dua misalnya

command: "sleep 20; echo 'a'"

chanllen
sumber