← КурсСамостоятельный просмотрПульт

Пара 9 / ноябрь

systemd, граф запуска и журналы

Запустить пользовательскую службу, проверить её статус и найти причину сбоя в journal.

Контекст

kernel journal, journal службы и файл приложения — разные потоки.

Запустить пользовательскую службу, проверить её статус и найти причину сбоя в journal.

Менеджер служб

Запуск, остановка и журнал должны иметь одного понятного владельца.

01Unit-файл
02systemd --user
03Процесс
04Журнал

Аналогия: заведующий сменой знает, кого запустить и где искать отчёт.

Работает и готов — разные состояния

active не заменяет запрос к /healthz.

01Запущен
02Слушает порт
03Готов
04Ответ проверен

Аналогия: сотрудник пришёл на смену, но касса ещё не открыта.

journalctl: временная линия

Причину ищем рядом с моментом отказа.

01Время
02Служба
03Событие
04Причина / действие

Аналогия: бортовой журнал объясняет последовательность, а не только итог.

Что делает systemd и что остаётся ядру

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

systemd — пользовательский менеджер, ядро продолжает управлять CPU и памятьюsystemd · PID 1Запускает и наблюдает unitssshd.serviceПроцесс и его потомкиstudypulse.serviceПроцесс и его потомкиuser@UID.serviceМенеджер пользователяcgroups помогают учитывать группу процессов; PID 1 не является ядром Linux.

Планировщик ядра. systemd задаёт организацию служб и может использовать ограничения ресурсов.

Unit — объект управления; service — процессная работа

target группирует, timer активирует, mount подключает файловую систему.

Unit описывает объект, service — только один тип unitmulti-user.targetГруппирует unitsWantsstudypulse.serviceExecStart запускает процессjournalstdout / stderrbackup.timerНаступило времяактивацияbackup.serviceОднократная задачаdata.mountМонтирование FSДругие типы: socket, path, device, slice, scope. Target сам не обязан иметь процесс.

Нет. Это группирующий объект менеджера, а не обязательный процесс.

Requires и After отвечают на разные вопросы

Нужен ли другой unit — и в каком порядке выполнять задания.

Зависимость запуска и порядок запуска — разные рёбраapi.serviceRequires=db.serviceактивация dbdb.serviceЗапросить запуск db вместе с apidb.serviceСначала завершается start jobAfter=db.serviceapi.serviceЗатем выполняется start job apiAfter не запускает db. Requires без After не задаёт последовательность.

Нет. Ordering ограничивает порядок присутствующих заданий; активация задаётся отдельно.

Загрузка — граф, а не один длинный shell-скрипт

Независимые работы можно выполнять одновременно.

systemd исполняет граф заданий; независимые ветви могут идти параллельноbasic.targetБазовое окружениеnetwork.serviceСвоя ветвьlocal-worker.serviceБез сетевой зависимостиmulti-user.targetГруппа нужных unitsГраф учебный: реальный состав и ordering смотрим systemctl и systemd-analyze.

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

active ещё не значит «готов отвечать»

Событие старта зависит от Type; готовность проверяется по контракту.

Запуск процесса ещё не доказывает готовность APIСоздан процессType=simple: forkexec выполненType=exec: программа запущенаИнициализацияФайлы, порт, подключенияREADY=1Type=notify + sd_notifyGET /healthzПроверка конкретного контрактаРеальный запросПроверка пути пользователяactive, READY и HTTP 200 — разные доказательства. Type=notify требует поддержки приложением.

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

start и enable не взаимозаменяемы

Сейчас работать и участвовать в будущей активации — разные свойства.

start меняет текущее состояние, enable меняет связи будущей активацииsystemctl start demoЗапустить сейчасПроцесс сейчас работаетБез enable после следующей загрузки может не стартоватьsystemctl enable demoСоздать связи из [Install]target.wants → demo.serviceБез --now текущее состояние может не изменитьсяenable --now сочетает операции; disabled-службу всё ещё может активировать зависимость.

Нет. Без --now установка связей не равна немедленному start; смотрим статус и журнал.

Restart не лечит причину сбоя

Пауза и лимит защищают от бесконечного быстрого цикла.

Менеджер службы связывает сбой, журнал и политику перезапускаExecStart: PythonПроцесс работаетexit ≠ 0failed / журналКод завершения и сообщениеRestart=on-failureПауза RestartSecЗатем новая попыткаstartStartLimitОграничить частые стартыРестарт не исправляет плохую конфигурацию. systemctl stop обычно не запускает автоперезапуск.

Нет. Это может быть цикл падений; журнал и пользовательский путь покажут причину.

Состояние → журнал → конкретная проверка

Собираем доказательства одной причины, затем проверяем исправление.

Одна служба связывает состояние, процессы и журналsystemctl statusactive / failed, PID, причинаsystemctl showMainPID, ExecMainStatusjournalctl -uСообщения этой службыОдна гипотезаПуть? права? порт? config?Сначала причина в журнале; затем исправление и проверка HTTP, а не только зелёный status.

Окружение, cwd, пользователь и способы разбора команды отличаются; нужно сравнить именно эти факты.

systemctl и systemctl --user управляют разными менеджерами

Системный сервер, сеанс пользователя и контейнер — разные области.

Система, пользователь и контейнер имеют разные области управленияСистемный systemdPID 1; системные unitssystemd --userUnits выбранного пользователяКонтейнерСвой PID namespacesystemctl statusСистемный менеджерsystemctl --user statusПользовательский менеджерPID 1: app / initНе обязательно systemdПользовательский сервис не равен постоянному серверу; время жизни сеанса/WSL проверяем отдельно.

Проверяется системный manager; для пользовательской службы нужен --user.

Логи нужно искать по источнику

kernel journal, journal службы и файл приложения — разные потоки.

Журналы имеют разные источники и способы храненияЯдроRing buffer → dmesg / journalСлужбаstdout / stderr → journalПриложениеФайл JSON / syslog / stdout/run/log/journalВременное хранение/var/log/journalПостоянное, если настроено/var/log/*Текстовые логи, если естьjournal бинарный: читаем journalctl. /var/log/syslog и auth.log зависят от установленной конфигурации.

journalctl -k -b; journalctl -u имя.service -b; journalctl --user -u studypulse.service; ls /var/log — каждый инструмент смотрит свою область.

Наблюдение механизмов

ps -p 1 -o pid,comm,args
systemctl --user cat studypulse.service
systemctl --user show studypulse.service -p MainPID -p Result -p ExecMainStatus
journalctl --user -u studypulse.service -n 20 --no-pager
curl --fail http://127.0.0.1:8000/healthz
# Optional dependency exercise
python3 lab/experiments/systemd_graph.py
journalctl -k -b -n 20 --no-pager
journalctl --user -u studypulse.service -n 20 --no-pager
ls -lah /var/log
Полный разбор команд в конспекте →

Команды и наблюдения

Ubuntu / Bash с systemd

ps -p 1 -o comm=
mkdir -p ~/.config/systemd/user
cp ~/devops-course/lab/studypulse.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user start studypulse
systemctl --user status studypulse --no-pager
journalctl --user -u studypulse -n 20 --no-pager
curl -i http://127.0.0.1:8000/healthz

Разбор результата

PID 1 = systemd; служба active; HTTP healthz = 200. Если systemd недоступен, сначала исправляется конфигурация WSL.

Пример unit использует %h/devops-course/lab; путь к скопированному проекту должен совпасть. Предыдущий ручной запуск остановите, чтобы освободить порт.

На macOS

macOS использует launchd, не systemd. Unit-файл .service и journalctl не переносимы; у launchd plist, LaunchAgents/LaunchDaemons и другой lifecycle. На схеме сравниваем механизмы, а обязательную лабораторную systemd выполняем в Ubuntu. Учебный launchd-пример с проверкой приведён в отдельной странице сравнения ОС.

launchctl print gui/$(id -u)
# Linux-specific exercise: use an Ubuntu VM or the partner WSL2 setup

Сломанный запуск

  1. Запустите предоставленный user-unit и подтвердите ответ HTTP.
  2. В учебной копии unit задайте MODEL_PATH=/missing/model.json.
  3. Выполните daemon-reload и restart, найдите причину в журнале.
  4. Восстановите значение, повторите запуск и проверку healthz; затем stop.

Что должно получиться

Ошибка из журнала, исправление и HTTP-доказательство восстановления.

Служба восстанавливается без root; студент различает start, restart и daemon-reload.

Ошибка для диагностики

После правки unit забыли daemon-reload или порт занят ручным запуском.

Симптом→Гипотеза→Проверка

Основные выводы

  1. Нет, нужен реальный запрос и проверка результата.
  2. Перечитывает описания unit, но не перезапускает автоматически приложение.

После пары

Добавить в README управление user-службой и диагностику занятого порта.

Конспект, команды и разбор →

Пара 10 / ноябрь

Диагностика и ремонт Linux

Диагностировать отказ по цепочке наблюдений и составить короткий отчёт.

Контекст

Исправление должно изменить причину и быть проверено тем же пользовательским действием.

Диагностировать отказ по цепочке наблюдений и составить короткий отчёт.

Гипотеза должна предсказывать наблюдение

Команда выбирается для проверки причины.

01Симптом
02Гипотеза
03Проверка
04Вывод

Аналогия: врач проверяет версию анализом, а не назначает все лекарства сразу.

Диагностическая лестница

Идём от адреса и процесса к журналу и конфигурации.

01Среда / URL
02Процесс / порт
03HTTP / журнал
04Конфигурация / ресурсы

Нет универсальной команды, которая докажет исправность всех слоёв.

Отчёт о восстановлении

Исправление должно воспроизводиться и проверяться.

01Факты
02Причина
03Исправление
04Проверка / профилактика

Аналогия: акт ремонта нужен следующей смене, а не только тому, кто крутил гайку.

Диагностика: от симптома к причине

Исправление должно изменить причину и быть проверено тем же пользовательским действием.

От симптома к исправлению: конкретная проверка каждого слояНет команды в PATHcommand -v, PATHНе запускается файлfile, shebang, праваНет ответа APIss, curl, адрес/портСбой приложенияjournal, config, versionДиск заполненdf -h, df -i, duRAM / зависаниеfree, vmstat, psPermission deniedid, путь, ACLDNS / маршрутgetent, ip route, curlИсправление выбирают после подтверждения причины. sudo, reboot и reinstall не являются универсальной диагностикой.

Подтвердите причину, исправьте её и повторите исходный запрос.

Наблюдение механизмов

command -v python3
file app.py
pwd
id
ls -ld . data
df -h .
df -i .
ss -lntp
curl --max-time 3 -i http://127.0.0.1:8000/healthz
Полный разбор команд в конспекте →

Команды и наблюдения

Ubuntu / Bash

cd ~/devops-course/lab
PORT=8001 .venv/bin/python app.py
# In another terminal
curl --connect-timeout 2 http://127.0.0.1:8000/healthz
ss -ltnp | grep -E ":8000|:8001"
curl -i http://127.0.0.1:8001/healthz

Разбор результата

На 8000 отказ соединения, на 8001 — 200; причина в несоответствии порта запроса и запуска.

Это воспроизводимая авария без изменения системных служб. После демонстрации Ctrl+C.

На macOS

Сценарии порта, пути, HTTP и Python одинаковы; замените ss на lsof. Не используйте systemctl для launchd. Все исследования остаются на своём localhost.

lsof -nP -iTCP:8000 -sTCP:LISTEN
lsof -nP -iTCP:8001 -sTCP:LISTEN
curl -i http://127.0.0.1:8001/healthz

Станции диагностики

  1. Станция A: преподаватель запускает сервис на другом порту. Найдите его и исправьте клиентский URL.
  2. Станция B: MODEL_PATH ссылается на отсутствующий артефакт. Восстановите путь.
  3. Станция C: запрос отправлен на /healtz. Определите различие между 404 и отказом соединения.
  4. На каждой станции оформите пять строк: симптом, проверка, причина, исправление, доказательство.

Что должно получиться

Три мини-отчёта и рабочий README проекта.

Каждая причина подтверждена наблюдением; healthz и predict работают после восстановления.

Ошибка для диагностики

Студент перезапускает всё, не сохранив доказательства.

Симптом→Гипотеза→Проверка

Основные выводы

  1. Неясно, какое изменение действительно исправило причину.
  2. Повтор исходного пользовательского запроса с ожидаемым статусом и содержимым.

После пары

Сдать Linux-чекпоинт: паспорт среды, README, скрипт сводки и один отчёт об аварии.

Конспект, команды и разбор →