Estou tentando listar serviços na minha imagem do CentOS em execução no Docker usando
systemctl list-units
mas recebo esta mensagem de erro:
Failed to get D-Bus connection: Operation not permitted
Alguma sugestão de qual pode ser o problema?
Meu palpite é que você está executando um
non-privileged
contêiner. O systemd requer o recurso CAP_SYS_ADMIN, mas o Docker descarta esse recurso nos contêineres não privilegiados, para adicionar mais segurança.systemd também requer acesso RO ao sistema de arquivos cgroup dentro de um container. Você pode adicioná-lo com
–v /sys/fs/cgroup:/sys/fs/cgroup:ro
Então, aqui estão algumas etapas sobre como executar o CentOS com o systemd dentro de um contêiner do Docker:
Construa -
docker build -t centos7-systemd - < mydockerfile
Execute um contêiner com
docker run --rm --privileged -ti -e container=docker -v /sys/fs/cgroup:/sys/fs/cgroup centos7-systemd /usr/sbin/init
Você deve ter systemd em seu contêiner
Esta não é uma resposta direta à sua pergunta, mas pode realmente ser mais importante, e me deparei com essa percepção enquanto lia as outras respostas aqui.
Eu tive alguma experiência em migrar alguns sistemas complicados para o Docker, e uma das percepções significativas que tive é que você deve idealmente ter um contêiner do Docker por aplicativo/serviço ou "por daemon".
Uma razão muito significativa para isso é que o Docker não encerrará de forma limpa os serviços que você inicia com systemctl e, na verdade, você pode acabar com o mesmo tipo de corrupção de banco de dados que vem de uma queda de energia inesperada.
Para mergulhar um pouco mais nisso: quando o Docker emite um comando "stop" para um contêiner, ele envia o sinal SIGTERM apenas para um único processo que foi iniciado com o CMD/ENTRYPOINT, não para todos os serviços e daemons. Para que um serviço tenha o aviso para ser encerrado de forma limpa e todos os outros sejam encerrados sem cerimônia.
Se você absolutamente precisa empacotar dois serviços no mesmo container (ou seja, seu aplicativo e um banco de dados PostgreSQL ou algo parecido), então você precisa que seu CMD/ENTRYPOINT seja um script que capture SIGTERM e então o retransmita para esses serviços conhecidos. Isso pode ser feito, mas se você tiver a oportunidade, repense sua solução e tente dividi-la em vários contêineres.
Um adendo
Há uma nota/página interessante no site do Docker sobre o uso do supervisord se você realmente precisar ter vários serviços em execução no mesmo contêiner.
Consegui corrigir esse problema em um contêiner CentOS:7 Docker. Eu segui principalmente o Guide on CentOS Docker image project .
Agora, construa a imagem e execute-a usando pelo menos os seguintes argumentos para
docker run
command:-v /run -v /sys/fs/cgroup:/sys/fs/cgroup:ro
Então o ponto principal é que
/usr/sbin/init
deve ser o primeiro processo dentro do container Docker.Portanto, se você quiser usar um script personalizado que execute alguns comandos antes de executar
/usr/sbin/init
, inicie-o no final do script usandoexec /usr/sbin/init
(em um script bash).Aqui está um exemplo:
E aqui está o conteúdo de
cmd.sh
:Você poderia ter
System is booting up. See pam_nologin(8)
se estiver usando o sistema PAM, nesse caso, delete/usr/lib/tmpfiles.d/systemd-nologin.conf
no seuDockerfile
porque ele cria o arquivo/var/run/nologin
que gera esse erro específico.Eu não queria ter que iniciar o systemd como init/PID 1. Depois de executar as etapas de limpeza mencionadas por outras pessoas, iniciei o systemd de dentro de um script de inicialização como
/usr/lib/systemd/systemd --system &
.Isso permitiu que o systemd iniciasse e iniciasse os serviços registrados, mas o systemctl estava falhando com o erro D-Bus.
Para mim, o elo perdido era a ausência do
/run/systemd/system
diretório, descobri issostrace
ing systemctl.Criar este diretório manualmente antes de executar o systemctl permite que o systemctl funcione para mim.