Поиск и анализ остановленных контейнеров в Marathon: практическое руководство | AdminWiki

Поиск и анализ остановленных контейнеров в Marathon: практическое руководство

30 июля 2026 7 мин. чтения

Остановленные контейнеры в Marathon не исчезают бесследно. Их записи остаются в хранилище ядер и доступны через REST API, даже если сам контейнер давно удален. Эта статья - прямой ответ на вопрос, как найти завершенные задачи, извлечь их конфигурацию и логи для аудита, отладки или восстановления после сбоя.

Вы получите готовые curl-запросы с фильтрацией по статусу, приложению и времени. Разберем механизм хранения, детальный анализ конкретной задачи и доступ к логам через Mesos Sandbox. Каждый шаг проверен на практике и подается без воды - только команды, параметры и расшифровка ответов API.

Где Marathon хранит информацию о завершенных задачах

Marathon ведет внутренний журнал всех задач - хранилище ядер (task store). Это не файл на диске, а структура в памяти, синхронизированная с состоянием Mesos. Когда контейнер завершается по любой причине - успешное выполнение, сбой, ручная остановка - запись о нем не удаляется мгновенно. Она переходит в исторический слой и остается доступной для запросов.

Срок хранения по умолчанию контролируется параметром --task_launch_timeout и связанными настройками сборщика мусора. Если задача не была подтверждена Mesos в течение этого таймаута, Marathon пометит ее как устаревшую. На практике записи о завершенных задачах живут от нескольких минут до часов - точное значение зависит от конфигурации кластера и интенсивности запуска новых контейнеров.

Для увеличения срока хранения настройте параметр --max_tasks_per_offer и лимиты на количество хранимых завершенных задач через --max_running_deployments. Прямого параметра «хранить историю N дней» в Marathon нет - при необходимости долгосрочного аудита логи и метрики задач направляют во внешние системы, такие как связка Prometheus и Grafana, о чем подробно рассказано в руководстве по построению конвейера телеметрии.

Главный вывод: API Marathon отдает данные о завершенных задачах, пока те не вытеснены новыми записями. Для оперативного расследования инцидентов этого окна достаточно. Для ретроспективного анализа за недели и месяцы потребуется внешнее хранилище логов.

Получение списка остановленных контейнеров через Marathon REST API

Базовый эндпоинт для поиска - /v2/tasks. Без параметров он возвращает все задачи, включая активные. Чтобы отфильтровать только остановленные, добавьте параметр status с одним из терминальных значений.

Ключевые статусы завершения:

  • TASK_FINISHED - задача успешно завершилась сама (код выхода 0);
  • TASK_FAILED - задача упала с ошибкой (ненулевой код выхода или потеря связи с исполнителем);
  • TASK_KILLED - задача принудительно остановлена пользователем или Marathon при масштабировании;
  • TASK_LOST - задача потеряна из-за сбоя агента Mesos или сетевого разрыва;
  • TASK_ERROR - ошибка на уровне Mesos, задача даже не стартовала.

Пример запроса для получения всех упавших задач:

curl -s "http://marathon-host:8080/v2/tasks?status=TASK_FAILED" | jq .

Ответ приходит в JSON. Для каждой задачи указаны id, appId, host, ports, startedAt, stagedAt и version. Поле message содержит текст ошибки, если Mesos его зафиксировал.

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

curl -s "http://marathon-host:8080/v2/tasks?status=TASK_FAILED&status=TASK_KILLED" | jq '.tasks[] | {id, appId, status, startedAt}'

Фильтрация завершенных задач по приложению

Параметр appId сужает выборку до конкретного приложения. Это критично для отладки: вы не тонете в сотнях записей со всего кластера, а видите только целевой сервис.

Синтаксис требует экранирования слешей в идентификаторе приложения. Вместо /my-app передавайте %2Fmy-app:

curl -s "http://marathon-host:8080/v2/tasks?status=TASK_FAILED&appId=%2Fmy-app" | jq .

Если приложение вложенное, например /team/service, экранируйте оба слеша: %2Fteam%2Fservice.

Фильтрация по временному диапазону

Прямого параметра ?from= или ?to= в Marathon API нет. Задачи можно отсортировать по времени запуска через параметр order и ограничить количество через limit, а затем отфильтровать на стороне клиента.

Запрос для получения 50 последних завершенных задач, отсортированных по убыванию времени старта:

curl -s "http://marathon-host:8080/v2/tasks?status=TASK_FINISHEDℴ=-startedAt&limit=50" | jq '.tasks[] | {id, startedAt, status}'

Дальше - парсинг на вашей стороне. Например, jq умеет фильтровать по дате, если привести startedAt к timestamp:

curl -s "http://marathon-host:8080/v2/tasks?status=TASK_FAILEDℴ=-startedAt&limit=200" | jq '.tasks[] | select(.startedAt >= "2026-07-23T00:00:00Z") | {id, startedAt, status}'

Этот подход покрывает сценарий «все упавшие задачи за неделю» без внешних инструментов.

Детальный анализ конкретной остановленной задачи

Когда список найден и нужная задача идентифицирована по id, следующий шаг - получить ее полную карточку через эндпоинт /v2/tasks/{taskId}.

curl -s "http://marathon-host:8080/v2/tasks/my-app.3f8a2b1c-5d4e-4a7b-9c0d-1e2f3a4b5c6d" | jq .

Ответ содержит расширенные поля, которых нет в списковом выводе:

  • statusSince - временная метка перехода в текущий статус. Позволяет точно определить, когда задача упала;
  • message - текст причины от Mesos: «Container exited with status 137» (убит по OOM), «Command exited with status 1» (ошибка приложения);
  • container - полный дамп настроек контейнера: образ Docker, переменные окружения, точки монтирования, сетевые параметры;
  • resources - запрошенные и реально выделенные ресурсы: CPU, память, диск;
  • slaveId - идентификатор агента Mesos, где работала задача. Это мост к логам через Mesos API.

Поле message - первая точка анализа. «Exit status 137» указывает на убийство по OOM Killer - проверьте лимиты памяти. «Exit status 1» - прикладная ошибка, нужно смотреть логи. «Task lost due to agent disconnection» - сетевой сбой или падение агента.

Извлечение конфигурации приложения из завершенной задачи

Завершенная задача хранит снапшот конфигурации приложения на момент запуска. Это спасает, когда приложение удалено из Marathon, а его определение нужно восстановить.

В ответе /v2/tasks/{taskId} ищите поле version - это временная метка версии конфигурации. Затем запросите историю версий приложения:

curl -s "http://marathon-host:8080/v2/apps/my-app/versions" | jq '.versions[]'

Найдите версию, совпадающую с version задачи, и запросите ее полное определение:

curl -s "http://marathon-host:8080/v2/apps/my-app/versions/2026-07-23T14:30:00.000Z" | jq .

В ответе - полный JSON с определением приложения: команда запуска, health checks, переменные окружения, сетевые настройки. Этот JSON можно передать в POST /v2/apps для воссоздания приложения.

Если приложение уже удалено и эндпоинт /v2/apps/{appId}/versions недоступен, используйте данные из поля container в карточке задачи - там достаточно информации для ручного восстановления критичных параметров.

Доступ к логам остановленных контейнеров

Marathon не хранит stdout/stderr задач. Эти данные находятся в песочнице Mesos на агенте, где работал контейнер. Пока агент жив и не очистил sandbox, логи доступны через Mesos Agent API.

Маршрут к логам: из Marathon получаете slaveId задачи, по нему находите хост агента, затем через Mesos API скачиваете файлы из sandbox. Пошагово это выглядит так.

Шаг 1 - получите детали задачи и зафиксируйте slaveId:

TASK_ID="my-app.3f8a2b1c-5d4e-4a7b-9c0d-1e2f3a4b5c6d"
SLAVE_ID=$(curl -s "http://marathon-host:8080/v2/tasks/$TASK_ID" | jq -r '.slaveId')
echo $SLAVE_ID

Шаг 2 - найдите хост агента через Mesos Master API:

AGENT_HOST=$(curl -s "http://mesos-master:5050/slaves" | jq -r ".slaves[] | select(.id==\"$SLAVE_ID\") | .hostname")
echo $AGENT_HOST

Шаг 3 - получите список файлов в sandbox задачи. Mesos Agent API слушает на порту 5051, путь к sandbox включает frameworkId Marathon и executorId задачи. executorId совпадает с id задачи:

FRAMEWORK_ID="marathon-framework-id"  # фиксированный для вашего Marathon
EXECUTOR_ID=$TASK_ID
curl -s "http://$AGENT_HOST:5051/files/read?path=/var/lib/mesos/slaves/$SLAVE_ID/frameworks/$FRAMEWORK_ID/executors/$EXECUTOR_ID/runs/latest" | jq .

Шаг 4 - скачайте stdout и stderr:

curl -s "http://$AGENT_HOST:5051/files/read?path=/var/lib/mesos/slaves/$SLAVE_ID/frameworks/$FRAMEWORK_ID/executors/$EXECUTOR_ID/runs/latest/stdout&offset=0&length=50000" > stdout.log
curl -s "http://$AGENT_HOST:5051/files/read?path=/var/lib/mesos/slaves/$SLAVE_ID/frameworks/$FRAMEWORK_ID/executors/$EXECUTOR_ID/runs/latest/stderr&offset=0&length=50000" > stderr.log

Параметр offset позволяет читать логи частями, если они большие. length задает размер чанка в байтах.

Использование Mesos API для доступа к файлам песочницы

Описанный выше метод - прямой доступ к файлам. Он работает, пока агент не очистил sandbox. Политика очистки задается параметром --gc_delay агента Mesos: по умолчанию это неделя, после чего sandbox удаляется.

Если агент недоступен или sandbox очищен, логи можно восстановить только из внешней системы агрегации. Для production-сред настоятельно рекомендуется настроить централизованный сбор логов. Подход с Fluentd, Prometheus и Grafana детально разобран в материале по конвейеру телеметрии.

Для оперативной отладки падающих контейнеров также полезны команды Docker - в шпаргалке по управлению контейнерами Docker собраны проверенные практики, применимые и к среде Marathon.

Типичные сценарии использования: аудит, отладка, восстановление

Три реальных кейса, которые объединяют описанные выше методы в законченные рабочие процессы.

Сценарий 1: Аудит всех упавших задач за неделю. Задача - получить отчет для руководства о стабильности сервисов. Последовательность действий:

  1. Запросить все задачи со статусами TASK_FAILED и TASK_LOST за последние 7 дней через /v2/tasks с order=-startedAt&limit=500.
  2. Отфильтровать jq по startedAt >= "2026-07-23T00:00:00Z".
  3. Сгруппировать по appId и подсчитать количество падений.
  4. Для топ-5 проблемных приложений запросить детали каждой задачи и извлечь message - это даст распределение причин сбоев.

Сценарий 2: Отладка конкретного сбоя. Пользователи жалуются, что сервис периодически отвечает 502. Вы знаете примерное время инцидента. Действия:

  1. Найти задачи приложения со статусом TASK_FAILED в этом временном окне.
  2. Для каждой задачи получить message - он укажет на OOM, панику приложения или таймаут health check.
  3. Если причина не ясна из message, получить slaveId и скачать stderr через Mesos API.
  4. Проанализировать логи. Если там следы нехватки памяти - увеличить лимиты в определении приложения. Если ошибки приложения - передать разработчикам стектрейс.

Сценарий 3: Восстановление удаленного приложения. Приложение случайно удалено через UI Marathon, резервной копии конфигурации нет. Действия:

  1. Найти последнюю завершенную задачу этого приложения через /v2/tasks?appId=%2Fmy-app&status=TASK_FINISHEDℴ=-startedAt&limit=1.
  2. Из ответа взять version.
  3. Если приложение еще не до конца вычищено - запросить /v2/apps/my-app/versions/{version} и получить полный JSON определения.
  4. Если версии недоступны - извлечь параметры из поля container задачи: образ, переменные окружения, порты, ресурсы.
  5. Сформировать JSON и отправить POST на /v2/apps для воссоздания.

Эти сценарии покрывают 90% рабочих ситуаций. Для углубленной диагностики проблем маршрутизации, которые часто сопутствуют падениям контейнеров, обратитесь к руководству по отладке ошибок маршрутизации. Если же вы работаете в смешанной среде Marathon-Kubernetes, методы анализа логов через kubectl из полного руководства по kubectl logs дополнят ваш инструментарий.

Поделиться:
Сохранить гайд? В закладки браузера