Docker

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

|

Tiempo de lectura: 4 minutos

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

68 respuestas

  1. 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 😉

  2. 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 😉

  3. 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 😉

  4. 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 😉

  5. 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 😉

Deja una respuesta

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

Newsletter

Suscríbete y recibe periódicamente consejos muy útiles para tu web y ecommerce 🙂 Además, te regalamos
3 guías
: Digitalización, WordPress y Ciberseguridad.

Conviértete en afiliado

Gana dinero recomendando dinahosting a todo el mundo.