Управление Docker контейнерами без Portainer и Dockge
Долгое время я сидел на Dockge, оно хостится у меня на малинке. А на самой малинке я гоняю: jellifyn, qbittorrent, grafana, prometheus, uptime kuma, watchyourlan, technitium dns.
читать первым в телеграм читать первым в макс
Для таких целей Portainer крайне избыточен, мне в хер не уперся космический корабль, да и многое в Portainer сделано через жопу, хрен чё найдешь.
Поэтому Dockge покрывает все мои хотелки. Но рано или поздно хочется нового.
И новое это — DockHand. Причем этот проект не просто пилит какой-то энтузиаст, проект с закосом на интерпрайз. Но полностью opensource.
Люблю opensource, за то, что если есть закос на интерпрайз, то можно посмотреть исходники и реверснуть лицензию. С DocHand я пока особо глубоко не ковырялся, но чуть позже обязательно пропатчу, как собственно провернул это с mattermost, gitlab и т.п.

Да, по функционалу DocHand ничем не уступает Portainer и даже превосходит его. Для меня важно, чтобы всё было очевидно и понятно, без - хуй чё найдешь. И тут с этим всё прекрасно.
Ладно, чем бы дитя не тешилось. Вкорячиваем:
services:
dockhand:
image: fnsys/dockhand:latest
container_name: dockhand
restart: unless-stopped
ports:
- 3000:3000
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- dockhand_data:/app/data
volumes:
dockhand_data:
Композник с официального сайта, там еще есть вариант добавить PostgreSQL, но это уже если у тебя там ебать нагрузки и куча юзеров. Мне хватит дефолтного, пусть оно в sqlite живет, похуй.
Стартуем docker compose up -d и наблюдаем ошибку:
Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint dockhand (a67fe04165e1dab95576a7b6cc5604737938659ff997d84809aea5d1f73587be): Bind for 0.0.0.0:3000 failed: port is already allocated
Ну понятно, чето у меня на 3000 крутится, поэтому в компознике меняю порт на 3002:3000. И перезапускаю. Отлично, даже под ARM из коробки нормально поднялось, а это уже очень ценно! Не все докер образы умеют с армами работать.

Опа, залетели даже без ввода учетных данных, этот момент сразу учитывай если разворачиваешь в открытом интернете. Но это решаемо из коробки.
Создание пользователя

Переходим в Settings → Authentication → Add user и создаем юзера:

И сверху тыкаем на OFF → ON

Перезагружаем страницу и видим форму авторизации. Супер, с этим разобрались.

После этого переходим в Settings → Environments → Add environment

И создаем первое окружение. Я заморачиваться не буду и назову его HOME. Все свои сервисы я буду хостить именно в этом окружении. Но ты можешь все раскидать как тебе хочется и по своим потребностям.

Тут особо ничего менять не нужно, всё по умолчанию в работоспособном режиме. Для проверки нажимаем Test connection и проверяем.

Ништяк. Всё подключилось. Жмем Add и радуемся.

Если у тебя докер каким-то чудным образом работает не через socket, то при добавлении окружения, поменяй
Connection type

Так, первый и единственный дашборд у меня готов:

Едем дальше. Нажимаем на окружение и проваливаемся:

Сейчас если нажать Check for update и проверить обновления контейнеров, то получим ошибку. Для РФ классическая ситуация, все забанено, заблокировано, замедленно.

НО. Раз есть проблема, значит её нужно решить, хотя она не такая уж и важная. Ну чё, давай решим раз мы словили неочевидную залупу.
Смотрим логи:

Оуууу, ёбтвою мать! Ну ежу понятно, что с этим делать.
А если ты хочешь так-же, как и я, взглянуть на ошибку и понять что с ней делать, вписывайся в мой интенсив, научу дебажить и разовью в тебе насмотренность. За 2 месяца превратишься в сеньора-помидора.
Фиксим:
docker exec -it dockhand sh
cat /etc/resolv.conf

Docker пытается использовать свой встроенный DNS (127.0.0.11), но у самого Docker нет ни одного внешнего DNS-сервера для пересылки запросов.
Добавляем в композник DNS:
services:
dockhand:
image: fnsys/dockhand:latest
container_name: dockhand
restart: unless-stopped
dns:
- 1.1.1.1
- 8.8.8.8
ports:
- 3002:3000
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- dockhand_data:/app/data
volumes:
dockhand_data:
Снова проверяем обновления иии… ПУШКА!

dockhand выделила рамкой контейнеры, которые можно обновить. НО как показывает практика, после обновления, не факт что у тебя всё будет работать как раньше. Поэтому предварительно запомни на какой версии у тебя работает сервис и только потом обновляйся. Если не взлетело, откатывайся.
Давай чёнить обновим, например Grafana:

Пошла возьня! Проверяем графану:

Работает сучка! Чуть позже обновлю все остальные. Довольно удобно. Кстати, если открыть настройки контейнера, то можно включить автоматическое обновление:

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

Тут же можно задать лимиты на ресурсы, подключить GPU и вообще чёрту хвосты накрутить. Всё гибко и максимально кастомится под хотелки.
А еще можно прям из коробки создавать новые контейнеры со всеми вытекающими настройками. То есть, если терпеть не можешь композники, у тебя есть возможность всё сделать через морду кликая мышкой.

НО настоящие инженеры мышкой не тыкают, поэтому сразу учись писать нормальные композники. В будущем это знание сослужит тебе добрую службу.
Смотрим логи
Тут тоже все интуитивно понятно и на поверхности. Я обычно сначала запускаю docker compose up потом смотрю логи, фикшу баги и только потом запускаю с ключом -d чтобы контейнер стартовал в фоне.

Тут можно стартануть сразу в фоне и позырить нужные логи. Банально конечно, но без логов пофиксить что-то неочевидное, достаточно проблематично. Фича этих логов — можно ставить на паузу, скачивать, автоскролить и т.п. Короче всё сделано для людей.
С шелом тоже всё понятно, проваливайся внутрь, выбираем оболочку, что-то смотрим, патчим:

Но такая простота влияет на твою дальнейшую судьбу, если просидеть пару месяцев с DockHand, то банально сотрется память и ты начнешь гуглить — как войти в интерактивный режим в консоли. Палка о двух концах. Вам шашечки, либо ехать.
Дальше там всё по стандарту, стеки, вольюмы, сети и т.п. Сам посмотришь, мне достаточно логов и шелов, в остальное обычно не лезу. Но например в images можно быстро глянуть какие контейнеры забивают место на диске и не используются:

А кнопкой Prune Unused их можно безболезненно почистить. Выкроешь пару десятков гигабайт без поисков по ncdu.
Управляем Стеками
Так как у меня ранее был Dockge, то DockHand в Source пишет — Untracked, то есть по сути оно мне говорит, что стек создан в другом приложении и иди нахуй. Но и это мы можем исправить и бесшовно переехать, без хуйни и смс.

Для этого правим композник:
services:
dockhand:
image: fnsys/dockhand:latest
container_name: dockhand
restart: unless-stopped
dns:
- 1.1.1.1
- 8.8.8.8
ports:
- 3002:3000
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- dockhand_data:/app/data
- /opt/stacks:/opt/stacks
volumes:
dockhand_data:
У меня все композники лежат на хосте в /opt/stacks, монтируем эту папку в контейнер DockHand, а затем проваливаемся в контейнер в разделе Stacks:

Нажимаем Browse for compose file и выбираем композник в папке, которую только что примонтировали:


Ага, появился. Теперь жмем Save & Redeplo и наслаждаемся.

Стек перешел в статус — Internal. Минимум телодвижений. Теперь мы можем управлять нашим композником прям из DockHand.
Я повторяю эту процедуру для каждого стека и потихоньку переношу контейнеры. Готово:

Удаленный docker хост
Дада, сюда можно подключить другие докер хосты, чтобы это провернуть, при создании нового Environments выбираем тип соединения: Hawser agent. Логично, что на удаленный сервер, нужно вкорячить агента. Давай попробуем.
Идем на удаленный сервер и запускаем агент:
docker run -d \
--name hawser \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /opt/hawser-stacks:/opt/hawser-stacks \
-e STACKS_DIR=/opt/hawser-stacks \
-p 2376:2376 \
-e TOKEN=your-secret-token \
ghcr.io/finsys/hawser:latest
Да, на официальном сайте агента, ты можешь выбрать любой доступный способ запуска. Я выбрал докер, мне так привычнее, не хочу возиться с systemd. Ну и в your-secret-token забиваю секретный ключ, чтобы оно смогло авторизоваться.
Секрет генерим, например так:
openssl rand -base64 32
Проверяем, все ок:

Для пущей безопасности рекомендую сделать сертификат и подключаться по HTTPS. Для демки подойдет HTTP, всеравно там воровать нечего.

Отлично, второе окружение подключено, теперь я могу наблюдать и манипулировать удаленным сервером.

Мля, мякотка!!!
Бонусом TLS
Чё уж вокруг ходить, давай TLS сделаем. Покажу на пальцах, как его внедрить и сделать по взрослому.
docker stop hawser
docker rm -f hawser
docker run -d \
--name hawser \
--restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /opt/hawser-stacks:/opt/hawser-stacks \
-v /var/lib/angie/acme/letsencrypt:/certs:ro \
-e STACKS_DIR=/opt/hawser-stacks \
-e TOKEN=your-secret-token \
-e TLS_CERT=/certs/certificate.pem \
-e TLS_KEY=/certs/private.key \
-p 2376:2376 \
ghcr.io/finsys/hawser:latest
У меня сертификаты уже получены с помощью Angie, поэтому я буду использовать их. Как настраивать авто SSL в Angie я рассказывал тут.
Запускаем агент, идем в морду dockhand и выставляем протокол HTTPS (TLS):

Не забываем поменять Agent Host на имя домена, на который выпущены сертификаты. Всё!

Дело в шляпе, теперь всё по взрослому.
Кстати мне удалось пропатчить лицензию и я открыл все Enterprise фичи.

О том как это сделать, напишу чуть позже. В принципе ничего сложного там нет, было бы желание. Всё делалось в рамках эксперимента и проверки продукта на стойкость. Так что авторам продукта волноваться не стоит, но к примеру модули wordpress патчатся намного сложнее.
