Containerizar una aplicación Angular
Requisitos previos
Antes de empezar, asegúrate de tener instaladas y disponibles las siguientes herramientas en tu sistema:
- La última versión de Docker Desktop.
- Un cliente git. Los ejemplos de esta sección usan git por línea de comandos, pero puedes usar cualquier cliente.
¿Nuevo en Docker?
Empieza con la guía Conceptos básicos de Docker para familiarizarte con conceptos clave como imágenes, contenedores y Dockerfiles.
Descripción general
Esta guía te recorre el proceso completo de containerizar una aplicación Angular con Docker. Aprenderás a crear una imagen Docker lista para producción siguiendo buenas prácticas que mejoran el rendimiento, la seguridad, la escalabilidad y la eficiencia del despliegue.
Al final de esta guía podrás:
- Containerizar una aplicación Angular con Docker.
- Crear y optimizar un Dockerfile para compilaciones de producción.
- Usar compilaciones multi-etapa para reducir el tamaño de la imagen.
- Servir la aplicación de forma eficiente con una configuración personalizada de Nginx.
- Crear imágenes Docker seguras y mantenibles siguiendo buenas prácticas.
Obtener la aplicación de ejemplo
Clona la aplicación de ejemplo para usarla en esta guía. Abre una terminal, ve al directorio donde quieras trabajar y ejecuta el siguiente comando para clonar el repositorio git:
$ git clone https://github.com/kristiyan-velkov/docker-angular-sample
Generar un Dockerfile
Docker ofrece una herramienta CLI interactiva llamada docker init que ayuda a generar los archivos de configuración necesarios para containerizar tu aplicación. Incluye la generación de Dockerfile, .dockerignore, compose.yaml y README.Docker.md.
Para empezar, ve a la raíz del directorio del proyecto:
$ cd docker-angular-sample
Then run the following command:
$ docker init
Verás 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 CLI te hará algunas preguntas sobre la configuración de tu aplicación. Para mantener la coherencia, usa las mismas respuestas del ejemplo siguiente cuando te lo pida:
| 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 start |
| What port does your server listen on? | 8080 |
Al terminar, el directorio del proyecto contendrá los siguientes archivos nuevos:
├── docker-angular-sample/
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── compose.yaml
│ └── README.Docker.mdCompilar la imagen Docker
El Dockerfile por defecto generado por docker init es un buen punto de partida para aplicaciones Node.js en general. Sin embargo, Angular es un framework front-end que compila en recursos estáticos, así que debemos adaptar el Dockerfile para optimizar cómo se compilan y sirven las aplicaciones Angular en producción.
Paso 1: Mejorar el Dockerfile y la configuración generados
En este paso mejorarás el Dockerfile y los archivos de configuración siguiendo buenas prácticas:
- Usar compilaciones multi-etapa para mantener la imagen final limpia y pequeña
- Servir la aplicación con Nginx, un servidor web rápido y seguro
- Mejorar rendimiento y seguridad incluyendo solo lo necesario
Estas mejoras ayudan a que tu aplicación sea fácil de desplegar, cargue rápido y esté lista para producción.
NoteUn
Dockerfilees un archivo de texto plano con instrucciones paso a paso para compilar una imagen Docker. Automatiza el empaquetado de tu aplicación con sus dependencias y entorno de ejecución.
Para más detalles, consulta la referencia de Dockerfile.
Paso 2: Configurar el Dockerfile
Antes de crear un Dockerfile, debes elegir una imagen base. Puedes usar la imagen oficial de Node.js o una Docker Hardened Image (DHI) del catálogo de imágenes endurecidas.
Elegir DHI ofrece una imagen lista para producción, ligera y segura. Para más información, consulta Docker Hardened Images.
ImportantEsta guía usa una etiqueta estable de imagen Node.js LTS considerada segura cuando se escribió la guía. Como se publican versiones y parches de seguridad con regularidad, la etiqueta mostrada puede dejar de ser la opción más segura cuando sigas la guía. Revisa siempre las etiquetas de imagen disponibles y elige 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 (DHI) están disponibles para Node.js en el catálogo de Docker Hardened Images. Las Docker Hardened Images están disponibles gratis para todos, sin suscripción. Puedes hacer pull y usarlas como cualquier otra imagen Docker tras iniciar sesión en el registro DHI. Para más información, consulta la guía de inicio rápido de DHI.
Inicia sesión en el registro DHI:
$ docker login dhi.ioHaz pull de la DHI de Node.js (consulta el catálogo para las versiones disponibles):
$ docker pull dhi.io/node:24-alpine3.22-dev
En el siguiente Dockerfile, la instrucción FROM usa dhi.io/node:24-alpine3.22-dev como imagen base.
# =========================================
# Stage 1: Build the Angular Application
# =========================================
# Use a lightweight DHI Node.js image for building
FROM dhi.io/node:24-alpine3.22-dev AS builder
# Set the working directory inside the container
WORKDIR /app
# Copy package-related files first to leverage Docker's caching mechanism
COPY package.json package-lock.json* ./
# Install project dependencies using npm ci (ensures a clean, reproducible install)
RUN --mount=type=cache,target=/root/.npm npm ci
# Copy the rest of the application source code into the container
COPY . .
# Build the Angular application
RUN npm run build
# =========================================
# Stage 2: Prepare Nginx to Serve Static Files
# =========================================
FROM dhi.io/nginx:1.28.0-alpine3.21-dev AS runner
# Copy custom Nginx config
COPY nginx.conf /etc/nginx/nginx.conf
# Copy the static build output from the build stage to Nginx's default HTML serving directory
COPY --chown=nginx:nginx --from=builder /app/dist/*/browser /usr/share/nginx/html
# Use a non-root user for security best practices
USER nginx
# Expose port 8080 to allow HTTP traffic
# Note: The default Nginx container now listens on port 8080 instead of 80
EXPOSE 8080
# Start Nginx directly with custom config
ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"]
CMD ["-g", "daemon off;"]Ahora debes crear un Dockerfile multi-etapa listo para producción. Sustituye el Dockerfile generado por la siguiente configuración optimizada:
# =========================================
# Stage 1: Build the Angular Application
# =========================================
ARG NODE_VERSION=24.12.0-alpine
ARG NGINX_VERSION=alpine3.22
# Use a lightweight Node.js image for building (customizable via ARG)
FROM node:${NODE_VERSION} AS builder
# Set the working directory inside the container
WORKDIR /app
# Copy package-related files first to leverage Docker's caching mechanism
COPY package.json *package-lock.json* ./
# Install project dependencies using npm ci (ensures a clean, reproducible install)
RUN --mount=type=cache,target=/root/.npm npm ci
# Copy the rest of the application source code into the container
COPY . .
# Build the Angular application
RUN npm run build
# =========================================
# Stage 2: Prepare Nginx to Serve Static Files
# =========================================
FROM nginxinc/nginx-unprivileged:${NGINX_VERSION} AS runner
# Copy custom Nginx config
COPY nginx.conf /etc/nginx/nginx.conf
# Copy the static build output from the build stage to Nginx's default HTML serving directory
COPY --chown=nginx:nginx --from=builder /app/dist/*/browser /usr/share/nginx/html
# Use a built-in non-root user for security best practices
USER nginx
# Expose port 8080 to allow HTTP traffic
# Note: The default Nginx container now listens on port 8080 instead of 80
EXPOSE 8080
# Start Nginx directly with custom config
ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"]
CMD ["-g", "daemon off;"]NoteUsamos nginx-unprivileged en lugar de la imagen estándar de Nginx para seguir buenas prácticas de seguridad. Ejecutar como usuario no root en la imagen final:
- Reduce la superficie de ataque
- Se alinea con las recomendaciones de Docker para endurecer contenedores
- Ayuda a cumplir políticas de seguridad más estrictas en entornos de producción
Paso 3: Configurar el archivo .dockerignore
El archivo .dockerignore indica a Docker qué archivos y carpetas excluir al compilar la imagen.
NoteEsto ayuda a:
- Reducir el tamaño de la imagen
- Acelerar el proceso de compilación
- Evitar que archivos sensibles o innecesarios (como
.env,.gitonode_modules) se añadan a la imagen final.Para más información, consulta la referencia de
.dockerignore.
Copia y sustituye el contenido de tu .dockerignore existente por la configuración siguiente:
# ================================
# Node and build output
# ================================
node_modules
dist
out-tsc
.angular
.cache
.tmp
# ================================
# Testing & Coverage
# ================================
coverage
jest
cypress
cypress/screenshots
cypress/videos
reports
playwright-report
.vite
.vitepress
# ================================
# Environment & log files
# ================================
*.env*
!*.env.production
*.log
*.tsbuildinfo
# ================================
# IDE & OS-specific files
# ================================
.vscode
.idea
.DS_Store
Thumbs.db
*.swp
# ================================
# Version control & CI files
# ================================
.git
.gitignore
# ================================
# Docker & local orchestration
# ================================
Dockerfile
Dockerfile.*
.dockerignore
docker-compose.yml
docker-compose*.yml
# ================================
# Miscellaneous
# ================================
*.bak
*.old
*.tmpPaso 4: Crear el archivo nginx.conf
Para servir tu aplicación Angular de forma eficiente dentro del contenedor, configurarás Nginx con una configuración personalizada. Está optimizada para rendimiento, caché del navegador, compresión gzip y enrutamiento del lado del cliente.
Crea un archivo llamado nginx.conf en la raíz del proyecto y añade el siguiente contenido:
NotePara 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;
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp_path;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
# Logging
access_log off;
error_log /dev/stderr warn;
# Performance
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
# Compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_min_length 256;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/x-javascript
application/json
application/xml
application/xml+rss
font/ttf
font/otf
image/svg+xml;
server {
listen 8080;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Angular Routing
location / {
try_files $uri $uri/ /index.html;
}
# Static Assets Caching
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg|map)$ {
expires 1y;
access_log off;
add_header Cache-Control "public, immutable";
}
# Optional: Explicit asset route
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
}Paso 5: Compilar la imagen de la aplicación Angular
Con tu configuración personalizada lista, ya puedes compilar la imagen Docker de tu aplicación Angular.
La configuración actualizada incluye:
- Una configuración de Nginx limpia y lista para producción, adaptada a Angular.
- Una compilación Docker multi-etapa eficiente que garantiza una imagen final pequeña y segura.
Tras completar los pasos anteriores, el directorio del proyecto debería contener los siguientes archivos:
├── docker-angular-sample/
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── compose.yaml
│ ├── nginx.conf
│ └── README.Docker.mdCon el Dockerfile configurado, puedes compilar la imagen Docker de tu aplicación Angular.
NoteEl comando
docker buildempaqueta tu aplicación en una imagen usando las instrucciones del Dockerfile. Incluye todos los archivos necesarios del directorio actual (el contexto de compilación).
Ejecuta el siguiente comando desde la raíz del proyecto:
$ docker build --tag docker-angular-sample .
Qué hace este comando:
- Usa el Dockerfile del directorio actual (.)
- Empaqueta la aplicación y sus dependencias en una imagen Docker
- Etiqueta la imagen como docker-angular-sample para referenciarla después
Paso 6: Ver imágenes locales
Tras compilar tu imagen Docker, puedes comprobar qué imágenes hay en tu máquina local con la CLI de Docker o Docker Desktop. Como ya trabajas en la terminal, usaremos la CLI de Docker.
Para listar todas las imágenes Docker disponibles en local, ejecuta:
$ docker images
Ejemplo de salida:
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-angular-sample latest 34e66bdb9d40 14 seconds ago 76.4MBEsta salida muestra detalles clave de tus imágenes:
- Repository – Nombre asignado a la imagen.
- Tag – Etiqueta de versión que identifica distintas compilaciones (p. ej., latest).
- Image ID – Identificador único de la imagen.
- Created – Marca de tiempo de cuándo se compiló la imagen.
- Size – Espacio en disco total que usa la imagen.
Si la compilación fue correcta, deberías ver la imagen docker-angular-sample en la lista.
Ejecutar la aplicación containerizada
En el paso anterior creaste un Dockerfile para tu aplicación Angular y compilaste una imagen Docker con el comando docker build. Ahora toca ejecutar esa imagen en un contenedor y comprobar que la aplicación funciona como se espera.
Dentro del directorio docker-angular-sample, ejecuta el siguiente comando en una terminal.
$ docker compose up --build
Abre un navegador y visita la aplicación en http://localhost:8080. Deberías ver una aplicación web Angular sencilla.
Pulsa 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 añadiendo la opción -d. Dentro del directorio docker-angular-sample, ejecuta el siguiente comando en una terminal.
$ docker compose up --build -d
Abre un navegador y visita la aplicación en http://localhost:8080. Deberías ver tu aplicación Angular en el navegador.
Para confirmar que el contenedor está en ejecución, usa el comando docker ps:
$ docker ps
Esto listará todos los contenedores activos 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
eb13026806d1 docker-angular-sample-server "nginx -c /etc/nginx…" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp docker-angular-sample-server-1Para detener la aplicación, ejecuta:
$ docker compose down
NotePara más información sobre los comandos de Compose, consulta la referencia de la CLI de Compose.
Resumen
En esta guía aprendiste a containerizar, compilar y ejecutar una aplicación Angular con Docker. Siguiendo buenas prácticas, creaste una configuración segura, optimizada y lista para producción.
Esto es lo que lograste:
- Inicializar el proyecto con
docker initpara generar los archivos de configuración Docker esenciales. - Sustituir el
Dockerfilepor defecto por una compilación multi-etapa que compila la aplicación Angular y sirve los archivos estáticos con Nginx. - Sustituir el
.dockerignorepor defecto para excluir archivos innecesarios y mantener la imagen limpia y eficiente. - Compilar la imagen Docker con
docker build. - Ejecutar el contenedor con
docker compose up, en primer plano y en segundo plano. - Verificar que la aplicación funcionaba visitando http://localhost:8080.
- Aprender a detener la aplicación containerizada con
docker compose down.
Ya tienes una aplicación Angular totalmente containerizada, en ejecución en un contenedor Docker y lista para desplegarse en cualquier entorno con confianza y consistencia.
Recursos relacionados
Consulta referencias oficiales y buenas prácticas para mejorar tu flujo con Docker:
- Compilaciones multi-etapa – Separa etapas de compilación y ejecución.
- Buenas prácticas para escribir Dockerfiles – Escribe Dockerfiles eficientes, mantenibles y seguros.
- Contexto de compilación en Docker – Cómo el contexto afecta a las compilaciones de imágenes.
- Referencia de la CLI
docker init– Genera recursos Docker automáticamente. - Referencia de la CLI
docker build– Compila imágenes Docker desde un Dockerfile. - Referencia de la CLI
docker images– Gestiona e inspecciona imágenes Docker locales. - Referencia de la CLI
docker compose up– Inicia y ejecuta aplicaciones multicontenedor. - Referencia de la CLI
docker compose down– Detiene y elimina contenedores, redes y volúmenes.
Próximos pasos
Con tu aplicación Angular ya containerizada, estás listo para el siguiente paso.
En la siguiente sección aprenderás a desarrollar tu aplicación con contenedores Docker, con un entorno de desarrollo consistente, aislado y reproducible en cualquier máquina.