Пролог

Я много и часто пишу про self-hosted сервисы и про то, как я их поднимаю. Понятно, что их пpиходится ещё как-то обслуживать. Я уже когда-то писал, какие программы я использую именно при работе с сервисами. С тех пор практически ничего не поменялось: я, по-прежнему, чаще всего использую командную строку. И вот почему.

Стек Docker Compose и Docker Compose UI

Все мои сервисы реализованы в виде стеков Docker Compose - настраиваются при помощи docker-compose.yml, запускаются, останавливаются и обновляются при помощи CLI docker-compose. Из всех просмотренных мною программ, предоставляющих web интерфейс, самым близким к идеальному решению мне показался Docker Compose UI. Она (программа) мне нравится, но есть некоторые особенности, которые мешают мне полноценно её использовать.

На самом деле, этой особенностью является организация её рабочего окружения - Docker Compose UI требует, чтобы все docker-compose.yml файлы находились каждый в своей подпапке, которые, в свою очередь, находились бы в одной родительской папке. Именно эта папка и настраивается в качестве основной для Docker Compose UI - начиная с неё осуществляется просмотр дерева каталогов в поисках docker-compose.yml. И программа, ожидаемо, может работать только с теми, которые нашла.

Эта концепция взаимодействия с файлами конфигурации docker-compose.yml привела, в конечном итоге, к тому, что я оставил все эти файлы в каталогах пользователей, под которыми запускаются соответствующие сервисы, а в основном каталоге Docker Compose UI (это каталог на моей виртуалке, примонтированный к контейнеру Docker Compose UI) создал на них "жёсткие" ссылки (hard links). Почему "жёсткие"? "Мягкие" (soft links) ссылки почему-то игнорировались сканером Docker Compose UI.

В конечном итоге, Docker Compose UI отображает список работающих сервисов, может управлять ими, отображать их состояние и журналы. Но если попытаться внести изменения в файл конфигурации, создаётся файл-дубликат, и, в результате, содержимое исходного файла в каталоге пользователя и файла в основном каталоге Docker Compose UI начинают различаться по содержимому. Именно это стало причиной того, что я не использую Docker Compose UI так часто, как мог (и как хотелось бы).

Portainer

Ещё одна программа, которую я использую, но тоже не в полную силу, это Portainer. Он замечательно работает с отдельными контейнерами, и не только (например, с образами), но не может полноценно работать со стеками Docker Compose. То есть, он их определяет, отображает запущенные контейнеры, но не может работать со стеком, как единым целым. Ещё он не позволяет просматривать содержимое соответствующих файлов docker-compose.yml, что уж говорить про их редактирование. Правда, у него есть возможность создавать свои стеки, с которыми он взаимодействует не в пример лучше - по крайней мере, должен.

Совсем недавно я поднимал сервис мониторинга за обновлениями Docker образов. Этот сервис основан на программе Watchtower, и, по своей реализации, весь сервис - это контейнер, запущенный из Docker образа. Но так как даже такие сервисы (основанные на единственном контейнере) я поднимаю при помощи Docker Compose, то первым делом надо было определить его конфигурацию - создать файл docker-compose.yml. И тут, совершенно случайно, я вспомнил про Portainer, после чего решил немного сменить стратегию. Как? Сейчас объясню.

Я уже выше писал, что Portainer не очень хорош при работе с "оригинальными" стеками контейнеров Docker Compose, но в нём есть возможность создавать собственные стеки контейнеров и полноценно управлять ими. И, что самое важное, формат описания стеков Portainer совпадает с форматом YML файлов Docker Compose версии 2. То есть, можно создать обычный файл docker-compose.yml, только храниться он будет в Portainer.

Собственно, я решил попробовать использовать эту функциональность Portainer для запуска контейнера Watchtower. Итак, начнём.

Работа со стеками в Portainer

Для начала, воспользуемся кнопкой создания стека:

Создание нового стека

Советую, также, обратить внимание на обведённую колонку Control - Portainer честно предупреждает, что контроль над этими стеками у него ограничен, а стеки эти - мои сервисы, которые я поднимаю при помощи Docker Compose.

После нажатия на кнопку создания стека на экране появляется окно, в котором и происходят все основные действия по конфигурированию стека Portainer.

Конфигурирование стека

Собственно, конфигурирование ничего сложного из себя не представляет, особенно, если вы знакомы с правилами написания YAML файлов для Docker Compose. Всё, что вам потребуется, это:

  • указать имя сервиса
  • при помощи текстового редактора записать содержимое compose файла (учитывая, что в настоящее время можно использовать возможности, соответствующие версии 2)
  • нажать кнопку Deploy the stack

Справедливости ради надо отметить, что есть возможность также указывать значения для переменных окружения, импортировать compose файл из репозитория Git или просто из локальной папки вашего компьютера. Кроме того, можно настроить права для управления создаваемым стеком.

После создания стека Portainer сразу видна разница между стеками последнего и Docker Compose:

Отличие стеков в списке

Если же копнуть чуть глубже, то разница станет ещё более очевидной:

Отличие стеков в свойствах и возможных действиях

Как видно из последнего рисунка, со стеком Docker Compose нельзя сделать вообще ничего, просто просмотреть информацию, а вот со стеком Portainer можно выполнять различные операции, как-то:

  • Редактировать конфигурацию (на закладке Editor)
  • Останавливать или удалять стек целиком, или же создавать из него шаблон, который можно будет использовать при создании новых стеков
  • Дублировать или переносить стек на другой хост

Что интересно, Portainer, "под капотом", так сказать, поступает точно так же как и Docker Compose UI - для стеков, описанных в нём, он создаёт структуру подкаталогов, и в каждом таком подкаталоге размещает файл docker-compose.yml. А в этих файлах - то самое описание сервиса, которое вводилось в текстовом редакторе при создании стека.

Эпилог

Наверное, это не всё, что можно провернуть при работе со стеками Portainer, но я пока только учусь, и не готов рассказывать о том, чего не знаю. На текущий момент я даже не совсем понимаю, как будет происходить обновление стека - какая альтернатива команде docker-compose pull? Наверное, обновлять надо образы (есть такая возможность), а пересоздавать контейнеры - остановкой и повторным запуском стека. Тут, кстати, помочь может установленный недавно Watchtower - он выкачивает образы, требующие обновления, а перезапуск должен использовать эти новые версии образов для пересоздания контейнеров. Посмотрим, так ли это всё будет...

Вот, и всё, что могу пока сообщить. По мере того, как будет накапливаться опыт - а я надеюсь на это - буду дополнять рассказ о стеках новыми подробностями. Такие дела...

P.S.

Пока готовил эту статью, пару раз успел обновиться docker образ containrrr/watchtower, который я использую для отслеживания обновлений, и мне удалось проверить свою теорию - речь про то, что Watchtower выкачает новый образ и останется просто остановить и заново запустить стек. Рад сообщить, что теория полностью подтвердилась 😀👍👌