Nguyên nhân một tập lệnh để thực thi sau khi mạng đã bắt đầu?


102

Tôi còn khá mới với systemd và đang học kiến ​​trúc của nó.

Ngay bây giờ, tôi đang cố gắng tìm ra cách để tạo một kịch bản shell tùy chỉnh để chạy. Kịch bản này cần chạy sau khi lớp mạng đã khởi động.

Tôi đang chạy Arch, sử dụng systemd cũng như netctl.

Để kiểm tra, tôi đã viết một kịch bản đơn giản chỉ cần thực thi ip addr list > /tmp/ip.txt. Tôi đã tạo tập tin dịch vụ sau cho kịch bản này.

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

[Service]
ExecStart=/root/test.script

[Install]
WantedBy=multi-user.target

Sau đó tôi đã kích hoạt tập lệnh với,

systemctl enable test

Khi khởi động lại, tập lệnh thực sự chạy, nhưng nó chạy trước khi mạng được khởi động. Nói cách khác, đầu ra trong ip.txthiển thị không có địa chỉ IPv4 được gán cho giao diện chính. Khi tôi đăng nhập, địa chỉ IPv4 thực sự đã được chỉ định và kết nối mạng.

Tôi đoán rằng tôi có thể thay đổi điểm mà kịch bản chạy bằng cách làm rối WantedBythông số, nhưng tôi không chắc làm thế nào để làm điều đó.

ai đó có thể chỉ cho tôi đi đúng hướng?

Câu trả lời:


126

Trên phụ thuộc cấu hình mạng systemd

Nó rất dễ ảnh hưởng đến đơn đặt hàng của systemd. Mặt khác, bạn cần cẩn thận về những gì một đơn vị hoàn thành đảm bảo.

Định cấu hình dịch vụ của bạn

Trên các hệ thống hiện tại, việc đặt hàng sau khi network.targetchỉ đảm bảo rằng dịch vụ mạng đã được bắt đầu, không phải là một số cấu hình thực tế. Bạn cần phải đặt hàng sau network-online.targetvà kéo nó vào để đạt được điều đó.

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

Để tương thích với các hệ thống cũ hơn, bạn cũng có thể cần phải đặt hàng sau network.target.

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

Đó là cho tập tin đơn vị dịch vụ của bạn và cho systemd.

Triển khai trong các phiên bản hiện tại của phần mềm

Bây giờ bạn cần đảm bảo rằng nó network-online.targethoạt động như mong đợi (hoặc ít nhất là bạn có thể sử dụng network.target).

Phiên bản hiện tại của NetworkManager cung cấp dịch vụ NetworkManager-wait-online.serviceđược kéo vào network-online.targetvà do đó bởi dịch vụ của bạn. Dịch vụ đặc biệt này đảm bảo rằng dịch vụ của bạn sẽ đợi cho đến khi tất cả các kết nối được định cấu hình tự động bắt đầu thành công, không thành công hoặc hết thời gian.

Phiên bản hiện tại của systemd-networkd chặn dịch vụ của bạn cho đến khi tất cả các thiết bị được cấu hình theo yêu cầu. Điều dễ dàng hơn là hiện tại nó chỉ hỗ trợ các cấu hình được áp dụng khi khởi động (cụ thể hơn là thời gian khởi động của `systemd-networkd.service).

Để hoàn thiện, /etc/init.d/networkdịch vụ trong Fedora, như được giải thích bởi các phiên bản hiện tại của systemd, các khối network.targetvà do đó gián tiếp chặn network-online.targetvà dịch vụ của bạn. Đó là một ví dụ về việc thực hiện dựa trên kịch bản.

Nếu việc triển khai của bạn, dù dựa trên daemon hoặc dựa trên tập lệnh, hoạt động như một trong các dịch vụ quản lý mạng ở trên, nó sẽ trì hoãn việc bắt đầu dịch vụ của bạn cho đến khi cấu hình mạng được hoàn thành thành công, vì lý do chính đáng hoặc hết thời gian sau một thời gian hợp lý Khung để hoàn thành.

Bạn có thể muốn kiểm tra xem netctl có hoạt động theo cùng một cách không và thông tin đó sẽ là một bổ sung có giá trị cho câu trả lời này.

Triển khai trong các phiên bản cũ hơn của phần mềm

Tôi không nghĩ rằng bạn sẽ thấy một phiên bản systemd đủ cũ, nơi nó sẽ không hoạt động tốt. Nhưng bạn có thể kiểm tra rằng ít nhất là network-online.targettồn tại và nó sẽ được đặt hàng sau network.target.

NetworkManager trước đây chỉ đảm bảo rằng ít nhất một kết nối sẽ được áp dụng. Và ngay cả để điều đó hoạt động, bạn sẽ phải kích hoạt một NetworkManager-wait-online.servicecách rõ ràng. Điều này đã được cố định từ lâu ở Fedora nhưng chỉ mới được áp dụng gần đây.

systemctl enable NetworkManager-wait-online.service

Ghi chú về việc triển khai network.target và network-online.target

Bạn không cần phải làm cho phần mềm của mình phụ thuộc vào NetworkManager.servicehoặc NetworkManager-wait-online.servicebất kỳ dịch vụ cụ thể nào khác. Thay vào đó, tất cả các dịch vụ quản lý mạng nên tự đặt hàng trước network.targetvà tùy chọn network-online.target.

Một dịch vụ quản lý mạng dựa trên tập lệnh đơn giản sẽ hoàn tất cấu hình mạng trước khi thoát và nên tự đặt hàng trước network.targetvà do đó gián tiếp trước network-online.target.

[Unit]
Before=network.target

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

Một dịch vụ quản lý mạng dựa trên daemon cũng nên tự đặt hàng trước network.targetmặc dù nó không hữu ích lắm.

[Unit]
Before=network.target

[Service]
Type=simple
ExecStart=...

Một dịch vụ chờ daemon kết thúc sẽ tự đặt hàng sau dịch vụ cụ thể và trước đó network-online.target. Nó nên được sử dụng Requisitetrên dịch vụ daemon để nó bị lỗi ngay lập tức nếu dịch vụ quản lý mạng tương ứng không được sử dụng.

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

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

Gói nên cài đặt một liên kết tượng trưng đến dịch vụ chờ trong wantsthư mục network-online.targetđể nó được kéo bởi các dịch vụ muốn chờ mạng được cấu hình.

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

Tài liệu liên quan

Ghi chú cuối cùng

Tôi hy vọng tôi không chỉ giúp trả lời câu hỏi của bạn tại thời điểm bạn hỏi mà còn góp phần cải thiện tình hình trong các bản phân phối ngược dòng và Linux, để bây giờ tôi có thể đưa ra câu trả lời tốt hơn có thể tại thời điểm viết bản gốc .


Bạn có nghĩa là tùy chọn tự động kết nối bằng cách "đợi cho đến khi tất cả các kết nối được cấu hình bắt đầu tự động thành công"? Tôi có thể tận dụng điều này khi tôi đặt no-auto-default = * nhưng tôi có tự động kết nối = có trên một trong các kết nối của mình không? Và câu hỏi cuối cùng - tôi không hiểu - tùy chọn chờ đợi để khởi động của trang trực tuyến và hướng dẫn sử dụng không giúp ích nhiều. Cảm ơn cho bài viết này, đánh giá cao!
lzap

Theo như tôi biết, nm-online không quan tâm no-auto-default, chỉ auto. Bạn có câu hỏi cụ thể nào không? Theo ý kiến ​​của tôi, trang man-online trực tuyến nói rõ rằng với -snó chờ tất cả các kết nối tự động được thử, tức là đã kết nối hoặc thất bại.
Pavel imerda

Sau khi làm hỏng chuyện tào lao này trong một giờ, tôi đã tìm ra giải pháp: apt-get install sysv-init. :-) Hệ thống phức tạp thêm vào như là một thay thế cho một vài tập lệnh shell đang gây chú ý.
Ai đó

@Someone Tôi sợ rằng initscripts không phải là câu trả lời trong trường hợp này. Nếu bạn đang sử dụng Trình quản lý mạng hoặc bất kỳ công cụ cấu hình động nào khác, các bản in không thể tự đặt hàng sau một mạng được định cấu hình đầy đủ. Bạn có thể nhận được một cấu hình động hạn chế bằng cách sử dụng /etc/init.d/networkhoặc tương tự nhưng điều đó không hoạt động phổ biến.
Pavel imerda

@Pavel imerda Ban đầu thực thi ser seri và một tập lệnh init thích hợp sẽ không quay trở lại cho đến khi hoàn thành việc thực hiện những gì các tập lệnh tiếp theo cần dựa vào. Đối với mạng có nghĩa là có tất cả các bộ điều hợp áp dụng và sẵn sàng. Trừ khi đó chỉ là thời điểm may mắn, NM cư xử tốt trong bối cảnh đó. Vấn đề thực sự tất nhiên là NM phát minh lại việc xử lý mạng thay vì xây dựng trên các cấu trúc đơn giản và đã thử và hiện có. Người để bàn dường như không có khái niệm về sự nguy hiểm của sự phức tạp. ;-)
Ai đó

9

Bạn có thể sử dụng Aftertrong [Unit]phần để xác định một dịch vụ nên được bắt đầu trước khi dịch vụ của bạn bắt đầu. Ví dụ: nếu bạn đang sử dụng NetworkManager, bạn có thể bắt đầu dịch vụ của mình sau khi NetworkManager được khởi động.

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

BindsToở đây không thích hợp vì dịch vụ là sự kiện một lần và không phải là dịch vụ liên tục (trừ khi nó cũng bao gồm một ExecStoptính năng để kích hoạt khi mạng ngừng hoạt động).
goldilocks

đã xóaBindsTo
phoops

Tuy nhiên, bạn có thể thêm một cái gì đó để thay thế BindsTo, ví dụ Requires, nếu bạn chỉ muốn dịch vụ chạy nếu NetworkManager thực hiện. Afterkhông thực sự làm điều đó - nó chỉ có nghĩa là nếu NM cũng đang chạy, sau đó chạy nó sau đó. Nếu NM không được chạy, dịch vụ sẽ được chạy ở một điểm tùy ý.
goldilocks

4
After = network.target tốt hơn After = NetworkManager.service vì nó chung chung hơn.
Pavel imerda

7
Lưu ý rằng việc chỉ định After=foosẽ không khiến foothiết bị khởi động nếu nó chưa được khởi động, nó sẽ chỉ cho systemd biết cách đặt hàng các đơn vị nếu cả hai đều khởi động cùng một lúc . Sử dụng cả hai After=foocũng như Wants=foohoặc Requires=foosẽ có tác dụng kéo vào foonếu nó không được khởi động và cũng làm cho systemd sắp xếp các đơn vị một cách chính xác.
Emil Lundberg

8

Nếu dịch vụ của bạn cung cấp một máy chủ, có thể chờ một cách thụ động để ai đó kết nối với nó, hãy sử dụng điều này:

[Unit]
After=network.target

Dịch vụ của bạn sẽ liên kết trên giao diện ký tự đại diện. Nếu nó sử dụng kích hoạt ổ cắm (được khuyến nghị) hoặc nếu chỉ ở chế độ cục bộ, bạn có thể bỏ qua hoàn toàn các mục tiêu mạng.

Nếu dịch vụ của bạn hoạt động như một khách hàng, hoặc ngang hàng, điều này phù hợp hơn:

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

Trước systemd 213 , network-online.target cần giải pháp khắc phục Pavel đã đề cập (bạn cần kích hoạt thủ công một dịch vụ sẽ chờ mạng hoạt động). Kể từ systemd 213, điều này được thực hiện theo mặc định. systemd-networkd-wait-onlinesẽ đợi ít nhất một địa chỉ (có thể định tuyến hoặc liên kết cục bộ) được định cấu hình trên giao diện không vòng lặp.

Cấu hình systemd-networkd, NetworkManager hoặc tương đương là một nhiệm vụ độc lập. DHCP (đối với IPv4) và NDP (đối với IPv6) có xu hướng hoạt động tốt, nhưng bạn nên định cấu hình chúng sao cho định nghĩa chính xác về mạng của bạn là lên mạng là những gì kích hoạt network-online.target.

Tài liệu:


Chỉ tò mò tại sao một câu trả lời mới và không chỉ là những cải tiến nhỏ cho câu trả lời hiện có và (hy vọng) có cấu trúc tốt.
Pavel imerda

Hai liên kết Tài liệu đầu tiên hiện không còn tồn tại.
Peter Hansen

Tại sao sử dụng Yêu cầu thay vì Muốn?
Karl Morrison

4

Tôi đoán rằng tôi có thể thay đổi điểm mà tập lệnh chạy bằng cách làm rối với tham số WantedBy

Điều đó sẽ có tác dụng ngược lại với những gì bạn muốn. Từ man systemd.unit:

WantedBy =, requiredBy =

[...] Một liên kết tượng trưng được tạo trong thư mục .wants / hoặc .requires / của mỗi đơn vị được liệt kê khi đơn vị này được cài đặt bởi systemctl enable. Điều này có tác mà phụ thuộc của loại Muốn = hoặc Yêu cầu = được bổ sung từ các đơn vị niêm yết với đơn vị hiện tại .

Dựa trên điều này, chúng ta có thể thấy tùy chọn đơn vị thích hợp là "Muốn" hoặc "Yêu cầu"; dựa trên mô tả của những điều đó, "Yêu cầu" có thể đúng, với việc thêm "Sau" để đảm bảo không chỉ dịch vụ mạng được chạy mà còn chạy trước đơn vị này.

Không có tùy chọn đơn vị nào, AFAIK, có thể bao gồm quy định rằng một điều kiện bắt đầu phải hoàn thành hoặc đạt đến một điểm nhất định (mạng có thể là dịch vụ daemon), chỉ có điều nó bắt đầu trước. Với suy nghĩ này, bạn có thể muốn tạo tập lệnh của mình Type=forkingvà đưa ra một độ trễ lành mạnh (giả sử là 30 giây) hoặc một loại vòng lặp thoát thành công bao gồm cả độ trễ, để đảm bảo rằng bạn có hợp đồng thuê DHCP trước.


1
Cả WantedBy và requiredBy đều không ảnh hưởng đến việc đặt hàng.
Pavel imerda

1
@ PavelŠimerda: Không ai ở đây tuyên bố họ đã làm. Đặt hàng là lý do tại sao tôi đề cập rõ ràng Afterkết hợp với Requires"để đảm bảo không chỉ dịch vụ mạng được chạy mà còn chạy trước đơn vị này".
goldilocks

1
Vâng, Afterlàm việc cùng Wantshoặc Requirestheo cách đó. Mặt khác, sự chậm trễ rõ ràng là một thói quen xấu trong các công cụ dựa trên phụ thuộc, đặc biệt là khi có một cách rõ ràng để đợi cho đến khi mạng được cấu hình được chỉ định bởi tài liệu systemd, vì vậy tôi phải nhấn mạnh vào downvote.
Pavel imerda

3

Sử dụng Aftertrong [Unit]phần để chỉ định những gì nên được bắt đầu trước dịch vụ của riêng bạn. (Phần lớn câu trả lời trước là đúng.)

Để bắt đầu dịch vụ của bạn sau khi mạng kết thúc, hãy sử dụng mục tiêu mạng, nên áp dụng cho dù bạn sử dụng NetworkManager, hệ thống conf.d / netctl trong Arch hay một số dịch vụ khác mà systemd biết.

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

Một cái nhìn ngắn gọn sẽ xác nhận rằng mọi dịch vụ khác trên hệ thống của bạn dựa trên kết nối mạng đều chứa chỉ thị này.

Nó cũng có thể được chuyển đến bất kỳ phân phối nào sử dụng systemd. Tệp đơn vị của bạn sẽ giống với Arch, Fedora, RHEL 7, các phiên bản tương lai của Debian ...


Các dịch vụ bắt đầu kết nối mạng, chẳng hạn như tập lệnh của Arch hoặc của riêng bạn, nên chỉ định như vậy trong các tệp đơn vị của riêng họ .

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

Tôi không hoàn toàn thích Wantsphần này vì nó có tác dụng phụ trên các gói khác. Hãy nhìn vào câu trả lời của tôi.
Pavel imerda

Chỉ cần nhận ra rằng Wantstrên network.targetlà một ý tưởng tốt ở đây.
Pavel imerda

bạn thực sự muốn sử dụng mạng-online.target. ref
Edward Torvalds

1

Tôi muốn thêm một điểm vào bài viết này. Hiện tại (mùa hè 2015) trong RHEL7 / CentOS 7, network-online.target được đặt không chính xác trước khi kết nối mạng IPv6, vì vậy các trình nền có

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

trong định nghĩa dịch vụ của họ cũng liên kết rõ ràng với các địa chỉ IPv6 có thể sẽ được bắt đầu trước khi IPv6 khởi động và chạy, khiến chúng bị lỗi.


Tôi đoán đây chỉ là trường hợp với cấu hình tự động IPv6 dựa trên kernel mà còn thiếu sót. Nếu bạn muốn đặt hàng đúng cách sau IPv6, bạn chắc chắn nên sử dụng NetworkManager thay vì /etc/init.d/network. Nếu bạn gặp vấn đề tương tự ngay cả với NM, thì đó là một lý do tốt để gửi yêu cầu tính năng. Tôi chưa kiểm tra với RHEL / CentOS, tôi có thể giúp bạn với các chi tiết nếu bạn quan tâm.
Pavel imerda

0
[Unit]
After=systemd-networkd.service

làm việc cho tôi


Không chắc chắn nếu nó hoạt động trong một số trường hợp đặc biệt nhưng nó là sai vì một vài lý do. Một trong số đó là networkdcung cấp dịch vụ riêng / chờ trực tuyến / dịch vụ. Kéo vào và đặt hàng sau network-online.targetlà cách phù hợp với bất kỳ dịch vụ nào hỗ trợ điều đó.
Pavel imerda
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.