Làm thế nào để thiết lập biến môi trường trong dịch vụ systemd?


162

Tôi có một hệ thống Arch Linux với systemd và tôi đã tạo ra dịch vụ của riêng mình. Dịch vụ cấu hình /etc/systemd/system/myservice.servicetrông như thế này:

[Unit]
Description=My Daemon

[Service]
ExecStart=/bin/myforegroundcmd

[Install]
WantedBy=multi-user.target

Bây giờ tôi muốn có một biến môi trường được đặt cho /bin/myforegroundcmd. Làm thế nào để làm điều đó?

Câu trả lời:


197

Thời gian thay đổi và do đó thực hành tốt nhất.

Cách tốt nhất hiện tại để làm điều này là chạy systemctl edit myservice, nó sẽ tạo một tệp ghi đè cho bạn hoặc cho phép bạn chỉnh sửa một tệp hiện có.

Trong các cài đặt thông thường, điều này sẽ tạo ra một thư mục /etc/systemd/system/myservice.service.dvà bên trong thư mục đó tạo một tệp có tên kết thúc bằng .conf(thông thường, override.conf) và trong tệp này, bạn có thể thêm hoặc ghi đè bất kỳ phần nào của đơn vị được phân phối.

Chẳng hạn, trong một tệp /etc/systemd/system/myservice.service.d/myenv.conf:

[Service]
Environment="SECRET=pGNqduRFkB4K9C2vijOmUDa2kPtUhArN"
Environment="ANOTHER_SECRET=JP8YLOc2bsNlrGuD6LVTq7L36obpjzxd"

Cũng lưu ý rằng nếu thư mục tồn tại và trống, dịch vụ của bạn sẽ bị vô hiệu hóa! Nếu bạn không có ý định đặt một cái gì đó vào thư mục, hãy đảm bảo rằng nó không tồn tại.


Để tham khảo, cách cũ là:

Cách được đề xuất để làm điều này là tạo một tệp /etc/sysconfig/myservicechứa các biến của bạn và sau đó tải chúng với EnvironmentFile.

Để biết chi tiết đầy đủ, hãy xem tài liệu của Fedora về cách viết tập lệnh systemd .


4
Tôi đoán sysconfigđường dẫn dành riêng cho Fedora nhưng câu hỏi là về Arch Linux. Câu trả lời của paluh thú vị hơn tôi nghĩ
Ludovic Kuty

1
/etc/sysconfiglà đặc trưng của Fedora. AFAIR Arch Linux đã cố gắng để có các tệp cấu hình ở đâu đó dành riêng cho gói /etchơn là vị trí dành riêng cho Fedora. Giống như /etc/myservice.conf, mặc dù sử dụng tập tin bổ sung dường như không đúng cách ở đây.
Michał Górny

5
Không không không. / etc / sysconfig không được đề xuất. Nó không được khuyến khích, cùng với / etc / default / * từ debian, vì chúng là vô nghĩa, và các tên là vô nghĩa và chỉ có ý nghĩa đối với các lý do tương thích ngược (tất cả / etc là về cấu hình của hệ thống, không chỉ / etc / sysconfig và / etc / mặc định là dành cho ghi đè, không phải mặc định). Chỉ cần đặt các định nghĩa trực tiếp trong tệp đơn vị, hoặc nếu không thể, trong một tệp liệt kê có vị trí cụ thể của gói (như nhận xét của Michał gợi ý).
zbyszek

1
@FrederickNord Nó chỉ là cặp biến = giá trị, chẳng hạn như DJANGO_SETTINGS_MODULE=project.settings, mỗi cặp trên một dòng.
Michael Hampton

1
@MichaelHampton Bạn có thể vui lòng thêm liên kết tài liệu cho "cách tốt nhất hiện tại" không?
jb.

77

Câu trả lời phụ thuộc vào việc biến số được cho là không đổi (nghĩa là không được sửa đổi bởi người dùng lấy đơn vị) hoặc biến (được cho là do người dùng đặt).

Vì là đơn vị địa phương của bạn, ranh giới khá mờ và một trong hai cách sẽ hoạt động. Tuy nhiên, nếu bạn bắt đầu phân phối nó và nó sẽ kết thúc /usr/lib/systemd/system, điều này sẽ trở nên quan trọng.

Giá trị hiện có

Nếu giá trị không cần thay đổi theo từng thể hiện, cách ưa thích sẽ là đặt nó Environment=trực tiếp vào tệp đơn vị:

[Unit]
Description=My Daemon

[Service]
Environment="FOO=bar baz"
ExecStart=/bin/myforegroundcmd

[Install]
WantedBy=multi-user.target

Ưu điểm của điều đó là biến được giữ trong một tệp duy nhất với đơn vị. Do đó, tập tin đơn vị dễ dàng di chuyển giữa các hệ thống.

Giá trị biến

Tuy nhiên, giải pháp trên không hoạt động tốt khi sysadmin được cho là thay đổi giá trị của biến môi trường cục bộ. Cụ thể hơn, giá trị mới sẽ cần được đặt mỗi khi tệp đơn vị được cập nhật.

Trong trường hợp này, một tập tin bổ sung sẽ được sử dụng. Làm thế nào - thường phụ thuộc vào chính sách phân phối.

Một giải pháp đặc biệt thú vị là sử dụng /etc/systemd/system/myservice.service.dthư mục. Không giống như các giải pháp khác, thư mục này được hỗ trợ bởi chính systemd và do đó không có đường dẫn dành riêng cho phân phối.

Trong trường hợp này, bạn đặt một tệp như thế /etc/systemd/system/myservice.service.d/local.confsẽ thêm các phần còn thiếu của tệp đơn vị:

[Service]
Environment="FOO=bar baz"

Sau đó, systemd hợp nhất hai tệp khi bắt đầu dịch vụ (hãy nhớ systemctl daemon-reloadsau khi thay đổi một trong hai tệp). Và vì đường dẫn này được sử dụng trực tiếp bởi systemd, bạn không sử dụng EnvironmentFile=cho đường dẫn này.

Nếu giá trị được cho là chỉ thay đổi trên một số hệ thống bị ảnh hưởng, bạn có thể kết hợp cả hai giải pháp, cung cấp mặc định trực tiếp trong đơn vị và ghi đè cục bộ trong tệp khác.


systemctl daemon-reloadlà lệnh tải lại systemd
Dmitry Buzolin

EnvironmentFile=sẽ tốt hơn khi các giá trị là bí mật như mật khẩu. Xem câu trả lời của tôi để biết chi tiết.
Don Kirkby


17

Các câu trả lời của MichaelMichał rất hữu ích và trả lời câu hỏi ban đầu về cách đặt biến môi trường cho dịch vụ systemd. Tuy nhiên, một cách sử dụng phổ biến cho các biến môi trường là định cấu hình dữ liệu nhạy cảm như mật khẩu ở một nơi không vô tình được cam kết kiểm soát nguồn với mã ứng dụng của bạn.

Nếu đó là lý do tại sao bạn muốn chuyển một biến môi trường cho dịch vụ của mình, không sử dụng Environment=trong tệp cấu hình đơn vị. Sử dụng EnvironmentFile=và trỏ nó đến một tệp cấu hình khác chỉ có thể đọc được bởi tài khoản dịch vụ (và người dùng có quyền truy cập root).

Các chi tiết của tệp cấu hình đơn vị được hiển thị cho bất kỳ người dùng nào bằng lệnh này:

systemctl show my_service

Tôi đặt một tập tin cấu hình /etc/my_service/my_service.confvà đặt bí mật của mình vào đó:

MY_SECRET=correcthorsebatterystaple

Sau đó, trong tập tin đơn vị dịch vụ của tôi, tôi đã sử dụng EnvironmentFile=:

[Unit]
Description=my_service

[Service]
ExecStart=/usr/bin/python /path/to/my_service.py
EnvironmentFile=/etc/my_service/my_service.conf
User=myservice

[Install]
WantedBy=multi-user.target

Tôi đã kiểm tra rằng ps auxekhông thể thấy các biến môi trường đó và những người dùng khác không có quyền truy cập /proc/*/environ. Kiểm tra trên hệ thống của riêng bạn, tất nhiên.


8

Michael đã đưa ra một giải pháp sạch nhưng tôi muốn nhận được biến env được cập nhật từ tập lệnh. Thật không may, thực thi các lệnh bash là không thể trong tệp đơn vị systemd. May mắn thay, bạn có thể kích hoạt bash bên trong ExecStart:

http://www.dsm.fordham.edu/cgi-bin/man-cgi.pl?topic=systemd.service&ect=5

Lưu ý rằng cài đặt này không hỗ trợ trực tiếp các dòng lệnh shell. Nếu các dòng lệnh shell được sử dụng, chúng cần phải được chuyển một cách rõ ràng đến một kiểu triển khai shell nào đó.

Ví dụ trong trường hợp của chúng tôi là:

[Service]
ExecStart=/bin/bash -c "ENV=`script`; /bin/myforegroundcmd"

7
Điều này sẽ không hoạt động vì nhiều lý do (trừ khi đó là dịch vụ "one-shot", khá vô nghĩa). Tôi quản lý để có được những điều sau đây để làm việc : /bin/bash -a -c 'source /etc/sysconfig/whatever && exec whatever-program'. Các -ađảm bảo môi trường được xuất khẩu sang các tiểu trình (trừ khi bạn muốn tiền tố tất cả các biến trong whatevervới export)
Otheus

Tại sao nó không hoạt động? Nó sẽ luôn luôn kích hoạt toàn bộ lệnh bao gồm thực thi tập lệnh, phải không?
dùng1830432

Có lẽ ExecStart=/usr/bin/env ENV=script /bin/myforegroundcmdlà một giải pháp tốt hơn một chút trong trường hợp này.
kstep

@Otheus: Câu trả lời tuyệt vời, được lưu theo ngày khi tôi phải tạo tệp Tomcat 8 Unit.
Daniel

1
Có một cách để thực thi lệnh bash "trong" tệp dịch vụ systemd. Xem liên kết này: coreos.com/os/docs/latest/ Mạnh
Mark Lakata
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.