Como implantar corretamente ao usar a opção de desenvolvimento / produção do Composer?

180

O Composer tem a opção de carregar várias dependências apenas enquanto estiver em desenvolvimento, para que as ferramentas não sejam instaladas na produção (no servidor ativo). Isso é (em teoria) muito útil para scripts que só fazem sentido no desenvolvimento, como testes, ferramentas de dados falsos, depurador etc.

O caminho a seguir é adicionar um require-devbloco adicional com as ferramentas necessárias no dev:

"require-dev": {
    "codeception/codeception": "1.6.0.3"
}

e depois (teoricamente) carregue essas dependências via

composer install --dev

Problema e pergunta:

O Composer mudou dramaticamente o comportamento de installe, updateem 2013, as require-devdependências agora estão instaladas por padrão (!), Sinta-se à vontade para criar um composer.json com um require-devbloco e execute um composer installpara reproduzir.

Como a maneira mais aceita de implantar é empurrar o compositor. lock (que mantém sua configuração atual do compositor) e, em seguida, executa um composer installno servidor de produção, isso também instalará o material de desenvolvimento.

Qual é a maneira correta de implantar isso sem instalar as dependências -dev?

Nota: Estou tentando criar uma pergunta / resposta canônica aqui para esclarecer a implantação estranha do Composer. Sinta-se livre para editar esta pergunta.

Sliq
fonte
@all: Não sei onde está a recompensa :( Vou começar outra abordagem.
Sliq
1
Se você não o premiar ativamente, e nenhuma resposta for aceita ou houver votos suficientes, ninguém recebe a recompensa.
Sven
2
Eu pessoalmente não gosto dessa abordagem. A composer.locknunca deve ser adicionado ao repositório Git, NUNCA. A abordagem correta é usar a atualização do compositor na preparação e sincronizar o arquivo na produção (se tudo funcionar, é claro). A preparação deve ser a cópia exata de um ambiente de produção. composer.lockdeve fazer parte .gitignore.
noun
6
O composer.lock definitivamente deve ser incluído no seu CSV !!! De que outra forma você garante que todos usem a mesma versão? NUNCA exclua o composer.lock do seu CSV !!!
Tobias Gaertner
3
@TobiasGaertner Acho que você quer dizer VCS (software de controle de versão), mas, caso contrário, você está correto e alinhado com as recomendações oficiais do projeto .
Xiong Chiamiov

Respostas:

327

Por quê

Há IMHO uma boa razão para o Composer usar a --devbandeira por padrão (na instalação e atualização) hoje em dia. O compositor é executado principalmente no cenário em que este é o comportamento desejado:

O fluxo de trabalho básico do Composer é o seguinte:

  • Um novo projeto é iniciado: composer.phar install --dev :, json e arquivos de bloqueio são confirmados no VCS.
  • Outros desenvolvedores começam a trabalhar no projeto: checkout do VCS e composer.phar install --dev .
  • Um desenvolvedor adiciona dependências:, composer.phar require <package>adicione--dev se desejar o pacote na require-devseção (e confirme).
  • Outros vão junto: (checkout e) composer.phar install --dev .
  • Um desenvolvedor deseja versões mais recentes de dependências: composer.phar update --dev <package> (e confirmação).
  • Outros vão junto: (checkout e) composer.phar install --dev .
  • O projeto está implantado: composer.phar install --no-dev

Como você pode ver o --dev sinalizador é usado (muito) mais do que o --no-devsinalizador, especialmente quando o número de desenvolvedores trabalhando no projeto aumenta.

Implantação de produção

Qual é a maneira correta de implantar isso sem instalar as dependências "dev"?

Bem, o arquivo composer.jsone composer.lockdeve estar comprometido com o VCS. Não omitacomposer.lock pois contém informações importantes sobre as versões do pacote que devem ser usadas.

Ao executar uma implementação de produção, você pode passar o --no-devsinalizador para o Composer:

composer.phar install --no-dev

O composer.lockarquivo pode conter informações sobre pacotes dev. Isso não importa. o--no-dev sinalizador garantirá que esses pacotes dev não estejam instalados.

Quando digo "implantação de produção", quero dizer uma implantação destinada a ser usada na produção. Não estou discutindo se isso composer.phar installdeve ser feito em um servidor de produção ou em um servidor intermediário, onde as coisas podem ser revisadas. Esse não é o escopo desta resposta. Estou apenas apontando como composer.phar installinstalar as dependências "dev".

Fora do assunto

O --optimize-autoloadersinalizador também pode ser desejável na produção (ele gera um mapa de classe que acelerará o carregamento automático no seu aplicativo):

composer.phar install --no-dev --optimize-autoloader

Ou quando a implantação automatizada for concluída:

composer.phar install --no-ansi --no-dev --no-interaction --no-plugins --no-progress --no-scripts --no-suggest --optimize-autoloader

Se a sua base de código suporta, você pode trocar --optimize-autoloaderpara --classmap-authoritative. Mais informações aqui

Jasper N. Brouwer
fonte
5
Eu concordo com a maioria do que é dito com uma exceção. A "instalação do compositor --no-dev" deve ser executada apenas em um ambiente intermediário e esse ambiente deve ser considerado imutável. Eu não gostaria de ter nenhuma dependência baixada diretamente no meu servidor de produção e sem passar pela visualização / preparação. Isso é apenas um pouco mais de cautela.
Escalável
3
@ Escalável: Embora eu concorde com você (e Sven cubra isso muito bem em sua resposta), esse não é o escopo da minha resposta, e não o que eu quis dizer com "implantação de produção". Eu adicionei um parágrafo para deixar isso claro.
Jasper N. Brouwer
5
Na verdade, acho que o padrão deve ser a opção menos perigosa. Tornar --dev o padrão e acidentalmente instalar um compositor na produção pode ser fatal.
Hector Ordonez
3
Bom ponto no --optimize-autoloader. Considere também --classmap-authoritative- Na documentação aqui, getcomposer.org/doc/03-cli.md, você pode ver o seguinte: "Carregar automaticamente classes apenas do mapa de classes. Ativa implicitamente --optimize-autoloader" para que você possa usar se conhecer as classes " there ", o que provavelmente deve acontecer em seu ambiente de prod, a menos que você gere classes dinamicamente.
Xavi Montero
6
Ótima resposta, eu sugeriria a adição optimize-autoloaderdireta no composer.json:{"config": { "optimize-autoloader": true } }
Yvan
79

Na verdade, eu recomendo CONTRA a instalação de dependências no servidor de produção.

Minha recomendação é fazer check-out do código em uma máquina de implantação, instalar dependências conforme necessário (isso inclui NÃO instalar dependências de desenvolvimento se o código for produzido) e depois mover todos os arquivos para a máquina de destino.

Por quê?

  • na hospedagem compartilhada, talvez você não consiga acessar uma linha de comando
  • mesmo se você tiver, o PHP pode ser restrito a ele em termos de comandos, memória ou acesso à rede
  • É provável que as ferramentas CLI do repositório (Git, Svn) não sejam instaladas, o que falharia se o seu arquivo de bloqueio registrasse uma dependência para fazer o checkout de uma certa confirmação em vez de fazer o download dessa confirmação como ZIP (você usou --prefer-source ou Composer tinha nenhuma outra maneira de obter essa versão)
  • se sua máquina de produção é mais como um pequeno servidor de teste (pense na micro instância do Amazon EC2), provavelmente não há nem memória suficiente instalada para executar composer install
  • enquanto o compositor tenta interromper as coisas, como você se sente ao terminar com um site de produção parcialmente quebrado porque alguma dependência aleatória não pôde ser carregada durante a fase de instalação do Composers

Resumindo: use o Composer em um ambiente que você possa controlar. Sua máquina de desenvolvimento está qualificada porque você já possui todas as coisas necessárias para operar o Composer.

Qual é a maneira correta de implantar isso sem instalar as dependências -dev?

O comando a ser usado é

composer install --no-dev

Isso funcionará em qualquer ambiente, seja o próprio servidor de produção ou uma máquina de implantação ou a máquina de desenvolvimento que deve fazer uma última verificação para descobrir se algum requisito de desenvolvedor é usado incorretamente para o software real.

O comando não instalará ou desinstalará ativamente os requisitos de desenvolvimento declarados no arquivo composer.lock.

Se você não se importa de implantar componentes de software de desenvolvimento em um servidor de produção, a execução composer installfaria o mesmo trabalho, mas simplesmente aumentaria a quantidade de bytes movimentados e também criaria uma declaração maior do carregador automático.

Sven
fonte
14
Fluxo de trabalho interessante, mas há uma grande desvantagem : os repositórios nunca devem conter a própria pasta / conteúdo do fornecedor (declarações oficiais na página Composer); portanto, eles nunca serão enviados diretamente à produção em uma implantação baseada em git (que é um padrão comum, Corrija-me se eu estiver errado). Então, basicamente, a solução acima funciona apenas com a implantação de FTP "old-school"! Por favor, vamos discutir isso melhor ...
SliQ
17
Meu fluxo de trabalho sugerido não inclui enviar o código via GIT para o servidor de produção. Na verdade, eu recomendaria não, porque isso o forçará a instalar dependências do Composer no servidor de produção, o que pode trazer vários problemas. Se você deseja que sua implantação funcione sem problemas, é necessário reunir todo o código necessário para executar o aplicativo antes de destruir a versão atual e substituí-la. Não gosta de FTP? Faça o RSync via SSH e alterne as versões lançando um link simbólico. Mas você também pode instalar por push, checkout e compositor em prod, se quiser.
Sven
2
@ Panique: Acabei de ver essa parte do seu comentário e tenho que responder: "enviado à produção em uma implantação baseada em git (que é um padrão comum, me corrija se estiver errado)" - Não, isso não é um padrão comum. É apenas uma maneira de fazê-lo.
Sven
1
A equipe em que integrou incorporou isso ao seu fluxo de trabalho com grande sucesso. Temos uma máquina de compilação (Jenkins, é claro) que: 1) faz check-out do SC 2) executa a instalação / atualização do compositor 3) executa testes de unidade 4) remove as dependências do dev 5) gera um arquivo phar ( app-1.34.pharetc). Há um mecanismo separado que é notificado e decide quando pegar esse arquivo, para onde transferi-lo e o que fazer com ele. Algumas equipes optam por descompactar o phar uma vez que está no servidor e algumas equipes o executam como estão. Isso deu muita confiança à estabilidade e à reprodutibilidade de nossas implantações.
Josh Johnson
3
Eu concordo 100% com esta resposta. O Composer não deve ser instalado no servidor de implantação, nem o git. Servidores de implantação / Intergration contínuas são exatamente suposto para gerenciar a fonte e dependências ir buscar: instalar git pull> compositor> deploy
Eric MORAND
4

Agora require-devestá ativado por padrão, para desenvolvimento local, você pode fazer composer installe composer updatesem a --devopção

Quando você deseja implantar na produção, verifique se composer.locknão possui nenhum pacote proveniente require-dev.

Você pode fazer isso com

composer update --no-dev

Depois de testar localmente, --no-devvocê pode implantar tudo na produção e instalação com base no composer.lock. Você precisa da --no-devopção novamente aqui, caso contrário, o compositor dirá "O arquivo de bloqueio não contém informações requer-dev" .

composer install --no-dev

Nota: Tenha cuidado com qualquer coisa que possa introduzir diferenças entre dev e produção! Geralmente, tento evitar o require-dev sempre que possível, pois incluir ferramentas de desenvolvimento não é uma grande sobrecarga.

dave1010
fonte
1
Na verdade, isso está incorreto nos detalhes. Não há necessidade de verificar composer.lockdependências de desenvolvimento. Você simplesmente executaria composer install --no-deve obteria apenas as dependências regulares instaladas - na verdade, o Composer também removerá todas as dependências de desenvolvimento nesta etapa.
Sven
Se meu local composer.locktivesse dependências de dev (e potencialmente afetasse as versões dos pacotes não-dev), eu gostaria de atualizá-lo para refletir como seria na produção. Isso também força você a executar a composer install --no-devprodução, como composer installocorrerá um erro. Tecnicamente, acho que você está certo; isso não é necessário, mas é um nível extra de segurança, do que eu gosto.
dave1010
Ok, cenário de demonstração: seu aplicativo requer dev/toole prod/lib:~1.0. O mais recente prod / lib é 1.3, mas o dev / tool também exige prod/lib:1.1.*. Resultado: você instalará a versão 1.1.9 (a mais nova da ramificação 1.1.x) e a utilizará durante o seu desenvolvimento. Eu diria que NÃO é seguro atualizar apenas --no-dev, portanto, inclua o mais recente prod / lib 1.3 e assuma que tudo funciona sem teste. E talvez o teste seja impossível por causa da falta de dev / tool. Eu diria que, como o dev / tool não é necessário na produção, ele não deve ser lançado, mas o software deve usar o prod / lib 1.1.9.
Sven
Se você estiver usando --no-dev, precisará testá-lo localmente, como mencionei na resposta. Eu ainda recomendaria não usar --no-devnada.
Dave1010
Então, basicamente, você sugere o seguinte composer update:, faça algum desenvolvimento, composer update --no-devfaça o teste de lançamento, empurre para produção e faça composer install --no-dev. Dois problemas: 1. Não consigo testar o lançamento sem dependências de desenvolvimento e 2. Não consigo instalar o Git, por exemplo, em produção.
Sven
3

Nos servidores de produção, renomeio vendorparavendor-<datetime> , e durante a implantação terá dois diretórios de fornecedores.

Um cookie HTTP faz com que meu sistema escolha o novo fornecedor autoload.php e, após o teste, faço uma alternância totalmente atômica / instantânea entre eles para desativar o diretório antigo do fornecedor para todas as solicitações futuras e, em seguida, excluo o diretório anterior alguns dias depois.

Isso evita qualquer problema causado pelos caches do sistema de arquivos que estou usando no apache / php e também permite que qualquer código PHP ativo continue usando o diretório do fornecedor anterior.


Apesar de outras respostas recomendarem, eu pessoalmente corro composer install no servidor, pois é mais rápido que o rsync da minha área de preparação (uma VM no meu laptop).

Eu uso --no-dev --no-scripts --optimize-autoloader. Você deve ler os documentos de cada um para verificar se isso é apropriado em seu ambiente.

Abhi Beckert
fonte
2

Eu acho que é melhor automatizar o processo:

Adicione o arquivo composer.lock no seu repositório git, certifique-se de usar o composer.phar install --no-dev ao liberar, mas na sua máquina dev você poderia usar qualquer comando do compositor sem preocupações, isso não irá para a produção. a produção baseará suas dependências no arquivo de bloqueio.

No servidor, você faz o check-out dessa versão ou etiqueta específica e executa todos os testes antes de substituir o aplicativo, se os testes passarem, você continuará a implantação.

Se o teste depender das dependências do desenvolvedor, pois o compositor não possui uma dependência do escopo do teste, uma solução não muito elegante pode ser executada com as dependências do desenvolvedor ( instalação do composer.phar ), remova a biblioteca do fornecedor, execute o compositer.phar install - -no-dev novamente, isso usará dependências em cache, portanto é mais rápido. Mas isso é um truque, se você conhece o conceito de escopos em outras ferramentas de construção

Automatize isso e esqueça o resto, vá beber uma cerveja :-)

PS .: Como no comentário do @Sven abaixo, não é uma boa ideia não fazer check-out do arquivo composer.lock, porque isso fará com que a instalação do compositor funcione como atualização do compositor.

Você pode fazer essa automação com http://deployer.org/ , é uma ferramenta simples.

Giovanni Silva
fonte
2
Não cometer e verificar composer.lockfará composer installagir como composer update. Portanto, as versões que você implanta não são as que você desenvolveu. É provável que isso gere problemas (e mais ainda à luz do único problema de segurança resolvido recentemente com "replace" no Composer). Você nunca deve executar composer updateautônoma sem verificar se não quebrou nada.
Sven
1
@ Mesmo assim, é uma sugestão no mesmo comentário para executar testes de unidade automaticamente antes da implantação. Mas você está certo, é melhor manter o arquivo composer.lock de qualquer maneira.
Giovanni Silva
Agora, a única coisa que você precisaria explicar: Como você executa os testes no servidor sem as dependências de desenvolvimento como PHPUnit?
Sven
Seria muito bom se dependências, testes e implantação fossem colocados juntos em uma ferramenta, como Java Gradle ou SBT ou mesmo Maven (o maven não é tão bom). Uma ferramenta PHP que faz com que a phpunit e a implantação do compositor funcionem juntas. Ou mesmo um plug-in Gradle ou Scala SBT para fazer isso, como são ferramentas de construção agnósticas, o plug-in pode até funcionar com recursos como minimizar javascript e compilar sass, minimizar css. Alguém sabe alguma coisa?
Giovanni Silva
1
É claro que isso é feito no servidor para testar o ambiente real, mas não diretamente no vhost do site, você pode fazer isso em uma pasta temporária separada e mover o resultado para o vhost quando for bem
Giovanni Silva