ฉันสามารถรันหลายโปรแกรมในคอนเทนเนอร์ Docker ได้หรือไม่


150

ฉันพยายามคลุมหัว Docker จากจุดที่ปรับใช้แอปพลิเคชันซึ่งมีวัตถุประสงค์เพื่อเรียกใช้กับผู้ใช้บนเดสก์ท็อป แอปพลิเคชันของฉันเป็นเพียงเว็บแอพพลิเคชั่นขวดและฐานข้อมูล Mongo โดยปกติฉันจะติดตั้งทั้งใน VM และส่งต่อพอร์ตโฮสต์ไปยังเว็บแอปของผู้เยี่ยมชม ฉันต้องการทดลองใช้ Docker แต่ฉันไม่แน่ใจว่าฉันตั้งใจจะใช้มากกว่าหนึ่งโปรแกรม เอกสารบอกว่ามีได้เฉพาะการเข้าใช้งานเท่านั้นดังนั้นฉันจะมี Mongo และแอพพลิเคชั่นกระติกน้ำของฉันได้อย่างไร หรือพวกเขาจำเป็นต้องอยู่ในภาชนะแยกต่างหากซึ่งในกรณีนี้พวกเขาคุยกันได้อย่างไรและวิธีนี้ทำให้การกระจายแอปง่ายขึ้นหรือไม่


2
จุดบน: ทำให้ฉันสงสัยว่าทำไมนักเทียบท่าจึงได้รับความนิยม .. (กระบวนการเดียว .. ?) - แต่เรามาดูกันว่าคำตอบบอกอะไรเราได้
บ้าง

คำตอบ:


120

สามารถมีได้เพียงรายการเดียว แต่เป้าหมายนั้นมักจะเป็นสคริปต์ที่เปิดใช้งานเป็นโปรแกรมจำนวนมากที่ต้องการ นอกจากนี้คุณยังสามารถใช้ตัวอย่างเช่นSupervisordหรือคล้ายกันเพื่อดูแลการเปิดตัวบริการต่างๆภายในคอนเทนเนอร์เดียว นี่คือตัวอย่างของตัวเทียบท่าที่ใช้ mysql, apache และ wordpress ภายในคอนเทนเนอร์เดียวภายในภาชนะเดียว

บอกว่าคุณมีฐานข้อมูลเดียวที่ใช้โดยเว็บแอปพลิเคชันเดียว จากนั้นก็อาจจะเรียกใช้ทั้งสองอย่างในคอนเทนเนอร์เดียวได้ง่ายขึ้น

หากคุณมีฐานข้อมูลที่ใช้ร่วมกันซึ่งมีการใช้งานมากกว่าหนึ่งแอปพลิเคชันจะเป็นการดีกว่าถ้าจะเรียกใช้ฐานข้อมูลในคอนเทนเนอร์ของตัวเองและแอปพลิเคชันแต่ละตัวในคอนเทนเนอร์ของตนเอง

มีความเป็นไปได้อย่างน้อยสองวิธีที่แอปพลิเคชันสามารถสื่อสารซึ่งกันและกันเมื่อทำงานในคอนเทนเนอร์ที่แตกต่างกัน:

  1. ใช้พอร์ต IP ที่เปิดเผยและเชื่อมต่อผ่านพอร์ตเหล่านั้น
  2. รุ่นล่าสุดนักเทียบท่าการสนับสนุนการเชื่อมโยง

1
ดูเหมือนว่าเวอร์ชันใหม่ของ Docker จะรองรับเครือข่ายคอนเทนเนอร์ของ Dockerแล้ว
jpierson

ตอนนี้ Docker สนับสนุนให้เรียกใช้งาน Supervisor ช่วยให้คุณสามารถแยกพฤติกรรมของแต่ละกระบวนการเช่น autorestart = true, stdout_logfile, stderr_logfile เป็นต้นดูที่docs.docker.com/engine/admin/using_supervisord
Andreas Lundgren

4
ฉันจะไม่แนะนำให้ลองเรียกใช้เว็บแอปพลิเคชั่นและ MongoDB ในคอนเทนเนอร์เดียวกันในตัวอย่างนี้ มีกรณีการใช้งานที่ดีของกระบวนการ supervisord หรือ init-like ที่คล้ายกันใน Docker แต่อันนี้ไม่ได้เป็นส่วนหนึ่งของพวกเขา มันเป็นวิธีที่ง่ายกว่าในการใช้นักเทียบท่าเพื่อเรียกใช้บริการสองอย่างในตู้คอนเทนเนอร์แยกต่างหาก
nicolas-van

@ nicolas-van ทำไมมันง่ายกว่า? เป็นเพราะถ้าฐานข้อมูลตายแล้วฉันสามารถรีสตาร์ทคอนเทนเนอร์ของฐานข้อมูลแทนที่จะต้องรีสตาร์ทสิ่งทั้งหมด?
brillout

แอปพลิเคชันบนเครื่องเดียวกันยังสามารถสื่อสารผ่านซ็อกเก็ตโดเมน Unixได้ รับประกันประสิทธิภาพสูงสุด
Jule ที่ไม่เชื่อ

21

ฉันมีความต้องการคล้ายกันในการเรียกใช้สแต็ค LAMP, Mongo DB และบริการของฉันเอง

นักเทียบท่าเป็นระบบเสมือนจริงบนระบบปฏิบัติการซึ่งเป็นเหตุผลว่าทำไมจึงแยกคอนเทนเนอร์ไว้รอบกระบวนการที่กำลังทำงานอยู่ดังนั้นจึงต้องใช้กระบวนการอย่างน้อยหนึ่งกระบวนการที่ทำงานใน FOREGROUND

ดังนั้นคุณจึงให้สคริปต์เริ่มต้นของคุณเองเป็นจุดเริ่มต้นดังนั้นสคริปต์เริ่มต้นของคุณจึงกลายเป็นสคริปต์รูปภาพ Docker เพิ่มเติมซึ่งคุณสามารถใช้บริการใด ๆ ก็ได้ตามจำนวนที่กำหนด เริ่มต้นบริการ FOREGROUND อย่างน้อยต่อปลาย

ดังนั้นไฟล์ภาพ Docker ของฉันมีสองบรรทัดด้านล่างในท้ายที่สุด:

COPY myStartupScript.sh /usr/local/myscripts/myStartupScript.sh
CMD ["/bin/bash", "/usr/local/myscripts/myStartupScript.sh"]

ในสคริปต์ของฉันฉันใช้งาน MySQL, MongoDB, Tomcat เป็นต้นในที่สุดฉันก็เรียกใช้ Apache ของฉันเป็นเธรดเบื้องหน้า

source /etc/apache2/envvars
/usr/sbin/apache2 -DFOREGROUND

สิ่งนี้ทำให้ฉันสามารถเริ่มบริการทั้งหมดของฉันและทำให้ภาชนะมีชีวิตอยู่ด้วยบริการล่าสุดที่เริ่มต้นที่อยู่เบื้องหน้า

หวังว่ามันจะช่วย

อัปเดต : เนื่องจากฉันตอบคำถามนี้ครั้งล่าสุดสิ่งใหม่ ๆ เกิดขึ้นเช่นDocker composeซึ่งสามารถช่วยให้คุณเรียกใช้บริการแต่ละอย่างบนคอนเทนเนอร์ของตัวเอง แต่ผูกทั้งหมดเข้าด้วยกันเป็นการอ้างอิงระหว่างบริการเหล่านั้นลองรู้เพิ่มเติมเกี่ยวกับนักเขียนและ ใช้มันเป็นวิธีที่หรูหรามากขึ้นเว้นแต่ความต้องการของคุณไม่ตรงกับมัน


6

ฉันไม่เห็นด้วยอย่างยิ่งกับโซลูชันก่อนหน้านี้บางอย่างที่แนะนำให้เรียกใช้บริการทั้งสองในคอนเทนเนอร์เดียวกัน มีการระบุไว้อย่างชัดเจนในเอกสารที่ไม่แนะนำ :

โดยทั่วไปเราแนะนำให้คุณแยกส่วนของความกังวลโดยใช้บริการหนึ่งรายการต่อตู้คอนเทนเนอร์ บริการนั้นอาจแยกเป็นหลาย ๆ กระบวนการ (ตัวอย่างเช่น Apache เว็บเซิร์ฟเวอร์เริ่มกระบวนการทำงานหลายอย่าง) มันก็โอเคที่จะมีกระบวนการหลายอย่าง แต่เพื่อให้ได้ประโยชน์สูงสุดจาก Docker ให้หลีกเลี่ยงคอนเทนเนอร์หนึ่งที่รับผิดชอบหลายแง่มุมของแอปพลิเคชันโดยรวมของคุณ คุณสามารถเชื่อมต่อหลายคอนเทนเนอร์โดยใช้เครือข่ายที่ผู้ใช้กำหนดและปริมาณที่แชร์

มีกรณีการใช้งานที่ดีสำหรับ supervisord หรือโปรแกรมที่คล้ายกัน แต่การรันเว็บแอปพลิเคชัน + ฐานข้อมูลไม่ใช่ส่วนหนึ่งของพวกเขา

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


2
นี่คือความคิดเห็นไม่ใช่คำตอบ โปรดพิจารณาเพิ่มคำอธิบายและ / หรือลิงก์เพื่อสนับสนุนตำแหน่งนี้ มิฉะนั้นจะไม่เป็นประโยชน์
Ivan Ivanov

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

คำถามเกี่ยวกับการรัน 2 กระบวนการในหนึ่งคอนเทนเนอร์ดังนั้นจึงไม่สนใจวิธีปฏิบัติที่ดีที่สุด ฉันจะให้ตัวอย่าง: ฉันต้องเรียกใช้ rabbitmq ภายในอิมเมจที่ใช้ PhotonOS และกระบวนการจาวาด้วยเช่นกันดังนั้นฉันจึงใช้สคริปต์รายการและใช้เป็น ENTRYPOINT :)
Vallerious

คำถามดั้งเดิมไม่ใช่คำถามทั่วไปเกี่ยวกับความเป็นไปได้ทางเทคนิคในการรันสองกระบวนการในคอนเทนเนอร์ Docker ระบุกรณีการใช้งานเฉพาะซึ่งเป็นการปรับใช้แอพพลิเคชั่น Python พร้อมกับฐานข้อมูล MongoDB และสำหรับกรณีการใช้งานนั้นคำแนะนำที่ดีที่สุดคือการกีดกันการใช้งานของคอนเทนเนอร์เดียวและแนะนำการใช้งานของนักเขียนที่ประกอบไปด้วย
nicolas-van

5

พวกเขาสามารถอยู่ในภาชนะที่แยกต่างหากและแน่นอนถ้าแอปพลิเคชันตั้งใจที่จะทำงานในสภาพแวดล้อมขนาดใหญ่พวกเขาอาจจะเป็น

ระบบหลายคอนเทนเนอร์จะต้องมีการเชื่อมต่อเพิ่มเติมเพื่อให้สามารถนำการพึ่งพาที่จำเป็นทั้งหมดมาใช้ได้แม้ใน Docker v0.6.5 + มีสิ่งอำนวยความสะดวกใหม่ที่จะช่วยในการสร้างการเชื่อมต่อเอง ด้วยโซลูชันที่มีหลายเครื่องยังคงเป็นสิ่งที่ต้องจัดการจากสภาพแวดล้อมของ Docker

ด้วยสองตู้คอนเทนเนอร์ที่แตกต่างกันสองส่วนยังคงสื่อสารผ่าน TCP / IP แต่ถ้าพอร์ตนั้นถูกล็อคโดยเฉพาะ (ไม่แนะนำเนื่องจากคุณไม่สามารถเรียกใช้มากกว่าหนึ่งสำเนา) คุณจะต้องผ่านพอร์ตใหม่ ฐานข้อมูลได้รับการเปิดเผยว่าเป็นแอปพลิเคชันเพื่อให้สามารถสื่อสารกับ Mongo ได้ นี่คือสิ่งที่การเชื่อมโยงสามารถช่วยได้

สำหรับการติดตั้งขนาดเล็กที่เรียบง่ายซึ่งการขึ้นต่อกันทั้งหมดกำลังเกิดขึ้นในคอนเทนเนอร์เดียวกันโดยมีทั้งฐานข้อมูลและ Python runtime เริ่มต้นโดยโปรแกรมที่เริ่มต้นเรียกว่า ENTRYPOINT สิ่งนี้สามารถทำได้ง่ายเหมือนเชลล์สคริปต์หรือตัวควบคุมกระบวนการอื่น ๆ - Supervisordค่อนข้างเป็นที่นิยมและมีตัวอย่างจำนวนมากใน Dockerfiles สาธารณะ


3

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

ในHipacheตัวอย่างเช่น Dockerfile ที่รวมจะรัน supervisord และไฟล์ supervisord.conf จะระบุทั้ง hipache และ redis-server ที่จะเรียกใช้


2

นักเทียบท่าให้ตัวอย่างสองสามอย่างเกี่ยวกับวิธีการทำ ตัวเลือกที่มีน้ำหนักเบาคือ:

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

#!/bin/bash

# Start the first process
./my_first_process -D
status=$?
if [ $status -ne 0 ]; then
  echo "Failed to start my_first_process: $status"
  exit $status
fi

# Start the second process
./my_second_process -D
status=$?
if [ $status -ne 0 ]; then
  echo "Failed to start my_second_process: $status"
  exit $status
fi

# Naive check runs checks once a minute to see if either of the processes exited.
# This illustrates part of the heavy lifting you need to do if you want to run
# more than one service in a container. The container will exit with an error
# if it detects that either of the processes has exited.
# Otherwise it will loop forever, waking up every 60 seconds

while /bin/true; do
  ps aux |grep my_first_process |grep -q -v grep
  PROCESS_1_STATUS=$?
  ps aux |grep my_second_process |grep -q -v grep
  PROCESS_2_STATUS=$?
  # If the greps above find anything, they will exit with 0 status
  # If they are not both 0, then something is wrong
  if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then
    echo "One of the processes has already exited."
    exit -1
  fi
  sleep 60
done

ถัดไป Dockerfile:

FROM ubuntu:latest
COPY my_first_process my_first_process
COPY my_second_process my_second_process
COPY my_wrapper_script.sh my_wrapper_script.sh
CMD ./my_wrapper_script.sh

2

คุณสามารถเรียกใช้ 2 waitกระบวนการในเบื้องหน้าโดยใช้ เพียงสร้างสคริปต์ทุบตีด้วยเนื้อหาต่อไปนี้ เช่นstart.sh:

# runs 2 commands simultaneously:

mongod & # your first application
P1=$!
python script.py & # your second application
P2=$!
wait $P1 $P2

ใน Dockerfile ของคุณเริ่มด้วย

CMD bash start.sh

0

sh -cถ้าสคริปต์ทุ่มเทดูเหมือนว่าค่าใช้จ่ายมากเกินไปคุณสามารถวางไข่กระบวนการที่แยกจากกันอย่างชัดเจนด้วย ตัวอย่างเช่น:

CMD sh -c 'mini_httpd -C /my/config -D &' \
 && ./content_computing_loop
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.