# systemd drop-ins - override без правки оригинала _Процессы и ресурсы · LinuxLab Knowledge Base_ **TL;DR:** Drop-in - `.conf` файл в `.d/` каталоге, который подмешивается к unit-файлу. Способ переопределить любую директиву unit'а **не правя оригинальный файл** из пакета. ## Зачем не править unit напрямую Допустим nginx из пакета пришёл с `/usr/lib/systemd/system/nginx.service`, и тебе нужно увеличить `LimitNOFILE`. Вариантов было исторически три: 1. Править файл прямо в `/usr/lib/systemd/system/` - **плохо**, обновление пакета его перезапишет. 2. Скопировать целиком в `/etc/systemd/system/nginx.service` и править - `/etc/` имеет приоритет, но: а) ты тащишь весь файл, б) при обновлении пакета новые директивы из upstream'а **не появятся** у тебя. 3. **Drop-in** - единственный правильный вариант: маленький файл с дельтой, базовый unit остаётся апдейтабельным. ## Как это работает Для unit'а `nginx.service` systemd при загрузке подмешивает все `.conf` файлы из этих каталогов: ``` /usr/lib/systemd/system/nginx.service.d/*.conf ← от пакетов (vendor) /run/systemd/system/nginx.service.d/*.conf ← runtime /etc/systemd/system/nginx.service.d/*.conf ← твои локальные (highest) ``` Файлы внутри одного каталога мерджатся **в алфавитном порядке** имени. Конвенция: `10-foo.conf`, `20-bar.conf` - числовой префикс задаёт порядок. Плюс есть «общие» drop-in каталоги по типу юнитов: - `service.d/` - для всех `.service` - `timer.d/` - для всех `.timer` Поэтому в `systemctl status` ты часто видишь: ``` Drop-In: /usr/lib/systemd/system/service.d └─10-timeout-abort.conf, 50-keep-warm.conf ``` Это общесистемные drop-in'ы которые дистро применяет ко всем сервисам. ## systemctl edit - самый правильный способ создать Не создавай drop-in руками - есть команда: ```bash sudo systemctl edit nginx.service ``` Что произойдёт: 1. Откроется `$EDITOR` с **пустым** буфером с инструкцией. 2. После сохранения systemd создаст файл `/etc/systemd/system/nginx.service.d/override.conf`. 3. Автоматически выполнит `daemon-reload`. ВАЖНО: писать там нужно **только то что меняешь**, с обязательным `[Section]`-заголовком: ```ini [Service] LimitNOFILE=65536 Environment="DEBUG=1" ``` Не писать заново `Description=`, `ExecStart=` и прочее - оно подтянется из оригинала. ## Аддитивные vs override-able директивы Директивы systemd делятся на два класса: **List-style** (аддитивные). `Wants=`, `Requires=`, `After=`, `ExecStartPre=`, `Environment=`, `EnvironmentFile=`. По умолчанию drop-in **добавляет** к оригинальному списку, не заменяет. **Single-value** (override). `Type=`, `User=`, `Restart=`, `LimitNOFILE=`. Drop-in просто перезаписывает. Чтобы **очистить и переопределить** список - нужна пустая строка-сброс ПЕРЕД новым значением: ```ini [Service] ExecStart= # очистить весь оригинальный ExecStart ExecStart=/usr/local/bin/nginx-wrapper # задать новый ``` Без первой пустой строки nginx запустится **дважды** - оригинальный ExecStart + новый. Это самая частая ошибка. То же для `Environment=`, `Wants=` и прочих list-style: ```ini [Unit] After= # очистить After=postgres.service redis.service ``` ## Проверить что в итоге получилось ```bash systemctl cat nginx.service ``` Это покажет **итоговый** unit с применёнными drop-in'ами в правильном порядке. Все строки помечены источником через `# /path/to/file` поверх каждой секции: ``` # /usr/lib/systemd/system/nginx.service [Unit] Description=The nginx HTTP and reverse proxy server After=network-online.target [Service] Type=forking ExecStart=/usr/sbin/nginx ... # /etc/systemd/system/nginx.service.d/override.conf [Service] LimitNOFILE=65536 ``` Дальше - `systemd-analyze verify` для проверки синтаксиса: ```bash systemd-analyze verify nginx.service ``` ## systemd-delta - что у меня переопределено Команда показывает все юниты в системе у которых есть drop-in'ы или полные override'ы: ```bash systemd-delta --type=extended # с drop-in'ами systemd-delta --type=overridden # юниты с полным override systemd-delta --type=masked # masked-юниты (→ /dev/null) ``` Полезно при наследовании сервера от кого-то - увидеть что админ-предшественник накрутил. ## systemctl revert - откатить Снести все drop-in'ы и /etc/-override'ы для юнита, оставить чистый vendor: ```bash sudo systemctl revert nginx.service ``` Удалит `/etc/systemd/system/nginx.service.d/` и сам `/etc/systemd/system/nginx.service` если он там был как полный override. ## Типичные кейсы **Увеличить лимиты:** ```ini [Service] LimitNOFILE=1048576 TasksMax=infinity ``` **Поменять User:** ```ini [Service] User= User=newuser ``` (Single-value - пустая строка не нужна, но лучше писать для читаемости.) **Добавить переменную окружения:** ```ini [Service] Environment="GOMAXPROCS=4" Environment="OTEL_ENDPOINT=http://collector:4318" ``` **Перенести логи в отдельный файл вместо journald:** ```ini [Service] StandardOutput=append:/var/log/myapp.log StandardError=inherit ``` Не забывать `daemon-reload` если правил **не** через `systemctl edit`: ```bash sudo systemctl daemon-reload sudo systemctl restart nginx ``` ## Команды ```bash sudo systemctl edit nginx.service ``` Создать drop-in для nginx - открывает редактор, после сохранения сам делает daemon-reload ```bash systemctl cat nginx.service ``` Показать итоговый unit с применёнными drop-in'ами и их источниками ```bash systemd-delta --type=extended ``` Все юниты системы у которых есть drop-in'ы - обзор кастомизации ```bash sudo systemctl revert nginx.service ``` Снести все drop-in'ы и override'ы, вернуть чистый vendor-юнит ```bash systemd-analyze verify /etc/systemd/system/nginx.service.d/override.conf ``` Проверить синтаксис drop-in'а до restart'а - поймать ошибки заранее ## См. также - [systemd - init и менеджер сервисов](/kb/systemd.md) - [Типы systemd-юнитов](/kb/systemd-unit-types.md) - [systemctl - управление сервисами systemd](/kb/cmd-systemctl.md)