Я большой фанат docker. Уже более чем 2 года я уверен в том, что этота технология изменит способ развертывания приложений. Не только web-приложений, но и инструментов командной строки, а, возможно, и графических приложений. Но такая точка зрения не отменяет кучи недостатков, с которыми я периодически сталкиваюсь.
Один из основных неприятных моментов, с которыми мне приходится постоянно сталкиваться, — это загромождение свободного места на диске. До недавнего времени я постоянно сталкивался с проблемами настройки окружений, потому что мне постоянно не хватало места на жестком диске, и я не мог понять, куда оно девается. Ниже я приведу несколько советов, как избежать хранения неиспользуемых docker-образов и предотвратить их появление.
Как свести занимаемое на диске место к минимуму
Во-первых, docker по-умолчанию не беспокоится о том, сколько места на диске занимают необходимые ему данные. Большинсво команд оставляют за собой кучу следов, копиируя или изменяя текущие данные образа и не удаляя предыдущую версию. Давайте рассмотрим наиболее популярные:
- Команды
docker pull
иdocker build
создают новые образы. Каждое изменение создает новый слой и кешируется, использует aufs для хранения, таким образом увеличивая занимаемое на диске место. Но при этом предыдущая версия/слой никуда не удаляются, и остаются болтаться бесполезным грузом.Удалить такие неиспользуемые образы, у которых нет метки, можно выполнив в консоли:
docker images --no-trunc | grep '<none>' | awk '{ print $3 }' | xargs -r docker rmi
- Команда
docker run
оставляет запускавшийся контейнер в том состоянии, в котором он был остановлен. Это удобно, если вам понадобится просмотреть результат позже — проверить логи, или статус завершения.Но, в рамках занимаемого места на диске, это может быть дорого, особенно в ходе тестирования. Не забывайте использовать флаг
docker run --rm
, если контейнер, в котором выполняется процесс, вам больше не понадобится. Этот флаг не работает для контейнеров, запущенных в фоне (-d
), так что в этом случае от следов запуска docker никуда не деться. Вычистить такие “мертвые” контейнеры поможет следующая команда:docker ps --filter status=dead --filter status=exited -aq | xargs docker rm -v
- Команда
docker rm
не удаляет тома, созданные контейнером. Мне не понятно, почему не сделать это поведением по-умолчанию, но на данный момент для удаления контейнеров и связанных с ними томов необходимо использовать флаг-v
.
Файловая система для хранения docker-томов
Docker для хранения файлов использует три способа:
- По-умолчанию, все, что вы сохраняете на диск внутри контейнера, сохраняется как aufs-слой. Это не создает проблем, если вы регулярно удаляете устаревшие и неиспользуемые контейнеры и образы.
- Если вы монтируете директорию с хостовой ОС (используя
docker run -v /host/path:/container/path ...
), то файлы сохраняются в файловой системе хостовой ОС, за ними не сложно следить и так же нет никаких проблем. - Третий вариант — docker-тома (volumes). Они представляют собой особые пути, которые указывают на определенную директорию в
/var/lib/docker/volumes/
хостовой ОС. Многие образы используют тома для организации общего доступа к файлам между контейнерами (используяvolumes-from
опцию) или для постоянного хранения данных, даже после завершения работы оснвного процесса.
А так, как нет инструмента, который бы отображал список томов и их состояние, очень просто забыть о них, оставив на диске после завершения работы основного процесса или даже после удаления связанных контейнеров. Следующая команда проверяет все контейнеры (запущенные или нет) и сравнивает их с созданными томами, выводя пути только к тем томам, на которые не ссылается ни один контейнер.
#!/usr/bin/env bash
find '/var/lib/docker/volumes/' -mindepth 1 -maxdepth 1 -type d | grep -vFf <(
docker ps -aq | xargs docker inspect | jq -r '.[]|.Mounts|.[]|.Name|select(.)'
)
Пошаговое выполнение этой команды включает в себя:
- Выводит список всех созданных томов
- Выводит список всех контейнеров и проверяет их, создавая JSON-массив со всеми записями
- Форматирует вывод используя
jq
чтобы получить имена всех смонтированных томов - Исключает (
grep -vFf
) смонтированные тома из списка всех созданных томов
Запускать этот скрипт необходимо с правами суперпользователя, и в системе должна быть установлена jq утилита
Команда ничего не удаляет, но направив результаты на xargs -r rm -fr
можно добавить эту функцию.
Заметка: docker 1.9 имеет новую систему управления томами, так что в этой версии все можно сделать проще:
docker volume ls -qf dangling=true | xargs -r docker volume rm
Итоги
Для очистки всех побочных продуктов работы с docker, сохраните себе следующий скрипт:
https://gist.github.com/mlebkowski/471d2731176fb11e81aa
#!/bin/bash
# удаляем завершенные контейнеры:
docker ps --filter status=dead --filter status=exited -aq | xargs -r docker rm -v
# удаляем неиспользуемые образы:
docker images --no-trunc | grep '<none>' | awk '{ print $3 }' | xargs -r docker rmi
# удаляем неиспользуемые тома (необходимы права суперпользователя):
find '/var/lib/docker/volumes/' -mindepth 1 -maxdepth 1 -type d | grep -vFf <(
docker ps -aq | xargs docker inspect | jq -r '.[]|.Mounts|.[]|.Name|select(.)'
) | xargs -r rm -fr
Такое “техническое обслуживание” должно удалить весь ненужный мусор из файловой системы и оставить в docker-окружении только актуальные контейнеры, образы и тома.