Cómo configurar un entorno de desarrollo PHP para integración continua Dockerizada
Gratuito. Debo poder eliminar y crear nuevos entornos a voluntad.
Inicio rápido. Cuando quiero usarlo, está disponible inmediatamente.
Fácil de actualizar. Las cosas cambian muy rápidamente en nuestra industria, por lo que tengo que poder actualizar fácilmente mi entorno de desarrollo a nuevas versiones de software.
Y Docker admite todas estas funciones y más. Puede destruir y reconstruir contenedores casi instantáneamente, y actualizar su entorno es tan simple como reconstruir la imagen que está utilizando actualmente.
Qué es un entorno de desarrollo PHP
Debido a la complejidad de las aplicaciones web actuales, un entorno de desarrollo PHP requiere muchas cosas y es necesario establecer varias restricciones para mantener el entorno sencillo.
En esta ocasión utilizamos Nginx, PHP5-FPM y MySQL para ejecutar el proyecto Synmfony. Debido a la complejidad de ejecutar la línea de comando en un contenedor, dejaré este aspecto para la próxima publicación del blog.
Mascotas y vacas
Otro punto de discusión es si queremos implementar el entorno de desarrollo en múltiples contenedores o en un solo contenedor. Ambos enfoques tienen ventajas:
Un único contenedor es fácil de distribuir y mantener. Al ser independientes, todo se ejecuta en el mismo contenedor, que es como una máquina virtual. Pero esto también significa que cuando quieras actualizar algo (como una nueva versión de PHP), necesitarás reconstruir todo el contenedor.
Múltiples contenedores proporcionan una mejor modularidad al agregar componentes. Debido a que cada contenedor contiene parte de la pila: Web, PHP, MySQL, etc., cada servicio se puede ampliar o agregar individualmente sin tener que reconstruir todo.
Como soy vago y necesito algo más en mi portátil, lo haremos con un solo contenedor.
Inicializando el proyecto
Lo primero que debemos hacer es inicializar un nuevo proyecto Symfony. El método recomendado es utilizar el comando crear proyecto del compositor. También es posible instalar Composer en la estación de trabajo, pero es demasiado sencillo. Esta vez lo usaremos a través de Docker.
Anteriormente publiqué un artículo sobre los comandos de Docker: crear comandos de Docker (Está bien, mentí, originalmente lo puse en este artículo, pero luego pensé que era mejor enumerarlo por separado. Es mejor publicarlo). ).
De todos modos, puedes leerlo. A continuación, puedes crear tu propio alias de compositor si aún no tienes uno.
$ alias compositor="docker run -i -t -v \$PWD:/srv ubermuda/composer"
Ahora puedes inicializar el proyecto Symfony:
$ compositor crear-proyecto symfony/ framwork-standard-edition SomeProject
¡Impresionante! Comienza el verdadero trabajo. (Un montón de tonterías ensimismadas omitidas en el blog.... Texto original: Genial. Choca esos cinco, toma una taza de café o el remedio líquido que prefieras y prepárate para ponerte manos a la obra.) p>
Contenedor
Construir un contenedor independiente que ejecute un proyecto estándar de Symfony es muy fácil de construir.
Todo lo que necesita hacer es instalar los habituales Nginx, PHP5-FPM y MySQL-Server, colocar los archivos de configuración del host virtual Nginx preparados previamente, copiar algunos archivos de configuración y listo.
El código fuente del contenedor se encuentra en el repositorio ubermuda/docker-symfony en GitHub. Dockerfile es el archivo de configuración utilizado por Docker para crear imágenes, echemos un vistazo:
De Debian: wheezy
ENV DEBIAN_FRONTEND no interactivo
EJECUTAR apt-get update -y
EJECUTAR apt-get install -y nginx php5-fpm php5-mysqlnd php5-cli mysql-server supervisor
EJECUTAR sed -e 's/;daemonize = yes/daemonize = no/' -i /etc/ php5/fpm/php-fpm.group/listen.group/' -i /etc/php5/fpm/pool.d/www.conf
EJECUTAR sed -e 's/ ;escuchar\.owner/listen.owner/' -i /etc/php5/fpm/pool.d/www.conf
EJECUTAR echo "\ndaemon off;" /nginx.conf
AÑADIR vhost.conf /etc/nginx/sites-available/default
AÑADIR supervisor.conf /etc/supervisor/conf.d/supervisor.conf p>
AÑADIR init.sh /init.sh
EXPOSE 80 3306
VOLUMEN ["/srv"]
WORKDIR /srv
CMD["/usr/bin/supervisord"]
Primero ampliamos la imagen base debian:wheezy y luego usamos una serie de comandos sed para configurar Nginx y PHP5-FPM.
EJECUTAR sed -e 's/;daemonize = yes/daemonize = no/' -i /etc/php5/fpm/php-fpm.conf
EJECUTAR sed -e ' s/;listen\.owner /listen.owner/' -i /etc/php5/fpm/pool.d/www.
EJECUTAR sed -e 's/;listen\.group/listen. grupo/' -i /etc/php5/fpm/pool.d/www.conf
EJECUTAR echo "\ndaemon off;" gt;gt;
Aquí tenemos que hacer dos cosas. Primero, configure PHP5-FPM y Nginx para que se ejecuten en primer plano para que el supervisor pueda rastrearlos.
Luego, configure PHP5-FPM para ejecutar el servidor web como el usuario especificado, prestando atención a los permisos de los archivos.
A continuación, debe instalar un conjunto de archivos de configuración, comenzando con el archivo de configuración del host virtual de Nginx, vhost.conf:
servidor {
escucha 80 <; /p>
nombre_servidor _;
access_log /var/log/nginx /access.log;
error_log /var/log/nginx/error.log; >
raíz /srv/web;
índice app_dev.php;
ubicación / {
try_files $uri $uri/ /app_dev.php? $query_string
}
ubicación ~ [^/]\.php(/|$) {
fastcgi_pass unix:/var/run/php5- fpm.sock;
incluye fastcgi_params;
}
}
Como no necesitamos un nombre de dominio, configuramos server_name a _ (Algo similar a la variable de marcador de posición $_ de Perl) y configure el directorio raíz (directorio raíz de documentos) en /srvr/web. Implementaremos la aplicación en /srv y el resto es una configuración estándar PHP5-FPM de Mginx.
Dado que el contenedor solo puede ejecutar un programa a la vez, necesitamos usar supervisord (o cualquier otro administrador de procesos, pero prefiero usar supervisord). ¡Afortunadamente, este administrador de procesos generará todos los procesos que necesitamos! php5-fpm]
command=/usr/sbin/php5-fpm
[programa: mysql]
command=/usr/bin/mysqld_safe p> p>
[programa:init]
command=/init.
autorestart=false
redirect_stderr=true
redirect_stdout =/srv/app/logs/init.log
Lo que debemos hacer aquí es definir todos los servicios y un programa especial: el proceso de inicio. Este proceso no es un servicio real, pero se ejecuta. el script de inicio. Una forma primitiva.
El problema con este script de inicio es que normalmente requiere que algunos servicios se inicien primero. Por ejemplo, es posible que desee inicializar algunas tablas de la base de datos, pero sólo después de ejecutar MySQL primero. Una posible solución es iniciar MySQL en el script de inicio, luego inicializar las tablas, luego, para evitar interferencias con la gestión de procesos del supervisor, detener MySQL y finalmente iniciar supervisor.
Un script de este tipo tendría el siguiente aspecto:
/etc/init.d/mysql start
app/console doctrina:schema:update --force
/etc/init.d/mysql stop
exec/usr/bin/supervisord
Se ve feo, hagamos lo contrario, dejemos que el supervisor se ejecute y nunca reiniciarlo.
El script init.sh real tiene este aspecto:
#! /bin/bash
RET=1
mientras [[ RET -ne 0 ]]]; hacer
dormir 1;
mysql -e 'salir' gt; /dev/null 2gt; amp; RET=$?
hecho
DB_NAME=${DB_NAME:-symfony}
mysqladmin -u root crea $DB_NAME
si [ -n "$INIT" ] entonces
/srv/$INIT
fi; p>
El script espera a que se inicie MySQL, luego crea la base de datos basada en la variable de entorno DB_NAME (el valor predeterminado es Symfony), luego busca el script para ejecutar en la variable de entorno INIT e intenta ejecutarlo. Al final de este artículo se explica cómo utilizar estas variables de entorno.
Crear y ejecutar imágenes
Comenzar es difícil. También necesitamos construir la imagen de Symfony Docker usando el comando docker build:
$ cd docker-symfony
$ docker build -t symfony.
Ahora Puedes usarlo para ejecutar tu proyecto Symfony:
$ cd SomeProject
$ docker run -i -t -P -v $PWD:/srv symfony
Veamos qué hace esta lista de opciones:
-i inicia el modo interactivo, lo que significa que STDIO (entrada y salida estándar) se conectará a su terminal actual. Es útil cuando desea recibir registros o enviar señales a un proceso.
-t crea un TTY virtual para el contenedor, generalmente usado junto con -i.
-P le dice al demonio Docker que anuncie todos los puertos especificados, en este caso el puerto 80.
-v $PWD:/srv Monta el directorio actual en el directorio /srv del contenedor. Montar un directorio hace que el contenido del directorio esté disponible en el punto de montaje de destino.
Ahora todavía recuerdas las variables de entorno DB_NAME e INIT mencionadas anteriormente, su función es: personalizar el entorno. Básicamente, puedes usar la opción -e de Docker Run para establecer variables de entorno en el contenedor y el script de inicio las recogerá, por lo que si tu base de datos se llama some_project_dev, puedes ejecutar el contenedor de esta manera:
$ docker run -i -t -P -v $PWD:/srv -e DB_NAME= some_project_dev Symfony
La variable de entorno INIT es más poderosa y le permite ejecutar un script específico al inicio.
Por ejemplo, tiene un script bin/setup que ejecuta el comando de instalación del compositor y establece el esquema de la base de datos:
#! /bin/bash
instalación del compositor
aplicación/consola doctrina:schema:update --force
Ejecutar con -e:
$ ventana acoplable ejecutar -i -t -P \
-v $PWD:/srv \
-e DB_NAME=some_project_dev \
-e INIT=bin /setup
Tenga en cuenta que la opción -e se puede usar varias veces en una ejecución de Docker y se ve bien. Además, el script de inicio requiere permisos ejecutables (chmod x).
Ahora, enviemos una solicitud al contenedor mediante curl para comprobar que todo está funcionando como se esperaba. Primero, necesitamos usar el comando docker port para obtener el puerto público **** asignado por Docker al puerto 80 del contenedor:
$ docker port $(docker ps -aql 1) 80
0.0 .0.0: 49153
docker ps -aql 1 es un buen comando para usar. En nuestro ejemplo, Docker asigna el puerto 80 del contenedor al puerto 49153. En nuestro ejemplo, Docker asigna el puerto 80 del contenedor al puerto 49153. Corramos curl y veamos.
$ curl http://localhost:49153
No puedes acceder al archivo. Consulte app_dev.php para obtener más información.
Cuando no obtenemos la identificación del contenedor de localhost, la identificación del contenedor se asignará al puerto 49153.
Cuando no obtenemos la identificación del contenedor de localhost, la identificación del contenedor se asignará al puerto 49153. (Es completamente normal recibir el mensaje de error predeterminado de Symfony sin acceder al controlador de desarrollo desde localhost, ya que no enviamos solicitudes curl desde el interior del contenedor, por lo que eliminar estas líneas del controlador de front-end web/app_dev.php es seguro.
// Esta verificación evita que el controlador frontal de depuración se implemente accidentalmente en el servidor de producción.
// No dude en eliminarlo, ampliarlo o crear una funcionalidad más compleja.
if (isset($_SERVER['HTTP_CLIENT_IP'])
|| isset($_SERVER['HTTP_X_FORWARDED_FOR '])
|| !( in_array (@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1'))|| php_sapi_name() === 'cli-server')
){
header(' HTTP/1.0 403 Prohibido');
exit('No tienes permiso para acceder a este archivo. Para obtener más información, consulta'. basename(__FILE__).');
}
Estas líneas impiden cualquier acceso al controlador de desarrollo desde fuera de localhost.
Ahora usa curl nuevamente o usa tu navegador para visitar http://localhost:.49153/:
Eso es fácil, ¿verdad? Ahora podemos activar y actualizar entornos rápidamente, pero todavía hay mucho margen de mejora.