Остановленные контейнеры в 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: Аудит всех упавших задач за неделю. Задача - получить отчет для руководства о стабильности сервисов. Последовательность действий:
- Запросить все задачи со статусами TASK_FAILED и TASK_LOST за последние 7 дней через
/v2/tasksсorder=-startedAt&limit=500. - Отфильтровать jq по
startedAt >= "2026-07-23T00:00:00Z". - Сгруппировать по
appIdи подсчитать количество падений. - Для топ-5 проблемных приложений запросить детали каждой задачи и извлечь
message- это даст распределение причин сбоев.
Сценарий 2: Отладка конкретного сбоя. Пользователи жалуются, что сервис периодически отвечает 502. Вы знаете примерное время инцидента. Действия:
- Найти задачи приложения со статусом TASK_FAILED в этом временном окне.
- Для каждой задачи получить
message- он укажет на OOM, панику приложения или таймаут health check. - Если причина не ясна из message, получить
slaveIdи скачать stderr через Mesos API. - Проанализировать логи. Если там следы нехватки памяти - увеличить лимиты в определении приложения. Если ошибки приложения - передать разработчикам стектрейс.
Сценарий 3: Восстановление удаленного приложения. Приложение случайно удалено через UI Marathon, резервной копии конфигурации нет. Действия:
- Найти последнюю завершенную задачу этого приложения через
/v2/tasks?appId=%2Fmy-app&status=TASK_FINISHEDℴ=-startedAt&limit=1. - Из ответа взять
version. - Если приложение еще не до конца вычищено - запросить
/v2/apps/my-app/versions/{version}и получить полный JSON определения. - Если версии недоступны - извлечь параметры из поля
containerзадачи: образ, переменные окружения, порты, ресурсы. - Сформировать JSON и отправить POST на
/v2/appsдля воссоздания.
Эти сценарии покрывают 90% рабочих ситуаций. Для углубленной диагностики проблем маршрутизации, которые часто сопутствуют падениям контейнеров, обратитесь к руководству по отладке ошибок маршрутизации. Если же вы работаете в смешанной среде Marathon-Kubernetes, методы анализа логов через kubectl из полного руководства по kubectl logs дополнят ваш инструментарий.