Un Dockerfile es un archivo de texto que contiene todas las instrucciones necesarias para construir una imagen de Docker. Estas imágenes son la base de los contenedores Docker, que son entornos ligeros, portables y autosuficientes que pueden ejecutar aplicaciones.
docker build
docker run
Nota: Dockerfile debe llamarse exactamente así (sin extensión) por convención, aunque técnicamente puede tener cualquier nombre.
Un Dockerfile típico contiene una serie de instrucciones en formato INSTRUCCIÓN argumentos
. Aquí un ejemplo básico:
# Imagen base
FROM ubuntu:20.04
# Metadatos
LABEL maintainer="dev@example.com"
LABEL version="1.0"
# Actualizar el sistema e instalar paquetes
RUN apt-get update && apt-get install -y \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
# Establecer el directorio de trabajo
WORKDIR /app
# Copiar archivos necesarios
COPY requirements.txt .
COPY app.py .
# Instalar dependencias
RUN pip3 install -r requirements.txt
# Puerto que expone el contenedor
EXPOSE 5000
# Comando a ejecutar al iniciar el contenedor
CMD ["python3", "app.py"]
El orden de las instrucciones en el Dockerfile es importante porque:
Mejor práctica: Coloca las instrucciones que cambian con menos frecuencia al principio y las que cambian más frecuentemente al final para aprovechar el caché de Docker.
Especifica la imagen base a utilizar. Debe ser la primera instrucción en un Dockerfile.
FROM <imagen>[:<tag>] [AS <nombre>]
Ejemplos:
FROM ubuntu:20.04
FROM python:3.9-slim
FROM node:14 AS builder
Ejecuta comandos durante la construcción de la imagen.
RUN <comando> (shell form)
RUN ["ejecutable", "param1", "param2"] (exec form)
Ejemplos:
RUN apt-get update && apt-get install -y curl
RUN ["/bin/bash", "-c", "echo hello"]
Especifica el comando por defecto al ejecutar el contenedor. Solo puede haber un CMD por Dockerfile.
CMD ["ejecutable","param1","param2"] (exec form, preferido)
CMD ["param1","param2"] (como parámetros para ENTRYPOINT)
CMD comando param1 param2 (shell form)
Ejemplos:
CMD ["python", "app.py"]
CMD ["nginx", "-g", "daemon off;"]
Configura el comando que siempre se ejecutará cuando el contenedor inicie. Puede combinarse con CMD.
ENTRYPOINT ["ejecutable", "param1", "param2"] (exec form, preferido)
ENTRYPOINT comando param1 param2 (shell form)
Ejemplo:
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
Ambas copian archivos del host al contenedor, pero con diferencias:
Instrucción | Descripción | Recomendación |
---|---|---|
COPY | Copia archivos/directorios locales | Usar para copiar archivos normales |
ADD | Además de copiar, puede descomprimir archivos y descargar URLs | Usar solo cuando se necesiten sus características adicionales |
Ejemplos:
COPY requirements.txt /app/
ADD https://example.com/file.tar.gz /tmp/
ADD file.tar.gz /tmp/
Establece el directorio de trabajo para las instrucciones siguientes.
WORKDIR /ruta/al/directorio
Ejemplo:
WORKDIR /app
RUN pwd # Output: /app
Establece variables de entorno.
ENV <clave>=<valor>
ENV <clave1>=<valor1> <clave2>=<valor2> ...
Ejemplo:
ENV APP_HOME=/app
ENV PYTHON_VERSION=3.9
ENV NODE_ENV=production
Documenta los puertos que el contenedor escuchará en tiempo de ejecución.
EXPOSE <puerto> [<puerto>/<protocolo>...]
Ejemplo:
EXPOSE 80
EXPOSE 443/tcp
EXPOSE 3000 5000 8000
Crea un punto de montaje para volúmenes persistentes o compartidos.
VOLUME ["/data"]
Ejemplo:
VOLUME /var/lib/mysql
VOLUME ["/app/data", "/app/config"]
Establece el usuario (y grupo) para las siguientes instrucciones.
USER <usuario>[:<grupo>]
Ejemplo:
USER nobody
USER 1000:1000
Define variables que pueden pasarse al momento de construir la imagen.
ARG <nombre>[=<valor por defecto>]
Ejemplo:
ARG APP_VERSION=1.0
ARG NODE_ENV
Ejemplo de optimización:
RUN apt-get update && apt-get install -y \
build-essential \
&& make \
&& make install \
&& apt-get remove -y build-essential \
&& apt-get autoremove -y \
&& rm -rf /var/lib/apt/lists/*
Colocar instrucciones que cambian menos frecuentemente al principio:
FROM python:3.9-slim
WORKDIR /app
# Copiar e instalar dependencias primero
COPY requirements.txt .
RUN pip install -r requirements.txt
# Luego copiar el resto del código
COPY . .
Permite separar el entorno de build del de ejecución:
# Fase de construcción
FROM node:14 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Fase de producción
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
ENV FLASK_APP=app.py
ENV FLASK_ENV=production
EXPOSE 5000
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
FROM node:14-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
ENV NODE_ENV=production
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY static /usr/share/nginx/html
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
FROM postgres:13
ENV POSTGRES_USER=myuser
ENV POSTGRES_PASSWORD=mypassword
ENV POSTGRES_DB=mydb
COPY init.sql /docker-entrypoint-initdb.d/
EXPOSE 5432
docker build -t nombre-imagen:tag .
Opciones comunes:
-f
: Especificar un Dockerfile con nombre diferente--no-cache
: Construir sin usar caché--build-arg
: Pasar argumentos de construccióndocker run -d -p 8080:80 --name mi-contenedor nombre-imagen
Opciones comunes:
-d
: Ejecutar en segundo plano (detached)-p
: Mapear puertos (host:contenedor)-e
: Establecer variables de entorno-v
: Montar volúmenesComando | Descripción |
---|---|
docker images |
Listar imágenes disponibles |
docker ps -a |
Listar todos los contenedores |
docker stop <contenedor> |
Detener un contenedor |
docker rm <contenedor> |
Eliminar un contenedor |
docker rmi <imagen> |
Eliminar una imagen |
docker exec -it <contenedor> bash |
Acceder a un contenedor en ejecución |
docker logs <contenedor> |
Ver logs de un contenedor |
Similar a .gitignore, permite excluir archivos y directorios del contexto de construcción.
# Excluir archivos de desarrollo y entornos virtuales .git .gitignore .env venv/ __pycache__/ # Excluir archivos de logs y temporales *.log *.tmp *.swp # Excluir directorios específicos node_modules/ dist/ build/
Técnica avanzada que permite usar múltiples etapas en un Dockerfile para crear imágenes más pequeñas y seguras.
# Etapa de construcción
FROM golang:1.16 AS builder
WORKDIR /go/src/app
COPY . .
RUN go get -d -v ./...
RUN go install -v ./...
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
# Etapa de producción
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/app/app .
CMD ["./app"]
Síntoma: Los cambios no se reflejan en builds posteriores.
Solución:
--no-cache
en el build: docker build --no-cache -t mi-imagen .
Síntoma: La aplicación no puede acceder a archivos dentro del contenedor.
Solución:
COPY --chown
para establecer permisos adecuadosUSER
instruction)Síntoma: Las imágenes son demasiado grandes.
Solución:
Síntoma: El contenedor no puede conectarse a servicios externos.
Solución:
--network
para redes personalizadasDockerfile es una herramienta poderosa para crear imágenes de contenedores reproducibles y portables. Dominar su sintaxis y mejores prácticas permite:
Para más información, consulta la documentación oficial de Dockerfile.