Contenedoriza una aplicación Vue.js
Requisitos previos
Antes de comenzar, asegúrate de que las siguientes herramientas estén instaladas y disponibles en tu sistema:
- Has instalado la última versión de Docker Desktop.
- Tienes un cliente de git. Los ejemplos de esta sección utilizan un cliente de git basado en línea de comandos, pero puedes utilizar cualquier cliente.
¿Es tu primera vez con Docker?
Comienza con la guía de conceptos básicos de Docker para familiarizarte con conceptos clave como imágenes, contenedores y Dockerfiles.
Descripción general
Esta guía te acompaña a lo largo de todo el proceso de contenedorización de una aplicación Vue.js con Docker. Aprenderás a crear una imagen de Docker lista para producción utilizando las mejores prácticas que mejoran el rendimiento, la seguridad, la escalabilidad y la eficiencia del despliegue.
Al final de esta guía, lograrás:
- Contenedorizar una aplicación Vue.js utilizando Docker.
- Crear y optimizar un Dockerfile para compilaciones de producción.
- Utilizar compilaciones multi-etapa (multi-stage) para minimizar el tamaño de la imagen.
- Servir la aplicación de manera eficiente con una configuración de Nginx personalizada.
- Compilar imágenes Docker seguras y fáciles de mantener siguiendo las mejores prácticas.
Obtén la aplicación de ejemplo
Clona la aplicación de ejemplo para usarla con esta guía. Abre una terminal, navega al directorio donde deseas trabajar y ejecuta el siguiente comando para clonar el repositorio de git:
$ git clone https://github.com/kristiyan-velkov/docker-vuejs-sample
Generar un Dockerfile
Docker proporciona una herramienta de CLI interactiva llamada docker init que ayuda a estructurar los archivos de configuración necesarios para contenedorizar tu aplicación. Esto incluye la generación de un Dockerfile, .dockerignore, compose.yaml y README.Docker.md.
Para comenzar, navega a la raíz del directorio de tu proyecto:
$ cd docker-vuejs-sample
Luego ejecuta el siguiente comando:
$ docker init
Deberías ver una salida similar a:
Welcome to the Docker Init CLI!
This utility will walk you through creating the following files with sensible defaults for your project:
- .dockerignore
- Dockerfile
- compose.yaml
- README.Docker.md
Let's get started!La interfaz de línea de comandos te hará algunas preguntas sobre la configuración de tu aplicación. Para mantener la coherencia, utiliza las mismas respuestas que se muestran en el ejemplo a continuación cuando se te solicite:
| Pregunta | Respuesta |
|---|---|
| What application platform does your project use? | Node |
| What version of Node do you want to use? | 24.12.0-alpine |
| Which package manager do you want to use? | npm |
| Do you want to run "npm run build" before starting server? | yes |
| What directory is your build output to? | dist |
| What command do you want to use to start the app? | npm run build |
| What port does your server listen on? | 8080 |
Una vez finalizado, el directorio de tu proyecto contendrá los siguientes archivos nuevos:
├── docker-vuejs-sample/
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── compose.yaml
│ └── README.Docker.mdCompilar la imagen de Docker
El Dockerfile predeterminado generado por docker init proporciona una base sólida para aplicaciones típicas de Node.js. Sin embargo, Vue.js es un framework de front-end que se compila en recursos estáticos, lo que significa que el Dockerfile debe personalizarse para adaptarse a cómo se compilan y se sirven de manera eficiente las aplicaciones Vue.js en un entorno de producción. Adaptarlo adecuadamente garantiza un mejor rendimiento, tamaños de imagen más pequeños y un proceso de despliegue más fluido.
Paso 1: Revisar los archivos generados
En este paso, mejorarás el Dockerfile y los archivos de configuración siguiendo las mejores prácticas:
- Utilizar compilaciones multi-etapa (multi-stage) para mantener la imagen final limpia y pequeña
- Servir la aplicación utilizando Nginx, un servidor web rápido y seguro
- Mejorar el rendimiento y la seguridad incluyendo únicamente lo necesario
Estas actualizaciones ayudan a garantizar que tu aplicación sea fácil de desplagar, rápida de cargar y esté lista para producción.
NoteUn
Dockerfilees un archivo de texto plano que contiene instrucciones paso a paso para compilar una imagen de Docker. Automatiza el empaquetado de tu aplicación junto con sus dependencias y el entorno de ejecución.
Para obtener detalles completos, consulta la referencia de Dockerfile.
Paso 2: Configurar el Dockerfile
Antes de crear un Dockerfile, debes elegir una imagen base. Puedes utilizar la imagen oficial de Node.js o una imagen protegida de Docker (DHI, Docker Hardened Image) del catálogo de imágenes protegidas.
Elegir una DHI ofrece la ventaja de contar con una imagen lista para producción que es ligera y segura. Para obtener más información, consulta Docker Hardened Images.
ImportantEsta guía utiliza una etiqueta de imagen LTS estable de Node.js que se considera segura en el momento de escribir la guía. Dado que se publican nuevas versiones y parches de seguridad de forma regular, es posible que la etiqueta que se muestra aquí ya no sea la opción más segura cuando sigas la guía. Revisa siempre las últimas etiquetas de imagen disponibles y selecciona una versión segura y actualizada antes de compilar o desplegar tu aplicación.
Imágenes Docker oficiales de Node.js: https://hub.docker.com/_/node
Las Docker Hardened Images (DHIs) están disponibles para Node.js en el catálogo de Docker Hardened Images. Las Docker Hardened Images están disponibles gratuitamente para todos sin necesidad de suscripción. Puedes descargarlas y utilizarlas como cualquier otra imagen de Docker después de iniciar sesión en el registro DHI. Para obtener más información, consulta la guía de inicio rápido de DHI.
Inicia sesión en el registro DHI:
$ docker login dhi.ioDescarga la DHI de Node.js (consulta el catálogo para ver las versiones disponibles):
$ docker pull dhi.io/node:24-alpine3.22-devDescarga la DHI de Nginx (consulta el catálogo para ver las versiones disponibles):
$ docker pull dhi.io/nginx:1.28.0-alpine3.21-dev
En el siguiente Dockerfile, las instrucciones FROM utilizan dhi.io/node:24-alpine3.22-dev y dhi.io/nginx:1.28.0-alpine3.21-dev como imágenes base.
# =========================================
# Etapa 1: Compilar la aplicación Vue.js
# =========================================
# Usar una imagen ligera DHI de Node.js para la compilación
FROM dhi.io/node:24-alpine3.22-dev AS builder
# Establecer el directorio de trabajo dentro del contenedor
WORKDIR /app
# Copiar primero los archivos relacionados con los paquetes para aprovechar el mecanismo de caché de Docker
COPY package.json package-lock.json* ./
# Instalar las dependencias del proyecto usando npm ci (garantiza una instalación limpia y reproducible)
RUN --mount=type=cache,target=/root/.npm npm ci
# Copiar el resto del código fuente de la aplicación en el contenedor
COPY . .
# Compilar la aplicación Vue.js
RUN npm run build
# =========================================
# Etapa 2: Preparar Nginx para servir archivos estáticos
# =========================================
FROM dhi.io/nginx:1.28.0-alpine3.21-dev AS runner
# Copiar la configuración personalizada de Nginx
COPY nginx.conf /etc/nginx/nginx.conf
# Copiar la salida estática de la compilación de la etapa de construcción al directorio de servicio HTML predeterminado de Nginx
COPY --chown=nginx:nginx --from=builder /app/dist /usr/share/nginx/html
# Usar un usuario no root incorporado como mejor práctica de seguridad
USER nginx
# Exponer el puerto 8080 para permitir el tráfico HTTP
# Nota: El contenedor Nginx predeterminado ahora escucha en el puerto 8080 en lugar del 80
EXPOSE 8080
# Iniciar Nginx directamente con la configuración personalizada
ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"]
CMD ["-g", "daemon off;"]Reemplaza el contenido de tu Dockerfile actual con la configuración optimizada a continuación. Esta configuración está adaptada específicamente para compilar y servir aplicaciones Vue.js en un entorno limpio, eficiente y listo para producción.
# =========================================
# Etapa 1: Compilar la aplicación Vue.js
# =========================================
ARG NODE_VERSION=24.12.0-alpine
ARG NGINX_VERSION=alpine3.22
# Usar una imagen ligera de Node.js para la compilación (personalizable mediante ARG)
FROM node:${NODE_VERSION} AS builder
# Establecer el directorio de trabajo dentro del contenedor
WORKDIR /app
# Copiar primero los archivos relacionados con los paquetes para aprovechar el mecanismo de caché de Docker
COPY package.json package-lock.json* ./
# Instalar las dependencias del proyecto usando npm ci (garantiza una instalación limpia y reproducible)
RUN --mount=type=cache,target=/root/.npm npm ci
# Copiar el resto del código fuente de la aplicación en el contenedor
COPY . .
# Compilar la aplicación Vue.js
RUN npm run build
# =========================================
# Etapa 2: Preparar Nginx para servir archivos estáticos
# =========================================
FROM nginxinc/nginx-unprivileged:${NGINX_VERSION} AS runner
# Copiar la configuración personalizada de Nginx
COPY nginx.conf /etc/nginx/nginx.conf
# Copiar la salida estática de la compilación de la etapa de construcción al directorio de servicio HTML predeterminado de Nginx
COPY --chown=nginx:nginx --from=builder /app/dist /usr/share/nginx/html
# Usar un usuario no root incorporado como mejor práctica de seguridad
USER nginx
# Exponer el puerto 8080 para permitir el tráfico HTTP
# Nota: El contenedor Nginx predeterminado ahora escucha en el puerto 8080 en lugar del 80
EXPOSE 8080
# Iniciar Nginx directamente con la configuración personalizada
ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"]
CMD ["-g", "daemon off;"]NoteEstamos utilizando nginx-unprivileged en lugar de la imagen estándar de Nginx para seguir las mejores prácticas de seguridad. Ejecutar la imagen final como un usuario no root:
- Reduce la superficie de ataque
- Se alinea con las recomendaciones de Docker para el aseguramiento (hardening) de contenedores
- Ayuda a cumplir con políticas de seguridad más estrictas en entornos de producción
Paso 3: Configurar el archivo .dockerignore
El archivo .dockerignore juega un papel crucial en la optimización de tu imagen de Docker al especificar qué archivos y directorios deben excluirse del contexto de compilación.
NoteEsto ayuda a:
- Reducir el tamaño de la imagen
- Acelerar el proceso de compilación
- Evitar que se añadan archivos sensibles o innecesarios (como
.env,.gitonode_modules) a la imagen final.Para obtener más información, consulta la referencia de .dockerignore.
Copia y reemplaza el contenido de tu archivo .dockerignore existente con la configuración a continuación:
# -------------------------------
# Directorios de dependencias
# -------------------------------
node_modules/
# -------------------------------
# Salidas de producción y compilación
# -------------------------------
dist/
out/
build/
public/build/
# -------------------------------
# Directorios de caché y de Vite/VuePress
# -------------------------------
.vite/
.vitepress/
.cache/
.tmp/
# -------------------------------
# Salidas de pruebas y cobertura
# -------------------------------
coverage/
reports/
jest/
cypress/
cypress/screenshots/
cypress/videos/
# -------------------------------
# Archivos de entorno y configuración
# -------------------------------
*.env*
!.env.production # Mantener el entorno de producción si es necesario
*.local
*.log
# -------------------------------
# Artefactos de TypeScript
# -------------------------------
*.tsbuildinfo
# -------------------------------
# Configuración de editores e IDEs
# -------------------------------
.vscode/
.idea/
*.swp
# -------------------------------
# Archivos del sistema
# -------------------------------
.DS_Store
Thumbs.db
# -------------------------------
# Archivos de bloqueo (opcional)
# -------------------------------
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# -------------------------------
# Archivos de Git
# -------------------------------
.git/
.gitignore
# -------------------------------
# Archivos relacionados con Docker
# -------------------------------
Dockerfile
.dockerignore
docker-compose.yml
docker-compose.override.ymlPaso 4: Crear el archivo nginx.conf
Para servir tu aplicación Vue.js de manera eficiente dentro del contenedor, configurarás Nginx con un diseño personalizado. Esta configuración está optimizada para el rendimiento, el almacenamiento en caché del navegador, la compresión gzip y el soporte para el enrutamiento del lado del cliente (client-side routing).
Crea un archivo llamado nginx.conf en la raíz del directorio de tu proyecto y añade el siguiente contenido:
NotePara obtener más información sobre la configuración de Nginx, consulta la documentación oficial de Nginx.
worker_processes auto;
pid /tmp/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
charset utf-8;
access_log off;
error_log /dev/stderr warn;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
gzip on;
gzip_comp_level 6;
gzip_proxied any;
gzip_min_length 256;
gzip_vary on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
server {
listen 8080;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg|map)$ {
expires 1y;
access_log off;
add_header Cache-Control "public, immutable";
add_header X-Content-Type-Options nosniff;
}
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header X-Content-Type-Options nosniff;
}
error_page 404 /index.html;
}
}Paso 5: Compilar la imagen de la aplicación Vue.js
Con tu configuración personalizada implementada, ya estás listo para compilar la imagen de Docker para tu aplicación Vue.js.
La configuración actualizada incluye:
- Una configuración de Nginx limpia y lista para producción adaptada específicamente para Vue.js.
- Una compilación Docker eficiente de múltiples etapas, garantizando una imagen final pequeña y segura.
Después de completar los pasos anteriores, el directorio de tu proyecto debería contener los siguientes archivos:
├── docker-vuejs-sample/
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── compose.yaml
│ ├── nginx.conf
│ └── README.Docker.mdAhora que tu Dockerfile está configurado, puedes compilar la imagen de Docker para tu aplicación Vue.js.
NoteEl comando
docker buildempaqueta tu aplicación en una imagen utilizando las instrucciones del Dockerfile. Incluye todos los archivos necesarios del directorio actual (llamado contexto de compilación).
Ejecuta el siguiente comando desde la raíz de tu proyecto:
$ docker build --tag docker-vuejs-sample .
Qué hace este comando:
- Utiliza el Dockerfile en el directorio actual (.)
- Empaqueta la aplicación y sus dependencias en una imagen Docker
- Etiqueta la imagen como docker-vuejs-sample para que puedas hacer referencia a ella más adelante
Paso 6: Ver imágenes locales
Después de compilar tu imagen de Docker, puedes verificar qué imágenes están disponibles en tu máquina local utilizando la CLI de Docker o Docker Desktop. Dado que ya estás trabajando en la terminal, utilicemos la CLI de Docker.
Para enumerar todas las imágenes de Docker disponibles localmente, ejecuta el siguiente comando:
$ docker images
Ejemplo de salida:
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-vuejs-sample latest 8c9c199179d4 14 seconds ago 76.2MBEsta salida proporciona detalles clave sobre tus imágenes:
- Repository – El nombre asignado a la imagen.
- Tag – Una etiqueta de versión que ayuda a identificar diferentes compilaciones (por ejemplo, latest).
- Image ID – Un identificador único para la imagen.
- Created – La marca de tiempo que indica cuándo se compiló la imagen.
- Size – El espacio total en disco utilizado por la imagen.
Si la compilación se completó con éxito, deberías ver la imagen docker-vuejs-sample en la lista.
Ejecutar la aplicación contenedorizada
En el paso anterior, creaste un Dockerfile para tu aplicación Vue.js y compilaste una imagen de Docker utilizando el comando docker build. Ahora es el momento de ejecutar esa imagen en un contenedor y verificar que tu aplicación funcione según lo esperado.
Dentro del directorio docker-vuejs-sample, ejecuta el siguiente comando en una terminal.
$ docker compose up --build
Abre un navegador y visualiza la aplicación en http://localhost:8080. Deberías ver una aplicación web Vue.js sencilla.
Presiona ctrl+c en la terminal para detener la aplicación.
Ejecutar la aplicación en segundo plano
Puedes ejecutar la aplicación desacoplada de la terminal (detached) agregando la opción -d. Dentro del directorio docker-vuejs-sample, ejecuta el siguiente comando en una terminal.
$ docker compose up --build -d
Abre un navegador y visualiza la aplicación en http://localhost:8080. Deberías ver tu aplicación Vue.js ejecutándose en el navegador.
Para confirmar que el contenedor se está ejecutando, utiliza el comando docker ps:
$ docker ps
Esto enumerará todos los contenedores activos junto con sus puertos, nombres y estado. Busca un contenedor que exponga el puerto 8080.
Ejemplo de salida:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
37a1fa85e4b0 docker-vuejs-sample-server "nginx -c /etc/nginx…" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp docker-vuejs-sample-server-1Para detener la aplicación, ejecuta:
$ docker compose down
NotePara obtener más información sobre los comandos de Compose, consulta la referencia de la CLI de Compose.
Resumen
En esta guía, aprendiste a contenedorizar, compilar y ejecutar una aplicación Vue.js utilizando Docker. Al seguir las mejores prácticas, creaste una configuración segura, optimizada y lista para producción.
Lo que lograste:
- Inicializaste tu proyecto utilizando
docker initpara estructurar los archivos de configuración esenciales de Docker. - Reemplazaste el
Dockerfilepredeterminado con una compilación multi-etapa que compila la aplicación Vue.js y sirve los archivos estáticos utilizando Nginx. - Reemplazaste el archivo
.dockerignorepredeterminado para excluir archivos innecesarios y mantener la imagen limpia y eficiente. - Compilaste tu imagen de Docker utilizando
docker build. - Ejecutaste el contenedor utilizando
docker compose up, tanto en primer plano como en modo desacoplado. - Verificaste que la aplicación se estuviera ejecutando visitando http://localhost:8080.
- Aprendiste a detener la aplicación contenedorizada utilizando
docker compose down.
Ahora tienes una aplicación Vue.js completamente contenedorizada, ejecutándose en un contenedor Docker y lista para ser desplegada en cualquier entorno con confianza y coherencia.
Recursos relacionados
Explora las referencias oficiales y las mejores prácticas para perfeccionar tu flujo de trabajo con Docker:
- Compilaciones multi-etapa – Aprende cómo separar las etapas de compilación y de ejecución.
- Mejores prácticas para escribir Dockerfiles – Escribe Dockerfiles eficientes, fáciles de mantener y seguros.
- Contexto de compilación en Docker – Aprende cómo afecta el contexto a las compilaciones de imágenes.
- Referencia de la CLI
docker init– Estructura automáticamente recursos de Docker. - Referencia de la CLI
docker build– Compila imágenes de Docker desde un Dockerfile. - Referencia de la CLI
docker images– Gestiona e inspecciona imágenes locales de Docker. - Referencia de la CLI
docker compose up– Inicia y ejecuta aplicaciones multi-contenedor. - Referencia de la CLI
docker compose down– Detiene y elimina contenedores, redes y volúmenes.
Siguientes pasos
Con tu aplicación Vue.js ahora contenedorizada, estás listo para pasar al siguiente paso.
En la siguiente sección, aprenderás cómo desarrollar tu aplicación utilizando contenedores Docker, lo que permite un entorno de desarrollo coherente, aislado y reproducible en cualquier máquina.