Ми помітили суттєве перевантаження сервера після переходу на запуск cron-завдань у Docker-контейнерах. Кількість і логіка завдань не змінилися – лише спосіб виконання. Це стало поштовхом до глибшого аналізу.
Виявлення причини
Першим кроком було налаштування моніторингу використання ресурсів на рівні процесів. Ми розгорнули process-exporter
і створили окремий дашборд. Спробували розрізнити джерела навантаження:
- Python-процеси
- процеси docker-compose
- пов’язані з Docker shim процеси
Зібрані дані показали, що основне навантаження створювали саме Python-процеси. Docker-процеси не мали суттєвого впливу. Але залишалося питання – чому перевантаження почалось лише після переходу на Docker-крони?
Формування гіпотез
Було висунуто дві основні гіпотези:
process-exporter
може мати надто рідкісну вибірку або створювати значне власне навантаження (він обходить увесь/proc
, де під час запусків cron може бути понад 5000 PIDів)- Особливості запуску Docker можуть приховувати реальний оверхед: контейнер готується через
runc init
, виконується кілька кроків налаштування, перш ніж запускається команда. Ці короткотривалі піки навантаження можуть бути непомітними у звичайних інтервалах моніторингу.
Початкова схема запуску cron
До оптимізації cron-завдання запускались так:
docker-compose run --rm app python script.py arguments
Кожне завдання створювало новий контейнер, який одразу після виконання видалявся.
Оптимізація
Було створено постійний фоновий контейнер для повторного використання:
docker-compose run --rm -d --name cron-runner app bash -c "while :; do sleep 60; done"
Після чого запуск cron-завдань перенесли на docker exec
у вже існуючий контейнер:
docker exec cron-runner python script.py arguments
Результати
Середнє навантаження (Load Average)
Після переходу на docker exec
середнє навантаження значно знизилось. На графіку за 2025-03-11 (06:00–22:00) видно чітке зменшення після ~15:50, коли було внесено зміни.

Використання CPU
Навантаження на CPU стало імпульсним – високі піки короткої тривалості замість широких плато з помірним навантаженням. Це свідчить про ефективніше використання CPU.


Зменшення IO
Також спостерігалося помітне зниження навантаження на диск між 14:00 та 18:00 того ж дня.

Аналіз
Причина перевантаження була не в Docker як такому, а в неправильному використанні Docker. Кожен docker-compose run
запускав:
- новий процес
runc
- створення namespace’ів
- монтування overlayfs
- fork і налаштування контейнера
- виконання
exec
цільової команди
Ці дії споживають ресурси і створюють затримки до фактичного запуску завдання.
Висновок
Якщо ви спостерігаєте неочікуване навантаження після переходу на Docker для cron-завдань – уникайте запуску нового контейнера для кожної задачі. Замість цього використовуйте довготривалий контейнер і docker exec
. Це суттєво знижує оверхед і покращує ефективність використання CPU та IO.