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

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.