Guía paso a paso: Configuración del entorno de trabajo con Docker

Introducción

Para todo desarrollo web, es fundamental contar con un entorno de trabajo adecuado que facilite la creación, prueba y despliegue de aplicaciones. Al final lo que necesitamos básicamente es:

  • Un servidor web (Nginx o Apache).
  • Un intérprete de PHP (PHP-FPM).
  • Un sistema de gestión de bases de datos (MySQL, PostgreSQL, etc.).

Existen en el mercado múltiples soluciones para crear este entorno de trabajo.

  1. Instalar cada uno de los componentes por separado en nuestro sistema operativo. Esta opción puede ser complicada y propensa a errores, además de que puede generar conflictos entre versiones de librerías y dependencias.
  2. Utilizar soluciones empaquetadas como XAMPP, WAMP, MAMP, etc. Estas soluciones son más fáciles de instalar, pero pueden ser limitadas en cuanto a personalización. Además no podemos controlar las versiones de los componentes.
  3. Utilizar máquinas virtuales (como Vagrant) o contenedores (como Docker). Estas soluciones permiten crear entornos aislados y reproducibles, facilitando la gestión de dependencias y versiones.
  4. Incluso lavaveltiene una solución personalizada que funciona con contenerdores laravel sail.

Seguramente cada desarrollador habrá encontrado su propia solución, pero en este curso vamos a utilizar Docker para crear nuestro entorno de trabajo. Docker es una plataforma que permite crear, desplegar y ejecutar aplicaciones en contenedores. Los contenedores son entornos ligeros y portátiles que contienen todo lo necesario para ejecutar una aplicación, incluyendo el código, las librerías y las dependencias.

Requisitos previos:

  1. Instalar Docker Desktop:

  2. Instalar VSCode:

    • Descargar VSCode
    • Recomendamos instalar la extensión Remote - Containers de VSCode para trabajar directamente en los contenedores.
  3. Instalar docker mySQL:

    En este punto tenemos tres opciones:

    • Opción 1: Instalar el contenedor de MySQL desde cero. Puedes seguir las instrucciones de la documentación oficial de Docker para crear un contenedor MySQL, y llamarle docker_mysql.
    • Opción 2: Utilizar un contenedor MySQL ya existente. En este caso, asumimos que ya tienes un contenedor MySQL en funcionamiento con las siguientes características:
    • Opción 3: Añadir a nuestro docker-compose.yml el contenedor de MySQL. En este caso, añadiremos un contenedor MySQL al archivo docker-compose.yml que vamos a crear a continuación.

    A partir de ahora en los apuntes vamos a seguir la opción 3. Vamos a crear un docker-compose.yml que incluye un contenedor MySQL.

    En función de la opción elegida, tendrás que adaptar la conexión a la base de datos en el código PHP que vamos a crear. En el caso de contar ya con un contenedor MySQL en funcionamiento, o acceso a un servicio mysql ya existente, el temario presupone que estas son las credenciales de acceso:

    • Nombre del contenedor: docker_mysql (Si utilizas un contenedor MySQL)
    • IP: localhost (o host.docker.internal si estás con docker en Windows o Mac)
    • Usuario: alumno
    • Contraseña: alumno
    • Base de datos: test

Paso 1: Preparación del proyecto

  1. Crea una carpeta para tu proyecto:

    • Abre una terminal (CMD, PowerShell, Terminal de VSCode, etc.).
    • Crea una nueva carpeta para tu proyecto y navega dentro de ella.

    Crear carpeta del proyecto

    mkdir mi-proyecto-php
    cd mi-proyecto-php
    
  2. Crea la estructura de carpetas:

    Dentro de la carpeta mi-proyecto-php, crea las siguientes carpetas y archivos:

    Estructura de carpetas

    mkdir nginx php php/conf.d mysql mysql/data mysql/tmp src
    touch docker-compose.yml nginx/default.conf
    touch php/Dockerfile php/conf.d/99-xdebug.ini
    touch src/index.php
    

    Una vez creada la estructura, debería verse así:

    .
    ├── docker-compose.yml        # Archivo principal de configuración de Docker
    ├── nginx/                    
    │   └── default.conf           # Configuración de Nginx
    ├── php/                      
    │   ├── Dockerfile             # Dockerfile para el contenedor PHP
    │   └── conf.d/               
    │       └── 99-xdebug.ini     # Configuración de Xdebug para PHP
    ├── mysql/                    
    │   ├── data/                 # Carpeta donde se almacenarán los datos de MySQL
    │   └── tmp/                  # Carpeta temporal para MySQL
    ├── src/                      
    │   └── index.php             # Archivo de entrada de tu proyecto PHP (por ejemplo, Laravel)
    

    Esta es la estructura básica que vamos a utilizar para nuestros proyecto PHP con Docker.


Paso 2: Configuración de docker-compose.yml

  1. Abre el archivo docker-compose.yml en tu editor de texto favorito (puede ser VSCode).

  2. Pega el siguiente contenido en el archivo docker-compose.yml:

Requisitos

En nuestro caso vamos a añadir un contenedor MySQL al archivo docker-compose.yml. Si ya tienes un servidor MySQL en funcionamiento, debes eliminar la sección del contenedor mysql del archivo docker-compose.yml y utilizar las credenciales de tu servidor MySQL.

  • Nombre del contenedor: dk_mysql
  • IP: localhost # IP o host.docker.internal si es un contenedor y estás en Windows o Mac
  • Usuario: alumno
  • Contraseña: alumno
  • Base de datos: test

El usuario alumno tiene permisos para acceder por la red a la base de datos test.

docker-compose.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
name: laravel_app
services:
  php:
    image: php:8.4-fpm
    build: ./php
    volumes:
      - ./src:/var/www/html
      - ./php/conf.d/99-xdebug.ini:/usr/local/etc/php/conf.d/99-xdebug.ini
    environment:
      - MYSQL_HOST=mysql
      - MYSQL_USER=alumno
      - MYSQL_PASSWORD=alumno
      - MYSQL_DB=test
  nginx:
    image: nginx:latest
    ports:
      - "8080:80"
    volumes:
      - ./src:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php

  mysql:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: administrador
      MYSQL_USER: alumno
      MYSQL_PASSWORD: alumno
      MYSQL_DATABASE: test
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/tmp:/tmp
    ports:
      - "3306:3306"
    networks:
      - default

networks:
 default:
   driver: bridge

Ficheros .yaml

Los ficheros .yaml son muy sensibles a los espacios y tabulaciones. Asegúrate de que la indentación es correcta para evitar errores al ejecutar Docker Compose. Si te da problemas puedes descargar el archivo de ejemplo desde aquí.

En el archivo docker-compose.yml:

  • name:
    • Docker-composelo utilizará como base para nombrar los contenedores.
    • Por ejemplo al contendor de mysql le llamará: laravel-app-mysql-1.
    • De esta manera, modificando el nombre del proyecto, podemos evitar conflictos si tenemos varios proyectos con contenedores Docker en la misma máquina.
  • php:
    • Utiliza la imagen php:8.4-fpm.
    • Monta el directorio src en /var/www/html dentro del contenedor.
    • Monta el archivo de configuración 99-xdebug.ini para habilitar Xdebug (opcional).
    • Define las variables de entorno para la conexión a MySQL y Mongodb.
  • nginx:
    • Utiliza la imagen nginx:latest.
    • Mapea el puerto 8080 del host al puerto 80 del contenedor.
    • Monta el directorio src y el archivo de configuración nginx/default.conf en el contenedor.
    • Depende del servicio php.
  • mysql:
    • Utiliza la imagen mysql:8.
    • Define las variables de entorno para la configuración de MySQL (usuario, contraseña, base de datos).
    • Monta los volúmenes para persistir los datos y los archivos temporales. El el Dockerfile de MySQL ya creamos el password administrador para el usuario root, y el usuario alumno con la contraseña alumno y la base de datos test.
    • Mapea el puerto 3306 del host al puerto 3306 del contenedor. (Asegúrate de que este puerto no esté en uso por otro servicio en tu máquina).

El contenido del fichero php/conf.d/99-xdebug.ini es opcional, pero si quieres usar Xdebug, puedes crear un archivo con el siguiente contenido:

Configuración Xdebug

zend_extension=xdebug.so

xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.log_level=0

Esto habilitará Xdebug en el contenedor PHP y permitirá la depuración remota.


Paso 3: Configuración de Nginx

  1. Abre el archivo nginx/default.conf.

  2. Pega el siguiente contenido en el archivo default.conf:

Configuración nginx

server {
   listen 80;
   server_name localhost;

   root /var/www/html;
   index index.php index.html;

   location / {
       try_files $uri $uri/ =404;
   }

   location ~ \.php$ {
       include fastcgi_params;
       fastcgi_pass php:9000;
       fastcgi_index index.php;
       fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
   }
}

Paso 4: Crear el Dockerfile para PHP

Este archivo define cómo se construye la imagen de PHP con las extensiones necesarias. Es necesario para que PHP pueda interactuar con MySQL, Nginx y otras librerías. Se ejecutará cuando construyamos el contenedor PHP.

  1. Abre el archivo php/Dockerfile.

  2. Pega el siguiente contenido para crear el contenedor de PHP con las extensiones necesarias, de momento las libreriás PDO y MySQL:

Sería recomendado compartir bind el directorio usr/local/etc/php/conf.d para que puedas modificar el archivo php.ini desde tu máquina host.

Dockerfile PHP

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
FROM php:8.4-fpm

# Instalar las dependencias necesarias 
RUN apt-get update && apt-get install -y \
    git \
    unzip \
    curl \
    libzip-dev \
    libpng-dev \
    libxml2-dev \
    libonig-dev \
    libssl-dev \
    libmongoc-1.0-0 \
    libjemalloc2 \
    && rm -rf /var/lib/apt/lists/*

# Instalar extensiones de PHP necesarias (como PDO y MySQL)
RUN docker-php-ext-install pdo pdo_mysql xml ctype zip 

# Instalamos Composer, gestor de dependencias de PHP
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Instalamos Xdebug 
RUN php -n /usr/local/bin/pecl install xdebug \
&& docker-php-ext-enable xdebug

# Configuración de PHP
RUN cp /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini

# Establecer la ruta de trabajo
WORKDIR /var/www/html

En el fichero anterior:

  1. FROM php:8.4-fpm: Utiliza la imagen base de PHP 8.2 con FPM.
  2. RUN apt-get update && apt-get install -y ...: Actualiza los repositorios e instala las dependencias necesarias para PHP y MongoDB.
  3. RUN docker-php-ext-install pdo pdo_mysql: Instala las extensiones de PHP necesarias para PDO y MySQL.
  4. RUN mv /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini: Copia el archivo de configuración de PHP de desarrollo a producción.
  5. RUN pecl install mongodb ...: Instala la extensión de MongoDB y la habilita. (Opcional)
  6. WORKDIR /var/www/html: Establece el directorio de trabajo dentro del contenedor.
  7. cp /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini: Copia el archivo de configuración de PHP de desarrollo, que seré el que se utilizará en el contenedor.

Paso 5: Crear un archivo PHP de prueba

Vamos a crear un archivo PHP simple para testear el entorno de trabajo. En un archivo vamos a conseguir:

a) Probar si nginx funciona correctamente. b) Probar si PHP funciona correctamente (Debe ejecutar código PHP). c) Probar si PHP se conecta correctamente a MySQL usando PDO.

  1. Abre el archivo src/index.php.

  2. Pega el siguiente contenido para crear un archivo PHP que se conecte a MySQL:

prueba php y conexión a MySQL

<?php
$host = getenv('MYSQL_HOST');  // IP o dominio del host
$db   = getenv('MYSQL_DB');    // Base de datos que utilizamos por defecto
$user = getenv('MYSQL_USER');  // Usuario
$pass = getenv('MYSQL_PASSWORD'); // Password

try {
    $pdo = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    echo "<p>Conexión exitosa a la base de datos!</p>";
} catch (PDOException $e) {
    echo "<p>Error al conectar a la base de datos: " . $e->getMessage() . "</p>";
    echo "<p>Host: $host, DB: $db, User: $user, Pass: $pass</p>";
    phpinfo(); // Muestra información de PHP para depuración
}
?>

Paso 6: Levantar el entorno con Docker

mysql/data

Asegúrate de que la carpeta mysql/data está vacía antes de levantar los contenedores por primera vez. El script de Dockerfile de MySQL fallará si estas carpetas no existen o no están vacías.

  1. Abre la terminal en la carpeta del proyecto.

  2. Levanta los contenedores de Docker usando docker-compose:

    La primera vez que levantes el contenedor, debes usar el siguiente comando para construir las imágenes y levantar los contenedores:

    docker-compose up --build
    

    Podemos añadir -d al final del comando para que se ejecute en segundo plano:

    docker-compose up --build -d
    

    Esto descargará las imágenes necesarias y construirá los contenedores.

    Las próximas veces que levantes el contenedor no será necesario usar --build, ya que no has hecho cambios en el Dockerfile ni en el docker-compose.yml. Si vuelves a utilizar --build, Docker volverá a construir la imagen, lo que puede tardar un poco más. Y puedes perder los cambios que hayas hecho en el contenedor. Para volver a levantar el contenedor, puedes usar:

    docker-compose up 
    

    Si quieres que se ejecute en segundo plano, puedes añadir -d al final del comando:

    docker-compose up -d
    

    Si quieres parar el contenedor, puedes usar:

    docker-compose down
    
    Para eliminar los contenedores y las imágenes asociadas a ellos, puedes usar:

    docker-compose down --rmi all
    

    Modificación de los contenedores

    Si modificas el Dockerfile o el docker-compose.yml, tendrás que volver a ejecutar docker-compose up --build para que los cambios surtan efecto. Pero antes es conveniente elminar los contenedores y las imágenes para evitar conflictos. Puedes hacerlo con:

    docker-compose down --rmi all
    

    Luego volvemos a construir los contenedores con:

    docker-compose up --build
    

Paso 7: Verificar el entorno

  1. Una vez que los contenedores estén levantados, abre tu navegador y accede a http://localhost:8080.

  2. Deberías ver el mensaje "Conexión exitosa a la base de datos!" si todo está configurado correctamente.

Mensaje

Mensaje de conexión exitosa


Paso 8: Conectarse al contenedor MySQL

En ocasiones puede ser necesario conectarse al contenedor MySQL para crear tablas, insertar datos, etc. Para ello:

  1. Conectarse al contenedor MySQL con el siguiente comando:

Para conectarnos al contenedor mysql ejecutando el cliente mysql tenemos dos opciones:

Conectarse a MySQL

docker exec -it laravel_app_mysql_1 mysql -uroot -p

docker-compose exec mysql mysql -uroot -p
En la segunda opción el primer mysql es el nombre del servicio definido en el docker-compose.yml. Y el segundo mysql es el comando que queremos ejecutar dentro del contenedor.

Atención

Si has utilizado otro nombre para el contenedor MySQL, debes sustituir laravel_app_mysql_1 por el nombre que hayas utilizado. Si has utilizado los datos de los apuntes la contraseña del usuario root es administrador.

  1. Una vez dentro del contenedor MySQL, puedes ejecutar comandos SQL como:

SHOW DATABASES;
El servidor mostrará las bases de datos disponibles.

Usuario alumno

Si durante la creación del contenedor de mysql no se ha creado el usuario alumno, puedes crearlo con los siguientes comandos SQL. Es el usuario que vamos a utilizar en los ejemplos de PHP para conectarnos a la base de datos.

CREATE USER 'alumno'@'%' IDENTIFIED BY 'alumno';
Si el usuario se ha creado necesitamos que tenga permisos para acceder a todas las bases de datos ya que es el usuario que utilizaremos en los ejemplos de PHP para conectarnos a la base de datos. Para ello ejecutamos:

GRANT ALL PRIVILEGES ON *.* TO 'alumno'@'%' with GRANT OPTION;
FLUSH PRIVILEGES;

Desde el punto de vista de seguridad, este usuario alumno no es recomendable en un entorno de producción, pero para fines educativos y de desarrollo es suficiente.

Para ver si esta creado el usuario alumno, puedes ejecutar:

SELECT user, host FROM mysql.user;
Esto mostrará los usuarios creados en el servidor MySQL. El usuario alumno debe aparecer en la lista como: user: alumno, host: %. Esto significa que el usuario alumno puede conectarse desde cualquier host.


Paso 9: Configurar Visual Studio Code para depuración con Xdebug

  1. Abre la carpeta del proyecto en Visual Studio Code.
  2. Ve a la pestaña de Run and Debug (o presiona Ctrl+Shift+D).
  3. Haz clic en create a launch.json file y selecciona PHP.
  4. Reemplaza el contenido del archivo launch.json con el siguiente:
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for XDebug",
            "type": "php",
            "request": "launch",
            "port": 9003,
            "pathMappings": {
                "/var/www/html": "${workspaceFolder}/src"
            },
            "log": true
        }
    ]
}

Esto te creará un archivo .vscode/launch.json en la raíz del proyecto. De esta manera cuando lancemos el entorno de depuración en VSCode, este se conectará al contenedor PHP y podrás depurar tu código PHP.

Para iniciar la depuración:

  1. Coloca un punto de interrupción (breakpoint) en tu código PHP. (index.php por ejemplo).
  2. Inicia la depuración en VSCode haciendo clic en el botón verde de Start Debugging o presionando F5.
  3. Accede a tu aplicación en el navegador (http://localhost:8080). Cuando el código alcance el punto de interrupción, VS se detendrá y podrás inspeccionar variables, pilas de llamadas, etc.

Depuración con Xdebug

Depuración con Xdebug

Paso 10: Usar VSCode con Docker

Para trabajar directamente en los contenedores desde VSCode:

  1. Instala la extensión de Docker de Microsoft en VSCode.
  2. Instala la extensión Container-tools en VSCode.
  3. En la extensión de Docker, Containers. Podremos ver los contenedores en ejecución. Pulsando con el botón derecho sobre el contenedor dk_php y seleccionando Attach Visual Studio Code, se abrirá una nueva ventana de VSCode conectada al contenedor PHP. Desde esta ventana, podrás editar los archivos directamente dentro del contenedor.

Conclusión

Has configurado un entorno de desarrollo PHP completo con Docker, incluyendo Nginx, PHP-FPM y MySQL. Puedes ahora desarrollar aplicaciones PHP utilizando este entorno aislado y reproducible.

Estructura del proyecto

Carpeta/Fichero Descripción
docker-compose.yml Define los servicios Docker: PHP y Nginx.
php/Dockerfile Imagen personalizada de PHP 8.2 con Composer y Xdebug.
php/conf.d/99-xdebug.ini Configuración de Xdebug para depuración.
nginx/default.conf Configuración de Nginx para servir la aplicación.
mysql/data Carpeta donde almacenaremos las bases de datos
mysql/tmp Carpeta temporal para MySQL.
src/ Carpeta donde instalaremos Laravel.
src/index.php Archivo de prueba para verificar la conexión a MySQL.
.vscode/launch.json Configuración de depuración en Visual Studio Code.

Puesta en marcha del entorno de desarrollo

Antes de poder trabajar con PHP recuerda poner en marcha el entorno de desarrollo con Docker. Para ello, abre una terminal en la carpeta del proyecto y ejecuta:

docker-compose up -d

Cuando termines de trabajar, puedes parar los contenedores con:

docker-compose down

Carpeta de trabajo

La carpeta de trabajo donde instalaremos Laravel y desarrollaremos nuestras aplicaciones es la carpeta src. Esta carpeta está montada en el contenedor PHP en la ruta /var/www/html, que es la ruta que Nginx utiliza para servir los archivos.

En esta carpeta puedes crear tus archivos PHP y crear aplicaciones web.