Не удалось установить соединение по шине D-Bus: операция не разрешена
Я пытаюсь перечислить сервисы на моем образе CentOS, работающем в Docker, используя
systemctl list-units
но я получаю это сообщение об ошибке:
Failed to get D-Bus connection: Operation not permitted
Любые предложения, в чем может быть проблема?
4 ответа
Я предполагаю, что вы управляете non-privileged
контейнер. systemd требуется возможность CAP_SYS_ADMIN, но Docker отбрасывает эту возможность в непривилегированные контейнеры, чтобы повысить безопасность.
systemd также требуется доступ RO к файловой системе cgroup внутри контейнера. Вы можете добавить его с –v /sys/fs/cgroup:/sys/fs/cgroup:ro
Итак, вот несколько шагов о том, как запустить CentOS с systemd внутри контейнера Docker:
- Вытащить изображение Centos
- Настройте файл Docker, как показано ниже:
FROM centos
MAINTAINER "Yourname" <youremail@address.com>
ENV container docker
RUN yum -y update; yum clean all
RUN yum -y install systemd; yum clean all; \
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
- Построить это -
docker build --rm -t centos7-systemd - < mydockerfile
Запустить контейнер с
docker run --privileged -ti -e container=docker -v /sys/fs/cgroup:/sys/fs/cgroup centos7-systemd /usr/sbin/init
Вы должны были бы systemd в вашем контейнере
Это не прямой ответ на ваш вопрос, но на самом деле это может быть более важным, и я столкнулся с этой реализацией, когда читал другие ответы здесь.
У меня был некоторый опыт миграции некоторых сложных систем в Docker, и одна из важных реализаций, которые у меня были, заключается в том, что в идеале у вас должен быть один контейнер Docker для приложения / службы или "на демон".
Одна из очень важных причин этого заключается в том, что Docker не будет корректно завершать работу служб, которые вы запускаете с помощью systemctl, и на самом деле вы можете столкнуться с такими же повреждениями базы данных, которые происходят из-за неожиданного отключения питания.
Чтобы углубиться в это немного глубже: когда Docker запускает команду "стоп" для контейнера, он отправляет сигнал SIGTERM только одному единственному процессу, который был запущен с CMD/ENTRYPOINT, а не всем службам и демонам. Так что один сервис имеет предупреждение о чистом завершении работы, а все остальные бесцеремонно прерываются.
Если вам абсолютно необходимо упаковать две службы в один и тот же контейнер (т.е. ваше приложение и базу данных PostgreSQL или что-то в этом роде), вам нужно, чтобы ваш CMD / ENTRYPOINT был сценарием, который перехватывает SIGTERM, а затем ретранслирует его на эти известные службы. Это можно сделать, но если у вас есть возможность, переосмыслите свое решение и попробуйте разбить его на несколько контейнеров.
Приложение
На сайте Docker есть интересная заметка / страница об использовании supervisord, если вам абсолютно необходимо иметь несколько служб, работающих в одном контейнере.
Мне удалось решить эту проблему в контейнере CentOS:7 Docker. Я следовал в основном Руководству по созданию изображений CentOS Docker.
FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
# Install anything. The service you want to start must be a SystemD service.
CMD ["/usr/sbin/init"]
Теперь создайте образ и запустите его, используя как минимум следующие аргументы: docker run
команда: -v /run -v /sys/fs/cgroup:/sys/fs/cgroup:ro
Тогда главное то, что /usr/sbin/init
должен быть первым процессом внутри контейнера Docker.
Так что если вы хотите использовать пользовательский скрипт, который выполняет некоторые команды перед запуском /usr/sbin/init
, запустите его в конце вашего скрипта, используя exec /usr/sbin/init
(в скрипте bash).
Вот пример:
ADD cmd.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/cmd.sh
CMD ["/usr/local/bin/cmd.sh"]
А вот и содержание cmd.sh
:
#!/bin/bash
# Do some stuffs
exec /usr/sbin/init # To correctly start D-Bus thanks to https://forums.docker.com/t/any-simple-and-safe-way-to-start-services-on-centos7-systemd/5695/8
Вы могли бы иметь System is booting up. See pam_nologin(8)
если вы используете систему PAM, в этом случае удалите /usr/lib/tmpfiles.d/systemd-nologin.conf
в вашем Dockerfile
потому что это создает файл /var/run/nologin
который генерирует эту конкретную ошибку.
Я не хотел запускать systemd в качестве init/PID 1. После выполнения действий по очистке, упомянутых другими, я запускаю systemd из сценария запуска как /usr/lib/systemd/systemd --system &
,
Это позволило systemd запускать и запускать зарегистрированные службы, но systemctl не работал с ошибкой D-Bus.
Для меня отсутствующей ссылкой было отсутствие каталога /run/systemd/system, обнаруженного strace
Системный контроль
Создание этого каталога вручную перед запуском systemctl позволяет systemctl работать на меня.