Como iniciar automaticamente um serviço ao executar um contêiner de docker?

157

Eu tenho um Dockerfile para instalar o servidor MySQL em um contêiner, que então começo assim:

sudo docker run -t -i 09d18b9a12be /bin/bash

Mas o serviço MySQL não inicia automaticamente, eu tenho que executar manualmente (de dentro do contêiner):

service mysql start

Como inicio automaticamente o serviço MySQL quando executo o contêiner do docker?

mtmacdonald
fonte
1
não, para um serviço simples, supervisor não é necessário, faz complicado para o usuário início
Larry Cai
8
você pode querer copiar o dockerfile aqui em vez de ligar para um arquivo que não existe mais
neo112
O artigo do docker sobre supervisord agora está aqui: docs.docker.com/config/containers/multi-service_container Usei o comando && tail para fazer meu serviço funcionar - mas precisava adicionar "--cap-add SYS_PTRACE" ao docker comando de execução.
precisa

Respostas:

205

Primeiro, há um problema no seu Dockerfile:

RUN service mysql restart && /tmp/setup.sh

As imagens do Docker não salvam os processos em execução. Portanto, seu RUNcomando é executado apenas durante a docker buildfase e para após a conclusão da compilação. Em vez disso, você precisa especificar o comando quando o contêiner for iniciado usando os comandos CMDou ENTRYPOINTcomo abaixo:

CMD mysql start

Em segundo lugar, o contêiner do docker precisa de um processo (último comando) para continuar em execução, caso contrário, o contêiner sairá / parará. Portanto, o service mysql startcomando normal não pode ser usado diretamente no Dockerfile.

Solução

Existem três maneiras típicas de manter o processo em execução:

  • Usando o servicecomando e acrescentar comando não-final depois disso, comotail -F

    CMD service mysql start && tail -F /var/log/mysql/error.log
    

Isso geralmente é preferido quando você tem um único serviço em execução, pois torna o log de saída acessível à janela de encaixe.

  • Ou use o comando de primeiro plano para fazer isso

    CMD /usr/bin/mysqld_safe
    

Isso funciona apenas se houver um script como mysqld_safe.

  • Ou envolva seus scripts start.she encerre isso

    CMD /start.sh
    

É melhor se o comando precisar executar uma série de etapas, novamente, /start.shpermanecer em execução.

Nota

Para iniciantes, o uso supervisordnão é recomendado. Honestamente, é um exagero. É muito melhor usar serviço único / comando único para o contêiner.

BTW: verifique https://registry.hub.docker.com para obter imagens existentes do mysql docker para referência

Larry Cai
fonte
Como você reiniciaria o serviço, uma vez iniciado no contêiner do docker?
K - A toxicidade no SO está crescendo.
3
@KarlMorrisondocker exec -it <CONTAINER NAME> mysql /etc/init.d/mysqld restart
kaiser
1
Eu não recomendaria o registro de erros do MySQL para determinar se o banco de dados está sendo executado ou não. Na maioria das configurações do mysqld, o servidor se recuperará dos erros do soe e, no processo, o log de erros será fechado e reaberto. Também não tenho certeza de que sua cauda -F funcionará para você em todos ou mesmo em alguns casos.
Brian Aker
Não sei por que, mas a primeira opção de solução funciona bem para o script de serviço. Quando você não usa cauda, ​​ela falhará, mesmo que o serviço seja iniciado (pelo menos para o serviço tomcat7). Com cauda funciona. Para ambos os casos, você precisa alternar o uso cap_add (- SYS_PTRACE cap-add para run) com pelo menos SYS_PTRACE
zhrist
1
Não, veja mais em stackoverflow.com/questions/46800594/…
Larry Cai
73

No seu Dockerfile, adicione na última linha

ENTRYPOINT service ssh restart && bash

Funciona para mim

E este é o resultado:

root@ubuntu:/home/vagrant/docker/add# docker run -i -t ubuntu
 * Restarting OpenBSD Secure Shell server sshd   [ OK ]                                                                      
root@dccc354e422e:~# service ssh status
 * sshd is running
Jia
fonte
2
isso é legal, mas acho que você não pode ter um contêiner desanexado dessa maneira.
Mdob 17/09/2015
1
Isso funcionou muito bem para mim. Eu estava tendo problemas para fazer o Nginx 1.8 iniciar automaticamente. Você pode adicionar os seguintes itens úteis: RUN echo "daemon off;" >> /etc/nginx/nginx.conf EXECUTAR ln -sf / dev / stdout /var/log/nginx/access.log EXECUTAR ln -sf / dev / stderr /var/log/nginx/error.log
Lionel Morrison
1
Há alguma desvantagem nessa solução?
srph
2
Finalmente, iniciar o Bash é uma péssima idéia quando você deseja interromper seus serviços normalmente, porque dessa maneira o conteúdo da janela de encaixe não pode ser interrompido docker stopou docker restartnormalmente, apenas pode ser eliminado .
Mohammed Noureldin
Eu estava trabalhando no empacotador para criar imagens do docker e isso parece corrigir meu problema com o conaitner no arquivo do empacotador. "changes": ["serviço ENTRYPOINT nginx start && / bin / bash"]
karthik101
8

Simples! Adicione no final do dockerfile:

ENTRYPOINT service mysql start && /bin/bash
Thiago
fonte
Esta é a melhor resposta que resolve meu atual problema Docker Container: Docker version 18.09.7, build 2d0083dsem && /bin/basho serviço irá parar imediatamente
Longo
7

Há outra maneira de fazer isso que eu sempre achei mais legível.

Digamos que você queira iniciar o rabbitmq e o mongodb ao executá-lo, então CMDserá algo assim:

CMD /etc/init.d/rabbitmq-server start && \
    /etc/init.d/mongod start

Como você pode ter apenas um CMDpor Dockerfiletruque, concatenar todas as instruções &&e usar \para cada comando iniciar uma nova linha.

Se você acabar adicionando muitos desses, sugiro que você coloque todos os seus comandos em um arquivo de script e inicie-o como @ larry-cai sugerido:

CMD /start.sh
Francesco Casula
fonte
3

No meu caso, eu tenho um aplicativo Web PHP sendo servido pelo Apache2 dentro do contêiner do docker que se conecta a um banco de dados back-end MYSQL. A solução de Larry Cai trabalhou com pequenas modificações. Criei um entrypoint.sharquivo no qual estou gerenciando meus serviços. Eu acho que criar um entrypoint.shquando você tiver mais de um comando para executar quando o contêiner for inicializado é uma maneira mais limpa de inicializar o docker.

#!/bin/sh

set -e

echo "Starting the mysql daemon"
service mysql start

echo "navigating to volume /var/www"
cd /var/www
echo "Creating soft link"
ln -s /opt/mysite mysite

a2enmod headers
service apache2 restart

a2ensite mysite.conf
a2dissite 000-default.conf
service apache2 reload

if [ -z "$1" ]
then
    exec "/usr/sbin/apache2 -D -foreground"
else
    exec "$1"
fi
Mr. Doomsbuster
fonte
Basta colocá-lo ao lado do seu Dockerfile. Em seu Dockerfile, você deve ter uma instrução que copie esse arquivo para o local desejado. Em seguida, aponte a ENTRYPOINT ['your location']instrução para o arquivo de script. Lembre-se de definir as permissões de execução no seu script. COPY entrypoint.sh /entrypoint.sh RUN chmod 755 /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"]. Neste exemplo, copiei meu ponto de entrada no diretório raiz no contêiner do docker.
Sr. Doomsbuster 13/01/19
onde está o Dockerfile?
Viktor Joras
3

Tenho o mesmo problema quando quero iniciar automaticamente o serviço ssh. Eu achei esse anexo

/etc/init.d/ssh start
para
~ / .bashrc
pode resolvê-lo, mas somente você o abre com o bash.

Weiping.Chen
fonte
1

Adicionei o seguinte código ao /root/.bashrc para executar o código apenas uma vez,

Confirme o contêiner na imagem antes de executar este script, caso contrário, o arquivo 'docker_services' será criado nas imagens e nenhum serviço será executado.

if [ ! -e /var/run/docker_services ]; then
    echo "Starting services"
    service mysql start
    service ssh start
    service nginx start
    touch /var/run/docker_services
fi
user136685
fonte
1

Aqui está como inicio automaticamente o serviço MySQL sempre que o contêiner do docker é executado.

No meu caso, eu preciso executar não apenas o MySQL, mas também PHP, Nginx e Memcached

Eu tenho as seguintes linhas no Dockerfile

RUN echo "daemon off;" >> /etc/nginx/nginx.conf
EXPOSE 80
EXPOSE 3306
CMD service mysql start && service php-fpm start && nginx -g 'daemon off;' && service memcached start && bash

Adicionar && bash manteria o Nginx, MySQL, PHP e Memcached em execução no contêiner.

Chris
fonte
1

Isso não funciona CMD service mysql start && /bin/bash

Isso não funciona CMD service mysql start ; /bin/bash ;

- Eu acho que o modo interativo não suporta primeiro plano.

Isso funciona !! CMD service nginx start ; while true ; do sleep 100; done;

Isso funciona !! CMD service nginx start && tail -F /var/log/nginx/access.log

cuidado que você deve usar docker run -p 80:80 nginx_bashsem o parâmetro de comando.

user3073309
fonte
0

A documentação a seguir do site do Docker mostra como implementar um serviço SSH em um contêiner do docker. Deve ser facilmente adaptável ao seu serviço:

Uma variação sobre essa pergunta também foi feita aqui:

Zammalad
fonte
A ferramenta nsenter é outra abordagem para entrar em um contêiner, sem a necessidade de instalação do servidor SSH: github.com/jpetazzo/nsenter . Mas essa abordagem requer um acesso ao host do Docker (geralmente o acesso SSH é suficiente).
Fabien Balageas
O link docs.docker.com/sorry/#/examples/running_ssh_service não funciona. Você pode atualizá-lo?
Ankur
0
docker export -o <nameOfContainer>.tar <nameOfContainer>

Pode ser necessário remover o contêiner existente usando a ...

Importe com as modificações necessárias:

cat <nameOfContainer>.tar | docker import -c "ENTRYPOINT service mysql start && /bin/bash" - <nameOfContainer>

Execute o contêiner, por exemplo, com a opção sempre reiniciar para garantir que ele seja retomado automaticamente após a reciclagem do host / daemon:

docker run -d -t -i --restart always --name <nameOfContainer> <nameOfContainer> /bin/bash

Nota lateral: Na minha opinião, razoável é iniciar apenas o serviço cron deixando o contêiner o mais limpo possível, em seguida, basta modificar o crontab ou cron.hourly, .daily etc ... com os scripts de verificação / monitoramento correspondentes. A razão é que você depende apenas de um daemon e, em caso de alterações, é mais fácil com o ansible ou o fantoche redistribuir scripts cron em vez de rastrear serviços que iniciam na inicialização.

Daniel
fonte