Linux и shell для бэкендера: логи, сигналы, переменные окружения

↑ 1.2 ОС и Linux для разработчика · ← Предыдущая · → Следующая

Желательно~5 мин чтенияУровень: junior

Зачем это на собесе

Сервисы живут в Linux-контейнерах. Бэкендер должен уметь зайти в контейнер, посмотреть логи и процессы, понять, почему сервис не стартует или не останавливается корректно.

Подтемы

  • Переменные окружения и конфигурация .NET
  • Сигналы и graceful shutdown
  • Логи
  • Команды для прода

Объяснение

Переменные окружения

Главный способ конфигурировать сервис в контейнере (12-factor app).

export ConnectionStrings__Postgres="Host=db;Database=clinic;Username=app;Password=..."
printenv | grep ASPNETCORE

В .NET переменные окружения — один из провайдеров конфигурации. Двойное подчёркивание __ = разделитель уровней (: в JSON):

// appsettings.json: { "Minio": { "Endpoint": "minio:9000" } }
// переопределение в docker-compose: Minio__Endpoint=minio-prod:9000
var endpoint = builder.Configuration["Minio:Endpoint"];

Важные: ASPNETCORE_ENVIRONMENT (Development, Staging, Production), ASPNETCORE_URLS или ASPNETCORE_HTTP_PORTS, DOTNET_ для настроек рантайма (DOTNET_gcServer).

Сигналы

  • SIGTERM (15) — вежливая просьба завершиться. Docker и Kubernetes шлют его при остановке.
  • SIGKILL (9) — немедленное убийство, перехватить нельзя. Docker шлёт его через 10 секунд (stop_grace_period) после SIGTERM.
  • SIGINT (2) — Ctrl+C.
  • SIGHUP — часто «перечитать конфиг» (nginx).

.NET Generic Host ловит SIGTERM и запускает graceful shutdown: перестаёт принимать запросы, дожидается текущих, вызывает StopAsync у фоновых сервисов.

builder.Services.Configure<HostOptions>(o => o.ShutdownTimeout = TimeSpan.FromSeconds(25));
 
public class Worker(ILogger<Worker> log) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)       // токен отменится по SIGTERM
            await ProcessBatchAsync(stoppingToken);
    }
}

PID 1 и shell-форма ENTRYPOINT

Если в Dockerfile ENTRYPOINT написан в shell-форме (ENTRYPOINT dotnet app.dll), PID 1 — это shell, который не пересылает SIGTERM приложению. Сервис убивается по SIGKILL без graceful shutdown. Используйте exec-форму: ENTRYPOINT ["dotnet", "app.dll"].

Логи

  • В контейнере: docker logs -f --tail 200 service, docker compose logs -f patient_storage.
  • На хосте с systemd: journalctl -u nginx -f --since "10 min ago".
  • Структурированные JSON-логи удобно фильтровать через jq.

Команды, которые пригодятся на проде

docker exec -it patient_storage sh          # зайти в контейнер
ps aux | grep dotnet                        # процессы
top / htop                                  # CPU и память
df -h ; du -sh /var/lib/docker/*            # место на диске
free -m                                     # память
ss -tlnp                                    # какие порты слушаются
curl -s localhost:8080/health | jq          # проверить сервис изнутри
env | sort                                  # переменные окружения процесса
tail -f /var/log/nginx/error.log

Нюансы и подводные камни

  • Секреты в переменных окружения видны через docker inspect и /proc/<pid>/environ. Для чувствительного — secrets-механизмы (Docker secrets, Vault, Kubernetes Secrets).
  • Переменные читаются при старте: изменение требует перезапуска (кроме файловых конфигов с reloadOnChange).
  • Exit code 137 = SIGKILL (часто OOMKilled), 143 = SIGTERM.
  • Минимальные образы (alpine, chiseled) не содержат bash, curl и ps: для отладки используют docker debug или временный образ.

Вопросы с ответами

Связанные темы