คำสั่งหลายคำสั่งในคำสั่ง Docker CMD


39

ไม่เข้าใจว่าเกิดอะไรขึ้นเมื่อฉันพยายามรันคำสั่งสองคำสั่งที่รันไทม์ผ่านคำสั่ง CMD ใน `Dockerfile ฉันคิดว่ามันน่าจะใช้ได้

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

แต่มันไม่ทำงาน ตู้คอนเทนเนอร์ยังไม่เริ่ม ดังนั้นฉันต้องทำเช่นนี้:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

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

เพิ่งจะทราบ - เดียวกันคือมีcommand:คำสั่งในdocker-compose.ymlตามที่คาดไว้

คำตอบ:


33

ฉันเชื่อว่าความแตกต่างอาจจะเกี่ยวข้องกับคำสั่งที่สองทำการประมวลผลเชลล์ในขณะที่ครั้งแรกไม่ได้ ตามเอกสารอย่างเป็นทางการมีexecและshellรูปแบบคำสั่งแรกของคุณเป็นรูปแบบการบริหารและมันไม่ได้สำหรับอินสแตนซ์ขยายตัวแปรสภาพแวดล้อมในขณะที่คนที่สองทำ ดังนั้นจึงเป็นไปได้ว่าโดยใช้แบบฟอร์ม exec คำสั่งอาจล้มเหลวเนื่องจากการพึ่งพาการประมวลผลเชลล์ คุณสามารถตรวจสอบสิ่งนี้ได้ด้วยการวิ่งdocker logs CONTAINERID

คำสั่งที่สองของคุณคือรูปแบบของเชลล์เทียบเท่ากับ -

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

ข้อความที่ตัดตอนมาจากเอกสาร -

หมายเหตุ: ซึ่งแตกต่างจากรูปแบบเปลือกรูปแบบ exec ไม่ได้เรียกเปลือกคำสั่ง ซึ่งหมายความว่าการประมวลผลเชลล์ปกติจะไม่เกิดขึ้น ยกตัวอย่างเช่นจะไม่ทำแทนค่าตัวแปรในCMD [ "echo", "$HOME" ] หากคุณต้องการการประมวลผลเปลือกแล้วทั้งใช้แบบฟอร์มเปลือกหรือรันเปลือกโดยตรงตัวอย่างเช่น:$HOMECMD [ "sh", "-c", "echo", "$HOME" ]


อาจคำสั่งล้มเหลวเนื่องจากตัวแปรสภาพแวดล้อม ฉันยังควรใช้execแบบฟอร์มนี้เนื่องจากเป็นรูปแบบที่ต้องการหรือไม่ ทำไมถึงเป็นที่ต้องการ หรือฉันควรใช้shellแบบฟอร์มที่ง่ายขึ้น?
วลาด

มันล้มเหลวเพราะการดำเนินการหนึ่งคำสั่งหลังจากนั้นเป็นฟังก์ชั่นเปลือก ตัวแปรสภาพแวดล้อมเป็นปลาเฮอริ่งแดง
ไบรอัน

หากคุณใช้งานหลายบริการใน Docker ฉันขอแนะนำให้ใช้ตัวจัดการกระบวนการเช่นหัวหน้างาน ด้วยวิธีนี้คุณจะเปิดใช้งาน supervisord ภายใต้ส่วนของ CMD เท่านั้นและจะดูแลการเริ่มบริการ คุณสามารถตรวจสอบรายละเอียดได้ที่นี่ - docs.docker.com/articles/using_supervisord
Daniel t

นี่เป็นบทความที่ฉันเพิ่งอ่าน :)
วลา

CMD [ "sh", "-c", "echo", "$HOME"]ผมก็ยังไม่เข้าใจว่าทำไมคุณต้องทำ ทำไมไม่CMD ["sh", "-c", "echo $HOME"]หรือสำหรับเรื่องที่CMD ["sh -c echo $HOME"]?
sixty4bit


2

ไวยากรณ์ JSON ของCMD(และRUNและENTRYPOINT) ผ่านการขัดแย้งเคอร์เนลโดยตรงเป็น syscall exec ไม่มีการแยกคำสั่งออกจากอาร์กิวเมนต์ด้วยช่องว่างการหลีกเลี่ยงคำพูดการเปลี่ยนเส้นทาง IO การแทนที่ตัวแปรการไพพ์ระหว่างคำสั่งการรันหลายคำสั่ง ฯลฯ ใน exec syscall syscall ใช้เวลาเรียกใช้งานเพื่อรันและรายการอาร์กิวเมนต์เพื่อส่งไปยังไฟล์เรียกใช้นั้นและรันได้

อักขระที่ต้องการ$ขยายตัวแปร;เพื่อแยกคำสั่ง(เว้นวรรค) เพื่อแยกอาร์กิวเมนต์&&และ||คำสั่งลูกโซ่>สำหรับการเปลี่ยนเส้นทางเอาต์พุตไป|ยังไพพ์ระหว่างคำสั่ง ฯลฯ เป็นคุณลักษณะทั้งหมดของเชลล์และต้องการอะไรบางอย่าง/bin/shหรือ/bin/bashต้องการตีความ


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

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

มิฉะนั้นไวยากรณ์ที่สองของคุณจะทำสิ่งเดียวกัน:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

โปรดทราบว่าฉันไม่แนะนำให้เรียกใช้หลายคำสั่งด้วยวิธีนี้ภายในคอนเทนเนอร์เนื่องจากไม่มีการจัดการข้อผิดพลาดหากคำสั่งแรกของคุณล้มเหลวโดยเฉพาะหากทำงานในพื้นหลัง นอกจากนี้คุณยังปล่อยให้เชลล์ทำงานเป็น pid 1 ภายในคอนเทนเนอร์ซึ่งจะทำลายการจัดการสัญญาณส่งผลให้เกิดความล่าช้า 10 วินาทีและฆ่าภาชนะของคุณโดยนักเทียบท่า การจัดการสัญญาณสามารถบรรเทาได้โดยใช้execคำสั่งเชลล์:

CMD /etc/init.d/nullmailer start ; exec /usr/sbin/php5-fpm

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


1

ฉันเดาคำสั่งแรกล้มเหลวเพราะในรูปแบบ DOCKER CMD เฉพาะพารามิเตอร์แรกเท่านั้นที่ถูกดำเนินการส่วนที่เหลือจะถูกป้อนเข้าสู่คำสั่งนี้

รูปแบบที่สองทำงานได้เนื่องจากคำสั่งทั้งหมดคั่นด้วย ";" ถูกป้อนเข้าสู่คำสั่ง sh ซึ่งดำเนินการ


1

ฉันไม่คิดว่าคุณควรใส่เครื่องหมายจุลภาคหลัง "เริ่ม"

แทนการใช้

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

ลอง

CMD ["/etc/init.d/nullmailer", "start", "/usr/sbin/php5-fpm"]

ตามที่นักเทียบท่าใช้ "sh -c" คำสั่งด้านบนจะถูกดำเนินการดังต่อไปนี้

/etc/init.d/nullmailer start
/etc/init.d/nullmailer /usr/sbin/php5-fpm

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