¡Esta es una revisión vieja del documento!
En el tema anterior vimos lo básico para empezar a usar Docker. En este tema vamos a ver aspectos mas avanzados de Docker y trucos a tener en cuenta para usarlo.
Mas información:
Podemos crear nuestras propias imágenes si ninguna de las que hay hace lo que nosotros necesitamos. PAra ello usaremos el comando docker build
.
El comando docker build
se utiliza para construir imágenes de contenedor Docker a partir de un Dockerfile. A continuación se presentan las principales características y uso de este comando.
<shx>
docker build -t nombre_imagen:etiqueta ruta_del_dockerfile
</shx>
Donde:
Dockerfile
por lo que sea pondrá un punto indicando que es el directorio actual.mi_aplicacion_web:1.0
sabiendo que el fichero Dockerfile
está en la carpeta actual.<shx> docker build -t mi_aplicacion_web:1.0 . </shx>
Un Dockerfile contiene instrucciones para la construcción de una imagen. Aquí se muestra una estructura básica:
# Especifica la imagen base FROM imagen_base:version # Instrucciones para configurar la imagen RUN comando1 RUN comando2 # Copia archivos locales al contenedor COPY origen destino # Expone un puerto en el contenedor EXPOSE puerto # Define variables de entorno ENV variable=valor # Comando para ejecutar la aplicación o servicio CMD ["comando", "argumento"]
- FROM: Indica la imagen base desde la cual se construirá la nueva imagen. La versión es opcional.
# Comentario: Descripción del propósito de la imagen FROM imagen_base:version # Especifica la imagen base
- RUN: Ejecuta comandos en una nueva capa del contenedor. Se utiliza para instalar paquetes, configurar el entorno y realizar otras acciones durante la construcción de la imagen.
RUN comando1 RUN comando2
- COPY: Copia archivos desde la ruta de origen en la máquina host hacia el contenedor en la ruta de destino.
COPY origen destino
- EXPOSE: Informa a Docker que el contenedor escuchará en el puerto especificado en tiempo de ejecución. No publica el puerto en el host.
EXPOSE puerto
- ENV: Define variables de entorno dentro del contenedor.
ENV variable=valor
- CMD: Especifica el comando predeterminado que se ejecutará cuando el contenedor se inicie.
CMD ["comando", "argumento"]
RUN
y CMD
es que RUN
se ejecuta cuando se crea la imagen con el comando docker build
,es decir configurándola mientras que CMD
se ejecuta cuando se crea el contenedor con el comando docker container run
Docker permite crear redes aisladas entre los distintos contenedores. De esa forma , si un contenedor es atacado, no se tendrá acceso por red al resto de los contenedores sino únicamente a los de su propia red.
Orden | Explicación |
---|---|
docker network create | Crea una red |
docker network rm | Borrar una red |
docker network ls | Ver las redes que hay |
docker network connect | Conecta un contenedor a una red |
docker network disconnect | Desconecta un contenedor de una red |
Para trabajar con redes, lo que debemos hacer es
docker network create nombreDeLaRed
docker network connect nombreDeLaRed nombreDelContenedor
docker container run
con la opción --network=nombreDeLaRed
docker container run \ -dit \ -v /opt/mariadb:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=root \ -p 4000:3306 \ --network=nombreDeLaRed \ --name prueba_mariadb \ mariadb:10.1
¿Recuerdas la cabecera Host
de HTTP? Servía para indicar a que servidor web iba dirigida la petición ya que en una misma máquina se ponían varios servidores web.
Pues vamos ahora a configurar Docker para que todos los servidores compartan el mismo puerto (el 80). Para ello vamos a usar un servidor proxy llamado Nginx. Obviamente, Nginx va estar dentro de otro contenedor de Docker. La imagen a usar es jwilder/nginx-proxy con tag 0.7.0.
Para arrancar el servidor usamos la siguiente orden:
sudo docker container run \ -dit \ -p 80:80 \ --restart always \ -v /var/run/docker.sock:/tmp/docker.sock:ro \ --name nginx-proxy \ nginxproxy/nginx-proxy:1.1.0
Como vemos no tiene nada de especial excepto la línea -v /var/run/docker.sock:/tmp/docker.sock:ro
pero solo decir que es para que Nginx pueda acceder al Docker real de la máquina real.
Y ahora , ¿Como arrancamos nuestro servidores web? Pues simplemente hay que añadir dos parámetros y quitar uno.
-p puertoExterno:puertoInterno
ya que ahora el contenedor no se va a exponer al exterior. -e VIRTUAL_PORT=puertoInterno
: Siendo puertoInterno donde está escuchando nuestro servidor Web. Esa información la sabremos por la documentación -e VIRTUAL_HOST=nombreDominio
: Siendo nombreDominio el nombre del dominio que queremos que gestione el servidor que estamos arrancando.Veamos el siguiente ejemplo:
sudo docker container run \ -dit \ -v /home/alumno/lorenzo/httpd:/var/www/html \ -e VIRTUAL_PORT=80 -e VIRTUAL_HOST=lorenzo.daw2.pve3.fpmislata.com \ --name lorenzo_apache \ php:8.1-apache-bullseye
Vemos que el servidor está escuchando en el puerto 80 y va a gestionar las peticiones del dominio lorenzo.daw2.pve3.fpmislata.com que lleguen a Nginx.
Mas información:
Ahora para que funcione el proxy con nginx ya no podemos acceder a la máquina real con la IP sino que habrá que usar el nombre de dominio. Si no tenemos acceso a un nombre de dominio real, podemos simular nosotros uno modificando el fichero hosts
de la máquina donde vayamos a hacer la petición.
El fichero hosts simplemente contiene IPs y nombre e dominio que usará nuestro ordenador. De esa forma simularemos tener un dominio.
En los siguientes artículos se explica como modificar el fichero hosts
Docker Compose es una herramienta que permite definir y administrar aplicaciones Docker de múltiples contenedores. Utiliza un archivo YAML para configurar los servicios, las redes y los volúmenes, facilitando la definición y el despliegue de aplicaciones complejas.
Un archivo `docker-compose.yml` define la configuración de una aplicación multi-contenedor. Aquí se presentan las secciones principales:
version: '3' # Versión de la sintaxis de Docker Compose services: # Definición de servicios servicio1: image: imagen_servicio1 ports: - "puerto_host:puerto_contenedor" volumes: - /ruta/host:/ruta/contenedor environment: - VARIABLE=valor servicio2: # Configuración del segundo servicio
networks: # Definición de redes
red1: # Configuración de la red1
volumes: # Definición de volúmenes
volumen1: # Configuración del volumen1
</shx>
services: Esta sección define los servicios de la aplicación, cada uno representado por un contenedor. Incluye configuraciones como la imagen a utilizar, puertos a exponer, volúmenes y variables de entorno.
networks: Permite definir redes personalizadas para la comunicación entre los servicios. Los contenedores dentro de la misma red pueden comunicarse entre sí.
volumes: Define volúmenes persistentes que pueden ser compartidos entre los servicios. Útil para almacenar datos fuera del ciclo de vida del contenedor.
- docker-compose up: Inicia la aplicación basada en la configuración de `docker-compose.yml`.
- docker-compose down: Detiene y elimina los contenedores, redes y volúmenes definidos en el archivo `docker-compose.yml`.
- docker-compose ps: Muestra el estado de los servicios de la aplicación.
Supongamos un archivo `docker-compose.yml` para una aplicación web con un servicio de frontend y otro de base de datos:
<shx> version: '3'
services:
web: image: nginx:latest ports: - "80:80" db: image: mysql:latest environment: - MYSQL_ROOT_PASSWORD=secreto
</shx>
Para iniciar esta aplicación, ejecutamos:
<shx> docker-compose up </shx>
Esto levantará los contenedores de frontend y base de datos con la configuración especificada.
Docker Compose simplifica la gestión de aplicaciones Docker complejas, permitiendo definir y coordinar múltiples servicios con facilidad.
Crea un contenedor llamado "maria_a" que sean de MariaDB:
Crea un contenedor llamado "maria_b" que sean de MariaDB:
Crea un contenedores llamado "apache_a" que sean del servidor web Apache con PHP:
.env
para guardar los datos de conexión a la base de datos
Crea un contenedores llamado "apache_b" que sean del servidor web Apache con PHP:
.env
para guardar los datos de conexión a la base de datos
Modifica únicamente el fichero .env
de cada servidor para que ahora se conecten a la otra base de datos. Deberá funcionar todo sin problemas.
Vuelve a dejar las conexiones como estaban antes del ejercicio.
Crea ahora dos redes llamadas:
Vuelve a crear los 4 contenedores de antes pero de forma que cada uno esté asociado a una red distinta.
Contenedor | Red |
---|---|
apache_a | red_a |
maria_a | red_a |
apache_b | red_b |
maria_b | red_b |
Prueba que los 2 servidores web siguen funcionando y accediendo a sus bases de datos correspondientes.
Modifica únicamente el fichero .env
de cada servidor para que ahora se conecten a la otra base de datos. No deberán poder conectarse
Vuelve a dejar las conexiones como estaban antes del ejercicio, es decir todas conectadas a "prueba_red".
Hasta ahora para acceder a cada servidor web usabas los puertos 3010
y 3020
. Vamos ahora a usar el servidor Proxy Nginx para que a ambos se pueda acceder por nombre de dominio y todos por el puerto 80. Para ello ya no vamos a usar nuestra máquina sino que vamos a usar la máquina que nos proporciona el centro, a la que nos tenemos que conectar por VPN. En esa máquina ya hemos instalado Nginx como proxy.
En esa máquina haz lo siguiente
VIRTUAL_HOST
vale "tuNombre.daw2.pve2.fpmislata.com"VIRTUAL_PORT
vale "80" /opt/tuNombre/docker/apache
/opt/tuNombre/docker/apache
/opt/tuNombre/docker/mariadb
Prueba a navegar la siguientes url (y deberá funcionar):
Crea un proyecto Web en GitHub llamado "ejemplodaw" en los que haya lo siguiente:
El proyecto es similar al anterior solo que ahora también hay código SASS.
Incluye en el proyecto un script de bash llamado deploy.sh
para desplegar el proyecto en docker. El script se ejecutará con npm run deploy
. El script hará lo siguiente:
src
a dist
dist
el código SASSdist
a /opt/tuNombre/docker/apache
En la máquina real ves a la carpeta /opt/tuNombre
y haz un git clone del proyecto que acabas de crear en GitHub. Se creará la carpeta /opt/tuNombre/ejemplodaw
.
Para probar que todo funciona haz cambios en el SASS en master , súbelos a GitHub y ejecuta dentro de la máquina Linux lo siguiente:
cd /opt/tuNombre/ejemplodaw git fetch --prune --force git checkout master git merge --ff-only origin/master npm run deploy
Prueba a navegar a http://tuNombre.daw2.pve2.fpmislata.com y se verán los cambios.