876просмотров
4 августа 2025 г.
Score: 964
Клиент-серверная архитектура Docker позволяет обращаться к демону dockerd не только с локального хоста, но и с удалённого. В привычном режиме демон открывает UNIX-сокет, в "удалённом" - обычный сетевой сокет, которым используется Docker Swarm, например. Вопрос авторизации в этой схеме решается при помощи mTLS, что нравится не всем: если пользователей, обращающихся к демону, много, то управление доступами потребует выписывать и отзывать сертификаты, а выполнение всех действий общим демоном затрудняет их аудирование - все операции на хосте будут происходить от имени единого процесса dockerd независимо от того, кто их инициировал. Оказывается, первую проблему Docker всё-таки решает: хоть и не без греха, Docker-клиент умеет подключаться к серверу по протоколу SSH и обращаться к демону уже через локальный сокет - странно, что соответствующая страница документации не попадалась на глаза ранее. Заставить docker подключаться по SSH можно по-разному: используя ключ -H, настроив context или выставив переменную окружения DOCKER_HOST, которую будем использовать в примерах далее. Чтобы удалённое подключение работало, надо удовлетворить двум условиям: 1. пользователь может обращаться к сокету dockerd; 2. на хост добавлен ключ авторизации. Если первое требование ещё как-то упоминается в документации, то о втором упоминаний я не нашёл, а об ошибках docker сообщит не слишком явно. Положим, авторизация на сервере настроена не по SSH-ключу, а по паролю:
DOCKER_HOST='ssh://mint@localhost' docker ps
error during connect: Get "http://docker.example.com/v1.50/containers/json": command [ssh -o ConnectTimeout=30 -T -l mint -- localhost docker system dial-stdio] has exited with exit status 255, ... Permission denied, please try again.
mint@localhost: Permission denied (publickey,password). В тексте ошибки docker раскрывает, что подключается к серверу, просто вызывая команду ssh с ключом -T - то есть, не аллоцируя терминал. Указать пароль в URL, судя по коду, тоже нельзя. А ещё команда раскрывает секретную опцию system dial-stdio - просто интересный факт :) Невыполнение второго условия влечёт другую неочевидную ошибку:
$ DOCKER_HOST='ssh://mint@localhost' docker ps
Cannot connect to the Docker daemon at http://docker.example.com. Is the docker daemon running?
Здесь docker пытается обратиться к UNIX-сокету dockerd на удалённом хосте и ему это не удаётся: непривилигированный процесс пользователя не отличает отсутствие сервера от нехватки прав:
# Manual check on a remote host:
$ curl --unix-socket /var/run/docker.sock 'http://docker.example.com/images/json'
curl: (7) Failed to connect to docker.example.com port 80 after 0 ms: Couldn't connect to server Добавив пользователя в группу docker, чтобы вызывать sudo не требовалось (что равносильно выдаче root-прав пользователю...), мы наконец доберёмся до хоста:
$ DOCKER_HOST='ssh://mint@localhost' docker ps
CONTAINER ID IMAGE ... Вся эта возня пригодится, если надо таскать образы в закрытый контур через хост-бастион. Находясь на хосте, с которого осуществляется прыжок в закрытый контур, образы можно передавать парой команд:
$ docker pull python:3.13
...
$ docker save python:3.13 -o python.tar
$ docker -H 'ssh://user:next-host' docker load -i python.tar Здесь нам не приходится передавать образ по scp, заходить на удалённый хост для его загрузки и удалять переданный образ с ФС. Экономия на спичках, но всё равно приятно :)