Docker

Cómo levantar un servicio web con Docker y Docker Compose

|

Actualizado el miércoles, 23 noviembre, 2022

Si, como yo, usas Linux en tus desarrollos, te habrás encontrado con que trabajar con las mismas versiones de software en tu sistema operativo que en producción puede llegar a ser un pequeño caos: dependencias que no puedes cumplir, no dispones de paquetería específica y acabas teniendo que compilar a mano servicios que, en muchas ocasiones, implican horas de cambios y reintentos para conseguir que todo funcione medianamente bien.

Por suerte, con la llegada de los contenedores y de Docker, muchos de estos problemas pertenecen ya al pasado. Para que veas lo sencillo que puede ser, preparamos un entorno con Apache, PHP y MySQL que puedes utilizar para probar tu web.

¿Qué es Docker?

Docker

Docker es un servicio que permite ejecutar pequeños contenedores de software sobre el núcleo de nuestro sistema operativo, por lo que es una opción más rápida y liviana que el uso de máquinas virtuales.

Por regla general, se suele empaquetar un solo servicio por contenedor, por lo que, para nuestro ejemplo, vamos a necesitar un orquestador, es decir, una herramienta que nos permita manejar en conjunto varios contenedores relacionados entre sí. De ahí el uso de Docker Compose.

Para servicios conocidos (Apache, PHP, MySQL…), tenemos contenedores oficiales disponibles en Docker Hub. Puedes distinguir fácilmente estas imágenes, puesto que están marcadas como official.

¡A jugar!

Hasta aquí la parte “aburrida”. Toca probar el juguete nuevo 😀

Vaya… No lo tengo instalado

Como ya habrás deducido, lo primero que necesitas es tener instalados Docker y Docker Compose en tu máquina. En muchas distribuciones Linux ya está incluido como parte de la paquetería disponible, por lo que podrás instalarlo desde tu herramienta de gestión de paquetería preferida. Pero, si prefieres estar a la última o no tienes disponible el paquete, siempre puedes seguir las instrucciones de la documentación:

Si usas Linux, mi consejo es que, a mayores, sigas los pasos de instalación adicionales. Te ayudarán, por ejemplo,  a no depender de ser root, o de utilizar sudo, incluyendo a tu usuario en el grupo de Docker.

Ahora que ya tengo Docker, ¿cómo lo configuro?

Para poder levantar los servicios que necesitas, tienes que indicarle a Docker Compose de alguna forma lo siguiente:

  • Contenedores a crear/levantar
  • Relación de los contenedores entre sí

Para ello creamos un fichero YAML, llamado “docker-compose.yml”, donde definimos cada uno de los servicios (puedes ver el fichero completo al final de esta sección).

Comienza tu fichero de configuración indicando la versión de sintaxis a utilizar y abriendo la sección de servicios:

version: "3"


services:

Configuración para MySQL

Primero, nos fijamos en el servicio donde incluiremos nuestra base de datos con el contenedor oficial de MySQL, que permite definir incluso el nombre de la base de datos que queremos usar, junto a sus datos de acceso. Actualmente, la última versión estable de MySQL es la 5.7, por lo que las líneas a incluir en el fichero son:

  miservicio_mysql:
    image: mysql:5.7
    environment:
      - MYSQL_DATABASE=nombre
      - MYSQL_ROOT_PASSWORD=claveroot
      - MYSQL_USER=miusuario
      - MYSQL_PASSWORD=mipassword
    volumes:
      # Montamos un volumen para MySQL para no perder los datos de bd
      - ./volumenes/mysql:/var/lib/mysql
    expose:
      - 3306

Una pequeña mejora. Si quieres acceder fácilmente al servicio MySQL desde tu aplicación favorita, puedes hacer que escuche en el puerto 3306 local, o en el que tú prefieras, solamente con añadir:

ports:
  - 3306:3306

Configuración para el servidor web

Aquí, por ser la opción más sencilla, usamos el contenedor oficial de PHP con Apache ya integrado, aunque también podríamos combinar un contenedor oficial de Apache con la versión FPM de este contenedor de PHP.

Como puedes ver en la documentación del contenedor, puedes elegir entre varias versiones:

  • php: 7-Apache. Última versión de PHP 7, actualmente la 7.2
  • php: 7.2-Apache. Última versión estable de PHP 7.2
  • php: 7.1-Apache. Última versión estable de PHP 7.1
  • php: 7.0-Apache. Última versión estable de PHP 7.0
  • php: 5.6-Apache. Última versión estable de PHP 5.6

Para este ejemplo me he decantado por usar la versión más actual de PHP 7. El servicio se configura así:

miservicio_php:
  image: php:7-apache
    volumes:
      # Montamos nuestra web desde fuera en el directorio web del contenedor
      - ./miweb/:/var/www/html
    expose:
      - 80
    ports:
      - 80:80
    links: 
      - miservicio_mysql

Con esto queda listo el fichero de configuración, así que ya podrías levantar el fichero. Por si prefieres copiar y pegar, aquí tienes la configuración completa de este ejemplo:

version: "3"

services:
  miservicio_mysql:
    image: mysql:5.7
    environment:
      - MYSQL_DATABASE=nombre
      - MYSQL_ROOT_PASSWORD=claveroot
      - MYSQL_USER=miusuario
      - MYSQL_PASSWORD=mipassword
    volumes:
      # Montamos un volumen para MySQL para no perder los datos de bd
      - ./volumenes/mysql:/var/lib/mysql
    expose:
      - 3306
    ports:
      - 3306:3306
  
  miservicio_php:
    image: php:7-apache
    volumes:
      # Montamos nuestra web desde fuera en el directorio web del contenedor
      - ./miweb/:/var/www/html
    expose:
      - 80
    ports:
      - 80:80
    links: 
      - miservicio_mysql

Añadiendo tu código y levantando Docker

Ya solo falta que incluyas el código en el directorio “miweb”, o el que hayas indicado en tu configuración, y ya podrás iniciar todos los servicios.

¡Un detalle! Asegúrate de que no tienes nada en tu máquina que esté utilizando los puertos que hemos definido para nuestros servicios (80 y 3306), pues de lo contrario no podrás iniciar los contenedores.

Lanzando contenedores en background

Esta es la opción más cómoda a la hora de no cerrar todo accidentalmente ya que, al quedar lanzados los contenedores en segundo plano, seguirán funcionando aunque cerremos la terminal. A cambio, para ver los logs tendrás que usar comandos de Docker para cada contenedor por separado. Para iniciar así el contenedor, solamente tendrás que situarte en la misma carpeta donde está el fichero docker-compose.yml y ejecutar:

docker-compose up -d

Si quieres detener los contenedores, puedes hacerlo también con el comando:

docker-compose down

Ejemplo Docker Compose

Lanzando contenedores en primer plano

Si, por el contrario, prefieres ver los logs directamente en pantalla y poder parar los contenedores solamente con pulsar Ctrl+C, inicia el servicio en primer plano, ejecutando el de inicio, pero sin “-d”:

docker-compose up

¡Y listo! Ya tienes funcionando un servicio web, con PHP 7.2 y MySQL 5.7, con el código de tu web en tu máquina. Solamente tendrás que acceder a http://localhost/.

Recuerda que este es un tutorial muy sencillo, con lo básico para arrancar los servicios y que funcionen, pero los límites los pones tú:

  • Añade extensiones al php y Apache, creando tu propio contenedor
  • Cambia rutas, configuraciones, variables de entorno…
  • Juega con el mapeo de puertos, por ejemplo:
    • Añade un segundo servidor web, con otro php y escuchando en otro puerto (por ejemplo 81, 8080), para probar tu web con diferentes versiones
    • Cambia el puerto del apache para mantener levantado tu servicio local

¡Esperamos tus comentarios!  Si te ha resultado útil, si quieres que profundicemos más en el tema… Recuerda que también puedes contactarnos si tienes cualquier duda o sugerencia, ¡que para eso estamos! 😀


Avatar de Víctor Rodríguez

Comentarios

64 respuestas a «Cómo levantar un servicio web con Docker y Docker Compose»

  1. Avatar de trucador
    trucador

    Que terminal es la que usas ? cmder???
    Gracias!
    muy buen post!

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola!

      Me alegra que el post te haya gustado y espero que te resulte útil.

      Sobre la terminal, utilizo la que viene por defecto en Ubuntu, pero he añadido bash-git-prompt para que me muestre datos sobre el repositorio de código, con algún cambio en los temas que trae por defecto. Usando asciinema he capturado todo lo que pasaba por la terminal y generado un gif para el post.

      Un saludo! 😉

  2. Avatar de diego
    diego

    como harias para añadir phpmyadmin porque tengo un problema con ello y no consigo que enlace con la base de datos

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Diego!

      La forma más sencilla es incluir el contenedor oficial de phpMyAdmin como un componente más, escuchando en el puerto 8080 de tu máquina y enlazado al contenedor de MySQL para que pueda acceder la base de datos. De esta forma podrás acceder al phpMyAdmin con la url http://localhost:8080/.

      Te dejo un ejemplo en este fragmento de código.

      Espero que esto te sirva de ayuda y no dudes en contactar de nuevo con nosotros si lo necesitas 😉

    2. Avatar de Daniel Alberto Diaz
      Daniel Alberto Diaz

      phpmyadmin:
      image: phpmyadmin/phpmyadmin:latest
      container_name: seafile-phpmyadmin
      restart: always
      links:
      – miservicio_mysql
      ports:
      – “8181:80”
      environment:
      – MYSQL_USERNAME=miusuario
      – MYSQL_ROOT_PASSWORD=mipassword

  3. Avatar de gallbers
    gallbers

    Hola Víctor!
    Muy bueno post! estuve intentando levantar el servidor pero me esta dando problemas con los permisos en el volumen “miweb” me podrías dar algún consejo de que podría hacer ??

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola gallbers!

      Me alegra que te guste la entrada 🙂 Sobre tu consulta:

      Si utilizas Linux, no debería ser necesario configurar nada para montar directorios de tu máquina en los contenedores, solamente debes recordar lanzar los comandos como root (vale con sudo) o añadir tu usuario al grupo “docker” para no necesitarlo.

      En el caso de Windows 10, con Docker for Windows, es posible que tengas que habilitar el uso de las unidades de disco de tu PC dentro de la configuración del propio Docker. Te dejo una captura:

      docker-for-windows-shared-drives

      En algunos casos, en Docker for Windows, si la unidad ya estaba compartida, la solución suele ser eliminarla de compartidos y volverla a compartir.

      De todas formas, si esto no te soluciona el problema, o utilizas otro sistema operativo, no dudes en contactar de nuevo y estaremos encantados de ayudarte.

      Un saludo!

  4. Avatar de Yolanda
    Yolanda

    Hola Víctor me gusto muchoo este post gracias.

    Sabrías como poner una IP al contenedor para que no tenga que escribir “localhost”, si no una IP propia del contenedor?

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Yolanda!

      Muchas gracias por tu comentario, siempre es agradable saber que a la gente le gusta lo que publicamos 😉

      Sobre tu pregunta, tienes varias opciones a la hora de acceder por IP:

      – Usar la IP de la máquina (PC, servidor…) en la que estás levantando el servicio
      – Obtener, mediante comandos de Docker, la IP que Docker ha asignado al contenedor
      – Definir una red la configuración de Docker Compose y asignar direcciones de esta red a los contenedores

      Te explico las dos últimas con un poco más de detalle:

      Usar la IP asignada por Docker al contenedor

      De las dos opciones que voy a explicar esta es la más sencilla, aunque tiene el inconveniente de que la dirección IP puede cambiar al detener y volver a levantar los contenedores.

      El comando docker inspect nos da todos los detalles sobre un contenedor, pero podemos limitar su respuesta especificando un formato para la misma, así haremos nos devuelva solamente el dato que nos interesa (por ejemplo, la dirección IP).

      En mi caso, mi contenedor se llama “apachephpdocker_miservicio_php_1” (para obtener un listado de los contenedores activos ejecutamos el comando “docker ps“), por lo que ejecuto el comando:

      docker inspect apachephpdocker_miservicio_php_1 –format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}’

      Con esto me devuelve el valor de la IP del contenedor:

      docker inspect

      Usando esta IP en nuestro navegador, siempre que Docker y el navegador estén en la misma máquina, podemos acceder al servicio.

      Definir la red de Docker para nuestros contenedores con Docker Compose

      Esta es una opción más avanzada que la anterior, las direcciones IP se mantienen, pero tenemos que tener cuidado con las redes que definimos para no tener conflictos con las direcciones.

      En este caso, definimos una nueva sección del fichero docker-compos.ymle para las redes, al mismo nivel que la de servicios y la usamos para asignar IPs a los contenedores.

      Para no alargar más el contenido del comentario, he actualizado este fragmento de código, de mi anterior comentario, para incluir también un ejemplo con configuraciones de red.

      Si tienes cualquier otra consulta, no dudes en contactar de nuevo, estaremos encantados de ayudarte.

      Un saludo!

  5. Avatar de Jonathan
    Jonathan

    Hola,

    A mi el apache me deja esto en el log y no logro ver “localhost:8090” (le cambie el puerto)

    AH00558: apache2: Could not reliably determine the server’s fully qualified domain name, using 172.23.0.3. Set the ‘ServerName’ directive globally to suppress this message

    [Thu Feb 20 01:29:31.208942 2020] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.38 (Debian) PHP/7.4.2 configured — resuming normal operations

    [Thu Feb 20 01:29:31.208985 2020] [core:notice] [pid 1] AH00094: Command line: ‘apache2 -D FOREGROUND’

    [Thu Feb 20 01:50:16.579510 2020] [mpm_prefork:notice] [pid 1] AH00169: caught SIGTERM, shutting down

    [Thu Feb 20 13:46:19.189547 2020] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.38 (Debian) PHP/7.4.2 configured — resuming normal operations

    [Thu Feb 20 13:46:19.189707 2020] [core:notice] [pid 1] AH00094: Command line: ‘apache2 -D FOREGROUND’

    HEEEELPPP

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Jonathan,

      En principio no deberías tener problemas para cambiar el puerto y que funcionase en el 8090, yo lo he probado con la siguiente configuración:


      version: "3"

      services:
      miservicio_mysql:
      image: mysql:8
      environment:
      - MYSQL_DATABASE=nombre
      - MYSQL_ROOT_PASSWORD=claveroot
      - MYSQL_USER=miusuario
      - MYSQL_PASSWORD=mipassword
      volumes:
      - ./volumenes/mysql:/var/lib/mysql
      expose:
      - 3306
      ports:
      - 3306:3306

      miservicio_php:
      image: php:7-apache
      volumes:
      - ./miweb/:/var/www/html
      expose:
      - 80
      ports:
      - 8090:80
      links:
      - miservicio_mysql


      En los logs puedes ver que el apache responde correctamente:

      AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.19.0.3. Set the 'ServerName' directive globally to suppress this message
      AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.19.0.3. Set the 'ServerName' directive globally to suppress this message
      [Mon Feb 24 08:01:12.335705 2020] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.38 (Debian) PHP/7.4.3 configured -- resuming normal operations
      Mon Feb 24 08:01:12.335753 2020] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
      172.19.0.1 - - [24/Feb/2020:08:01:14 +0000] "GET / HTTP/1.1" 200 22300 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0"

      Revisa que tu configuración sea correcta y recuerda que, si no tienes nada en el directorio con el código de la web (./miweb/), el apache te devolverá un error 403 (Forbidden).

      Espero haberte sido de ayuda. si necesitas cualquier otra cosa, no dudes en volver a contactar o comentar.

      Un saludo 😉

  6. Avatar de JB
    JB

    Revisa que tu configuración sea correcta y recuerda que, si no tienes nada en el directorio con el código de la web (./miweb/), el apache te devolverá un error 403 (Forbidden).

    Como hago esta configuración que tu dices?
    buen aporte.
    Saludos!!!

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola JB,

      Principalmente asegúrate de que los puertos están definidos en el orden correcto en el docker-compose.yml, siempre primero el puerto de la máquina “anfitrión” y luego el puerto del contenedor. También de que la carpeta que montas es la correcta (a mí ya me ha jugado alguna mala pasada omitir un punto y usar “/carpeta” en lugar de “./carpeta”…).

      Por lo demás, con el resto de configuraciones no deberías tener problemas.

      Espero haberte sido de ayuda. Un saludo 😉

  7. Avatar de Juan
    Juan

    Hola.
    Muy bueno el post!
    Consultas:
    1.- pude levantar ambos dockers sin problema, pero como sólo tengo carpetas dentro del directorio me devuelve “Forbidden” como explicaste. El problema es que dentro de las carpetas sí tengo archivos index.php y no me los reconoce.
    Podrías indicarme que hacer? Es un tema de configuración del docker con apache o es problema de mi SO host?
    2.- Para hacer lo mismo para sistemas con Windows, tengo que compartir una carpeta dentro del directorio del usuario o puedo compartir cualquier carpeta con el docker?

    version: ‘3.0’

    services:

    apache:
    image: php:7.4-apache
    container_name: apache
    expose:
    – 80
    ports:
    – 80:80
    volumes:
    – /var/www/html:/var/www/html
    links:
    – mysql:mysql

    mysql:
    image: mysql:8.0.13
    container_name: mysql
    expose:
    – 3306
    ports:
    – 3306:3306
    command: –default-authentication-plugin=mysql_native_password
    environment:
    MYSQL_DATABASE: db
    MYSQL_ROOT_PASSWORD: root
    volumes:
    – /var/lib/mysql:/var/lib/mysql

    Esto es desde un sistema con SO Ubuntu 18.04.
    Desde ya, muchas gracias!

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Juan,

      Sobre el contenido en carpetas, aunque al acceder a “http://localhost/” te muestre el “forbidden”, debería de funcionar correctamente si añades manualmente la carpeta a la URL (por ejemplo: “http://localhost/micarpeta”). De todas formas, siempre puedes cambiar el comportamiento de Apache creando tu propio fichero “000-default.conf” y montándolo como volumen en el contenedor. Mi consejo si haces esto: crea una carpeta, dentro de esta pon el fichero “000-default.conf” y móntala como un volumen en la ruta /etc/apache2/sites-available/ del contenedor de PHP. Recuerda que si la configuración de Apache no es correcta, el contenedor finalizará (por el error de Apache).

      Con Windows, si tienes habilitado el acceso de Docker a la unidad (lo tienes en un comentario anterior de esta entrada) y puedes acceder a la carpeta, no deberías de tener problemas en usarlas en Docker, al menos lo poco que yo lo he probado en este sistema operativo.

      Espero haber resuelto tus dudas.

      Un saludo 😉

  8. Avatar de Daniel Alberto Diaz
    Daniel Alberto Diaz

    No entiendo porque expones el puerto y luego lo declaras? cual es el fin de esto?

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Daniel,

      En este caso, “expose” y “ports” hacen 2 cosas distintas:

      Los puertos definidos en expose solamente se exponen a los servicios en la red interna que se crea entre ellos, pero no estarían accesibles en la máquina que ejerce de anfitrión.

      Los puertos definidos en ports se mapean a puertos de la máquina anfitrión haciendo más sencillo acceder a los servicios.

      Realmente, de acuerdo con la documentación de Docker Compose, solo necesitaríamos exponer del puerto 3306 de MySQL en la red interna del Docker y mapear los puertos del servicio web a nuestra máquina.

      Espero haber resuelto tu consulta.

      Un saludo 😉

  9. Avatar de Adrian
    Adrian

    Muy bueno el post, me podrías indicar cómo hacer que mi proyecto de docker compose levante automáticamente cuando se reinicia el server , que no lo tenga que hacer manualmente.

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Adrian,

      Docker Compose tiene ya una opción específica para reiniciar los servicios automáticamente, solo tendrías que añadir la opción “restart: always” a cada uno de los servicios del docker-compose.yml que quieres que siempre estén activos. Por ejemplo:

      version: "3"
       
      services:
        mysql:
          image: mysql:8
          environment:
            - MYSQL_DATABASE=nombre
            - MYSQL_ROOT_PASSWORD=claveroot
            - MYSQL_USER=miusuario
            - MYSQL_PASSWORD=mipassword
          volumes:
            - ./volumenes/mysql:/var/lib/mysql
          expose:
            - 3306
          ports:
            - 3306:3306
          restart: always
         
        php:
          image: php:7-apache
          volumes:
            - ./miweb/:/var/www/html
          expose:
            - 80
          ports:
            - 8090:80
          links: 
            - mysql
          restart: always
      
        phpmyadmin:
          image: phpmyadmin/phpmyadmin
          ports:
           - 8080:80
          links: 
            - mysql:db
          restart: always
      
      

      Espero haber solucionado tu duda.

      Un saludo 😉

  10. Avatar de Sergi

    Realmente muy bueno el post.
    Tengo un pequeño problema. Por supuesto, en local funciona ala perfeccion. Cuando lo subo a mi VPS, no hay forma de abrir el PHPmyadmin. Con la URL:8080 no encuentra el servicio.
    ¿Como puedo solucionarlo?
    Muchisimas gracias por adelantado.

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Sergi,

      En este caso podría deberse a varias cosas:

      En primer lugar comprueba que todos los contenedores están levantados, puedes hacerlo con el comando “docker-compose ps” y fíjate que todos están en estado “Up”. Si el de phpMyAdmin no lo estuviera, prueba a levantar todo sin el “-d” para ver los logs y ver lo que pasa, es posible que el puerto 8080 ya esté en uso por alguna otra aplicación o servicio.

      Si todo está correcto, revisa las posibles reglas de firewall en la máquina, seguramente tengas limitado/bloqueado el acceso a puerto 8080 de la misma. En este caso podrás optar por habilitar el acceso al puerto en el firewall de tu máquina o utilizar otro puerto que no tengas bloqueado.

      Recuerda que si tienes cualquier duda con tu servidor, siempre puedes ponerte en contacto con nuestro Equipo de Soporte y te ayudarán a resolverlo sin problemas.

      Espero haber resuelto tus dudas.

      Un saludo 😉

  11. Avatar de Ramiro
    Ramiro

    Hola Victor! Muy buen post!
    Si tenemos tres contenedores, uno corriendo Apache, otro PHP con el código fuente y otro corriendo MySql ¿Cada uno de ellos son Microservicios o simplemente servicios?

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Ramiro,

      La verdad es que, cuando pienso en un microservicio, me imagino algo más complejo que un MySQL por si mismo, o un Apache2. Entiendo que un microservicio es funcional por si solo, aunque el resto de microservicios con los que interactúa no estén activos en este momento.

      Sin embargo, podríamos preguntarle a varios desarrolladores y acabaríamos generando un debate sobre esto, en el que parte los verían como microservicios y otros no. Al final es un tema de como lo percibimos cada uno de nosotros.

      ¡Un saludo!

  12. Avatar de Yulianny Betancourt
    Yulianny Betancourt

    Si ya tengo laradock en docker, es decir, levante un proyecto de laravel con laradock usando nginx, mysql, phpmyadmin, mi pregunta es, ¿Si quiero un proyecto que requiere esos contenedores, debo configurarlo aparte, seguir este tutorial, o me sirven los contenedores que ya tengo?
    Es confusa mi pregunta ¿?, espero que no.
    Gracias de antemano.

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Yulianny,

      No conocía Laradock, pero le he echado un vistazo rápido y, por lo que he podido ver, ya te da un entorno de desarrollo mucho más completo que el que conseguirías tener siguiendo este tutorial al pie de la letra.

      Según veo en sus características, puedes gestionar varios proyectos con un solo Laradock o tener múltiples Laradocks, uno por proyecto.

      Si vas a trabajar con Laravel yo le daría una oportunidad, tiene muy buena pinta.

      Espero haber resuelto tu pregunta 😉

      ¡Un saludo!

      1. Avatar de Yulianny Betancourt
        Yulianny Betancourt

        Sí, está genial, ya lo estoy probando, sí me sirvio sus comentarios, para aclarar dudas.

        MI inquitud era especificamente con los contenedores, que si debía crearlos otra vez, y eso hice, uno parecido al que tiene acá pero con phpmyadmin, y me va bien. Lo dejaré por si alguien más lo desea usar.

        version: ‘2’
        services:
        mysql:
        image: mysql:8.0
        container_name: mysqlserver
        command: –default-authentication-plugin=mysql_native_password
        working_dir: /application
        volumes:
        – .:/application
        restart: always
        environment:
        – MYSQL_ROOT_PASSWORD=123456
        – MYSQL_DATABASE=BD
        – MYSQL_USER=root
        – MYSQL_PASSWORD=123456
        ports:
        – “8082:3306”
        website:
        container_name: php73
        build:
        context: ./
        links:
        – “mysql:database”
        volumes:
        – ./src:/var/www/html
        ports:
        – 8000:80
        depends_on:
        – mysql

        phpmyadmin:
        image: phpmyadmin/phpmyadmin
        container_name: phpmyadmin
        environment:
        – PMA_ARBITRARY=1
        restart: always
        ports:
        – 8080:80
        volumes:
        – /sessions

  13. Avatar de Yulianny Betancourt
    Yulianny Betancourt

    Y en caso de que me sirva, me recomiendas algún tutorial o post que me ayude con eso, por fa.

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola de nuevo,

      Como te indicaba en mi otro comentario, no conocía Laradock, aunque, ahora que lo he visto, me parece interesante.

      Ante este desconocimiento, no sabría recomendarte un tutorial específico. Yo empezaría por el “Getting Started” de su documentación y luego buscaría en mi buscador preferido.

      Espero haberte sido de ayuda.

      ¡Un saludo! 😉

  14. Avatar de César

    Funciona, genial. Dockers es otro mundo.
    Cómo ponerle una IP del mismo rango que el host?
    Un saludo y ánimos!

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola César,

      La verdad es que esto es algo que nunca me había planteado, hasta ahora solamente “mapeaba” los puertos que necesitaba al host para poder acceder a ellos.

      Lo he estado revisando y no he conseguido hacer funcionar algo correctamente asignado direcciones en esa misma red que el host.

      De todas formas, si en un futuro consigo hacerlo funcionar, ten por seguro que te responderé de nuevo a este comentario (o, si es lo bastante grande, se convertirá en una nueva entrada en el blog).

      Gracias por comentar! Un saludo 😉

  15. Avatar de Seienshi
    Seienshi

    Hola, me parecio excelente tu post, ahora necesito una mano, necesito que esta activo pdo-mysql y mysqli

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Seienshi,

      En este caso tendrás que personalizar el contendor web creando tu propio “Dockerfile”, siguiendo las instrucciones que se indican en la documentación del propio contenedor de PHP.

      Lo más sencillo es que partas del contenedor que usamos (php con apache) y en tu Dockerfile personalizado hagas que instale las extensiones que te interesa con la instrucción “docker-php-ext-install”, haciendo algo similar a esto:


      FROM php:7-apache

      RUN docker-php-ext-install pdo pdo_mysql mysqli


      Luego solo tendrás que cambiar tu “docker-compose.yml” para que, en lugar de usar una imagen por defecto, construya la que acabas de definir, cambiando el “image: php:7-apache” por un “build: ruta/carpeta/deldockerfile” o “build: .” si el dockerfile está en la raíz.

      Espero haber resuelto tu consulta.

      Gracias por comentar. Un saludo 😉

  16. Avatar de Alejandro
    Alejandro

    Buenas muy bueno el post, mi consulta o mas bien una orientación. Tengo un aplicación básica( ya terminada) que quiero que se utilice en un entorno local, la cual esta desarrollada en Angular y consume una api de Laravel y un motor postgre.
    Ahora es posible deployar y correr de forma local sin llevarlo a un servidor web utilizando docker?? o existe alguna otra herramienta con la cual pueda investigar para este cometido?
    Desde ya muchas gracias

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Alejandro,

      No deberías tener problema, siempre que en la máquina donde quieres hacerlo funcionar tengas disponibles Docker y Docker Compose, o puedas instalarlos.

      Puedes partir de una configuración similar a la de este post, cambiando el contenedor de MySQL por el de PostgreSQL e irla adaptando a tus necesidades. Posiblemente necesites personalizar el contenedor de PHP (hay un comentario anterior donde se da una explicación de como habilitar pdo_mysql que te puede servir) o, incluso, te puedes plantear el uso de Laradock.

      Otra opción es la de crear tu propio contenedor de PHP partiendo de una imagen básica del sistema operativo, como podrían ser Ubuntu o Debian. En este caso, ten en cuenta que tendrás que preparar todo tú (servidor web, php, librerías…) y dedicar mucho más tiempo, pero tendrás el contenedor tal y como quieres que sea.

      Espero haber resulto tu consulta.

      Gracias por comentar. Un saludo 😉

      1. Avatar de Alejandro
        Alejandro

        Lo estoy invetigandooo!Gracias por tu respuesta, te lo agradezco.

  17. Avatar de Luias
    Luias

    Muchas gracias por el tutorial! Muy completo! Soy totalmente novata en Docker y también bastante en php.

    Estoy desarrollando una aplicación php en Docker. He utilizado el código ampliado que indicaste con un tercer contenedor phpmyadmin.

    Quiero acceder a phpmyadmin (con localhost:8080 que es el puerto asingado) a través del navegador pero me aparece el siguiente error:

    phpMyadmin – Error

    Error during session stat_ please check your PHP and/or webserver log file and configure php installation properly. Also ensure that are enabled in your browser.

    session_write_close() write failed. No space left on device (28)

    session_write_close():Failed to write session data (files). Please verify that the current of session_save_path is correct ().

    He comprobado que sí que tengo espacio en /var tanto de la máquina host como del contenedor. No sé por qué puede ser, si es que tengo que configurar algún archivo más para dar acceso remoto…

    Agradecería alguna idea please!!!

    Gracias!

    Saludos!

    1. Avatar de Adriana Freire
      Adriana Freire

      Hola Luias,

      ¡Gracias por comentar!

      Sin los logs de error no podríamos saber con mayor exactitud qué sucede. De todas formas, lo mejor sería:

      1. Vaciar la caché del navegador y eliminar las Cookies
      2. Verificar que /var/lib/php/session/ tenga permisos de acceso
      3. Verificar en el php.ini que la directiva session.save_path esté correctamente establecida

      Un saludo!

  18. Avatar de Seienshi
    Seienshi

    Ante todo muchisimas gracias por la aclaratoria anterior.

    Ahora tengo otra duca, tengo en un vps dos contenedores cada uno con un sitio web distinto, un sitio lo publico por el puerto 80 del anfitrion y el otro por el 8080, hasta alli todo bien, pero ahora debo hacer que sean visibles al mundo, tengo solo una ip, pero el sitio que publico por el puerto 80 debe apuntar a dominioa.com y el que publico por el puerto 8080 debe apuntar a dominiob.com

    1. Avatar de Ret
      Ret

      Creo que lo que necesitas es un Reverse-proxy. Basicamente es un servidor que recibe pedidos externos y los reenvia a los servicios internos que correspondan.
      Fijate en Traefik que tambien viene en contenedor

    2. Avatar de Adriana Freire
      Adriana Freire

      ¡Hola!

      Asumiendo que están los puertos 80 y 8080 del Docker mapeados con el 80 y 8080 del VPS, y que está correcta la configuración del servicio web y sus VirtualHost (Apache) o ServerBlock (Nginx), entonces habría que apuntar la zona @ de cada uno de los dominios a la IP del VPS. Con esto, luego de que se propague la zona, el dominio será accesible a nivel público.

      ¡Esperamos haberte sido de ayuda!

  19. Avatar de vectorino
    vectorino

    Hola felicitaciones por el excelente blog!

    Por favor podrías orientarme respecto de lo siguiente, estoy experimentando con docker-compose y joomla.
    Utilicé el procdimiento que plantea bitnami y todo funciona muy bien.
    Pero ahora tengo la necesidad de instalar un certificado SSL, y encontré un tutorial para que mediante jrcs/letsencrypt-nginx-proxy-companion pueda agregarlo, sin embargo mi pregunta es, ¿si detengo el actual contenedor con docker-compose down y luego modifico el docker-compose.yml para finalmente levantarlo nuevamente con docker-compose up -d, el sitio que existía no se verá dañado?

    1. Avatar de Adriana Freire
      Adriana Freire

      ¡Hola!

      Cuando se monta el volumen en el docker-compose.yml, lo que hace es enlazar la carpeta indicada del anfitrión con la indicada del Docker. Por ejemplo:
      volumes:
      – ./miweb/:/var/www/html # Donde miweb es la carpeta del anfitrión y /var/www/html la del docker.

      Si se hacen cambios tanto desde fuera del Docker (en la carpeta miweb) como desde dentro del Docker (/var/www/html), estos cambios serán permanentes, por lo que en el momento de hacer un docker-compose down no se eliminará contenido.

      ¡Esperamos haberte sido de ayuda!

  20. Avatar de Mauricio
    Mauricio

    Muy buen post! Bien Claro y simple, gracias!!!

    1. Avatar de Adriana Freire
      Adriana Freire

      A ti por comentar, Mauricio. Quedamos a tu disposición para lo que necesites.

  21. Avatar de julio
    julio

    Hola agradezco mucho la ayuda con esto, solo que aunque ya se crearon mis contenedores, cuando lanzo en localhost me aparece un Forbiden, ya lei los demas comentarios y aconsejas desde windows compartir el recurso de la carpeta donde esta mi proyecto que quiero correr con docker pero aun y con eso no me permite verlo
    ¿alguna recomendacion? Gracias de antemano

    1. Avatar de Adriana Freire
      Adriana Freire

      Hola Julio,

      Aunque un Forbidden podría darse por muchos motivos, tal y como hemos montado este escenario te recomendaríamos lo siguiente:

      -Verifica que tienes permisos en la carpeta donde tienes la web.
      -Verifica que la carpeta tiene contenido. Si intentas acceder a la web y no tienes ningún fichero este también podría ser el motivo del error. Podrías crear un fichero index.html o index.php (con sintaxis correcta) en caso de no tenerlo y acceder de nuevo.

      ¡Un saludo!

  22. Avatar de Adrian Rivera
    Adrian Rivera

    Hola, me encanto el post, para personas como yo que estan iniciando en este mundo de docker es de mucha ayuda post como estos.
    Ahora mi consulta es, resulta que necesito instalar en un contenedor docker aparte un CMS (sea Worpress o Drupal), enlazarlo con apache y php, y a mi base de datos aparte (es lo que piden en el proyecto) ¿Como puedo hacer esto? resulta que Nginx es sumamente fácil pero no he encontrado un solo post que lo haga con apache en docker. ¿Me podrian ayudar con eso?

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Adrian,

      Entiendo que lo que necesitas es que WordPress o Drupal funcionen con Apache y PHP, quizás la opción más sencilla sea usar los contenedores oficiales de WordPress o Drupal que tienes disponibles en Dockerhub, ambos usan por defecto Apache.

      En ambos casos tienes ejemplos en la propia documentación en dockerhub de como lanzar ambos servicios junto a otro contenedor a parte con la base de datos mediante docker hub, con MySQL para WordPress y con PostgreSQL para Drupal.

      Espero haber resuelto tus dudas.

      Gracias por comentar. Un saludo 🙂

  23. Avatar de Alejandro
    Alejandro

    Gracias por el post!!! tengo el siguiente docker-compose :

    version: “3.0”
    networks:
    laravel:
    services:
    nginx:
    image: nginx:1.18.0-alpine
    container_name: nginx
    ports:
    – “8088:80”
    volumes:
    – ./backend:/var/www/html
    – ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
    – php
    – mysql
    networks:
    – laravel

    mysql:
    image: mysql:5.7.31
    container_name: mysql
    restart: unless-stopped
    tty: true
    ports:
    – “4306:3306”
    volumes:
    – ./mysql:/var/lib/mysql
    environment:
    MYSQL_DATABASE: cec
    MYSQL_USER: admin
    MYSQL_PASSWORD: admin
    MYSQL_ROOT_PASSWORD: admin
    SERVICE_NAME: mysql
    SERVICE_TAGS: dev
    networks:
    – laravel

    php:
    build:
    context: .
    dockerfile: Dockerfile.backend
    container_name: php
    volumes:
    – ./backend:/var/www/html
    ports:
    – “9000:9000”
    networks:
    – laravel
    composer:
    image: composer:1.8.6 #especificar tags
    container_name: composer
    volumes:
    – ./backend:/var/www/html
    working_dir: /var/www/html
    networks:
    – laravel

    npm:
    build:
    context: .
    dockerfile: Dockerfile.frontend
    container_name: npm
    ports:
    – “4200:4200”
    volumes:
    – ./frontend:/app
    # working_dir: /app
    # entrypoint: [“npm”]
    networks:
    – laravel

    artisan:
    build:
    context: .
    dockerfile: Dockerfile.backend
    container_name: artisan
    volumes:
    – ./backend:/var/www/html
    depends_on:
    – mysql
    working_dir: /var/www/html
    entrypoint: [“php”, “/var/www/html/artisan”]
    networks:
    – laravel
    tengo una problema con docker-compose y no logro solucionarlo, el tema es cuando construyo las contenedores tengo problema de permiso de modificación e incluso ejecute:
    chmod -R gu+w
    chmod -R guo+w
    en el contenedor y me permite la modificación pero si agrego otro archivo ese no me deja.
    Alguna sugerencia? se lo agradecería.
    Saludos

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Alejandro,

      Piensa en cada uno de tus contenedores como si fuera una máquina distinta en la que, cuando creas un usuario o un grupo, a estos se les asigna un identificador (UID para usuarios, GID para el grupo).

      Si compartes volúmenes/carpetas entre diferentes máquinas y el UID o el GID no coinciden, este usuario no dispondrá de los permisos adecuados.

      Un ejemplo: el contenedor oficial de Apache con PHP ejecuta el Apache con el usuario www-data y el UID 33. Cualquier fichero o carpeta que crees desde una aplicación PHP de ese contenedor tendrá los permisos definidos para el usuario con UID 33 que funcione en otro contenedor diferente y que acceda al mismo volumen.

      Si los contenedores son tuyos propios y creas usuarios, puedes intentar crearlos asegurándote de que tienen el mismo UID, de forma que sepas que van a poder compartir los ficheros. Si partes desde otros contenedores siempre puedes “extenderlos”, usándolos como base de tu Dockerfile e incluyendo los cambios que necesites.

      ¡Espero haberte ayudado!

      Gracias por comentar 😉

  24. Avatar de José Manuel
    José Manuel

    Hola Victor.

    He creado un docker WordPress y en local funciona perfectamente.
    He querido rizar el rizo y quiero que sea accesible desde la red pública. Abro el puerto 80 de mi router y lo dirijo a la ip interna y puerto de la máquina que contiene el Docker WordPress. Sin problema.

    El problema surge cuando navego por la página web, ya que en la navegación adopta la IP local y por tanto no navegable desde el exterior. Alguna idea?

    Un saludo.

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola José Manuel,

      Al instalar WordPress se configuran las URLs para el mismo, que son las que está usando cuando intentas navegar. Para cambiarlas y poder navegar con la nueva dirección tendrás que actualizar los campos “Dirección de WordPress (URL)” y “Dirección del sitio (URL)” dentro de Ajustes->Generales, con esto deberías de poder navegar sin problema.

      Espero haber resuelto tus dudas.

      Gracias por comentar. Un saludo 😉

  25. Avatar de Gus
    Gus

    Estoy muy perdido con el tema del SSL, he intentado un montón de cosas para modificar el servicio web y habilitar la conexión por HTTPS, pero no encuentro manera. He visto que muchos usan Dockerfile para esto, si alguien puede ayudarme lo agradecería bastante.

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola Gus!

      En principio tendrías dos opciones relativamente sencillas, dependiendo de lo que quieras hacer:

      Tienes la opción de usar un certificado que hayas contratado (si no dispones de ninguno puedes contratarlo en dinahosting). En este caso tendrás que modificar la configuración del apache/nginx de tu contenedor web para utilizar estos certificados.

      También tienes la opción de usar un certificado de Let’s Encrypt, mediante un contenedor adicional que se encargue de solicitar este certificado y funcione como proxy inverso para tu web. Un ejemplo de esto podría ser steveltn/https-portal.

      Espero haberte sido de ayuda. Un saludo 🙂

  26. Avatar de leo
    leo

    Hola Víctor que gran post, me sirve de mucho, te quería hacer una consulta, estoy implementando angular, django y postgresql con docker, adelante un proxy con jwilder, pero tengo unas dudas al hacer las peticiones desde angular a django(sirve como api para angular) mi consulta va, a que url tendría que apuntar angular para hacer las peticiones a django, acaso a la ip del contenedor? , muchas gracias.

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      Hola, leo,

      En el caso que me comentas, entiendo que estás usando jwilder/nginx-proxy, y por lo tanto, a cada contenedor le habrás definido una variable de entorno “VIRTUAL_HOST” con la que el proxy redigirá a ellos esas peticiones. Lo más sencillo sería dirigir esas peticiones al virtualhost que has definido y ya el proxy se encargará de que lleguen al contenedor correcto.

      Por cierto, no conocía jwilder/nginx-proxy. Me lo anoto para futuras ocasiones (yo me configuraba el proxy con nginx a mano).

      Espero haber resuelto tus dudas 😉

  27. Avatar de naveganteAnonimo

    Excelente tutorial ! muy practico y sencillo aclaraste muchas dudas que tenia ! sin duda excelente post

    1. Avatar de Víctor Rodríguez
      Víctor Rodríguez

      ¡Genial que te haya resultado útil! Gracias por comentar 😉

  28. Avatar de Jorge A

    Hola a todos, una consulta, hay alguna forma de montar un servidor web en este caso uso nginx, donde tengo alojado el frontend en angular, que apunte a un servidor de aplicaciones que es nodejs y este a la bd en mongo, sin exponer los puertos de el backend? , ya mapee el backend con la bd por medio de los nombres de los servicios que declaro en el compose, y conectan, ya expuse los puertos internos, pero no quiero exponer el puerto del back al localhost, si no que el angular conecte al back por el puerto interno, espero que se haya entendido.. muchisimas gracias

    1. Avatar de Marta Mariño
      Marta Mariño

      ¡Hola Jorge!

      Lamentamos no poder darte una respuesta. Lo cierto es que tu caso es muy concreto y requeriría componer un escenario específico del que no disponemos en estos momentos.
      A ver si algún lector del post se ha visto con una situación similar y puede responderte 🙂

      ¡Un saludo!

  29. Avatar de Antonio
    Antonio

    Hola
    estoy intentando hacer tu manual en Windows instalando Ubuntu 22.04.

    tengo instalado Docker en Windows y se carga toda la información en los contenedores

    Creo el archivo dockercompose.yml dentro de la carpeta mi web y lo ejecuto.

    elcr4ck@elcr4ck:~/miweb$ sudo nano docker-compose.yml
    elcr4ck@elcr4ck:~/miweb$ docker-compose up -d
    [+] Running 2/26
    ⠴ miservicio_php Pulling 60.6s
    ⠿ a603fa5e3b41 Pull complete 33.8s
    ⠿ c428f1a49423 Pull complete 33.8s
    ⠋ 156740b07ef8 Downloading [==================================> ] … 58.0s
    ⠋ fb5a4c8af82f Download complete 58.0s
    ⠋ 25f85b498fd5 Download complete 58.0s
    ⠋ 9b233e420ac7 Download complete 58.0s
    ⠋ fe42347c4ecf Download complete 58.0s
    ⠋ d14eb2ed1e17 Download complete 58.0s
    ⠋ 66d98f73acb6 Download complete 58.0s
    ⠋ d2c43c5efbc8 Download complete 58.0s
    ⠋ ab590b48ea47 Download complete 58.0s
    ⠋ 80692ae2d067 Downloading [==================================================>] … 58.0s
    ⠋ 05e465aaa99a Download complete 58.0s
    ⠴ miservicio_mysql Pulling 60.6s
    ⠏ d26998a7c52d Downloading [============================> ] … 57.9s
    ⠏ 4a9d8a3567e3 Download complete 57.9s
    ⠏ bfee1f0f349e Download complete 57.9s
    ⠏ 71ff8dfb9b12 Download complete 57.9s
    ⠏ bf56cbebc916 Download complete 57.9s
    ⠏ 2e747e5e37d7 Download complete 57.9s
    ⠏ 711a06e512da Downloading [=============> ] … 57.9s
    ⠏ 3288d68e4e9e Waiting 57.9s
    ⠏ 49271f2d6d15 Waiting 57.9s
    ⠏ f782f6cac69c Waiting 57.9s
    ⠏ 701dea355691 Pulling fs layer

    [+] Running 3/3
    ⠿ Network miweb_default Created 0.9s
    ⠿ Container miweb-miservicio_mysql-1 Started 3.0s
    ⠿ Container miweb-miservicio_php-1 Started 2.4s
    elcr4ck@elcr4ck:~/miweb$

    Apararentemente se instala.

    en docker de windows me sale esto

    Only show running containers

    Search

    NAME
    ACTIONS
    miweb


    Running (2/2)

    miservicio_mysql-1

    dfed5cf57f06

    mysql:5.7
    Running

    3306:3306
    2 minutes ago
    miservicio_php-1

    4a6002f8045f

    php:7-apache
    Running

    80:80
    2 minutes ago

    y en docker me sale cosas en rojo 🙁

    1. Avatar de Marta Mariño
      Marta Mariño

      ¡Hola Antonio!

      Aparentemente, está todo correcto y los servicios de Docker levantados, pero si te salen cosas en rojo puede ser porque te falte algo.
      Te recomendamos revisar si los puertos configurados no están en uso o si los volúmenes que exportas en la configuración existen dentro del directorio.

      ¡Esperamos haberte sido de ayuda!

  30. Avatar de Juan
    Juan

    Hola Víctor, ¿es posible utilizar docker en dinahosting?
    Gracias

    1. Avatar de Marta Mariño
      Marta Mariño

      ¡Hola Juan!
      Sí, es posible utilizar Docker en los servicios No Administrados (Dedicados o VPS). Ahí cuentas con credenciales de Administrador para instalar las herramientas que necesites.

      ¡Un saludo!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Newsletter

Recibe quincenalmente consejos muy útiles para tu web y ecommerce. Además, con tu alta te regalamos 3 guías: la Gran Guía de la Digitalización, la Guía de WordPress más completa y la Guía de Ciberseguridad para mantener tu web y pyme seguras.

Conviértete en afiliado

Gana dinero recomendando dinahosting a todo el mundo.