จะทำให้คอนเทนเนอร์ Docker ทำงานหลังจากเริ่มบริการได้อย่างไร


156

ฉันได้เห็นแบบฝึกหัดมากมายที่ดูเหมือนจะทำแบบเดียวกันกับที่ฉันพยายามทำ แต่ด้วยเหตุผลบางอย่างที่นักเทียบท่าของฉันออกจากคอนเทนเนอร์ โดยพื้นฐานแล้วฉันกำลังตั้งค่าเว็บเซิร์ฟเวอร์และ daemons สองสามตัวภายในคอนเทนเนอร์ Docker ฉันทำส่วนสุดท้ายของสิ่งนี้ผ่านสคริปต์ทุบตีที่เรียกrun-all.shว่าฉันทำงานผ่าน CMD ใน Dockerfile ของฉัน run-all.shมีลักษณะเช่นนี้:

service supervisor start
service nginx start

และฉันเริ่มมันภายใน Dockerfile ของฉันดังนี้

CMD ["sh", "/root/credentialize_and_run.sh"]

ฉันเห็นว่าบริการทั้งหมดเริ่มต้นขึ้นอย่างถูกต้องเมื่อฉันทำงานด้วยตนเอง (เช่นไปยังรูปภาพด้วย -i -t / bin / bash) และทุกอย่างดูเหมือนว่าจะทำงานอย่างถูกต้องเมื่อฉันเรียกใช้รูปภาพ แต่ออกทันที มันเสร็จสิ้นการเริ่มต้นกระบวนการของฉัน ฉันต้องการให้กระบวนการทำงานไปเรื่อย ๆ และเท่าที่ฉันเข้าใจคอนเทนเนอร์ต้องทำงานต่อไปเพื่อให้สิ่งนี้เกิดขึ้น อย่างไรก็ตามเมื่อฉันวิ่งdocker ps -aฉันเห็น:

➜  docker_test  docker ps -a
CONTAINER ID        IMAGE                            COMMAND                CREATED             STATUS                      PORTS               NAMES
c7706edc4189        some_name/some_repo:blah   "sh /root/run-all.sh   8 minutes ago       Exited (0) 8 minutes ago                        grave_jones

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


1
คุณเปิดเผยพอร์ตของบริการถึงภายนอกหรือไม่ (-p ตัวเลือกในการทำงานของนักเทียบท่า) (แน่นอนว่าสิ่งนี้จะป้องกันไม่ให้พวกเขาออกจาก)
ribamar

1
ฉันใช้ ENTRYPOINT ใน Dockerfile ของฉันและหลังจากที่สคริปต์กำหนดไว้ใน ENTRYPOINT (สคริปต์เริ่มต้นของฉัน) วิ่งไปแล้วมันปรากฏในบันทึก แต่ดูเหมือนว่าคอนเทนเนอร์ของฉันจะออก ดังนั้นแทนที่จะเป็น ENTRYPOINT ฉันใช้คำสั่ง RUN เพื่อเรียกใช้สคริปต์และคอนเทนเนอร์ยังคงทำงานในพื้นหลัง
ypahalajani

คำตอบ:


50

นี่ไม่ใช่วิธีที่คุณควรออกแบบคอนเทนเนอร์ Docker ของคุณ

เมื่อมีการออกแบบภาชนะหางที่คุณควรจะสร้างมันดังกล่าวว่ามีเพียงหนึ่งกระบวนการทำงานอยู่ (เช่นคุณควรมีหนึ่งคอนเทนเนอร์สำหรับ Nginx และอีกหนึ่งสำหรับ supervisord หรือแอปที่กำลังทำงานอยู่); นอกจากนี้กระบวนการนั้นควรทำงานในเบื้องหน้า

คอนเทนเนอร์จะ "ออก" เมื่อกระบวนการออกจากตัวเอง (ในกรณีของคุณกระบวนการนั้นคือสคริปต์ทุบตีของคุณ)


แต่ถ้าคุณจริงๆต้อง (หรือต้องการ) เพื่อเรียกใช้บริการหลายในภาชนะหางของคุณให้พิจารณาเริ่มต้นจาก"หางฐาน Image"ซึ่งใช้runitเป็นกระบวนการหลอก init (runitจะอยู่ออนไลน์ในขณะที่ Nginx และหัวหน้าวิ่ง) ซึ่งจะอยู่ เบื้องหน้าในขณะที่กระบวนการอื่นของคุณทำสิ่งนั้น

พวกเขามีเอกสารจำนวนมากดังนั้นคุณควรจะสามารถบรรลุสิ่งที่คุณพยายามทำอย่างง่ายดายพอสมควร


1
คุณช่วยอธิบายได้หรือไม่ว่าทำไมฉันควรมีบริการเพียงบริการเดียวเท่านั้น ฉันสามารถเพิ่ม nginx ให้กับหัวหน้างานหากจำเป็น แต่ไม่แน่ใจว่าทำไมเรื่องนี้จึงจำเป็น
อีไล

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

1
@Eli การโพสต์บล็อกของ Docker นี้ทำให้กรณีที่รันหลายกระบวนการ (และในวงกว้างการพูดว่าการดูคอนเทนเนอร์ในฐานะ "VPS เล็ก") นั้นไม่ดีเท่าที่ควร ในกรณีของคุณเธรดความคิดเห็นอาจมีความเกี่ยวข้องมากกว่าการโพสต์บล็อกจริง
โทมัส Orozco

1
ภาพฐานนักเทียบท่าเป็นทางออกที่น่ากลัวสำหรับปัญหาองค์กรจำนวนมากเนื่องจากมี บริษัท ที่จริงจังเพียงไม่กี่แห่งที่ใช้อูบุนตูเลือกที่จะใช้ต้นไม้ RHEL / Centos แทน
วิศวกรซอฟต์แวร์

9
"บริษัท ที่มีอยู่จริงน้อยคน" ดูเหมือนไม่อาจป้องกันได้ ตัวเลือกของระบบปฏิบัติการดูเหมือนจะเป็นไปตามกรณีการใช้งานทั้งหมด บริษัท ใดก็ตามที่มีสภาพแวดล้อมที่แตกต่างกันมากมายรวมถึงการใช้นักพัฒนาภายใน, การใช้พนักงานภายใน, การสนับสนุนการขาย, การจัดเตรียม, POCs และในที่สุดการผลิต (และแม้จะเป็นคำที่คลุมเครือ) ฉันไม่เชื่อว่า OP กล่าวถึงกรณีการใช้งานของพวกเขาดังนั้น (ขออภัยที่ต้องเป็น nitpicky) แต่ความคิดเห็นประเภทนี้ดูเหมือนจะเป็นประเภทที่เผยแพร่ข้อมูลที่มีความเห็นสูงโดยไม่มีเหตุผลว่าทำไม
John Carrell

155

หากคุณใช้ Dockerfile ให้ลอง:

ENTRYPOINT ["tail", "-f", "/dev/null"]

(เห็นได้ชัดว่านี่เป็นเพียงเพื่อจุดประสงค์ในการพัฒนาเท่านั้นคุณไม่จำเป็นต้องเก็บภาชนะไว้จนกว่าจะใช้กระบวนการเช่น nginx ... )


5
ฉันใช้CMD["sleep", "1d"]แต่โซลูชันของคุณดูดีขึ้น
George Pligoropoulos

@GeorgiosPligoropoulos สิ่งนี้จะติดอยู่ในบรรทัดนั้น อาจจะทำงานในพื้นหลังจะทำงาน
Prashanth Sams

5
CMD["sleep", "infinity"]นอกจากนี้ยังสามารถใช้
Romain

5
หรือ 'แมว' แต่ผู้คนอาจบอกว่าเป็นการทารุณสัตว์ xD
lawphotog

คุณอาจเสร็จสิ้นสคริปต์จุดเข้าใช้งานด้วยexec tail -f /dev/nullแต่การใช้tailเป็นจุดเข้าใช้งานเป็นคำตอบที่ผิด
Torsten Bronger

86

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

docker run -td <image>

นี่คือสิ่งที่ธงทำ (ตามdocker run --help):

-d, --detach=false         Run container in background and print container ID
-t, --tty=false            Allocate a pseudo-TTY

สิ่งที่สำคัญที่สุดคือ-tธง -dเพียงให้คุณเรียกใช้คอนเทนเนอร์ในพื้นหลัง


3
ฉันทำซ้ำไม่ได้ คุณช่วยยกตัวอย่างได้ไหม มีอะไรพิเศษ (เช่น: CMD) เกี่ยวกับ Dockerfile ที่เราต้องการเพื่อให้มันใช้งานได้หรือไม่
Matheus Santana

2
สิ่งนี้ไม่ได้ผลสำหรับฉัน ฉันใช้คำสั่งdocker logs <image>เพื่อให้แน่ใจว่าเป็นข้อผิดพลาดที่ทำให้คอนเทนเนอร์นักเทียบท่าของฉันออก สถานะการออกคือ0และผลลัพธ์สุดท้ายคือความสับสนที่lighttpdเซิร์ฟเวอร์ของฉันกำลังทำงาน:[ ok ] Starting web server: lighttpd.
ob1

ฉันไม่ได้ทำงานกับ Docker มาระยะหนึ่งแล้ว ดังนั้นจึงเป็นไปได้ว่าอินเตอร์เฟสบรรทัดคำสั่งเปลี่ยนไปและคำสั่งนี้จะไม่ทำงานอีกต่อไป
arne.z

4
ฉันสามารถยืนยันได้ว่านี่ใช้งานได้กับนักเทียบท่ารุ่นล่าสุด หากคุณต้องการแนบกับเซสชันนี้ในภายหลังการใช้ -dit จะทำงานได้เช่นกัน
John Hamilton

1
@ ยาวสคริปต์จะไม่ยอมรับ tty เพิ่มexec bashหรือexec shหากไม่ได้ติดตั้ง bash ไว้ที่ส่วนท้ายของ start.sh จากนั้นคุณสามารถใช้แฟ
123

43

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

คุณสามารถใช้หัวหน้างานในการทำทุกอย่างหากเรียกใช้ด้วยแฟล็ก "-n" ซึ่งถูกแจ้งว่าไม่ให้ daemonize ดังนั้นมันจะยังคงเป็นกระบวนการแรก:

CMD ["/usr/bin/supervisord", "-n"]

และ supervisord.conf ของคุณ:

[supervisord]
nodaemon=true

[program:startup]
priority=1
command=/root/credentialize_and_run.sh
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
autorestart=false
startsecs=0

[program:nginx]
priority=10
command=nginx -g "daemon off;"
stdout_logfile=/var/log/supervisor/nginx.log
stderr_logfile=/var/log/supervisor/nginx.log
autorestart=true

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

ด้วยวิธีนี้คุณสามารถใช้ supervisord ในกรณีที่คุณอาจต้องใช้ nginx และ php5-fpm และมันไม่สมเหตุสมผลเลยที่จะแยกมันออกจากกัน


มันอยู่ที่ไหนในเอกสารบอกว่าถ้า PID 1 สิ้นสุดที่นักเทียบท่าคอนเทนเนอร์หยุดทำงาน?
8oh8

@ 8oh8 นั่นคือการทำงานของกระบวนการเนมสเปซ มันไม่ได้เฉพาะ Docker มากเท่า "สิ่งที่ต้นแบบภาชนะทั้งหมด" จากman7.org/linux/man-pages/man7/pid_namespaces.7.html :If the "init" process of a PID namespace terminates, the kernel terminates all of the processes in the namespace via a SIGKILL signal. This behavior reflects the fact that the "init" process is essential for the correct operation of a PID namespace.
dannysauer

40

คุณสามารถเรียกใช้ธรรมดาcatโดยไม่มีข้อโต้แย้งตามที่ bro @ Sa'ad กล่าวไว้เพื่อให้การทำงานของคอนเทนเนอร์คงที่ [ไม่ทำอะไรเลยนอกจากรอการป้อนข้อมูลจากผู้ใช้] (ปลั๊กอิน Docker ของ Jenkins ทำสิ่งเดียวกัน)


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

1
catหรือ ปลั๊กอินนักเทียบท่าของ jenkin ทำเช่นนั้น
Sa'ad

12

ตรวจสอบให้แน่ใจว่าคุณเพิ่มdaemon off;ให้กับคุณ nginx.conf หรือรันด้วยCMD ["nginx", "-g", "daemon off;"]ตามรูป nginx อย่างเป็นทางการ

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

service supervisor start && nginx

ในบางกรณีคุณจะต้องมีมากกว่าหนึ่งกระบวนการในคอนเทนเนอร์ของคุณดังนั้นการบังคับให้คอนเทนเนอร์มีหนึ่งกระบวนการไม่ทำงานและสามารถสร้างปัญหาเพิ่มเติมในการปรับใช้

ดังนั้นคุณต้องเข้าใจการแลกเปลี่ยนและตัดสินใจตามนั้น


7

แรงจูงใจ:

มีอะไรผิดปกติในการทำงานหลายกระบวนการภายในของภาชนะนักเทียบท่า ถ้าใครชอบที่จะใช้นักเทียบท่าเป็น VM น้ำหนักเบา - ไม่ว่าจะเป็น คนอื่น ๆ ชอบที่จะแยกแอปพลิเคชันของพวกเขาออกเป็นบริการไมโคร ฉันคิดว่า: โคมไฟสแต็คในภาชนะเดียว? ดีเพียง.

คำตอบ:

ติดกับภาพฐานที่ดีเช่นภาพฐาน Phusion อาจมีคนอื่น โปรดแสดงความคิดเห็น.

และนี่ก็เป็นอีกหนึ่งคำขอร้องให้หัวหน้างาน เพราะอิมเมจฐานฟิชชิ่งให้ผู้ดูแลนอกเหนือจากสิ่งอื่นเช่น cron และ locale setup สิ่งที่คุณต้องการติดตั้งเมื่อใช้งาน VM ที่มีน้ำหนักเบา สำหรับสิ่งที่คุ้มค่าก็ยังมีการเชื่อมต่อ SSH ลงในภาชนะ

อิมเมจฟิวชั่นนั้นจะเริ่มและทำงานต่อไปหากคุณออกแถลงการณ์การรันตัวเทียบท่าพื้นฐาน

moin@stretchDEV:~$ docker run -d phusion/baseimage
521e8a12f6ff844fb142d0e2587ed33cdc82b70aa64cce07ed6c0226d857b367
moin@stretchDEV:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS
521e8a12f6ff        phusion/baseimage   "/sbin/my_init"     12 seconds ago      Up 11 seconds

หรือตายง่าย ๆ :

หากภาพฐานไม่เหมาะกับคุณ ... สำหรับ CMD ที่รวดเร็วเพื่อให้ทำงานต่อไปฉันจะสมมติว่าเป็นเช่นนี้เพื่อทุบตี:

CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"

หรือนี่สำหรับ busybox:

CMD exec /bin/sh -c "trap : TERM INT; (while true; do sleep 1000; done) & wait"

นี้เป็นสิ่งที่ดีเพราะมันจะออกทันทีdocker stopบน เพียงแค่ธรรมดาsleepหรือcatจะใช้เวลาสองสามวินาทีก่อนที่คอนเทนเนอร์จะออก


ฉันปรับแต่งรูปภาพพื้นฐาน centos7 เพื่อโหลด PostgreSQL 11 คุณเริ่มต้นด้วยการเรียกไปที่ / usr / pgsql-11 / bin / pg_ctl แต่ pg_ctl ออกจากเซิร์ฟเวอร์เมื่อเซิร์ฟเวอร์ทำงาน ข้อเสนอแนะของคุณเพื่อใช้กับดักทำงานได้ดี เป็นบรรทัดสุดท้ายของสคริปต์ของฉัน pgstartwait.sh
Alchemistmatt

6

จับ PID ของกระบวนการ ngnix ในตัวแปร (เช่น $ NGNIX_PID) และในตอนท้ายของไฟล์จุดเข้าใช้งาน

wait $NGNIX_PID 

ด้วยวิธีนี้คอนเทนเนอร์ของคุณควรทำงานจนกว่า ngnix จะยังมีชีวิตอยู่เมื่อ ngnix หยุดทำงานคอนเทนเนอร์ก็จะหยุดเช่นกัน


0

วิธีการเกี่ยวกับการใช้รูปแบบการดูแลบริการถ้ามี?

บริการ YOUR_SERVICE ดูแล

เมื่อการควบคุมดูแลทำงานได้สำเร็จจะไม่ออกจนกว่าจะถูกฆ่าหรือถูกขอให้ออกโดยเฉพาะ

บันทึกโดยไม่ต้องสร้าง supervisord.conf

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