ทำให้สคริปต์ทำงานหลังจากเริ่มระบบเครือข่ายหรือไม่


102

ฉันค่อนข้างใหม่กับ systemd และฉันกำลังเรียนรู้สถาปัตยกรรมของมัน

ตอนนี้ฉันกำลังพยายามหาวิธีที่จะทำให้เชลล์สคริปต์ที่กำหนดเองทำงาน สคริปต์นี้ต้องเรียกใช้หลังจากเลเยอร์เครือข่ายเริ่มต้นขึ้น

ฉันใช้งาน Arch โดยใช้ systemd เช่นเดียวกับ netctl

ip addr list > /tmp/ip.txtในการทดสอบผมเขียนสคริปต์ง่ายที่เพียงรัน ฉันสร้างไฟล์บริการต่อไปนี้สำหรับสคริปต์นี้

(/etc/systemd/system/test.service)
[Unit]
Description=test service

[Service]
ExecStart=/root/test.script

[Install]
WantedBy=multi-user.target

ฉันเปิดใช้งานสคริปต์ด้วย

systemctl enable test

เมื่อรีสตาร์ทสคริปต์จะทำงานจริง ๆ แต่จะทำงานก่อนที่เครือข่ายจะเริ่มต้น กล่าวอีกนัยหนึ่งเอาต์พุตในip.txtไม่แสดงที่อยู่ IPv4 ที่กำหนดให้กับอินเทอร์เฟซหลัก ตามเวลาที่ฉันเข้าสู่ระบบที่อยู่ IPv4 ได้รับการกำหนดแน่นอนและการเชื่อมต่อเครือข่ายขึ้น

ฉันคาดเดาว่าฉันสามารถแก้ไขจุดที่สคริปต์ทำงานโดยไปยุ่งกับWantedByพารามิเตอร์ แต่ฉันไม่แน่ใจว่าจะทำอย่างไร

ใครช่วยชี้ฉันในทิศทางที่ถูกต้องได้ไหม

คำตอบ:


126

ในการพึ่งพาการกำหนดค่าเครือข่าย systemd

มันง่ายมากที่จะส่งผลกระทบต่อการสั่งซื้อหน่วยของ systemd ในอีกทางหนึ่งคุณต้องระวังเกี่ยวกับสิ่งที่รับประกันว่าจะเสร็จสมบูรณ์

กำหนดค่าบริการของคุณ

ในระบบปัจจุบันการสั่งซื้อหลังจากnetwork.targetเพิ่งรับประกันได้ว่าบริการเครือข่ายได้เริ่มขึ้นแล้วไม่ใช่ว่ามีการกำหนดค่าจริงบางอย่าง คุณต้องสั่งซื้อหลังจากนั้นnetwork-online.targetและดึงมันเข้าไปเพื่อให้บรรลุ

[Unit]
Wants=network-online.target
After=network-online.target

เพื่อความเข้ากันได้กับระบบเก่าคุณอาจต้องสั่งซื้อหลังจาก network.target เช่นกัน

[Unit]
Wants=network-online.target
After=network.target network-online.target

นั่นคือไฟล์หน่วยบริการของคุณและสำหรับ systemd

การติดตั้งซอฟต์แวร์เวอร์ชันปัจจุบัน

ตอนนี้คุณต้องแน่ใจว่าใช้network-online.targetงานได้ตามที่คาดไว้ (หรืออย่างน้อยคุณก็สามารถใช้งานได้network.target)

NetworkManagerเวอร์ชันปัจจุบันเสนอสิ่งNetworkManager-wait-online.serviceที่ถูกดึงเข้ามาnetwork-online.targetด้วยบริการของคุณ บริการพิเศษนี้ช่วยให้มั่นใจว่าบริการของคุณจะรอจนกว่าการเชื่อมต่อทั้งหมดที่กำหนดค่าให้เริ่มต้นจะสำเร็จโดยอัตโนมัติล้มเหลวหรือหมดเวลา

เวอร์ชันปัจจุบันของsystemd-networkdบล็อกบริการของคุณจนกว่าอุปกรณ์ทั้งหมดจะได้รับการกำหนดค่าตามที่ร้องขอ มันง่ายกว่าที่จะรองรับการกำหนดค่าที่ใช้ในเวลาบูตเท่านั้น (โดยเฉพาะเวลาเริ่มต้นของ `systemd-networkd.service)

เพื่อความสมบูรณ์/etc/init.d/networkบริการใน Fedora ที่ตีความโดย systemd รุ่นปัจจุบันบล็อกnetwork.targetและบล็อกทางอ้อมnetwork-online.targetและบริการของคุณ นี่เป็นตัวอย่างของการใช้งานสคริปต์

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

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

การใช้งานในซอฟต์แวร์รุ่นเก่า

ฉันไม่คิดว่าคุณจะเห็น systemd เวอร์ชันเก่าพอที่จะทำงานได้ไม่ดี แต่คุณสามารถตรวจสอบว่าอย่างน้อยnetwork-online.targetมีอยู่และได้รับคำสั่งหลังจากnetwork.targetนั้น

ก่อนหน้าNetworkManagerรับประกันได้ว่าจะมีการเชื่อมต่ออย่างน้อยหนึ่งการเชื่อมต่อ และแม้กระทั่งการทำงานคุณก็ต้องเปิดใช้งานNetworkManager-wait-online.serviceอย่างชัดเจน สิ่งนี้ได้รับการแก้ไขใน Fedora มานาน แต่เพิ่งจะใช้กับต้นน้ำ

systemctl enable NetworkManager-wait-online.service

หมายเหตุเกี่ยวกับการใช้งาน network.target และ network-online.target

คุณไม่จำเป็นต้องทำให้ซอฟต์แวร์ของคุณขึ้นอยู่กับNetworkManager.serviceหรือNetworkManager-wait-online.serviceไม่หรือบริการเฉพาะอื่น ๆ แต่ทุกบริการจัดการเครือข่ายควรสั่งตัวเองก่อนและเลือกnetwork.targetnetwork-online.target

บริการจัดการเครือข่ายตามสคริปต์ง่ายควรจะเสร็จสิ้นการกำหนดค่าเครือข่ายก่อนที่จะออกและควรสั่งตัวเองก่อนและทำให้ทางอ้อมก่อนnetwork.targetnetwork-online.target

[Unit]
Before=network.target

[Service]
Type=oneshot
ExecStart=...
RemainAfterExit=yes

บริการการจัดการเครือข่ายบน daemon ควรสั่งซื้อเองก่อนnetwork.targetแม้ว่าจะไม่มีประโยชน์มาก

[Unit]
Before=network.target

[Service]
Type=simple
ExecStart=...

บริการที่รอให้ daemon เสร็จสิ้นควรสั่งตัวเองหลังจากบริการที่เฉพาะเจาะจงและก่อนหน้าnetwork-online.targetนี้ ควรใช้Requisiteกับบริการ daemon เพื่อให้ล้มเหลวทันทีหากไม่ได้ใช้บริการการจัดการเครือข่ายที่เกี่ยวข้อง

[Unit]
Requisite=...
After=...
Before=network-online.target

[Service]
Type=oneshot
ExecStart=...
RemainAfterExit=yes

แพคเกจควรติดตั้ง symlink ไปยังบริการที่รอในwantsไดเรกทอรีnetwork-online.targetเพื่อที่จะได้รับการดึงโดยบริการที่ต้องการรอเครือข่ายที่กำหนดค่า

ln -s /usr/lib/systemd/system/... /usr/lib/systemd/system/network-online.target.wants/

เอกสารที่เกี่ยวข้อง

บันทึกสุดท้าย

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


คุณหมายถึงตัวเลือกการเชื่อมต่ออัตโนมัติโดย "รอจนกระทั่งการเชื่อมต่อทั้งหมดที่กำหนดค่าให้เริ่มต้นโดยอัตโนมัติสำเร็จ" ฉันสามารถใช้ประโยชน์จากสิ่งนี้เมื่อฉันตั้ง no-auto-default = * แต่ฉันมี autoconnect = ใช่ในหนึ่งในการเชื่อมต่อของฉัน? และคำถามสุดท้าย - ฉันไม่เข้าใจ - ตัวเลือกการรอสำหรับการเริ่มต้นของ nm-online และหน้าคู่มือไม่ได้ช่วยอะไรมาก ขอบคุณสำหรับการเขียนนี้ชื่นชมอย่างมาก!
lzap

เท่าที่ผมรู้ว่านาโนเมตรออนไลน์ไม่ได้เกี่ยวกับการดูแลเท่านั้นno-auto-default autoคุณมีคำถามเฉพาะหรือไม่? ในความคิดของฉัน nm- ออนไลน์ manpage ระบุอย่างชัดเจนว่า-sมันรอการเชื่อมต่ออัตโนมัติทั้งหมดที่จะพยายามคือการเชื่อมต่อหรือล้มเหลว
Pavel Šimerda

หลังจาก messing กับอึนี้เป็นเวลาหนึ่งชั่วโมงฉันพบวิธีแก้ปัญหา: apt-get install sysv-init :-) ความซับซ้อนของ systemd เพิ่มเข้ามาแทนที่เชลล์สคริปไม่กี่อันก็เป็นสิ่งที่เหลือเชื่อ
ใครบางคน

@ ใครบางคนฉันกลัวว่าข้อความอ้างอิงไม่ใช่คำตอบในกรณีนี้ หากคุณกำลังใช้ NetworkManager หรือเครื่องมือกำหนดค่าแบบไดนามิกอื่น ๆ initscripts ไม่สามารถสั่งซื้อด้วยตนเองหลังจากเครือข่ายที่กำหนดค่าไว้อย่างสมบูรณ์ คุณสามารถได้รับการกำหนดค่าแบบไดนามิกที่ จำกัด โดยใช้/etc/init.d/networkหรือคล้ายกัน แต่ไม่ได้ทำงานในระดับสากล
Pavel Šimerda

@Pavel Šimerda Init ดำเนินการตามลำดับและสคริปต์ init ที่เหมาะสมจะไม่ส่งคืนจนกว่าจะเสร็จสิ้นการทำสิ่งที่สคริปต์ต่อไปที่จำเป็นต้องพึ่งพา สำหรับเครือข่ายที่หมายถึงการมีอะแดปเตอร์ที่ใช้ได้ทั้งหมดและพร้อมใช้งาน เว้นแต่จะเป็นเพียงช่วงเวลาที่โชคดี NM จะทำงานได้ดีในบริบทนั้น ปัญหาที่แท้จริงของหลักสูตรคือ NM บูรณาการการจัดการเครือข่ายแทนการสร้างโครงสร้างที่เรียบง่ายและมีอยู่แล้วและทดสอบแล้ว ผู้ใช้เดสก์ท็อปดูเหมือนจะไม่มีแนวคิดเรื่องอันตรายของความซับซ้อน ;-)
คน

9

คุณสามารถใช้Afterใน[Unit]ส่วนเพื่อกำหนดบริการที่ควรเริ่มต้นก่อนที่บริการของคุณจะเริ่ม ตัวอย่างเช่นถ้าคุณใช้ NetworkManager คุณสามารถทำให้บริการของคุณเริ่มต้นได้หลังจากที่ NetworkManager เริ่มทำงาน

[Unit]
Description=test service
After=NetworkManager.service

BindsToไม่เหมาะสมเพื่อให้ที่นี่ตั้งแต่บริการเป็นเหตุการณ์หนึ่งออกและไม่ได้เป็นบริการถาวร (ยกเว้นว่าจะยังมีExecStopคุณสมบัติที่จะยิงเมื่อเครือข่ายลงไป)
goldilocks

ลบออกBindsTo
phoops

คุณสามารถเพิ่มสิ่งที่ต้องการแทนที่BindsToเช่นRequiresหากคุณต้องการให้บริการทำงานหาก NetworkManager ทำ Afterไม่ได้ทำอย่างนั้นจริง - มันหมายถึงว่าหาก NM ยังทำงานอยู่ดังนั้นให้เรียกใช้งานในภายหลัง หาก NM ไม่ได้ถูกเรียกใช้บริการจะทำงานที่จุดใดก็ได้
goldilocks

4
After = network.target ดีกว่า After = NetworkManager.service เนื่องจากเป็นแบบทั่วไปมากขึ้น
Pavel Šimerda

7
ขอให้สังเกตที่ระบุว่าAfter=fooจะไม่ก่อให้เกิดfooหน่วยที่จะเริ่มต้นหากยังไม่ได้เริ่มต้นแล้วก็จะเพียงบอก systemd วิธีการสั่งซื้อหน่วยถ้าพวกเขาทั้งสองเริ่มต้นในเวลาเดียวกัน การใช้ทั้งสองAfter=fooอย่างWants=fooหรือRequires=fooจะมีผลในการดึงfooถ้ามันไม่ได้เริ่มและทำให้ systemd สั่งซื้อหน่วยอย่างถูกต้อง
Emil Lundberg

8

หากบริการของคุณมีเซิร์ฟเวอร์ซึ่งสามารถรอให้ใครบางคนเชื่อมต่อกับเซิร์ฟเวอร์ได้ให้ใช้สิ่งนี้:

[Unit]
After=network.target

บริการของคุณควรเชื่อมโยงกับส่วนต่อประสานสัญลักษณ์แทน หากใช้การเปิดใช้งานซ็อกเก็ต (แนะนำ) หรือหากเป็นแบบโลคัลเท่านั้นคุณสามารถละเว้นเป้าหมายเครือข่ายทั้งหมดได้

หากบริการของคุณทำหน้าที่เป็นลูกค้าหรือเป็นแบบเพื่อนต่อเพื่อนสิ่งนี้จะเหมาะสมกว่า:

[Unit]
After=network-online.target
Requires=network-online.target

ก่อนที่จะsystemd 213 , network-online.target ต้องการวิธีแก้ปัญหาที่กล่าวถึง Pavel (คุณต้องเปิดใช้งานบริการด้วยตนเองที่จะรอให้เครือข่ายทำงาน) ในฐานะที่เป็นของ systemd 213 นี้จะทำตามค่าเริ่มต้น systemd-networkd-wait-onlineจะรออย่างน้อยหนึ่งที่อยู่ (สามารถกำหนดเส้นทางได้หรือ link-local) เพื่อกำหนดค่าบนอินเทอร์เฟซที่ไม่วนซ้ำ

การกำหนดค่า systemd-networkd, NetworkManager หรือเทียบเท่าเป็นงานอิสระ DHCP (สำหรับ IPv4) และ NDP (สำหรับ IPv6) มีแนวโน้มที่จะทำงานออกจากกล่อง แต่คุณควรกำหนดค่าพวกเขาเพื่อให้คำนิยามที่แม่นยำของคุณของ“เครือข่าย” network-online.targetเป็นสิ่งที่ทริกเกอร์

เอกสารอ้างอิง:


แค่อยากรู้ว่าทำไมคำตอบใหม่และไม่ใช่แค่การปรับปรุงเพียงเล็กน้อยกับคำตอบที่มีอยู่และหวังว่าจะได้คำตอบที่มีโครงสร้าง
Pavel Šimerda

ลิงก์เอกสารสองลิงก์แรกหมดอายุในขณะนี้
Peter Hansen

ทำไมต้องใช้แทนต้องการ?
Karl Morrison

4

ฉันคาดเดาว่าฉันสามารถแก้ไขจุดที่สคริปต์ทำงานโดยไปยุ่งกับพารามิเตอร์ WantedBy

นั่นจะมีผลตรงกันข้ามกับสิ่งที่คุณต้องการ จากman systemd.unit:

WantedBy =, RequiredBy =

[... ] ลิงก์สัญลักษณ์ถูกสร้างขึ้นใน. .wants / or .requires / directory ของแต่ละหน่วยที่แสดงรายการไว้เมื่อติดตั้งหน่วยนี้โดย systemctl เปิดใช้งาน นี้มีผลกระทบที่เป็นเมืองขึ้นของประเภทต้องการ = = หรือต้องมีการเพิ่มจากหน่วยจดทะเบียนกับหน่วยปัจจุบัน

จากนี้เราสามารถเห็นตัวเลือกหน่วยที่เหมาะสมคือ "ต้องการ" หรือ "ต้องการ"; ขึ้นอยู่กับคำอธิบายของผู้ที่ "ต้อง" อาจถูกต้องด้วยการเพิ่ม "หลังจาก" เพื่อให้แน่ใจว่าไม่เพียง แต่บริการเครือข่ายที่จะทำงาน แต่มันจะทำงานก่อนที่หน่วยนี้

ไม่มีตัวเลือกหน่วยใด AFAIK สามารถรวมข้อกำหนดที่ต้องเริ่มต้นต้องเสร็จสมบูรณ์หรือถึงจุดที่แน่นอน (เครือข่ายอาจเป็นบริการ daemon) เฉพาะที่เริ่มต้นก่อน เมื่อคำนึงถึงสิ่งนี้คุณอาจต้องการสร้างสคริปต์ของคุณType=forkingและทำให้เกิดการหน่วงเวลาที่ดีต่อสุขภาพ (กล่าวคือ 30 วินาที) หรือวนลูปออกจากความสำเร็จรวมถึงการหน่วงเวลาเพื่อให้แน่ใจว่าคุณมีสัญญาเช่า DHCP ก่อน


1
ทั้ง WantedBy และ RequiredBy ส่งผลกระทบต่อการสั่งซื้อ
Pavel Šimerda

1
@ PavelŠimerda: ไม่มีใครที่นี่อ้างว่าพวกเขาทำ การสั่งซื้อคือสาเหตุที่ฉันพูดถึงอย่างชัดเจนAfterพร้อมกับRequires"เพื่อให้แน่ใจว่าไม่เพียง แต่บริการเครือข่ายเท่านั้นที่จะทำงานได้ แต่มันจะทำงานก่อนหน่วยโฆษณานี้"
goldilocks

1
ใช่Afterทำงานร่วมกับWantsหรือRequiresด้วยวิธีนั้น ในทางกลับกันความล่าช้าอย่างชัดเจนเป็นนิสัยที่ไม่ดีในเครื่องมือตามการพึ่งพาโดยเฉพาะอย่างยิ่งเมื่อมีวิธีที่ชัดเจนที่จะรอจนกว่าเครือข่ายมีการกำหนดค่าที่ระบุไว้ในเอกสาร systemd ดังนั้นฉันต้องยืนยันใน downvote
Pavel Šimerda

3

ใช้Afterใน[Unit]ส่วนเพื่อระบุสิ่งที่ควรเริ่มก่อนบริการของคุณเอง (คำตอบก่อนหน้านี้ส่วนใหญ่ถูกต้องแล้ว)

ในการเริ่มบริการของคุณหลังจากที่เครือข่ายหมดให้ใช้เป้าหมายเครือข่ายซึ่งควรนำไปใช้ไม่ว่าคุณจะใช้ NetworkManager, ระบบ conf.d / netctl ใน Arch หรือบริการอื่น ๆ ที่ systemd รับรู้อยู่

[Unit]
#.....
After=network.target

ดูสั้น ๆ จะยืนยันว่าทุกบริการอื่น ๆในระบบของคุณที่อาศัยการเชื่อมต่อเครือข่ายมีคำสั่งนี้

นอกจากนี้ยังสามารถพกพาไปยังการกระจายใด ๆ ที่ใช้ systemd ไฟล์หน่วยของคุณจะเหมือนกันสำหรับ Arch, Fedora, RHEL 7, Debian รุ่นอนาคต ...


บริการที่เริ่มการเชื่อมต่อเครือข่ายเช่นสคริปต์ของ Arch หรือของคุณเองควรระบุไว้ในไฟล์หน่วยของตนเอง

[Unit]
Wants=network.target
Before=network.target

ฉันไม่ชอบชิ้นWantsส่วนทั้งหมดเพราะมันมีผลข้างเคียงกับแพ็คเกจอื่น ๆ ดูคำตอบของฉันได้ไหม
Pavel Šimerda

เพิ่งรู้ว่าWantsบนnetwork.targetเป็นความคิดที่ดีที่นี่
Pavel Šimerda

คุณต้องการใช้ network-online.target จริงๆ ref
Edward Torvalds

1

ฉันต้องการเพิ่มจุดในบทความนี้ ปัจจุบัน (ฤดูร้อนปี 2015) ใน RHEL7 / CentOS 7, network-online.target ถูกตั้งค่าอย่างไม่ถูกต้องก่อนที่เครือข่าย IPv6 จะอัพดังนั้น daemons ที่มี

Wants=network-online.target
After=network-online.target

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


ฉันเดาว่านี่เป็นกรณีที่มีเฉพาะการกำหนดค่าอัตโนมัติตาม IPv6 เคอร์เนลซึ่งมีข้อบกพร่องอยู่แล้ว หากคุณต้องการที่จะต้องสั่งซื้อหลังจาก IPv6 คุณแน่นอนควรใช้ NetworkManager /etc/init.d/networkแทน หากคุณได้รับปัญหาเดียวกันแม้กับ NM ก็เป็นเหตุผลที่ดีที่จะยื่นคำขอคุณลักษณะ ฉันไม่ได้ตรวจสอบกับ RHEL / CentOS ฉันสามารถช่วยคุณในรายละเอียดหากคุณสนใจ
Pavel Šimerda

0
[Unit]
After=systemd-networkd.service

ทำงานได้สำหรับฉัน


ไม่แน่ใจว่ามันใช้งานได้ในบางกรณี แต่มันผิดด้วยเหตุผลสองประการ หนึ่งในนั้นคือการnetworkdให้ / รอออนไลน์ / บริการของตัวเอง การดึงและสั่งซื้อหลังจากนั้นnetwork-online.targetเป็นวิธีที่เหมาะสมในการไปกับบริการใด ๆ ที่สนับสนุนสิ่งนั้น
Pavel Šimerda
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.