ฉันสังเกตเห็นว่าสคริปต์ entrypoint.sh จำนวนมากสำหรับนักเทียบท่าทำสิ่งนี้:
#!/bin/bash
set -e
... code ...
exec "$@"
คืออะไรset -e
และมีexec "$@"
ไว้เพื่ออะไร?
ฉันสังเกตเห็นว่าสคริปต์ entrypoint.sh จำนวนมากสำหรับนักเทียบท่าทำสิ่งนี้:
#!/bin/bash
set -e
... code ...
exec "$@"
คืออะไรset -e
และมีexec "$@"
ไว้เพื่ออะไร?
คำตอบ:
โดยทั่วไปจะใช้อาร์กิวเมนต์บรรทัดคำสั่งใด ๆ ที่ส่งผ่านไปentrypoint.sh
และดำเนินการเป็นคำสั่ง โดยพื้นฐานแล้วเจตนาคือ "ทำทุกอย่างในสคริปต์. sh นี้จากนั้นในเชลล์เดียวกันให้รันคำสั่งที่ผู้ใช้ส่งผ่านในบรรทัดคำสั่ง"
ดู:
exec "$@"
จะแทนที่กระบวนการที่กำลังทำงานอยู่ด้วยกระบวนการใหม่ที่สร้างขึ้นสำหรับอาร์กิวเมนต์ที่ส่งผ่าน สิ่งสำคัญสำหรับการส่งสัญญาณ Docker: stackoverflow.com/a/32261019/99717
set -e
ตั้งค่าตัวเลือกเชลล์เพื่อออกทันทีหากคำสั่งใด ๆ ที่กำลังรันออกด้วยรหัสออกที่ไม่ใช่ศูนย์ สคริปต์จะส่งคืนพร้อมกับรหัสออกของคำสั่งที่ล้มเหลว จากหน้า bash man:
ชุด -e:
ออกทันทีหากไปป์ไลน์ (ซึ่งอาจประกอบด้วยคำสั่งง่ายๆเพียงคำสั่งเดียว) รายการหรือคำสั่งผสม (ดู SHELL GRAMMAR ด้านบน) ออกโดยมีสถานะไม่เป็นศูนย์ เชลล์จะไม่ออกหากคำสั่งที่ล้มเหลวเป็นส่วนหนึ่งของรายการคำสั่งทันทีหลังจากคีย์เวิร์ด while หรือ until ซึ่งเป็นส่วนหนึ่งของการทดสอบตามคำสงวน if หรือ elif ซึ่งเป็นส่วนหนึ่งของคำสั่งใด ๆ ที่ดำเนินการใน && หรือ || รายการยกเว้นคำสั่งตามหลังสุดท้าย && หรือ || คำสั่งใด ๆ ในไปป์ไลน์ แต่สุดท้ายหรือหากค่าส่งคืนของคำสั่งกลับด้านด้วย! ถ้าคำสั่งผสมอื่นที่ไม่ใช่ subshell ส่งคืนสถานะที่ไม่ใช่ศูนย์เนื่องจากคำสั่งล้มเหลวในขณะที่ -e ถูกละเว้นเชลล์จะไม่ออก กับดักบน ERR หากตั้งค่าไว้จะถูกเรียกใช้งานก่อนที่เชลล์จะออก
หากคำสั่งผสมหรือฟังก์ชันเชลล์ดำเนินการในบริบทที่ -e ถูกละเว้นคำสั่งใด ๆ ที่ดำเนินการภายในคำสั่งผสมหรือเนื้อความของฟังก์ชันจะได้รับผลกระทบจากการตั้งค่า -e แม้ว่าจะตั้งค่า -e และคำสั่งจะส่งกลับ a สถานะความล้มเหลว หากคำสั่งผสมหรือฟังก์ชันเชลล์ตั้งค่า -e ขณะดำเนินการในบริบทที่ -e ถูกละเว้นการตั้งค่านั้นจะไม่มีผลใด ๆ จนกว่าคำสั่งผสมหรือคำสั่งที่มีการเรียกใช้ฟังก์ชันจะเสร็จสิ้น
exec "$@"
โดยทั่วไปจะใช้เพื่อทำให้จุดเข้าใช้งานผ่านจากนั้นจึงรันคำสั่งนักเทียบท่า มันจะแทนที่เชลล์ที่กำลังรันอยู่ในปัจจุบันด้วยคำสั่งที่"$@"
ชี้ไป โดยค่าเริ่มต้นตัวแปรนั้นจะชี้ไปที่อาร์กิวเมนต์บรรทัดคำสั่ง
หากคุณมีรูปภาพที่มีจุดเข้าใช้ชี้ไปที่ entrypoint.sh และคุณเรียกใช้คอนเทนเนอร์ของคุณเป็นdocker run my_image server start
สิ่งนั้นจะแปลเป็นการทำงานentrypoint.sh server start
ในคอนเทนเนอร์ ที่เส้น exec entrypoint.sh
เปลือกทำงานตาม pid 1 server start
จะเข้ามาแทนที่ตัวเองด้วยคำสั่ง
นี่เป็นสิ่งสำคัญสำหรับการจัดการสัญญาณ โดยไม่ต้องใช้exec
การserver start
ในตัวอย่างข้างต้นจะทำงานเป็น pid อีกและหลังจากที่มันออกคุณจะกลับไปสคริปต์เปลือกของคุณ ด้วยเชลล์ใน pid 1 SIGTERM จะถูกละเว้นโดยค่าเริ่มต้น นั่นหมายถึงสัญญาณหยุดที่สง่างามที่docker stop
ส่งไปยังคอนเทนเนอร์ของคุณจะไม่ได้รับจากserver
กระบวนการ หลังจากผ่านไป 10 วินาที (โดยค่าเริ่มต้น) docker stop
จะยอมหยุดการปิดเครื่องอย่างสง่างามและส่ง SIGKILL ที่จะบังคับให้แอปของคุณออก แต่ด้วยการสูญเสียข้อมูลที่อาจเกิดขึ้นหรือการเชื่อมต่อเครือข่ายปิดผู้พัฒนาแอปอาจเข้ารหัสได้หากได้รับสัญญาณ นอกจากนี้ยังหมายความว่าคอนเทนเนอร์ของคุณจะใช้เวลา 10 วินาทีในการหยุดเสมอ
โปรดทราบว่าด้วยคำสั่งเชลล์เช่นshift
และset --
คุณสามารถเปลี่ยนค่าของ"$@"
. ตัวอย่างเช่นนี่เป็นส่วนสั้น ๆ ของสคริปต์ที่ลบออก/bin/sh -c "..."
จากคำสั่งที่สามารถปรากฏขึ้นหากคุณใช้ไวยากรณ์เชลล์ของนักเทียบท่าสำหรับCMD
:
# convert `/bin/sh -c "server start"` to `server start`
if [ $# -gt 1 ] && [ x"$1" = x"/bin/sh" ] && [ x"$2" = x"-c" ]; then
shift 2
eval "set -- $1"
fi
....
exec "$@"
test
ซึ่งแสดงว่า-a
ล้าสมัย [ "$#" -gt 1 ] && [ "$1" = /bin/sh ]
เป็นการแทนที่ที่ถูกต้อง (ไม่จำเป็นต้องx"$1"
แฮ็กเกอร์เมื่อใช้เฉพาะไวยากรณ์ที่ไม่ล้าสมัย)
shift 2; set -- $1
ไม่เหมือนกับวิธีการeval
แยกวิเคราะห์สตริง พิจารณา/bin/sh -c 'printf "%s\n" "hello world" "goodbye world"'
ถ้าคุณต้องการกรณีทดสอบคอนกรีตและดูทุบตีไม่คำพูดไม่ได้แจงเมื่อมีการแปลงสตริงอาร์กิวเมนต์
eval
นี้ฉันเชื่อว่าฉันยังคงต้องการให้สิ่งนั้นสะท้อนถึงพฤติกรรมของ/bin/sh -c
สตริง แต่โปรดแจ้งให้เราทราบหากฉันขาดอะไรไป
set -e
- ออกจากสคริปต์หากคำสั่งใด ๆ ล้มเหลว (ค่าที่ไม่ใช่ศูนย์)
exec "$@"
- จะเปลี่ยนเส้นทางตัวแปรอินพุตดูเพิ่มเติมที่นี่
exec
แน่นอนว่ามีโหมดการใช้งานที่กำลังทำการเปลี่ยนเส้นทาง แต่นี่ไม่ใช่โหมดนั้น
set -e
ถือว่าเกิดข้อผิดพลาดได้ง่ายกว่าการจัดการข้อผิดพลาดด้วยมือ (หากรีบร้อนให้ข้ามการเปรียบเทียบที่ด้านบนสำหรับแบบฝึกหัดด้านล่าง)