¿Cómo implementar correctamente cuando se usa el interruptor de desarrollo / producción de Composer?

180

Composer tiene la opción de cargar varias dependencias solo mientras está en desarrollo, por lo que las herramientas no se instalarán en producción (en el servidor en vivo). Esto es (en teoría) muy útil para los scripts que solo tienen sentido en el desarrollo, como pruebas, herramientas de datos falsos, depurador, etc.

El camino a seguir es agregar un require-devbloque adicional con las herramientas que necesita en dev:

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

y luego (teóricamente) cargar estas dependencias a través de

composer install --dev

Problema y pregunta:

Composer ha cambiado el comportamiento de forma dramática instally updateen 2013, las require-devdependencias ahora están instaladas por defecto (!), Siéntase libre de crear un composer.json con un require-devbloque y ejecutar un composer installpara reproducir.

Como la forma más aceptada de implementar es presionar al compositor. bloquear (que contiene la configuración actual de su compositor) y luego hacer un composer installen el servidor de producción, esto también instalará las cosas de desarrollo.

¿Cuál es la forma correcta de implementar esto sin instalar las dependencias -dev?

Nota: Estoy tratando de crear un Q / A canónico aquí para aclarar la extraña implementación de Composer. Siéntase libre de editar esta pregunta.

Sliq
fuente
@todos: No sé dónde está la recompensa :( Comenzaré otro enfoque.
Sliq
1
Si no lo otorga activamente, y no se acepta ninguna respuesta o recibe suficientes votos a favor, nadie obtiene la recompensa.
Sven
2
Personalmente no me gusta este enfoque en absoluto. El composer.locknunca debe agregarse al repositorio de Git, NUNCA. El enfoque correcto es utilizar la actualización del compositor en la preparación y luego sincronizar el archivo en producción (si todo funciona, por supuesto). La puesta en escena debe ser la copia exacta de un entorno de producción. composer.lockdebe ser parte de .gitignore.
sustantivo el
66
¡composer.lock definitivamente debe incluirse en su CSV! ¿De qué otra manera te aseguras de que todos usen la misma versión? ¡¡¡NUNCA excluya composer.lock de su CSV !!!
Tobias Gaertner
3
@TobiasGaertner Creo que te refieres a VCS (software de control de versiones), pero por lo demás estás en lo correcto y en línea con las recomendaciones oficiales del proyecto .
Xiong Chiamiov

Respuestas:

327

Por qué

En mi humilde opinión, hay una buena razón por la cual Composer usará la --devbandera de forma predeterminada (en instalación y actualización) hoy en día. Composer se ejecuta principalmente en escenarios donde este es el comportamiento deseado:

El flujo de trabajo básico de Composer es el siguiente:

  • Se inicia un nuevo proyecto: los composer.phar install --devarchivos json y lock se confirman en VCS.
  • Otros desarrolladores comienzan a trabajar en el proyecto: pago de VCS y composer.phar install --dev.
  • Un desarrollador agrega dependencias: composer.phar require <package>agregue --devsi desea el paquete en la require-devsección (y commit).
  • Otros van a lo largo: (pago y envío) composer.phar install --dev.
  • Un desarrollador quiere nuevas versiones de dependencias: composer.phar update --dev <package>(y commit).
  • Otros van a lo largo: (pago y envío) composer.phar install --dev.
  • El proyecto se implementa: composer.phar install --no-dev

Como puede ver, el --devindicador se usa (mucho) más que el --no-devindicador, especialmente cuando aumenta el número de desarrolladores que trabajan en el proyecto.

Despliegue de producción

¿Cuál es la forma correcta de implementar esto sin instalar las dependencias "dev"?

Bueno, el archivo composer.jsony composer.lockdebe estar comprometido con VCS. No lo omita composer.lockporque contiene información importante sobre las versiones de paquetes que deben usarse.

Al realizar una implementación de producción, puede pasar el --no-devindicador a Composer:

composer.phar install --no-dev

El composer.lockarchivo puede contener información sobre paquetes de desarrollo. Esto no importa La --no-devbandera se asegurará de que esos paquetes de desarrollo no estén instalados.

Cuando digo "despliegue de producción", me refiero a un despliegue destinado a ser utilizado en producción. No estoy discutiendo si se composer.phar installdebe hacer en un servidor de producción o en un servidor de ensayo donde las cosas se pueden revisar. Ese no es el alcance de esta respuesta. Simplemente estoy señalando cómo hacerlo composer.phar installsin instalar dependencias "dev".

Sin relación

El --optimize-autoloaderindicador también puede ser deseable en la producción (genera un mapa de clase que acelerará la carga automática en su aplicación):

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

O cuando se realiza la implementación automatizada:

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

Si su base de código lo admite, puede cambiarlo --optimize-autoloaderpor --classmap-authoritative. Más información aquí.

Jasper N. Brouwer
fuente
55
Estoy de acuerdo con la mayoría de lo que se dice con una excepción. "composer install --no-dev" debe ejecutarse solo en un entorno provisional y ese entorno debe considerarse inmutable. No quisiera tener ninguna dependencia descargada directamente en mi servidor de producción y sin pasar por la vista previa / puesta en escena. Eso es solo un poco más de precaución.
Escalable el
3
@Scalable: aunque estoy de acuerdo con usted (y Sven lo cubre muy bien en su respuesta), ese no es el alcance de mi respuesta, y no lo que quise decir con "despliegue de producción". He agregado un párrafo para aclarar eso.
Jasper N. Brouwer
55
En realidad, creo que el valor predeterminado debería ser la opción menos peligrosa. Hacer que --dev sea el valor predeterminado y accidentalmente hacer una instalación del compositor en producción podría ser fatal.
Hector Ordonez
3
Buen punto en el --optimize-autoloader. Considere también --classmap-authoritative: de la documentación aquí getcomposer.org/doc/03-cli.md puede ver esto: "Clases de carga automática solo desde el mapa de clase. Activa implícitamente --optimize-autoloader" para que pueda usarlo si conoce las clases "son allí ", que probablemente debería ocurrir en su entorno de producción a menos que genere clases dinámicamente.
Xavi Montero
66
Gran respuesta, sugeriría agregar optimize-autoloaderdirectamente en composer.json:{"config": { "optimize-autoloader": true } }
Yvan
79

En realidad, recomendaría encarecidamente CONTRA instalar dependencias en el servidor de producción.

Mi recomendación es verificar el código en una máquina de implementación, instalar dependencias según sea necesario (esto incluye NO instalar dependencias de desarrollo si el código va a producción) y luego mover todos los archivos a la máquina de destino.

¿Por qué?

  • en el alojamiento compartido, es posible que no pueda acceder a una línea de comando
  • incluso si lo hiciera, PHP podría estar restringido allí en términos de comandos, memoria o acceso a la red
  • es probable que las herramientas de la CLI del repositorio (Git, Svn) no se instalen, lo que fallaría si su archivo de bloqueo ha registrado una dependencia para verificar un determinado compromiso en lugar de descargar ese compromiso como ZIP (usted usó --prefer-source, o Composer tenía no hay otra forma de obtener esa versión)
  • Si su máquina de producción se parece más a un pequeño servidor de prueba (piense en la micro instancia de Amazon EC2), probablemente no haya suficiente memoria instalada para ejecutar composer install
  • mientras el compositor intenta no romper cosas, ¿cómo se siente al terminar con un sitio web de producción parcialmente roto porque no se pudo cargar alguna dependencia aleatoria durante la fase de instalación de Compositores?

Larga historia corta: use Composer en un entorno que pueda controlar. Su máquina de desarrollo califica porque ya tiene todas las cosas necesarias para operar Composer.

¿Cuál es la forma correcta de implementar esto sin instalar las dependencias -dev?

El comando a usar es

composer install --no-dev

Esto funcionará en cualquier entorno, ya sea el servidor de producción en sí, o una máquina de implementación, o la máquina de desarrollo que se supone que debe hacer una última verificación para determinar si algún requisito de desarrollo se usa incorrectamente para el software real.

El comando no instalará ni desinstalará activamente los requisitos de desarrollo declarados en el archivo composer.lock.

Si no le importa implementar componentes de software de desarrollo en un servidor de producción, la ejecución composer installharía el mismo trabajo, pero simplemente aumentaría la cantidad de bytes movidos y también crearía una declaración de autocargador más grande.

Sven
fuente
14
Flujo de trabajo interesante, pero hay una gran desventaja : los repositorios nunca deben contener la carpeta / contenido del proveedor en sí (declaraciones oficiales en la página del Compositor), por lo que nunca se los llevará directamente a producción en una implementación basada en git (que es un afaik estándar común, corrígeme si me equivoco). ¡Entonces, básicamente, la solución anterior solo funciona con la implementación FTP "de la vieja escuela"?
Discutamos
17
Mi flujo de trabajo sugerido no incluye enviar el código a través del GIT al servidor de producción. De hecho, recomendaría no hacerlo, ya que hacerlo lo obligará a instalar las dependencias de Composer en el servidor de producción, lo que puede plantear cualquier número de problemas. Si desea que su implementación se ejecute sin problemas, debe reunir todo el código necesario para ejecutar la aplicación antes de destruir la versión actual y reemplazarla. ¿No te gusta el FTP? RSync a través de SSH, luego cambie las versiones volteando un enlace simbólico. Pero también puede presionar, finalizar la compra e instalar el compositor en prod si lo desea.
Sven
2
@Panique: Acabo de ver esa parte de tu comentario y tengo que responder: "empujado a producción en una implementación basada en git (que es un afaik estándar común, corrígeme si estoy equivocado)" - No, esto No es un estándar común. Es solo una forma de hacerlo.
Sven
1
El equipo en el que estoy ha incorporado esto a su flujo de trabajo con gran éxito. Tenemos una máquina de compilación (Jenkins, por supuesto) que: 1) extrae del SC 2) ejecuta la instalación / actualización del compositor 3) ejecuta pruebas unitarias 4) elimina las dependencias del desarrollador 5) genera un archivo phar ( app-1.34.pharetc.). Hay un mecanismo separado que se notifica y decide cuándo tomar ese archivo, a dónde transferirlo y luego qué hacer con él. Algunos equipos optan por desempaquetar el phar una vez que está en el servidor y algunos equipos lo ejecutan tal cual. Ha prestado mucha confianza a la estabilidad y reproducibilidad de nuestros despliegues.
Josh Johnson
3
Estoy de acuerdo al 100% con esta respuesta. Composer no debe instalarse en el servidor de implementación, ni git. Se supone que los servidores de implementación / integración continua administran exactamente la
obtención de
4

Ahora require-devestá habilitado de forma predeterminada, para el desarrollo local puede hacerlo composer instally composer updatesin--dev opción.

Cuando desee implementar en producción, deberá asegurarse de composer.lockque no tenga ningún paquete que provenga derequire-dev .

Puedes hacer esto con

composer update --no-dev

Una vez que haya probado localmente --no-dev, puede implementar todo en producción e instalar segúncomposer.lock . Necesita la --no-devopción nuevamente aquí; de lo contrario, el compositor dirá "El archivo de bloqueo no contiene información de solicitud de desarrollo" .

composer install --no-dev

Nota: ¡ Tenga cuidado con cualquier cosa que tenga el potencial de introducir diferencias entre desarrollo y producción! Generalmente trato de evitar require-dev siempre que sea posible, ya que incluir herramientas de desarrollo no es una gran sobrecarga.

dave1010
fuente
1
Esto es realmente incorrecto en los detalles. No hay necesidad de verificar las composer.lockdependencias de desarrollo. Simplemente ejecutará composer install --no-dev, y obtendrá solo las dependencias regulares instaladas; de hecho, Composer también eliminará cualquier dependencia de desarrollo en este paso.
Sven
Si mi local composer.locktuviera dependencias de desarrollo (y potencialmente afectara las versiones de los paquetes que no son de desarrollo), me gustaría actualizarlo para reflejar cómo estaría en producción. Esto también te obliga a correr composer install --no-deven producción, como lo composer installhará el error. Técnicamente creo que tienes razón; esto no es obligatorio, pero es un nivel adicional de seguridad, que me gusta.
dave1010
Ok, escenario de demostración: su aplicación requiere dev/tooly prod/lib:~1.0. El prod / lib más nuevo es 1.3, pero también se requiere dev / tool prod/lib:1.1.*. Resultado: instalará la versión 1.1.9 (la más nueva de la rama 1.1.x) y la usará durante su desarrollo. Yo diría que NO es seguro simplemente actualizar --no-dev, por lo tanto, incluya el prod / lib 1.3 más nuevo y asuma que todo funciona sin pruebas. Y tal vez las pruebas sean imposibles debido a la falta de desarrollo / herramienta. Supongo que debido a que dev / tool no es necesario en la producción, no debe implementarse, pero el software debe usar prod / lib 1.1.9 entonces.
Sven
Si está usando, --no-deventonces necesita probarlo localmente, como mencioné en la respuesta. Todavía recomiendo no usar --no-deven absoluto.
dave1010
Básicamente, sugieres esto: composer updateluego haz algo de desarrollo, luego hazlo composer update --no-dev, luego haz las pruebas de lanzamiento, luego pasa a producción y hazlo composer install --no-dev. Dos problemas: 1. No puedo probar la versión sin dependencias de desarrollo, y 2. No puedo instalar con, por ejemplo, Git en producción.
Sven
3

En servidores de producción renombre vendoravendor-<datetime> , y durante el despliegue tendrá dos directorios de proveedores.

Una cookie HTTP hace que mi sistema elija el nuevo proveedor autoload.php , y después de probarlo, realizo un cambio totalmente atómico / instantáneo entre ellos para deshabilitar el antiguo directorio del proveedor para todas las solicitudes futuras, luego elimino el directorio anterior unos días después.

Esto evita cualquier problema causado por los cachés del sistema de archivos que estoy usando en apache / php, y también permite que cualquier código PHP activo continúe usando el directorio del proveedor anterior.


A pesar de otras respuestas que recomiendan no hacerlo, personalmente ejecuto composer installen el servidor, ya que esto es más rápido que rsync desde mi área de preparación (una VM en mi computadora portátil).

Yo uso --no-dev --no-scripts --optimize-autoloader. Debe leer los documentos de cada uno para verificar si esto es apropiado para su entorno.

Abhi Beckert
fuente
2

Creo que es mejor automatizar el proceso:

Agregue el archivo composer.lock en su repositorio git, asegúrese de usar composer.phar install --no-dev cuando lo lance, pero en su máquina de desarrollo podría usar cualquier comando composer sin preocupaciones, esto no irá a producción, el Production basará sus dependencias en el archivo de bloqueo.

En el servidor, comprueba esta versión o etiqueta específica y ejecuta todas las pruebas antes de reemplazar la aplicación, si las pruebas pasan, continúa la implementación.

Si la prueba depende de las dependencias del desarrollador, ya que el compositor no tiene una dependencia del alcance de la prueba, se podría ejecutar una solución no muy elegante con las dependencias del desarrollador ( instalación composer.phar ), elimine la biblioteca del proveedor, ejecute la instalación composer.phar - -no-dev nuevamente, esto usará dependencias en caché, por lo que es más rápido. Pero eso es un truco si conoce el concepto de ámbitos en otras herramientas de compilación

Automatiza esto y olvida el resto, ve a tomar una cerveza :-)

PD .: Como en el comentario de @Sven a continuación, no es una buena idea no retirar el archivo composer.lock, porque esto hará que la instalación del compositor funcione como una actualización del compositor.

Podrías hacer esa automatización con http://deployer.org/ es una herramienta simple.

Giovanni Silva
fuente
2
No comprometerse y retirar composer.lockhará composer installactuar como composer update. Entonces, las versiones que implementa no son las que desarrolló. Es probable que esto genere problemas (y más aún a la luz del único problema de seguridad resuelto recientemente con "reemplazar" en Composer). NUNCA debe ejecutarse composer updatedesatendido sin verificar que no haya roto nada.
Sven
1
@Sven, esta es una sugerencia en el mismo comentario para ejecutar pruebas unitarias automáticamente antes de la implementación. Pero tienes razón, es mejor mantener el archivo composer.lock de todos modos.
Giovanni Silva
Ahora, lo único que tendría que explicar: ¿cómo ejecuta las pruebas en el servidor sin las dependencias de desarrollo como PHPUnit?
Sven
Sería muy bueno si las dependencias, las pruebas y la implementación se unieran en una herramienta, como Java Gradle o SBT o incluso Maven (maven no es tan bueno). Una herramienta PHP que hace que el compositor phpunit y la implementación trabajen juntos. O incluso un complemento SBT Gradle o Scala para hacer estas cosas, ya que son herramientas de compilación agnósticas, el complemento incluso podría funcionar con activos como minimizar JavaScript y compilar sass, minimizando css. Alguien sabe algo?
Giovanni Silva
1
Por supuesto, esto se hace en el servidor para probar el entorno real, pero no directamente en el sitio vhost, puede hacerlo en una carpeta temporal separada y mover el resultado al vhost cuando tenga éxito
Giovanni Silva