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

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

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

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

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

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.