web-dev-qa-db-fra.com

impossible d'obtenir la connexion D-Bus: opération non autorisée

J'essaie de répertorier les services sur mon image CentOS exécutée dans Docker à l'aide

systemctl list-units  

mais je reçois ce message d'erreur:

Failed to get D-Bus connection: Operation not permitted

Des suggestions sur le problème?

33
Snowcrash

Je suppose que vous exécutez un non-privileged récipient. systemd nécessite la capacité CAP_SYS_ADMIN mais Docker supprime cette capacité dans les conteneurs non privilégiés, afin d'ajouter plus de sécurité.

systemd nécessite également RO accès au système de fichiers cgroup dans un conteneur. Vous pouvez l'ajouter avec –v /sys/fs/cgroup:/sys/fs/cgroup:ro

Voici donc quelques étapes pour exécuter CentOS avec systemd dans un conteneur Docker:

  1. Pull image centos
  2. Configurez un fichier Docker comme celui ci-dessous:
FROM centos
MAINTAINER "Yourname" <[email protected]>
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"]
  1. Construit le - docker build --rm -t centos7-systemd - < mydockerfile
  2. Exécutez un conteneur avec docker run --privileged -ti -e container=docker -v /sys/fs/cgroup:/sys/fs/cgroup centos7-systemd /usr/sbin/init

  3. Vous devriez avoir systemd dans votre conteneur

28
13dimitar

Ce n'est pas une réponse directe à votre question, mais c'est peut-être plus important, et je suis tombé sur cette prise de conscience en lisant les autres réponses ici.

J'ai eu une certaine expérience de la migration de certains systèmes complexes vers Docker, et l'une des réalisations importantes que j'ai eues est que vous devriez idéalement avoir un conteneur Docker par application/service ou "par démon".

Une raison très importante à cela est que Docker ne fermera pas proprement les services que vous démarrez avec systemctl et en fait vous pouvez vous retrouver avec le même type de base de données corruptions qui proviennent d'une panne de courant inattendue.

Pour approfondir ceci: lorsque Docker émet une commande "stop" vers un conteneur, il envoie le signal SIGTERM uniquement le seul processus qui a été démarré avec le CMD/ENTRYPOINT, pas à tous les services et démons. Pour qu'un service ait l'avertissement de s'arrêter proprement et que tous les autres se terminent sans cérémonie.

Si vous devez absolument empaqueter deux services dans le même conteneur (c'est-à-dire votre application et une base de données PostgreSQL ou quelque chose comme ça), vous devez avoir votre CMD/ENTRYPOINT être un script qui attrape SIGTERM puis le rediffuse vers ces services connus. Cela peut être fait, mais si vous en avez l'occasion, repensez votre solution et essayez de la diviser en plusieurs conteneurs.

Un addendum

Il y a une intéressante note/page sur le site Docker sur l'utilisation de supervisord si vous avez absolument besoin d'avoir plusieurs services en cours d'exécution dans le même conteneur.

4

J'ai réussi à résoudre ce problème dans un conteneur Docker CentOS: 7. J'ai suivi principalement le guide sur le projet d'image 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"]

Maintenant, créez l'image et exécutez-la en utilisant au moins les arguments suivants à la commande docker run: -v /run -v /sys/fs/cgroup:/sys/fs/cgroup:ro

Ensuite, le point principal est que /usr/sbin/init Doit être le premier processus à l'intérieur du conteneur Docker.

Donc, si vous souhaitez utiliser un script personnalisé qui exécute certaines commandes avant d'exécuter /usr/sbin/init, Lancez-le à la fin de votre script en utilisant exec /usr/sbin/init (Dans un script bash).

Voici un exemple:

ADD cmd.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/cmd.sh

CMD ["/usr/local/bin/cmd.sh"]

Et voici le contenu de 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

Vous pourriez avoir System is booting up. See pam_nologin(8) si vous utilisez le système PAM, dans ce cas, supprimez /usr/lib/tmpfiles.d/systemd-nologin.conf Dans votre Dockerfile car cela crée le fichier /var/run/nologin Qui génère ce erreur spécifique.

3
Anthony O.

Je ne voulais pas avoir à lancer systemd en tant que init/PID 1. Après avoir effectué les étapes de nettoyage mentionnées par d'autres, je lance systemd à partir d'un script de démarrage en tant que /usr/lib/systemd/systemd --system &.

Cela a permis à systemd de démarrer et de lancer les services enregistrés, mais systemctl échouait avec l'erreur D-Bus.

Pour moi, le lien manquant était l'absence du répertoire/run/systemd/system, découvert par straceing systemctl.

La création manuelle de ce répertoire avant d'exécuter systemctl permet à systemctl de fonctionner pour moi.

1
Chaim Geretz