Docker без sudo: первое, что нужно сделать после установки
Я ненавижу sudo. Не потому что это небезопасно (хотя и это тоже), а потому что он вечно просит пароль не вовремя. Особенно бесит, когда ставишь Docker, запускаешь docker ps, и вместо списка контейнеров получаешь: permission denied. А потом — sudo docker ps. И так каждый раз. Привыкнуть можно, но когда ты работаешь с Docker активно — запускаешь контейнеры, останавливаешь, смотришь логи, билдишь образы — sudo превращается в постоянный раздражитель. Я как-то подсчитал: за день набирается 30-40 команд docker, и каждую нужно набирать с sudo — это примерно минута потраченного времени в день, а за месяц — полчаса чистой потери времени на долбанный sudo. А если учесть, что sudo пароль просят раз в 15 минут (если не настроен sudo NOPASSWD), то это ещё и постоянное прерывание потока работы — набрал команду, а тебе «sudo: required», и приходится отвлекаться на ввод пароля.
Проблема в том, что Docker-демон слушает на Unix-сокете /var/run/docker.sock, который по умолчанию принадлежит root и группе docker. Если ты не в группе docker — доступ закрыт. Демон работает от root, потому что ему нужно управлять сетевыми интерфейсами, монтировать файловые системы и создавать контейнеры на уровне ядра — это всё привилегированные операции. Но доступ к сокету можно делегировать через группы пользователей, и это безопасно, если ты доверяешь пользователям, которым даёшь доступ.
Лечится добавлением пользователя в группу docker одной командой:
sudo usermod -aG docker $USER
Флаг -a — добавить в группу (append), -G — указать группу. Без -a ты затрёшь существующие группы пользователя, и он может потерять доступ к другим сервисам. Я однажды так сделал — добавил пользователя в docker, но забыл -a, и он вылетел из группы sudo. Пришлось заходить через root и возвращать. После этого я всегда пишу usermod -aG.
После команды нужно выйти из сессии и зайти заново. Или выполнить newgrp docker, чтобы группа применилась сразу. Обрати внимание: выход из системы — обязательно. Если просто закрыть терминал и открыть новый, группа может не примениться, потому что группы назначаются при создании процесса входа. Я потратил 10 минут, думая что команда не сработала, пока не перезагрузил сессию целиком. Можно ещё перезагрузить систему, но это огород из пушки.
Я помню, как впервые это сделал на свежеустановленном Ubuntu Server. Добавил пользователя, вышел, зашёл обратно и набрал docker ps. Увидел список контейнеров без sudo — испытал чувство глубокого удовлетворения. Прямо как когда первый раз настроил SSH по ключу и забыл про пароли. Этот момент «оно работает» — ради него я и занимаюсь администрированием.
Но есть нюанс. Риск безопасности: пользователь в группе docker получает root-доступ к системе через Docker API. По сути, он может запустить контейнер с монтированием /etc и поменять что угодно. Например, такая команда даёт полный доступ к файловой системе хоста: docker run -v /:/hostroot -it ubuntu bash. После этого можно менять любой файл на хосте, включая /etc/shadow, /etc/sudoers, SSH-ключи. Поэтому давать доступ к docker стоит только тем, кому реально нужно. У меня на сервере только мой пользователь в группе docker — никаких www-data или deploy-пользователей. Если нужно дать доступ к Docker для CI/CD — лучше пробросить сокет во временный контейнер, чем добавлять Jenkins-агента в группу docker.
Если хочешь совсем без sudo и без группы — можно настроить Docker на TCP-сокет с сертификатами. Но это для извращенцев. Я так делал один раз, когда нужно было дать доступ к Docker из Jenkins-агента на другой машине. Намучился с сертификатами — генерация CA, подписание клиентских и серверных сертификатов, настройка docker daemon на прием TCP-соединений через флаг -H tcp://0.0.0.0:2376. В итоге Docker стал отвечать по IP, но пришлось открывать порт 2376 в файрволе, настраивать iptables, переживать за безопасность и регулярно обновлять сертификаты. В итоге вернулся к группе docker и пробросил сокет в Jenkins через bind mount: docker run -v /var/run/docker.sock:/var/run/docker.sock jenkins/jenkins. Это даёт контейнеру Jenkins доступ к Docker-демону без лишних открытых портов. Если Jenkins работает на той же машине — это идеальное решение.
На MacOS и Windows Docker Desktop не требует sudo — он работает через гипервизор, и доступ к docker CLI есть сразу. Там Docker запускается в виртуальной машине на базе HyperKit или Hyper-V, и сокет проксируется на хост. Но на Linux, где Docker ставится через apt, без группы docker ты будешь вводить пароль вечно. Кстати, если у тебя Podman вместо Docker — там другая философия. Podman по умолчанию работает без демона и без root, но с Docker Compose у него совместимость не полная. Я пробовал Podman на CentOS, но половина моих docker-compose.yml отказывалась работать из-за различий в обработке путей и сетей. Вернулся на Docker — он хоть и требует группу, но работает предсказуемо.
После добавления в группу docker я ещё поставил автодополнение команд. Оно идёт в комплекте с Docker:
sudo apt install bash-completion
sudo cp /usr/share/bash-completion/completions/docker /etc/bash_completion.d/
Теперь жму docker r[Tab] — и он сам подставляет run. Мелкая деталь, но экономит кучу времени. Особенно полезно для команд с длинными флагами — docker container prune, docker system df, docker builder prune. Пальцы устают набирать эти команды вручную каждый день. Для zsh автодополнение работает из коробки — нужно только подключить плагин docker в oh-my-zsh.
Ещё один совет — после добавления в группу docker установи ctop. Это аналог htop для контейнеров. Открываешь терминал, запускаешь ctop и видишь в реальном времени, сколько CPU и RAM жрёт каждый контейнер. Я держу его на втором мониторе и сразу замечаю, если какой-то контейнер начинает потреблять аномально много ресурсов. Недавно так поймал контейнер с Redis, который начал жрать 4 ГБ RAM вместо обычных 200 МБ — оказалось, что в коде приложения утечка памяти, и Redis хранил ключи, которые никогда не удалялись. Ещё один полезный инструмент — lazydocker, терминальный UI для управления Docker. Позволяет смотреть логи, перезапускать контейнеры и чистить систему стрелочками, без набора команд.
Docker без sudo — это первый шаг. Дальше — docker compose, docker swarm, Portainer. Но без шага с группой начинать бесполезно. Как только ты убрал sudo из каждого docker-запроса, работа с контейнерами перестаёт раздражать и начинает приносить удовольствие. По крайней мере, у меня так было. Я теперь могу написать docker ps, docker logs, docker exec не задумываясь — это как дышать. А когда вижу в туториалах команды с sudo docker, меня передёргивает — сразу хочется написать в комментариях «добавь пользователя в группу docker, выйди и зайди заново».
Важно понимать, что добавление в группу docker решает проблему только для пользователей на этой машине. Если ты заходишь на сервер по SSH под пользователем, который не в группе docker — sudo всё равно понадобится. Поэтому на новых серверах я первым делом запускаю скрипт инициализации, который создаёт пользователя, добавляет его в группы sudo и docker, настраивает SSH-ключи и bash-алиасы. Входит туда же alias dk=’docker’ и dkc=’docker compose’. Экономит по паре символов на каждой команде.
Ещё один трюк — если ты используесть VS Code Remote — SSH, не забудь добавить пользователя в группу docker на сервере. VS Code подключается к серверу и выполняет команды от твоего пользователя. Если пользователь не в группе docker — расширение Docker для VS Code не увидит контейнеры. У меня так было — полдня тупил, почему VS Code не показывает запущенные контейнеры, а в терминале через SSH всё работает. Оказалось, что VS Code создаёт отдельную сессию, и если группа не подхватилась — расширение видит пустой список. Перезагрузка сервера решила проблему.
Кстати, для тех, кто хочет максимальной изоляции — есть rootless Docker. Это режим, при котором и демон, и контейнеры работают без root-прав. Ставится отдельно, через скрипт dockerd-rootless-setupinstall.sh. Я пробовал на тестовом сервере. Работает, но есть ограничения: не работают привилегированные порты (ниже 1024), сложнее с сетью и cgroups. Для прода — не советую, для дома — почему бы и нет. Но лично я предпочитаю классический Docker с группой — проще и надёжнее.
Ещё один момент, о котором часто забывают — Docker генерирует логи контейнеров, которые со временем могут занять гигабайты на диске. По умолчанию Docker пишет логи в JSON-файлы без ротации. Я однажды обнаружил, что /var/lib/docker/containers/ занял 40 ГБ — это логи nginx за полгода. После добавления в группу docker (и соответственно, получения контроля над демоном) я настроил ограничение логов через daemon.json: {«log-driver»: «json-file», «log-opts»: {«max-size»: «10m», «max-file»: «3»}}. Теперь каждый контейнер пишет не больше трёх файлов по 10 мегабайт. И главное — для этого не нужен sudo, если ты в группе docker.
В итоге: usermod -aG docker $USER, выход из сессии, вход обратно — и ты забываешь про sudo навсегда. Пять минут работы, которые экономят часы в перспективе. Если админ не добавил себя в группу docker — он либо мазохист, либо не знает про эту возможность. Теперь ты знаешь, так что иди и сделай.
Кстати, если ты используешь сервер для хобби-проектов (как я), то Docker без sudo — это ещё и удобство автоматизации. Все мои скрипты деплоя запускаются от обычного пользователя: git pull, docker compose build, docker compose up -d. Никаких sudo в скриптах, никаких паролей в plain text. Если бы я оставил sudo — пришлось бы настраивать sudoers с NOPASSWD для docker, что создаёт те же риски безопасности, но с дополнительным геморроем. Группа docker элегантно решает и эту проблему тоже.
Подведём итог коротко: sudo usermod -aG docker $USER, выйти из SSH, зайти обратно, docker ps. Три шага, и ты забываешь про sudo в Docker навсегда. Я сделал это на всех своих серверах — и на домашнем Proxmox, и на VPS, и на тестовых машинах. Ни разу не пожалел.