Por que é recomendável executar apenas um processo em um contêiner?

79

Em muitos posts e opiniões gerais, há um ditado que diz "um processo por contêiner".

Por que essa regra existe? Por que não executar ntp, nginx, uwsgi e mais processos em um único contêiner que precisa ter todos os processos para funcionar?

postagens de blog mencionando esta regra:

Evgeny
fonte
Mas - seria bom ter um contêiner muito "gordo" com dezenas de processos para organizar uma implantação e operação de um servidor corporativo que ainda não pode ter o Docker?
Peter
@ J.Doe provavelmente não vai ficar bem. Como os contêineres são diferentes das VMs, existem vários pequenos problemas, mesmo para um aplicativo pequeno - para um lançamento corporativo, será um projeto de dois anos para que tudo seja executado em um contêiner em primeiro lugar.
Evgeny

Respostas:

65

Vamos esquecer os argumentos arquitetônicos e filosóficos de alto nível por um momento. Embora possa haver alguns casos extremos em que várias funções em um único contêiner possam fazer sentido, há razões muito práticas pelas quais você pode considerar seguir uma "função por contêiner" como regra geral:

  • O dimensionamento de contêineres horizontalmente é muito mais fácil se o contêiner estiver isolado em uma única função. Precisa de outro contêiner apache? Gire um em outro lugar. No entanto, se meu contêiner apache também tiver meu DB, cron e outras peças, isso complica as coisas.
  • Ter uma única função por contêiner permite que ele seja facilmente reutilizado para outros projetos ou propósitos.
  • Também torna mais portátil e previsível que os desenvolvedores retirem um componente da produção para solucionar problemas localmente, em vez de um ambiente de aplicativo inteiro.
  • A aplicação de patches / atualizações (tanto o SO quanto o aplicativo) pode ser feita de maneira mais isolada e controlada. O malabarismo com vários bits e bobs em seu contêiner não apenas gera imagens maiores, mas também une esses componentes. Por que desligar o aplicativo X e Y apenas para atualizar o Z?
    • Acima também é válido para implantações de código e reversões.
  • A divisão de funções em vários contêineres permite mais flexibilidade do ponto de vista de segurança e isolamento. Você pode querer (ou exigir) que os serviços sejam isolados no nível da rede - fisicamente ou dentro de redes de sobreposição - para manter uma forte postura de segurança ou cumprir com coisas como PCI.
  • Outros fatores menores, como lidar com stdout / stderr e enviar logs para o log de contêineres, mantendo os contêineres o mais efêmeros possível etc.

Note que estou dizendo função, não processo. Esse idioma está desatualizado. A documentação oficial do docker deixou de dizer "um processo" para recomendar "uma preocupação" por contêiner.

Jon
fonte
1
Ainda assim, parece que o argumento de baixo nível contra threads se encaixa aqui ... web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf
jeffmcneill
Ótima resposta abrangente!
Rob Wells
A ideia de que a pergunta não significou realmente 'processo' no sentido do SO - que o docker e os escritos relacionados estavam usando uma terminologia diferente que agora foi esclarecida ao mudar para a palavra 'função'? Porque, caso contrário, embora reconheça que essa é a resposta aceita e com a classificação mais alta, acho que não responde à pergunta que foi feita.
Tom
27

Tendo matado um contêiner de "dois processos" há alguns dias, houve alguns pontos problemáticos para mim, o que me levou a usar dois contêineres em vez de um script python que iniciou dois processos:

  1. O Docker é bom em reconhecer contêineres com falhas. Não pode fazer isso quando o processo principal parece bom, mas algum outro processo sofreu uma morte horrível. Claro, você pode monitorar seu processo manualmente, mas por que reimplementá-lo?
  2. os logs do docker ficam muito menos úteis quando vários processos estão enviando seus logs para o console. Novamente, você pode gravar o nome do processo nos logs, mas o docker também pode fazer isso.
  3. Testar e raciocinar sobre um contêiner fica muito mais difícil.
Christian Sauer
fonte
Essa deve ser a resposta aceita.
ClintM
Acordado. Embora existam algumas outras respostas com alguns grandes pontos, o ponto chave é sobre a manipulação da janela de encaixe de PID 1.
Brett Wagner
13

A recomendação vem do objetivo e do design da virtualização no nível do sistema operacional

Os contêineres foram projetados para isolar um processo para outros, fornecendo a ele seu próprio espaço de usuário e sistema de arquivos.
Essa é a evolução lógica da chrootqual estava fornecendo um sistema de arquivos isolado; a próxima etapa foi isolar os processos dos outros para evitar sobrescrições de memória e permitir o uso do mesmo recurso (por exemplo, porta TCP 8080, por exemplo) de vários processos sem conflitos.

O principal interesse em um contêiner é empacotar a biblioteca necessária para o processo sem se preocupar com conflitos de versão. Se você executar vários processos que precisam de duas versões da mesma biblioteca no mesmo espaço de usuário e sistema de arquivos, precisará ajustar pelo menos LDPATH para cada processo, para que a biblioteca apropriada seja encontrada primeiro e algumas bibliotecas não possam ser ajustadas dessa maneira, como o caminho deles é codificado no executável no momento da compilação, consulte esta pergunta para mais detalhes.
No nível da rede, você precisará configurar cada processo para evitar o uso das mesmas portas.

A execução de vários processos no mesmo contêiner exige alguns ajustes pesados ​​e, no final do dia, derrota o objetivo de isolamento, se você estiver apto a executar múltiplos processos no mesmo espaço de usuário, compartilhando o mesmo sistema de arquivos e recursos de rede, por que não executá-los? no próprio host?

Aqui está a lista não exaustiva dos pesados ​​ajustes / armadilhas em que consigo pensar:

  • Manipulando os logs

    Estar com um volume montado ou intercalado no stdout, isso traz algum gerenciamento. Se usar um volume montado, seu contêiner deve ter seu próprio "local" no host ou dois contêineres iguais lutarão pelo mesmo recurso. A intercalação no stdout para tirar proveito docker logsdisso pode se tornar um pesadelo para análise, se as fontes não puderem ser identificadas facilmente.

  • Cuidado com os processos zumbis

    Se um de seu processo ocorrer em uma falha de contêiner, a supervisord poderá não conseguir limpar os filhos em um estado de zumbi, e o init do host nunca os herdará. Depois de esgotar o número de pids disponíveis (2 ^ 22, aproximadamente 4 milhões), um monte de coisas irá falhar.

  • Separação de preocupações

    Se você executar duas coisas separadas, como um servidor apache e um logstash no mesmo contêiner, isso pode facilitar o manuseio do log, mas você deverá encerrar o apache para atualizar o logstash. (Na realidade, você deve usar o driver de log do Docker) Será uma parada agradável para aguardar o término ou não das sessões atuais? Se for uma parada agradável, pode demorar um pouco e demorar muito para lançar a nova versão. Se você matar, afetará os usuários de um remetente de logs e isso deve ser evitado no IMHO.

Finalmente, quando você tem vários processos, está reproduzindo um sistema operacional e, nesse caso, o uso de uma virtualização de hardware parece mais compatível com essa necessidade.

Tensibai
fonte
3
Acho esses argumentos não convincentes. Há uma enorme diferença entre um processo com vários contêineres e em execução no host. Embora a explicação da intenção original dos contêineres seja um pouco relevante, não é realmente um motivo convincente para evitar contêineres com vários processos. IOW, você está respondendo "por que não" com "por que sim", o que não é tão útil quanto poderia ser. Pode ser muito conveniente executar vários processos no mesmo contêiner - é por isso que sim. O porquê não deve ser explicado.
precisa saber é o seguinte
1
Você não elaborou o tipo de ajuste que tinha em mente. E você não defendeu que esse ajuste é mais trabalhoso do que configurar vários contêineres. Vamos dar um exemplo concreto: muitas vezes você vê imagens de janela de encaixe empacotadas que têm supervisord executando algum processo principal e algum processo auxiliar. Isso é muito fácil de configurar; indiscutivelmente tão fácil quanto separar os recipientes. por exemplo, aplicativo e expedidor de logs. Portanto, creio que o ônus é de sua parte, argumentar por que não é esse o caso.
Assaf Lavie
1
BTW, acredito que existem argumentos válidos contra contêineres com vários processos, mas você não mencionou nenhum deles. Mas, de qualquer forma, está longe de ser um caso claro. Em alguns casos, é perfeitamente aceitável permitir mais de um processo. Heck, algumas imagens muito populares geram vários subprocessos - isso também é ruim? O que estou dizendo é que existem compensações e sua resposta mostra uma imagem unilateral que carece de nuances e detalhes.
Assaf Lavie
1
interessante ... Parece que temos uma opinião semelhante (idêntica) sobre isso. Talvez você devesse ignorá-lo neste caso, porque era de alguém que queria ganhar o distintivo Critic ... e decidiu abusar da sua resposta para obtê-lo ...
Pierre.Vriens
1
Não me apresso à conclusão ... apenas recomendo que você a ignore. Mas "você" não pode mudar de idéia sobre o que vi com meus próprios olhos sobre quem é o defensor anônimo da sua resposta. De qualquer forma, é hora de seguir em frente ...
Pierre.Vriens
6

Como na maioria dos casos, não é tudo ou nada. A orientação de "um processo por contêiner" decorre da idéia de que os contêineres devem servir a um propósito distinto. Por exemplo, um contêiner não deve ser um aplicativo Web e um servidor Redis.

Há casos em que faz sentido executar vários processos em um único contêiner, desde que ambos suportem uma única função modular.

Dave Swersky
fonte
2

O processo que chamarei como serviço aqui, 1 contêiner ~ 1 serviço , se algum dos meus serviços falhar, apenas girarei o contêiner respectivo e, em segundos, tudo estará novamente em funcionamento. Portanto, não haverá dependências entre os serviços. É uma prática recomendada manter o tamanho do seu contêiner menor que 200 MB e máximo de 500 MB (a exceção dos contêineres nativos do Windows tem mais de 2 GB). Caso contrário, será semelhante à máquina virtual, não exatamente, mas o desempenho é suficiente. Além disso, leve em consideração alguns parâmetros como dimensionamento, como eu poderia tornar meus serviços resilientes, implantar automaticamente etc.

Além disso, é sua decisão a escolha de como fazer seus padrões arquiteturais, como microsserviço em ambiente de poligonais, usando a tecnologia de contêineres que melhor se adapta ao seu ambiente e automatizará as coisas para você.

mohan08p
fonte