ENFOQUE BB:BUENO
La sintaxis en
docker-compose.ymles:volumes: - ./ruta/local:/ruta/en/contenedor
. significa "busca el Dockerfile en la carpeta actual".¿Qué hace - ./:/var/www/html?
./es la carpeta actual de tu host (donde está eldocker-compose.yml)./var/www/htmles la ruta dentro del contenedor.Efecto: Todo lo que esté en
./se ve dentro del contenedor en/var/www/html, y todo lo que se cree dentro del contenedor en/var/www/htmlaparecerá automáticamente en tu./. Es una sincronización bidireccional y en tiempo real.
El "bind mount" (volumes: - ./:/var/www/html) es el corazón de la sincronización entre tu PC y el contenedor.
Tutorial Docker con Laravel (Enfoque: Contenedor Primero)
¿Qué logramos?
Tu máquina host solo necesita Docker y Docker Compose.
El proyecto Laravel se genera dentro del contenedor
app.Todo el código se sincroniza automáticamente con tu host gracias a los volúmenes.
1. Estructura de archivos (en tu host)
Crea una carpeta para tu proyecto (estará vacía al principio) y dentro de ella los siguientes archivos:
mi-proyecto-laravel/
├── docker/
│ ├── nginx/
│ │ └── default.conf
│ └── php/
│ └── Dockerfile
└── docker-compose.yml2. Archivo Dockerfile (para PHP)
Ruta: docker/php/Dockerfile
(Aquí solo preparamos el entorno PHP, aún no copiamos ningún código).
FROM php:8.2-fpm
# Instalar dependencias del sistema
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
# Instalar extensiones de PHP para Laravel
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
# Instalar Composer (lo necesitaremos dentro para crear el proyecto)
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Establecer directorio de trabajo
WORKDIR /var/www/html
# Exponer puerto de PHP-FPM
EXPOSE 9000
CMD ["php-fpm"]3. Configuración de Nginx
Ruta: docker/nginx/default.conf
server {
listen 80;
server_name localhost;
root /var/www/html/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass app:9000; # Apunta al servicio 'app'
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}4. Docker Compose (el orquestador)
Ruta: docker-compose.yml (en la raíz de tu proyecto)
version: '3.8'
services:
app:
build:
context: .
dockerfile: docker/php/Dockerfile
container_name: laravel_app
restart: unless-stopped
working_dir: /var/www/html
volumes:
- ./:/var/www/html # Montamos la carpeta VACÍA de nuestro host
networks:
- laravel
depends_on:
- db
- redis
webserver:
image: nginx:alpine
container_name: laravel_webserver
restart: unless-stopped
ports:
- "8000:80" # Puerto 8000 de tu navegador
volumes:
- ./:/var/www/html # Mismo volumen montado para que Nginx vea el código
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
networks:
- laravel
db:
image: mysql:8.0
container_name: laravel_db
restart: unless-stopped
ports:
- "3306:3306"
environment:
MYSQL_DATABASE: laravel
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_USER: laraveluser
MYSQL_PASSWORD: secret
volumes:
- db_data:/var/lib/mysql
networks:
- laravel
redis:
image: redis:alpine
container_name: laravel_redis
restart: unless-stopped
ports:
- "6379:6379"
networks:
- laravel
networks:
laravel:
driver: bridge
volumes:
db_data:5. ¡Levantamos los contenedores (aún sin código)!
Ejecuta en la terminal (estando en la raíz de mi-proyecto-laravel):
docker-compose up -d --buildVerifica que los 4 contenedores estén corriendo:
docker-compose psDeberías ver: app, webserver, db y redis con estado Up.
6. Entramos al contenedor y CREAMOS el proyecto Laravel
Aquí viene la magia de tu enfoque. Vamos a entrar dentro del contenedor app y usaremos Composer para generar el proyecto justo en la carpeta montada (/var/www/html).
docker-compose exec app bashAhora estás dentro del contenedor. Ejecuta:
composer create-project laravel/laravel .Ojo con el punto (
.) : Significa "instálalo en la carpeta actual". Como el volumen está montado, todos estos archivos aparecerán automáticamente en tu carpeta del host (mi-proyecto-laravel). ¡Abré tu explorador de archivos y verás cómo se van creando!
7. Configurar el archivo .env (dentro del contenedor)
Sigue dentro del bash. Copia el entorno de ejemplo y edítalo:
cp .env.example .env
nano .env # o usa vi si prefieresAsegúrate de que las variables de la base de datos apunten a los servicios de Docker:
DB_CONNECTION=mysql
DB_HOST=db # IMPORTANTE: es el nombre del servicio en docker-compose
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laraveluser
DB_PASSWORD=secret
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379Guarda el archivo (Ctrl+O y Ctrl+X en nano).
8. ¡EL PASO CRUCIAL! (Arreglar permisos en tu host)
Esto es lo más importante. Como creaste los archivos dentro del contenedor (como usuario www-data o root), en tu máquina host esos archivos te pertenecerán a root y no podrás editarlos con tu editor de código (en Linux) o no tendrás permisos para borrar la carpeta vendor.
Sal del bash del contenedor (escribe exit y presiona Enter) para volver a tu terminal del host. Luego ejecuta este comando:
docker-compose exec app chown -R $(id -u):$(id -g) .¿Qué hace esto?
$(id -u)obtiene tu número de usuario en el host.$(id -g)obtiene tu número de grupo.Se lo pasa al comando
chowndentro del contenedor para que cambie la propiedad de TODOS los archivos recién creados a tu usuario del host.
(Si usas Windows o Mac, este problema de permisos suele ser menor, pero ejecutarlo no hace daño).
9. Ejecutar migraciones (ya desde el host, opcional)
Ahora que el proyecto está creado y los permisos arreglados, puedes ejecutar Artisan. Puedes hacerlo desde el host (recomendado) para no tener que entrar al bash cada vez:
docker-compose exec app php artisan migrateTe preguntará si quieres crear la base de datos, escribe yes.
10. ¡Abre tu navegador!
Ve a:
http://localhost:8000Deberías ver la pantalla de bienvenida de Laravel. ¡Felicidades! Has creado un proyecto Laravel dentro del contenedor.
Comandos de uso diario (desde el host)
Como el código ya está en tu máquina, puedes editarlo con VSCode, PHPStorm, etc. Para ejecutar comandos:
# Ejecutar Artisan
docker-compose exec app php artisan make:controller MiControlador
# Ejecutar Composer para instalar paquetes
docker-compose exec app composer require spatie/laravel-permission
# Entrar rápidamente al bash del contenedor
docker-compose exec app bash¿Qué pasa si borro la carpeta del host?
No pasa nada. Como el proyecto se creó dentro del contenedor pero con volumen, los archivos existen en ambos lados. Si borras todo en el host, los archivos dentro del contenedor /var/www/html también se borrarían (por el volumen).
Para recuperarlo, solo tendrías que volver a ejecutar el paso 6 (composer create-project dentro del contenedor). Así de fácil.
Diferencias clave con el Enfoque A (el del tutorial anterior)
| Característica | Enfoque B (TU enfoque) |
|---|---|
| PHP/Composer en host | ❌ No necesitas instalar nada |
| Creación del proyecto | Se hace dentro del contenedor con composer create-project |
| Permisos (Linux) | Requiere el paso 8 (chown) para poder editar archivos en el host |
| Velocidad inicial | Un poco más lento la primera vez (descarga de dependencias dentro del contenedor) |
| Portabilidad | Máxima: solo necesitas Docker para arrancar desde cero |
Solución a problemas comunes con este enfoque
Error "Permission denied" al editar archivos en el host: Ejecuta el paso 8 (el
chown). Siempre que instales nuevas dependencias concomposer requiredentro del contenedor, los nuevos archivos envendor/pueden volver a cambiar de dueño; repite elchownsi te pasa.Composer es lento dentro del contenedor: Puedes pasarle la flag
--prefer-distpara que baje las versiones empaquetadas.Quiero usar Xdebug: Se añade en el Dockerfile con
pecl install xdebug, pero eso ya es para un tutorial más avanzado.
¿Qué te parece? Este enfoque es el que usa mucha gente en equipos donde cada uno tiene un sistema operativo diferente, porque evita el "en mi máquina funciona" al 100%. ¡Dime si te queda alguna duda!
Enfoque A (El que puse en el tutorial): Proyecto en el Host
Cómo es: Instalas Composer en tu máquina, creas el proyecto Laravel en tu disco duro y luego montas esa carpeta dentro del contenedor con un
volumes:.Ventajas:
Rendimiento: En Windows/Mac, los volúmenes montados son más rápidos para el IDE (PHPStorm, VSCode) porque los archivos están en el sistema de archivos nativo.
Permisos: En Linux, evitas que los archivos generados dentro del contenedor (como
vendor/obootstrap/cache) pertenezcan al usuariorootowww-data, lo que te obligaría a usarsudopara borrarlos.Git: Puedes hacer
git statusdirectamente sin entrar al contenedor.
Desventaja: Necesitas tener PHP y Composer instalados en tu máquina host.
Enfoque B (El que propones): Contenedor primero, proyecto dentro
Cómo es: Solo tienes Docker instalado. Creas los contenedores vacíos y, desde dentro del contenedor
app, ejecutascomposer create-projectpara generar Laravel.Ventajas:
Cero dependencias en el host: No necesitas instalar PHP, Composer ni nada más que Docker.
Versiones exactas: La versión de PHP la dicta el contenedor, no tu sistema operativo.
Desventajas:
Permisos (el gran problema): En Linux, si ejecutas
composerdentro del contenedor, los archivos se crearán con el usuariowww-data(oroot). En tu host, esos archivos te pertenecerán a ti, pero comoroot, y no podrás editarlos con tu usuario normal sinsudo.Rendimiento: Crear el proyecto dentro de un volumen montado puede ser un poco más lento en algunos sistemas.
¿Cómo se hace exactamente el Enfoque B (el tuyo)?
Te enseño los pasos para que lo hagas como prefieres. Asumiendo que tienes la misma estructura de docker-compose.yml que te puse antes:
1. Levanta solo los contenedores (sin código aún)
Asegúrate de que la carpeta ./mi-proyecto esté vacía (o ni siquiera la crees). Ejecuta:
docker-compose up -d --buildEsto levantará los contenedores app, webserver, db, etc. La carpeta de tu host estará vacía, pero dentro del contenedor /var/www/html también estará vacía.
2. Entra al contenedor app
docker-compose exec app bash3. Dentro del contenedor, crea el proyecto Laravel
Una vez dentro del bash del contenedor, ejecuta:
composer create-project laravel/laravel .Importante: El punto (
.) al final es clave, porque estás diciendo "instálalo en la carpeta actual" (/var/www/html).
4. Ajusta el .env
Dentro del contenedor, edita el .env o cópialo desde .env.example:
cp .env.example .env
nano .env # O usa viAsegúrate de poner las credenciales de la BD como te mostré antes (DB_HOST=db).
5. Sal del contenedor y da permisos (solo si usas Linux)
Vuelve a tu terminal del host y ejecuta:
# Esto asegura que los archivos creados dentro del contenedor
# sean propiedad de TU usuario en el host, y no de 'root'
docker-compose exec app chown -R $(id -u):$(id -g) .(En Windows/Mac esto suele ser menos problemático porque Docker maneja la traducción de usuarios internamente).
6. Ejecuta las migraciones
docker-compose exec app php artisan migrateEl método "oficial" de Laravel: Laravel Sail
Curiosamente, Laravel Sail (la herramienta oficial de Laravel para Docker) combina ambos métodos:
Primero te pide que crees el proyecto con Composer en el host (Enfoque A).
Pero si no tienes Composer, te dan un comando mágico con Docker para crearlo dentro (Enfoque B):
# Así se crea un proyecto Laravel usando Docker sin tener Composer instalado:
docker run --rm \
-v $(pwd):/opt \
-w /opt \
laravelsail/php83-composer:latest \
bash -c "composer create-project laravel/laravel mi-proyecto"¿Cuál te recomiendo?
Si usas Windows o Mac: Cualquiera de los dos funciona bien. El del tutorial (Enfoque A) es más rápido para empezar.
Si usas Linux: Te recomiendo el Enfoque A (crear el proyecto en el host) para evitar dolores de cabeza con los permisos de
vendor/ystorage/.
Dicho esto, tu intuición es totalmente acertada. Hacerlo dentro del contenedor es más "puro" en términos de contenerización. Si te encuentras con problemas de permisos en Linux, ya sabes el comando chown para arreglarlo.
¿Qué sistema operativo usas? Si me dices eso, puedo darte la receta exacta para que no tengas ni un solo problema de permisos
Comentarios
Publicar un comentario