ใช้ Docker-Compose, วิธีการใช้งานหลายคำสั่ง


500

ฉันต้องการทำสิ่งนี้ซึ่งฉันสามารถเรียกใช้หลายคำสั่งตามลำดับ

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

คำตอบ:


861

bash -cคิดออกใช้

ตัวอย่าง:

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

ตัวอย่างเดียวกันใน multilines:

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

หรือ:

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

6
@Pedram ตรวจสอบให้แน่ใจว่าคุณใช้รูปภาพที่ติดตั้งทุบตีจริง ภาพบางภาพอาจต้องการเส้นทางตรงไปสู่การทุบตีเช่น/bin/bash
codemaven

5
หากไม่มีการทุบตีติดตั้งคุณสามารถลอง sh -c "คำสั่งของคุณ"
Chaoste

ให้แน่ใจว่าคุณห่อคำสั่งของคุณในใบเสนอราคาเมื่อผ่านไปทุบตีและฉันต้องลื่น "sleep 5" เพื่อให้แน่ใจว่าฐานข้อมูลขึ้น แต่มันทำงานสำหรับฉัน
traday

74
ดูเหมือนว่าภาพที่ใช้อัลไพน์จะไม่มีการติดตั้งทุบตี - ทำเช่น @Chaoste แนะนำและใช้shแทน:[sh, -c, "cd /usr/src/app && npm start"]
Florian Loch

1
ยังสามารถใช้ได้เฉพาะashบนเทือกเขาแอลป์ :)
Jonathan

160

ฉันเรียกใช้ข้อมูลก่อนการเริ่มต้นเช่นการย้ายข้อมูลในที่เก็บชั่วคราวแบบแยกเช่น (หมายเหตุไฟล์การเขียนต้องเป็นเวอร์ชัน '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

สิ่งนี้ช่วยให้สิ่งต่าง ๆ รักษาความสะอาดและแยกจากกัน สองสิ่งที่ควรพิจารณา:

  1. คุณต้องแน่ใจว่าลำดับการเริ่มต้นที่ถูกต้อง (ใช้ depend_on)

  2. คุณต้องการหลีกเลี่ยงการสร้างหลายครั้งซึ่งทำได้โดยการติดแท็กรอบแรกโดยใช้การสร้างและรูปภาพ คุณสามารถอ้างถึงภาพในภาชนะอื่น ๆ แล้ว


2
นี่เป็นตัวเลือกที่ดีที่สุดสำหรับฉันและฉันต้องการใช้มัน คุณสามารถอธิบายรายละเอียดเกี่ยวกับการตั้งค่าการติดแท็กเพื่อหลีกเลี่ยงการสร้างได้หลายงานหรือไม่? ฉันต้องการหลีกเลี่ยงขั้นตอนเพิ่มเติมดังนั้นหากต้องการบางอย่างฉันอาจไปด้วยbash -cด้านบน
Stavros Korokithakis

3
ใน yaml ด้านบนการสร้างและการติดแท็กเกิดขึ้นในส่วนการย้ายข้อมูล ไม่ชัดเจนตั้งแต่แรกเห็น แต่แท็กนักเทียบท่าเขียนเมื่อคุณระบุคุณสมบัติสร้างและรูปภาพ - โดยคุณสมบัติรูปภาพระบุแท็กสำหรับบิลด์นั้น ซึ่งสามารถนำมาใช้ได้ในภายหลังโดยไม่ทริกเกอร์บิลด์ใหม่ (ถ้าคุณดูเว็บคุณจะเห็นว่ามันไม่มีบิลด์ แต่มีเพียงอิมเมจคุณสมบัติ) นี่คือรายละเอียดเพิ่มเติมdocs.docker.com/compose/compose-file )
Bjoern Stiel

26
ในขณะที่ฉันชอบความคิดของเรื่องนี้ปัญหาคือขึ้นอยู่กับว่าทำให้พวกเขาเริ่มต้นในลำดับที่ไม่เพียง แต่พวกเขาพร้อมที่จะอยู่ในลำดับที่ wait-for-it.sh อาจเป็นทางออกที่บางคนต้องการ
traday

2
นั่นเป็นสิ่งที่ถูกต้องและเป็นความอัปยศที่นักแต่งเพลงไม่สนับสนุนการควบคุมที่ละเอียดยิ่งขึ้นเช่นการรอให้คอนเทนเนอร์ออกจากหรือเริ่มฟังพอร์ต แต่ใช่สคริปต์ที่กำหนดเองแก้ปัญหานี้ได้ดี!
Bjoern Stiel

1
คำตอบนี้ให้ข้อมูลที่ไม่ถูกต้องและเป็นอันตรายเกี่ยวกับวิธีการทำงานของ depend_on
antonagestam

96

ฉันขอแนะนำให้ใช้shแทนที่จะเป็นbashเพราะมันพร้อมใช้งานมากขึ้นในภาพที่ใช้ระบบปฏิบัติการยูนิกซ์ (อัลไพน์ ฯลฯ )

นี่คือตัวอย่าง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"

สิ่งนี้จะเรียกคำสั่งต่อไปนี้ตามลำดับ:

  • python manage.py wait_for_db - รอให้ db พร้อมใช้งาน
  • python manage.py migrate - เรียกใช้การโยกย้ายใด ๆ
  • python manage.py runserver 0.0.0.0:8000 - เริ่มเซิร์ฟเวอร์การพัฒนาของฉัน

2
โดยส่วนตัวนี่เป็นวิธีที่ฉันชอบและสะอาดที่สุด
BugHunterUK

1
ของฉันด้วย. @LondonAppDev เป็นจุดเริ่มต้น, การทุบตีจะไม่สามารถใช้งานได้ในทุกตู้คอนเทนเนอร์เพื่อเพิ่มประสิทธิภาพในพื้นที่ (เช่นตู้คอนเทนเนอร์ส่วนใหญ่ที่สร้างจากด้านบนของ Alpine Linux)
ewilan

2
ฉันต้องหลบหนีออกจากสาย & & ด้วย \
Andre Van Zuydam

@AndreVanZuydam อืมมันแปลกฉันไม่จำเป็นต้องทำ คุณล้อมรอบด้วยคำพูดหรือไม่? คุณกำลังรสชาติแบบไหนของนักเทียบท่า?
LondonAppDev

2
@oligofren the >ถูกใช้เพื่อเริ่มอินพุตหลายบรรทัด (ดูstackoverflow.com/a/3790497/2220370 )
LondonAppDev

40

สิ่งนี้ใช้ได้กับฉัน:

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

นักเทียบท่าพยายามที่จะแยกแยะตัวแปรก่อนที่จะรันคำสั่งดังนั้นหากคุณต้องการทุบตีเพื่อจัดการกับตัวแปรคุณจะต้องหลีกเลี่ยงสัญญาณดอลลาร์โดยเพิ่มพวกเขาเป็นสองเท่า ...

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

... มิฉะนั้นคุณจะได้รับข้อผิดพลาด:

รูปแบบการแก้ไขไม่ถูกต้องสำหรับตัวเลือก "คำสั่ง" ในบริการ "เว็บ":


สวัสดีเพื่อน ฉันพบปัญหา: `` `อาร์กิวเมนต์ที่ไม่รู้จัก: / bin / bash -c python3 /usr/local/airflow/__init__.py -C Local -T Windows -`` คำสั่งใน docker-compose.yml ของฉันคือ: คำสั่ง: - / bin / bash - -c - | python3 /usr/local/airflow/__init__.py -C $ {Client} -T $ {ประเภท} คุณรู้วิธีแก้ไขไหม ฉันเพิ่มลูกค้าและประเภทในไฟล์. env ของฉัน
Newt

นี่คือเอกสารสำหรับคุณ: docs.docker.com/compose/compose-file/#variable-subtionฉันคิดว่าสิ่งที่เกิดขึ้นคือไฟล์. env ของคุณวางตัวแปรเหล่านั้นไว้ในสภาพแวดล้อมของตู้คอนเทนเนอร์ แต่นักเทียบท่ากำลังมองหาสภาวะแวดล้อมเชลล์ของคุณ . ลองแทนและ$${Types} $${Client}ผมคิดว่านี่จะป้องกันไม่ให้เขียนนักเทียบท่าจากการตีความตัวแปรเหล่านั้นและกำลังมองหาค่าของพวกเขาในสิ่งที่คุณเรียกเปลือกนักเทียบท่า-เขียนจากซึ่งจะหมายความว่าพวกเขายังคงรอบทุบตีเพื่อ dereference พวกเขา ( หลังจากที่นักเทียบท่ามีการประมวลผลของ.envไฟล์)
MatrixManAtYrService

ขอบคุณสำหรับความคิดเห็นของคุณ ฉันทำสิ่งที่คุณพูดในความเป็นจริง ดังนั้นฉันได้รับ $ (ลูกค้า) ในข้อมูลข้อผิดพลาด ฉันเปลี่ยนวิธีการอ่านตัวแปรสภาพแวดล้อมเพื่อใช้ os.getenv ใน python ซึ่งง่ายกว่า ขอบคุณอยู่ดี
Newt

23

คุณสามารถใช้จุดเข้าใช้งานที่นี่ entrypoint ใน docker ถูกเรียกใช้งานก่อนคำสั่งขณะที่คำสั่งเป็นคำสั่งเริ่มต้นที่ควรรันเมื่อคอนเทนเนอร์เริ่มทำงาน ดังนั้นโดยทั่วไปแอปพลิเคชั่นส่วนใหญ่จะมีโพรซีเดอร์การติดตั้งในไฟล์จุดเข้าใช้งานและในที่สุดพวกเขาอนุญาตให้เรียกใช้คำสั่ง

ทำให้ไฟล์เชลล์สคริปต์อาจเป็นdocker-entrypoint.sh(ชื่อไม่สำคัญ) โดยมีเนื้อหาดังต่อไปนี้

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

ในไฟล์ docker-compose.yml ใช้กับentrypoint: /docker-entrypoint.shและคำสั่ง register เป็นcommand: python manage.py runserver 0.0.0.0:8000 PS: อย่าลืมคัดลอกdocker-entrypoint.shพร้อมกับรหัสของคุณ


โปรดทราบว่าสิ่งนี้จะทำงานเมื่อคุณทำdocker-compose run service-name ....
thisismydesign

18

ความคิดอื่น:

หากในกรณีนี้คุณสร้างคอนเทนเนอร์เพียงแค่วางสคริปต์เริ่มต้นไว้ในนั้นและเรียกใช้สิ่งนี้ด้วยคำสั่ง หรือติดตั้งสคริปต์เริ่มต้นเป็นไดรฟ์ข้อมูล


ใช่ในตอนท้ายฉันสร้างสคริปต์ run.sh: #!/bin/bash \n python manage.py migrate \n python manage.py runserver 0.0.0.0:8000(ugly oneline)
fero

9

* อัพเดท *

ฉันคิดว่าวิธีที่ดีที่สุดในการเรียกใช้คำสั่งบางอย่างคือการเขียน Dockerfile แบบกำหนดเองที่ทำทุกอย่างที่ฉันต้องการก่อนจะเรียกใช้ CMD อย่างเป็นทางการจากรูปภาพ

นักเทียบท่า-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)

นี่อาจเป็นวิธีที่สะอาดที่สุดที่จะทำ

* วิธีเก่า *

ฉันสร้างเชลล์สคริปต์ด้วยคำสั่งของฉัน ในกรณีนี้ฉันต้องการเริ่มmongodและเรียกใช้mongoimportแต่โทรmongodบล็อกคุณจากการทำงานที่เหลือ

นักเทียบท่า-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

ดังนั้นส้อมนี้ mongo ทำ monogimport แล้วฆ่า mongo ทางแยกที่ถูกถอดออกแล้วเริ่มต้นใหม่อีกครั้งโดยไม่แยกออก ไม่แน่ใจว่ามีวิธีเชื่อมต่อกับกระบวนการที่แยกไว้หรือไม่ แต่จะใช้งานได้

หมายเหตุ: หากคุณต้องการโหลดข้อมูลเริ่มต้นบางส่วนอย่างเคร่งครัดนี่เป็นวิธีที่ทำได้:

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

mongo_fixtures / *. ไฟล์ json ถูกสร้างขึ้นผ่านคำสั่ง mongoexport

นักเทียบท่า-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

หากคุณต้องการเรียกใช้มากกว่าหนึ่งกระบวนการ daemon มีข้อเสนอแนะในเอกสารประกอบ Docker เพื่อใช้ Supervisordในโหมดไม่แยกเดี่ยวดังนั้น sub-daemons ทั้งหมดจะส่งออกไปยัง stdout

จากคำถาม SO อื่นฉันค้นพบว่าคุณสามารถเปลี่ยนเส้นทางลูกประมวลผลผลลัพธ์ไปยัง stdout ด้วยวิธีนี้คุณจะเห็นผลลัพธ์ทั้งหมด!


เมื่อดูที่นี้อีกครั้งคำตอบนี้ดูเหมือนจะเหมาะสำหรับการเรียกใช้หลายคำสั่งในแบบคู่ขนานแทนที่จะเป็นแบบอนุกรม
Tim Tisdall

3

bash -cเมื่อต้องการเรียกใช้คำสั่งหลายในแฟ้มนักเทียบท่า-เขียนโดยใช้

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

ที่มา: https://intellipaat.com/community/19590/docker-run-multiple-commands-using-docker-compose-at-once?show=19597#a19597


1

ใช้เครื่องมือเช่นการรอคอยสำหรับมันหรือdockerize เหล่านี้คือสคริปต์แรปเปอร์ขนาดเล็กซึ่งคุณสามารถรวมไว้ในภาพแอปพลิเคชันของคุณ หรือเขียนสคริปต์ wrapper ของคุณเองเพื่อดำเนินการคำสั่งเฉพาะแอปพลิเคชันเพิ่มเติม ตาม: https://docs.docker.com/compose/startup-order/


0

ฉันวิ่งเข้าไปในนี้ในขณะที่พยายามที่จะได้รับการตั้งค่าภาชนะเจนกินส์ของฉันเพื่อสร้างภาชนะนักเทียบท่าเป็นผู้ใช้เจนกินส์

ฉันจำเป็นต้องแตะไฟล์ docker.sock ใน Dockerfile ขณะที่ฉันลิงก์ในภายหลังในไฟล์ที่ประกอบขึ้นด้วยนักเทียบท่า ถ้าฉันไม่ได้แตะมันก่อนมันก็ยังไม่มีอยู่ สิ่งนี้ใช้ได้สำหรับฉัน

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

นักเทียบท่า-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

ดูเหมือนว่าคำตอบของคำถามที่แตกต่างกัน
kenorb

-7

ลองใช้ ";" เพื่อแยกคำสั่งถ้าคุณอยู่ใน verion สองเช่น

command: "sleep 20; echo 'a'"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.