Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions wiki/systemd_and_docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Подход к запуску сервисов с использованием systemd

## Вариант 1: Нативные бинарники через systemd

### Преимущества:
1. **Минимальные накладные расходы** - нет слоя виртуализации
2. **Прямой доступ к железу** - важно для CPU binding
3. **Проще управление зависимостями** в Yocto
4. **Более предсказуемое поведение** - нет слоев контейнеризации

### Недостатки:
1. Сложнее управлять версиями зависимостей
2. Труднее масштабировать (особенно PUnit)
3. Сложнее развертывать обновления

### Реализация:
Для каждого сервиса создается unit-файл в `/etc/systemd/system/`

Пример для контроллера:
```
[Unit]
Description=Controller Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/controller
Restart=always
User=controller
CPUAffinity=0 #привязка к конкретному CPU

[Install]
WantedBy=multi-user.target
```
**Пояснения**:
- **[Unit]**:
- `Description=Controller Service`: описание юнита. Это поле помогает понимать, какой сервис будет управляться этим юнитом.
- `After=network.target`: сервис должен быть запущен после того, как сеть станет доступной (сервис зависит от сети).

- **[Service]**:
- `Type=simple`: сервис является простым (не требует какого-либо дополнительного процесса для запуска). То есть, process будет управляться напрямую.
- `ExecStart=/usr/bin/controller`: команда для запуска основного процесса сервиса. путь к бинарнику, который должен быть запущен.
- `Restart=always`: сервис должен быть перезапущен, если он завершится/упадет
- `User=controller`: определяет пользователя, от имени которого будет запущен процесс. важно для безопасности, чтобы сервис не работал от имени root
- `CPUAffinity=0`: привязка сервиса к конкретному процессорному ядру. В данном примере сервис будет работать только на ядре 0

- **[Install]**:
- `WantedBy=multi-user.target`: сервис должен быть активирован в момент перехода системы в `multi-user.target`, который является стандартным состоянием для многопользовательской работы


## Вариант 2: Docker контейнеры, управляемые через systemd

### Преимущества:
1. **Изоляция сервисов** - каждый в своем окружении
2. **Простое масштабирование** (особенно для PUnit)
3. **Упрощенное управление зависимостями**
4. **Гибкость развертывания** - образы можно обновдлять независимо
5. **Переносимость** - между разными узлами кластера

### Недостатки:
1. **Дополнительный слой абстракции** для IPC и CPU binding

### Реализация:
Пример unit-файла для управления Docker контейнером:

```
[Unit]
Description=Controller Container
Requires=docker.service
After=docker.service

[Service]
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker stop controller
ExecStartPre=-/usr/bin/docker rm controller
ExecStart=/usr/bin/docker run --name controller \
--cpuset-cpus=0 \
-v /etc/controller:/config \
controller-image
ExecStop=/usr/bin/docker stop controller
Restart=always

[Install]
WantedBy=multi-user.target
```
**Пояснения**:
- **[Unit]**:
- `Description=Controller Container`: описание юнита для контейнера.
- `Requires=docker.service`: контейнер зависит от сервиса Docker. Этот юнит не запустится, если Docker не работает.
- `After=docker.service`: контейнер должен быть запущен только после того, как будет запущен сервис Docker.

- **[Service]**:
- `TimeoutStartSec=0`: время ожидания запуска в 0 секунд.
- `ExecStartPre=-/usr/bin/docker stop controller`: Перед запуском контейнера, если он уже существует, команда остановит его. Символ `-` перед командой означает, что даже если контейнер не существует, ошибка не остановит выполнение юнита.
- `ExecStartPre=-/usr/bin/docker rm controller`: удаляет контейнер, если он существует, перед запуском нового.
- `ExecStart=/usr/bin/docker run --name controller --cpuset-cpus=0 -v /etc/controller:/config controller-image`: команда для запуска Docker-контейнера. Параметры:
- `--name controller`: дает контейнеру имя `controller`.
- `--cpuset-cpus=0`: привязка контейнера к процессору 0.
- `-v /etc/controller:/config`: монтирует локальную директорию `/etc/controller` в контейнер как `/config`. важно для конфигурации контейнера.
- `controller-image`: исмя Docker-образа, который будет запущен.
- `ExecStop=/usr/bin/docker stop controller`: команда для остановки контейнера при завершении работы сервиса.
- `Restart=always`: контейнер должен быть перезапущен в случае его падения.

- **[Install]**:
- `WantedBy=multi-user.target`: сервис будет запущен в момент перехода системы в состояние многопользовательского режима.

## Гибридный подход

1. **Базовые сервисы (Controller, Logs Collector, Metrics Collector)** - нативные бинарники с systemd
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Почему тут обязательно нативно?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

необязательно, это собственное виденье из анализа выше, оно может быть ошибочным, можно тестировать

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

У нас Logs Collector, Metrics Collector разворачиваются на хосте. Не уверен, что стоит хост модифицировать и добавлять на него systemd сервисы

- Эти компоненты критичны к производительности и требуют прямого доступа к железу
- Их версии меняются редко

2. **PUnit** - Docker контейнеры
- Позволяет легко масштабировать и обновлять
- Изоляция между экземплярами
- Можно использовать разные версии для разных задач

3. **CLI Tool** - нативный бинарник
- Должен работать без зависимостей

## Детали реализации для гибридного подхода

### 1. Нативные сервисы
Для каждого нативного сервиса:
1. Собираем бинарник в Yocto
2. Создаем systemd unit-файл
3. Настраиваем зависимости через `After=` и `Requires=`
4. Конфигурация через файлы в `/etc/`

### 2. Docker-сервисы
Для Docker-сервисов:
1. Собираем образы с помощью Yocto (meta-virtualization, класс docker-image)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Может стоит сразу пример добавить? Как сбилдить образ

2. Разрабатываем systemd unit для управления контейнерами
3. Настраиваем volumes для конфигурации и данных


## Выводы
Для проекта я рекомендую гибридный подход:
- Критичные к производительности и низкоуровневые компоненты - нативные systemd сервисы
- Масштабируемые и изолированные компоненты (PUnit) - Docker контейнеры

Это обеспечит баланс между производительностью, управляемостью и гибкостью системы.