Skip to content

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 -p docker/mysql/init docker/nginx docker/php scripts src
    touch docker-compose.yml
    touch docker/mysql/init/01-grants.sql
    touch docker/nginx/default.conf
    touch docker/php/Dockerfile
    touch docker/php/xdebug.ini
    touch scripts/.gitkeep
    touch src/index.php
    

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

    .
    ├── docker-compose.yml            # Archivo principal de configuración de Docker
    └── docker/
        ├── nginx/
        │   └── default.conf          # Configuración de Nginx
        ├── php/
        │   ├── Dockerfile            # Dockerfile para el contenedor PHP
        │   └── xdebug.ini            # Configuración de Xdebug para PHP
        ├── scripts/
        │   └── .gitkeep              # Git keep para mantener la carpeta vacía
        └── mysql/
            └── init/
                └── 01-grants.sql     # Script de inicialización 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

services:
    php:
        build:
        context: .
        dockerfile: docker/php/Dockerfile
        working_dir: /var/www
        volumes:
        - ./src:/var/www
        - ./scripts:/scripts
        environment:
        # Xdebug apagado por defecto; se activa con XDEBUG_MODE=debug
        XDEBUG_CONFIG: "client_host=host.docker.internal client_port=9003"

        # Variables “tipo curso” (PHP puro)
        MYSQL_HOST: mysql
        MYSQL_USER: alumno
        MYSQL_PASSWORD: alumno
        MYSQL_DB: test

        # Variables estándar Laravel (por si las necesitas)
        extra_hosts:
        - "host.docker.internal:host-gateway"
        user: "${UID:-1000}:${GID:-1000}"
        depends_on:
        - mysql

    nginx:
        image: nginx:alpine
        ports:
        - "8080:80"
        depends_on:
        - php
        volumes:
        - ./src:/var/www:ro
        - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro

    mysql:
        image: mysql:8.0
        environment:
        MYSQL_ROOT_PASSWORD: administrador
        MYSQL_DATABASE: test
        MYSQL_USER: alumno
        MYSQL_PASSWORD: alumno
        ports:
        # Evita colisiones con MySQL local del host
        - "3307:3306"
        volumes:
        - dbdata:/var/lib/mysql
        - ./scripts:/scripts
        - ./docker/mysql/init:/docker-entrypoint-initdb.d:ro
        tmpfs:
        - /tmp

    volumes:
        dbdata:

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:

  • 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 docker/php/xdebug.ini es opcional, pero si quieres usar Xdebug, puedes crear un archivo con el siguiente contenido:

Configuración Xdebug

xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_port=9003
xdebug.client_host=host.docker.internal
xdebug.discover_client_host=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 _;
    root /var/www/public;

    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

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 docker/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:

Dockerfile PHP

FROM php:8.3-fpm

RUN apt-get update && apt-get install -y \
    git curl unzip zip libzip-dev libpng-dev \
    && docker-php-ext-install pdo_mysql zip gd \
    && pecl install xdebug \
    && docker-php-ext-enable xdebug \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

COPY docker/php/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini
WORKDIR /var/www
CMD ["php-fpm"]

En el fichero anterior:

  1. Se utiliza la imagen base php:8.3-fpm que incluye PHP 8.3 con FastCGI Process Manager (FPM).
  2. Se instalan las dependencias necesarias para PHP, incluyendo git, curl, unzip, zip, libzip-dev y libpng-dev.
  3. Se instalan las extensiones de PHP necesarias para trabajar con MySQL (pdo_mysql), archivos ZIP (zip) y manipulación de imágenes (gd).
  4. Se instala Xdebug para la depuración remota.
  5. Se copia el archivo de configuración de Xdebug al directorio de configuración de PHP.
  6. Se establece el directorio de trabajo en /var/www.
  7. Se define el comando de inicio para ejecutar PHP-FPM.

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.