Tabla de Contenidos
4 Despliegue avanzado en Servidor
En el apartado anterior vimos lo básico para empezar a usar Docker. En este apartado vamos a ver como crear nuestras propias imágenes.
Mas información:
Creación de imágenes
Podemos crear nuestras propias imágenes si ninguna de las que hay hace lo que nosotros necesitamos. Para ello usaremos el comando docker buildx build.
El comando docker buildx 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.
docker buildx build --tag nombre_imagen:etiqueta --file ruta_del_dockerfile ruta_contexto_ficheros
Donde:
–tag nombre_imagen:etiqueta: Nombre y tag de la imagen que se va a crear–file ruta_del_dockerfile: Ruta al fichero que contiene el Dockerfile. Si no se indica se usará el ficheroDockerfiledel directorio actual.ruta_contexto_ficheros: Ruta donde se encuentran los ficheros a copiar dentro de la imagen. Esto es importante ya que las rutas absolutas delCOPYempiezan en/ruta/al/contexto
- Ejemplo de uso: Crea la imagen llamada
mi_aplicacion_web:1.0sabiendo que el ficheroDockerfileestá en la carpeta actual y los ficheros a copiar están en el directorio./src.
docker buildx build -t mi_aplicacion_web:1.0 ./src
Estructura Básica del Dockerfile
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 # Documenta que puerto usa el contenedor EXPOSE puerto #El directorio de trabajo WORKDIR /directorio # 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.
FROM eclipse-temurin:17.0.10_7-jdk
- 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 mkdir /opt/app
- COPY: Copia archivos desde la ruta de origen en la máquina host hacia el contenedor en la ruta de destino.
COPY ./app.jar /opt/app
ruta_al_contexto del comando de buildx
COPY o que la propia imagen los descargue con una comando RUN?
| Opción | Ventaja | Desventaja |
|---|---|---|
Copiar ficheros desde fuera con COPY | Siguen estando aunque desparezcan de internet | Para crear la imagen es necesario que lo hayamos descargado previamente |
Descargar ficheros desde el RUN | No necesitas descargar nada previamente y es más cómodo | No podrás crear la imagen si desaparecen esos ficheros de internet. |
- EXPOSE: Informa a Docker que el contenedor escuchará en el puerto especificado en tiempo de ejecución. No publica el puerto en la máquina real ni hace realmente nada. Es simplemente para documentar en que puerto
EXPOSE 8080
- WORKDIR: Establece el directorio de trabajo para cualquier instrucción posterior en el Dockerfile. Se usando tanto para crear la imagen como en el contenedor.
WORKDIR /opt/app
- ENV: Define variables de entorno dentro del contenedor.
ENV ENTORNO=produccion
- CMD: Especifica el comando predeterminado que se ejecutará cuando el contenedor se inicie. Solo puede haber una comando CMD
CMD ["java", "-jar","/opt/app/app.jar"]
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
Ejemplo: Ejecutar app java
Una imagen basada en el JDK 17 que ya incluye maven.
Al crear la imagen se hace lo siguiente
- Instalar Git
- Descargar el código fuente
- Compilar
Al arrancar el contenedor se ejecuta
java -jar target/tienda-back-0.0.1-SNAPSHOT.jar
FROM maven:3.9.11-eclipse-temurin-21-noble ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update RUN apt-get install -y git RUN mkdir /opt/app WORKDIR /opt/app RUN git clone https://github.com/lgonzalezmislata/tienda-back.git WORKDIR /opt/app/tienda-back RUN mvn clean install EXPOSE 8080 CMD ["java","-jar", "target/tienda-back-0.0.1-SNAPSHOT.jar"]
Para crear la imagen ejecutamos
docker buildx build --tag tienda-back:1.0 .
Finalmente la ejecutamos con
docker container run -p 8081:8080 --name tienda-back tienda-back:1.0
Multiples imagenes
Acabamos de ver que hemos tenido la suerte de tener una imagen con el JDK y con maven pero no siempre tenemos esa suerte. Para Angular necesitamos hacer el build con una imagen que tenga NodeJS pero tambien que tenga NGINX. Podemos construir una imagen con todo ello pero lo más sencillo es una 2 imágenes distintas y copiar el resultado de uno en el otro.
Vamos a ver ahora como un Dockerfile puede ser con 2 imágenes de forma que el resultado de una se copie a la otra.
- Imagen con NodeJS para compilar el código de Angular
- Imagen con NGINX que hace de servidor HTTP para desplegar la aplicación
FROM node:22.19.0 AS build RUN apt-get update RUN apt-get install -y git RUN mkdir /opt/app WORKDIR /opt/app RUN git clone https://github.com/lgonzalezmislata/tienda-front.git WORKDIR /opt/app/tienda-front RUN npm ci RUN npm run build --prod FROM nginx:1.28.0-alpine3.21 COPY --from=build /opt/app/tienda-front/dist/tienda-front/browser/ /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
- En la línea 1 vemos como se usa la imagen
node:22.19.0y la llamamosbuild - En las siguientes lineas compilamos el código de Angular
- En la línea 15 se crea una nueva imagen
nginx:1.28.0-alpine3.21 - En la línea 16 es cuando se copia el código compìlado de Angular desde la imagen
builda la imagen de NGINX. Notar que se usa–from=buildpara indicar que es desde la primera imagen. ¿Y como sabemos que hay que copiar las cosas en/usr/share/nginx/html? Pues mirando en https://hub.docker.com/_/nginx/
Para crear la imagen ejecutamos
docker buildx build --tag tienda-front:1.0 .
Finalmente la ejecutamos con
docker container run -p 80:80 --name tienda-front tienda-front:1.0
Ejercicios
Ejercicio 1:Crear la imagen
Crea una imagen de docker basada en eclipse-temurin:17.0.10_7-jdk que haga lo siguiente:
- Con
RUN:Crear el directorio/opt/app. - Con
CMD:Que ejecute un jar llamadojapp.jar
La imagen se llamará tu-nombre-java-app.
Crea un contenedor con esa imagen de forma que con -v esté el japp.jar en /opt/app
Ejercicio 2:Sin crear imagen
En la imagen eclipse-temurin:17.0.10_7-jdk ya existe la carpeta /tmp y en docker container run se puede poner al final de la línea la orden a ejecutar.
Así que ejecuta un jar de la siguiente manera:
sudo docker container run \ -v /mi-proyecto/target:/tmp \ eclipse-temurin:17.0.10_7-jdk \ java -jar /tmp/mi.jar
docker container run faltan más parámetros que hay que añadir.
Ejercicio 3:Maven
Ahora vamos a generar el jar en base al código fuente, para ello vamos a usar una imagen que ya tiene maven instalado: Docker image maven y concretamente maven:3.9.6-eclipse-temurin-17.
Para hacerlo hay que poner el código fuente en /usr/src/mymaven y especificar que el directorio de trabajo será ese, para ello usaremos el argumento -w. Al final del todo indicaremos la orden de maven a ejecutar.
sudo docker container run \ -v /mi-proyecto:/usr/src/mymaven \ -w /usr/src/mymaven \ maven:3.9.6-eclipse-temurin-17 \ mvn clean package
docker container run faltan más parámetros que hay que añadir.
-d-i-t- ????
Ejercicio 4:Deploy
Has un script en la máquina real llamado deploy.sh que haga lo siguiente:
- Se baje el código fuente de git
- Genere el
jarpero se ejecutará maven dentro del contenedor de docker cuya imagen es:maven:3.9.6-eclipse-temurin-17 - Ejecute el
jardentro del contenedor de docker cuya imagen es:eclipse-temurin:17.0.10_7-jdk
Ejercicio 5:MySQL
Crea ahora una base de datos MySQL en un contenedor docker de forma que sea la que estás usando en el módulo de servidor. Rellena la base de datos con los datos.
Ejercicio 6:Deploy proyecto
Compila y desplega el proyecto que usas en el módulo de servidor de forma que se genere el jar en un contenedor de docker y se ejecute en un contenedor de docker. Este último contenedor deberá conectarse al contenedor de MySQL que has creado.
Ejercicio 7:Deploy proyecto
Modifica el proyecto de Maven de forma que tambien se haga lo necesario para "compilar" la parte de Angular. Esa parte la vimos en el tema 3 en el apartado de maven
Ejercicio 8: MySQL compañero
Prueba ahora a modificaar el código de forma que te conectes al MySQL de tu compañero. Deberá dejarte.
Ejercicio 9:Red
Crea ahora una red llamada mi-nombre-mi-proyecto.
Modifica la creación de los contenedores para que estén asociados a la red que acabas de crear.
Prueba que todo sigue funcionando.
Ejercicio 10: MySQL compañero
Prueba ahora a modificaar el código de forma que te conectes al MySQL de tu compañero. No debería dejarte ya que estáis en redes distintas.
Ejercicio 11: Docker compose
Modifica el script deploy.sh de forma que en vez de crear directamente los 2 contenedores de MySQL y Java se use docker compose up.
Para ello deberás crear un fichero llamado docker-compose.yml
