Як встановити змінну середовища в системній службі?


162

У мене система Arch Linux з systemd і я створив власну службу. Служба налаштування /etc/systemd/system/myservice.serviceвиглядає приблизно так:

[Unit]
Description=My Daemon

[Service]
ExecStart=/bin/myforegroundcmd

[Install]
WantedBy=multi-user.target

Тепер я хочу встановити змінну середовища для /bin/myforegroundcmd. Як це зробити?

Відповіді:


197

Часи змінюються, і тому найкраща практика.

Тока кращий спосіб зробити це , щоб бігти systemctl edit myservice, який створить файл перевизначення для вас або дозволяють редагувати існуючий.

У звичайних установках це створить каталог /etc/systemd/system/myservice.service.d, а всередині цього каталогу створіть файл, ім'я якого закінчується .conf(як правило, override.conf), і в цьому файлі ви можете додати або замінити будь-яку частину одиниці, що постачається дистрибутивом.

Наприклад, у файлі /etc/systemd/system/myservice.service.d/myenv.conf:

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

Також зауважте, що якщо каталог існує і порожній, ваша послуга буде відключена! Якщо ви не збираєтесь щось класти в каталог, переконайтесь, що воно не існує.


Для довідки, старий спосіб:

Рекомендований спосіб зробити це - створити файл, /etc/sysconfig/myserviceякий містить ваші змінні, а потім завантажити їх EnvironmentFile.

Повні відомості див. У документації Fedora про те, як написати системний сценарій .


4
Я думаю, що sysconfigшлях специфічний для Fedora, але питання стосується Arch Linux. Відповідь paluh цікавіше, я думаю
Людовик Куті

1
/etc/sysconfigє специфічним для Fedora. AFAIR Arch Linux наполягав на тому, щоб конфігураційні файли були десь специфічними для пакета, а не в певному для /etcFedora місці. Начебто /etc/myservice.conf, хоча використання додаткового файлу тут не здається правильним.
Michał Górny

5
Ні-ні-ні. / etc / sysconfig не рекомендується. Він відсторонений, а також / etc / default / * від debian, тому що вони безглузді, а назви безглузді і мають сенс лише з міркувань зворотної сумісності (усе / etc стосується конфігурації системи, а не тільки / etc / sysconfig та / etc / defaults - це заміщення, а не за замовчуванням). Просто помістіть визначення безпосередньо у файл файлу, або якщо це неможливо, у файл оточення, який має певне місце для пакета (як це говорить коментар Міхала).
zbyszek

1
@FrederickNord Це просто змінна = пара значень, наприклад DJANGO_SETTINGS_MODULE=project.settings, одна на рядок.
Майкл Хемптон

1
@MichaelHampton Не могли б ви додати посилання на документацію для "найкращого поточного поточного способу"?
jb.

77

Відповідь залежить від того, чи повинна змінна бути постійною (тобто не повинна змінюватися користувачем, що отримує одиницю) або змінною (повинна бути встановлена ​​користувачем).

Оскільки це ваша локальна одиниця, межа досить розмита, і в будь-якому випадку вона може працювати. Однак якщо ви почали його розповсюджувати, і він закінчився би /usr/lib/systemd/system, це стане важливим.

Постійне значення

Якщо значення не потрібно змінювати на екземпляр, кращим способом було б розмістити його як Environment=безпосередньо у файлі одиниці:

[Unit]
Description=My Daemon

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

[Install]
WantedBy=multi-user.target

Перевагою цього є те, що змінна зберігається в одному файлі з одиницею. Тому файл одиниці легше переміщувати між системами.

Змінне значення

Однак вищевказане рішення не працює добре, коли sysadmin повинен змінити значення змінної середовища локально. Більш конкретно, нове значення потрібно встановлювати щоразу, коли одиничний файл оновлюється.

У цьому випадку слід використовувати додатковий файл. Як - зазвичай залежить від політики розподілу.

Одним з особливо цікавих рішень є використання /etc/systemd/system/myservice.service.dкаталогу. На відміну від інших рішень, цей каталог підтримується самим systemd і тому не має конкретних шляхів розподілу.

У цьому випадку ви розміщуєте такий файл, /etc/systemd/system/myservice.service.d/local.confякий додає відсутні частини файлу одиниці:

[Service]
Environment="FOO=bar baz"

Після цього systemd об'єднує два файли під час запуску послуги (пам’ятайте, що systemctl daemon-reloadпісля зміни будь-якого з них). А оскільки цей шлях використовується безпосередньо systemd, ви не використовуєте EnvironmentFile=для цього.

Якщо значення, як передбачається, буде змінено лише для деяких систем, на які постраждали, ви можете комбінувати обидва рішення, надаючи за замовчуванням безпосередньо в блоці та локальне переопределення в іншому файлі.


systemctl daemon-reloadкоманда перезавантажити systemd
Дмитро Бузолін

EnvironmentFile=краще, коли значення є секретами, як паролі. Детальну інформацію див. У моїй відповіді .
Дон Кіркбі


17

Відповіді Майкла та Міхала є корисними та відповідають на оригінальне запитання про те, як встановити змінну середовища для системної служби. Однак одне поширене використання змінних оточуючих середовищ - це налаштування конфіденційних даних, таких як паролі, у місці, яке випадково не буде зобов’язане керувати джерелом з кодом програми.

Якщо ви хочете передати змінну середовища у вашу службу, не використовуйте Environment=у файлі конфігурації пристрою. Використовуйте EnvironmentFile=та вкажіть його на інший файл конфігурації, який читається лише обліковим записом служби (та користувачам із кореневим доступом).

Деталі файлу конфігурації пристрою можуть бути видимі будь-якому користувачеві з цією командою:

systemctl show my_service

Я поміщаю файл конфігурації /etc/my_service/my_service.confі вкладаю свої секрети:

MY_SECRET=correcthorsebatterystaple

Потім у файлі сервісного блоку я використав 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

Я перевірив, що ps auxeне можуть бачити ці змінні середовища, і інші користувачі не мають доступу до них /proc/*/environ. Перевірте, звичайно, власну систему.


8

Майкл дав одне чисте рішення, але я хотів отримати оновлену змінну env зі сценарію. На жаль, виконання файлів bash неможливо у файлі системного блоку. На щастя, ви можете запустити баш всередині ExecStart:

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

Зауважте, що цей параметр безпосередньо не підтримує командні рядки оболонки. Якщо повинні використовуватися командні рядки оболонки, їх потрібно явно передати в якусь реалізацію оболонки.

Приклад у нашому випадку:

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

7
Це не спрацює з декількох причин (якщо тільки це "однократна" послуга, що досить безглуздо). Мені вдалося отримати наступні до роботи: /bin/bash -a -c 'source /etc/sysconfig/whatever && exec whatever-program'. У -aГарантує середу експортується в подпроцесса (якщо ви не хочете , щоб префікс всі змінні whateverз export)
Otheus

чому це не буде працювати? Він завжди повинен запускати всю команду, яка включає виконання сценарію, чи не так?
користувач1830432

Можливо, ExecStart=/usr/bin/env ENV=script /bin/myforegroundcmdв цьому випадку трохи краще рішення.
kstep

@Otheus: Чудова відповідь, збережена за день, коли мені довелося створити файл Tomcat 8 Unit.
Даніель

1
Існує спосіб виконати команду bash "in" системного файлу служби. Дивіться це посилання: coreos.com/os/docs/latest/…
Марк Лаката
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.