Por que não posso usar o Docker CMD várias vezes para executar vários serviços?

96

Eu construí uma imagem base do Dockerfile chamada centos + ssh. No Dockerfile do centos + ssh, eu uso o CMD para executar o serviço ssh.

Em seguida, quero criar uma imagem para executar outro serviço chamado rabbitmq, o Dockerfile:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD /opt/mq/sbin/rabbitmq-server start

Para iniciar o contêiner rabbitmq, execute:

docker run -d -p 222:22 -p 4149:4149 rabbitmq

mas o serviço ssh não funciona, parece que o CMD do Dockerfile da rabbitmq substitui o CMD do centos.

  1. Como o CMD funciona dentro da imagem do docker?
  2. Se eu quiser executar vários serviços, como? Usando o supervisor?
feijão edwards
fonte

Respostas:

62

Mesmo que o CMD seja escrito no Dockerfile, ele realmente é uma informação de tempo de execução. Exatamente como EXPOSE, mas ao contrário de, por exemplo, RUN e ADD. Com isso, quero dizer que você pode substituí-lo mais tarde, em um Dockerfile de extensão, ou simplesmente no seu comando de execução, que é o que você está experimentando. Em todos os momentos, pode haver apenas um CMD.

Se você deseja executar vários serviços, eu realmente usaria o supervisor. Você pode fazer um arquivo de configuração do supervisor para cada serviço, ADICIONÁ-los em um diretório e executar o supervisor supervisord -c /etc/supervisorpara apontar para um arquivo de configuração do supervisor que carrega todos os seus serviços e se parece com

[supervisord]
nodaemon=true

[include]
files = /etc/supervisor/conf.d/*.conf

Se você quiser mais detalhes, escrevi um blog sobre este assunto aqui: http://blog.trifork.com/2014/03/11/using-supervisor-with-docker-to-manage-processes-supporting-image- herança/

qkrijger
fonte
Obrigado, supervisor é uma boa ideia, mas eu me pergunto como o CMD funciona dentro da imagem do docker
edwardsbean
2
Você fez duas perguntas, 2. sobre a execução de vários serviços. Ao se perguntar como o CMD funciona, explique o que você deseja saber especificamente. Já mencionei que são informações de tempo de execução e que serão substituídas por qualquer novo CMD.
qkrijger
118

Você está certo, o segundo Dockerfile irá sobrescrever o CMDcomando do primeiro. O Docker sempre executará um único comando, não mais. Portanto, no final do seu Dockerfile, você pode especificar um comando a ser executado. Não mais.

Mas você pode executar os dois comandos em uma linha:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD service sshd start && /opt/mq/sbin/rabbitmq-server start

O que você também pode fazer para tornar seu Dockerfile um pouco mais limpo, é colocar seus comandos CMD em um arquivo extra:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD sh /home/centos/all_your_commands.sh

E um arquivo como este:

service sshd start &
/opt/mq/sbin/rabbitmq-server start
Thomas Uhrig
fonte
1
obrigado, acho que usar o supervisor é melhor. mas por que o docker executa apenas um CMD? o que acontece dentro?
edwardsbean
1
Não sei o que está acontecendo lá dentro. Mas acho que foi projetado assim. Quando você tem uma imagem e executa um comando nela (por exemplo, com CMD), ele inicia um contêiner. O contêiner é executado enquanto o comando for executado. E assim que o comando termina, o contêiner também para. Portanto, cada contêiner representa um único comando (em execução).
Thomas Uhrig
acho que talvez seja por causa do lcx ou algo assim
edwardsbean
2
@ Tyguy7 .. porque ................?
StartupGuy
1
&&A técnica funcionará apenas com serviços não interativos (que podem iniciar em segundo plano), caso contrário, apenas o primeiro será executado.
noraj
26

Embora eu respeite a resposta do qkrijger explicando como você pode contornar esse problema, acho que podemos aprender muito mais sobre o que está acontecendo aqui ...

Para realmente responder à sua pergunta de " por que " ... acho que seria útil para você entender como o docker stopcomando funciona e que todos os processos devem ser desligados de forma limpa para evitar problemas quando você tenta reiniciá-los (arquivo corrompido, etc.).

Problema: E se estivador fez SSH início a partir dele do comando e começou RabbitMQ de seu arquivo Docker? " O comando docker stop tenta parar um contêiner em execução primeiro enviando um sinal SIGTERM para o processo raiz (PID 1) no contêiner. " Qual processo o docker está rastreando como PID 1 que obterá o SIGTERM? Será SSH ou Coelho ?? "De acordo com o modelo de processo Unix, o processo init - PID 1 - herda todos os processos filhos órfãos e deve colhê-los. A maioria dos contêineres Docker não tem um processo init que faz isso corretamente e, como resultado, seus contêineres ficam cheios de processos zumbis ao longo do tempo. "

Resposta: O Docker simplesmente pega o último CMD como aquele que será iniciado como o processo raiz com PID 1 e obterá o SIGTERM de docker stop.

Solução sugerida: você deve usar (ou criar) uma imagem de base feita especificamente para executar mais de um serviço, como phusion / baseimage

Deve ser importante observar que o tini existe exatamente por esse motivo, e a partir do Docker 1.13 e superior, o tini é oficialmente parte do Docker, o que nos diz que a execução de mais de um processo no Docker É VÁLIDO .. então, mesmo que alguém afirme que seja mais habilidoso em relação ao Docker, e insista que você é absurdo por pensar em fazer isso, saiba que não é. Existem situações perfeitamente válidas para fazer isso.

Bom saber:

StartupGuy
fonte
3

A resposta oficial do docker para Executar vários serviços em um contêiner .

Ele explica como você pode fazer isso com um sistema init (systemd, sysvinit, upstart), um script ( CMD ./my_wrapper_script.sh) ou um supervisor semelhante supervisord.

A &&solução alternativa pode funcionar apenas para serviços que começam em segundo plano (daemons) ou que serão executados rapidamente sem interação e liberarão o prompt. Fazendo isso com um serviço interativo (que mantém o prompt) e apenas o primeiro serviço será iniciado.

Noraj
fonte
0

Para entender por que o CMD foi projetado para executar apenas um serviço por contêiner, vamos apenas perceber o que aconteceria se os servidores secundários executados no mesmo contêiner não fossem triviais / auxiliares, mas "principais" (por exemplo, armazenamento empacotado com o aplicativo front-end). Para começar, ele quebraria vários recursos importantes de conteinerização, como escalonamento (auto) horizontal e reescalonamento entre nós, ambos assumindo que há apenas um aplicativo (fonte de carga da CPU) por contêiner. Depois, há a questão das vulnerabilidades - mais servidores expostos em um contêiner significa patching mais frequente de CVEs ...

Então, vamos admitir que é um 'empurrão' dos designers do Docker (e Kubernetes / Openshift) em direção às boas práticas e não devemos reinventar soluções alternativas (SSH não é necessário - nós docker exec / kubectl exec / oc rshprojetamos para substituí-lo).

  • Mais informações

/devops/447/why-it-is-recommended-to-run-only-one-process-in-a-container

mirekphd
fonte