วิธีเรียกใช้หลายบริการในคอนเทนเนอร์ Docker เดียว
เผยแพร่แล้ว: 2022-06-30Docker เป็นเทคโนโลยีสำหรับส่วนประกอบบรรจุภัณฑ์ของสแต็คของคุณเป็นคอนเทนเนอร์แบบแยกส่วน เป็นเรื่องปกติที่จะรันแต่ละกระบวนการของคุณในคอนเทนเนอร์ของตัวเอง ทำให้เกิดการแบ่งแยกที่ชัดเจนระหว่างส่วนประกอบต่างๆ สิ่งนี้ช่วยปรับปรุงโมดูลาร์และช่วยให้คุณเข้าถึงประโยชน์ของการปรับขยายได้ของคอนเทนเนอร์
ยังคงมีสถานการณ์ที่คุณต้องการเรียกใช้หลายบริการภายในคอนเทนเนอร์เดียว แม้ว่าสิ่งนี้จะไม่เกิดขึ้นตามธรรมชาติในระบบนิเวศของ Docker แต่เราจะแสดงวิธีต่างๆ สองสามวิธีที่คุณสามารถใช้เพื่อสร้างคอนเทนเนอร์ที่มีกระบวนการที่มีอายุการใช้งานยาวนานมากกว่าหนึ่งกระบวนการ
การระบุปัญหา
คอนเทนเนอร์ Docker เรียกใช้กระบวนการพื้นหน้าเดียว สิ่งนี้ถูกกำหนดโดยคำสั่ง ENTRYPOINT
และ CMD
ของรูปภาพ ENTRYPOINT
ถูกตั้งค่าภายใน Dockerfile
ของรูปภาพ ในขณะที่ CMD
สามารถแทนที่ได้เมื่อสร้างคอนเทนเนอร์ คอนเทนเนอร์จะหยุดโดยอัตโนมัติเมื่อออกจากกระบวนการเบื้องหน้า
คุณสามารถเปิดใช้กระบวนการอื่นๆ จาก CMD
ได้ แต่คอนเทนเนอร์จะยังคงทำงานต่อในขณะที่กระบวนการพื้นหน้าเดิมยังมีชีวิตอยู่ การรักษาคอนเทนเนอร์ให้ทำงานตลอดอายุการใช้งานร่วมกันของบริการอิสระสองบริการไม่สามารถทำได้โดยตรงโดยใช้กลไก ENTRYPOINT/CMD
การรวมกระบวนการหลายขั้นตอนไว้ในจุดเข้าใช้งานเดียว
สคริปต์ Wrapper เป็นวิธีแก้ปัญหาที่ง่ายที่สุด คุณสามารถเขียนสคริปต์ที่เริ่มกระบวนการทั้งหมดของคุณและรอให้เสร็จสิ้นได้ การตั้งค่าสคริปต์เป็น Docker ENTRYPOINT
ของคุณจะเรียกใช้เป็นกระบวนการเบื้องหน้าของคอนเทนเนอร์ ทำให้คอนเทนเนอร์ทำงานต่อไปจนกว่าจะมีสคริปต์ที่ห่อหุ้มตัวใดตัวหนึ่งออก
#!/bin/bash /opt/ขั้นแรก & /opt/ขั้นตอนที่สอง & รอ -n ออก $?
สคริปต์นี้เริ่มต้นไบนารี /opt/first-process
และ /opt/second-process
ภายในคอนเทนเนอร์ การใช้ &
อนุญาตให้สคริปต์ดำเนินการต่อโดยไม่ต้องรอให้แต่ละกระบวนการออก wait
ใช้เพื่อระงับสคริปต์จนกว่ากระบวนการใดกระบวนการหนึ่งจะยุติลง สคริปต์จะออกมาพร้อมกับรหัสสถานะที่ออกโดยสคริปต์ที่เสร็จสิ้น
โมเดลนี้ส่งผลให้คอนเทนเนอร์ทำงานทั้ง first-process
ที่หนึ่งและกระบวนการ second-process
จนกระทั่งหนึ่งในนั้นออกจากกระบวนการ เมื่อถึงจุดนั้น คอนเทนเนอร์จะหยุด แม้ว่ากระบวนการอื่นอาจยังทำงานอยู่
หากต้องการใช้สคริปต์นี้ ให้แก้ไข ENTRYPOINT
และ CMD
ของอิมเมจ Docker เพื่อให้เป็นกระบวนการเบื้องหน้าของคอนเทนเนอร์:
ENTRYPOINT ["/bin/sh"] CMD ["./path/to/script.sh"]
ตัวเลือก --init
คอนเทนเนอร์
ความท้าทายประการหนึ่งในการจัดการกระบวนการคอนเทนเนอร์คือการทำความสะอาดอย่างมีประสิทธิภาพขณะออกจากระบบ นักเทียบท่าใช้งาน CMD
ของคุณเป็น ID กระบวนการ 1 ทำให้รับผิดชอบในการจัดการสัญญาณและกำจัดซอมบี้ หากสคริปต์ของคุณไม่มีความสามารถเหล่านี้ คุณอาจจบลงด้วยกระบวนการลูกที่ถูกละเลยยังคงอยู่ในคอนเทนเนอร์ของคุณ
คำสั่ง docker docker run
มีแฟ --init
ที่ปรับเปลี่ยนจุดเข้าใช้งานเพื่อใช้ tini
เป็น PID 1 นี่เป็นกระบวนการเริ่มต้นขั้นต่ำที่รัน CMD
ของคุณ จัดการการส่งต่อสัญญาณ และเก็บเกี่ยวซอมบี้อย่างต่อเนื่อง
การใช้ --init
นั้นคุ้มค่าหากคุณคาดหวังว่าจะเกิดกระบวนการจำนวนมากและไม่ต้องการจัดการการล้างข้อมูลด้วยตนเอง Tini เป็นรส init น้ำหนักเบาที่ออกแบบมาสำหรับภาชนะบรรจุ มันมีขนาดเล็กกว่าทางเลือกที่เต็มเปี่ยมมากเช่น systemd
และ upstart
การใช้ตัวจัดการกระบวนการเฉพาะ
การเขียนสคริปต์แบบแมนนวลนั้นเหมาะสมที่สุดอย่างรวดเร็วเมื่อคุณมีกระบวนการมากมายที่ต้องจัดการ การใช้ตัวจัดการกระบวนการเป็นอีกวิธีหนึ่งในการเรียกใช้บริการต่างๆ ภายในคอนเทนเนอร์ Docker ของคุณ ผู้จัดการกระบวนการจะกลายเป็น ENTRYPOINT
ของคุณและมีหน้าที่รับผิดชอบในการเริ่มต้น บำรุงรักษา และทำความสะอาดหลังจากกระบวนการของผู้ปฏิบัติงานของคุณ
มีหลายทางเลือกเมื่อนำแนวทางนี้ไปใช้ supervisord
เป็นตัวเลือกยอดนิยมซึ่งสามารถกำหนดค่าได้อย่างง่ายดายผ่านไฟล์ /etc/supervisor/conf.d/supervisord.conf
:
[โปรแกรม:อาปาเช่2] command=/usr/sbin/apache2 -DFOREGROUND [โปรแกรม:mysqld] command=/usr/sbin/mysqld_safe
ไฟล์กำหนดค่านี้กำหนดค่า supervisord
เพื่อเริ่ม Apache และ MySQL หากต้องการใช้ในคอนเทนเนอร์ Docker ให้เพิ่มแพ็คเกจที่จำเป็นทั้งหมดลงในอิมเมจของคุณ จากนั้นคัดลอกไฟล์ config supervisord
ของคุณไปยังตำแหน่งที่ถูกต้อง ตั้งค่า supervisord
เป็น CMD
ของอิมเมจเพื่อเรียกใช้โดยอัตโนมัติเมื่อคอนเทนเนอร์เริ่มทำงาน
จากอูบุนตู:ล่าสุด เรียกใช้ apt-get install -y apache2 mysql-server Supervisor COPY Supervisord.conf /etc/supervisor/conf.d/supervisord.conf ENTRYPOINT ["/bin/sh"] CMD ["/usr/bin/supervisord"]
เนื่องจาก supervisord
ทำงานอย่างต่อเนื่อง จึงเป็นไปไม่ได้ที่จะหยุดคอนเทนเนอร์เมื่อกระบวนการตรวจสอบของคุณออกจากกระบวนการ ตัวเลือกอื่นคือ s6-overlay
ซึ่งมีความสามารถนี้ มันใช้โมเดลบริการประกาศที่คุณวางสคริปต์บริการโดยตรงใน /etc/services.d
:
# เพิ่ม s6-overlay ให้กับรูปภาพของคุณ เพิ่ม https://github.com/just-containers/s6-overlay/releases/download/v3.1.0.0/s6-overlay-noarch.tar.xz /tmp รัน tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz เรียกใช้ printf "#!/bin/shn/usr/sbin/apache2 -DFOREGROUND" > /etc/services.d/first-service/run เรียกใช้ chmod +x /etc/services.d/first-service/run # ใช้ s6-overlay เป็นจุดเริ่มต้นสำหรับรูปภาพของคุณ ENTRYPOINT ["/init"]
คุณสามารถเพิ่มสคริปต์ finish
ที่เรียกใช้งานได้ภายในไดเร็กทอรีบริการของคุณเพื่อจัดการกับการหยุดคอนเทนเนอร์ด้วย docker stop
s6-overlay
จะเรียกใช้สคริปต์เหล่านี้โดยอัตโนมัติเมื่อกระบวนการได้รับสัญญาณ TERM
เนื่องจากคำสั่ง stop
สคริปต์ที่เสร็จสิ้นจะได้รับรหัสออกจากบริการเป็นอาร์กิวเมนต์แรก รหัสถูกตั้งค่าเป็น 256 เมื่อบริการถูกฆ่าเนื่องจากสัญญาณที่ไม่ถูกตรวจจับ สคริปต์จำเป็นต้องเขียนโค้ดทางออกสุดท้ายไปที่ /run/s6-linux-init-container-results/exitcode
; s6-overlay จะอ่านไฟล์นี้และออกพร้อมกับค่าภายใน ทำให้โค้ดนั้นถูกใช้เป็นโค้ดหยุดของคอนเทนเนอร์ของคุณ
#!/bin/sh echo "$1" > /run/s6-linux-init-container-results/exitcode
เมื่อใดที่คุณควรเรียกใช้หลายกระบวนการในคอนเทนเนอร์
เทคนิคนี้ใช้ดีที่สุดกับกระบวนการที่เชื่อมต่อกันอย่างแน่นหนา ซึ่งคุณไม่สามารถแยกให้ทำงานเป็นคอนเทนเนอร์อิสระได้ คุณอาจมีโปรแกรมที่อาศัยยูทิลิตีผู้ช่วยเบื้องหลังหรือแอปพลิเคชันแบบเสาหินที่ดำเนินการจัดการแต่ละกระบวนการของตนเอง เทคนิคที่แสดงด้านบนสามารถช่วยให้คุณจัดเก็บซอฟต์แวร์ประเภทนี้ได้
ควรหลีกเลี่ยงการเรียกใช้หลายกระบวนการในคอนเทนเนอร์ในทุกที่ที่ทำได้ การยึดติดกับกระบวนการเบื้องหน้าเพียงขั้นตอนเดียวจะช่วยเพิ่มการแยกสาร ป้องกันส่วนประกอบที่รบกวนกันและกัน และปรับปรุงความสามารถในการดีบักและทดสอบชิ้นส่วนเฉพาะ คุณสามารถปรับขนาดส่วนประกอบทีละรายการโดยใช้คอนเทนเนอร์ออร์เคสตรา ทำให้คุณมีความยืดหยุ่นในการเรียกใช้อินสแตนซ์ของกระบวนการที่ใช้ทรัพยากรมากที่สุดของคุณมากขึ้น
บทสรุป
คอนเทนเนอร์มักจะมีขั้นตอนเดียวและทำงานตราบเท่าที่ยังมีชีวิตอยู่ โมเดลนี้สอดคล้องกับแนวทางปฏิบัติที่ดีที่สุดสำหรับคอนเทนเนอร์และช่วยให้คุณได้รับประโยชน์สูงสุดจากเทคโนโลยี
ในบางสถานการณ์ คุณอาจต้องใช้หลายกระบวนการในการรันในคอนเทนเนอร์ เนื่องจากรูปภาพทั้งหมดมีจุดเข้าใช้งานเดียวในท้ายที่สุด คุณต้องเขียนสคริปต์ตัวตัดทอนหรือเพิ่มตัวจัดการกระบวนการที่รับผิดชอบในการเริ่มต้นไบนารีเป้าหมายของคุณ
ตัวจัดการกระบวนการให้ทุกสิ่งที่คุณต้องการ แต่ขยายภาพของคุณด้วยแพ็คเกจและการกำหนดค่าเพิ่มเติม สคริปต์ Wrapper นั้นง่ายกว่า แต่อาจต้องจับคู่กับแฟ --init
ของ Docker เพื่อป้องกันการแพร่กระจายของกระบวนการซอมบี้