Manual Completo de Dockerfile

1. Introducción a Dockerfile

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.

1.1 Conceptos básicos

1.2 Flujo de trabajo típico

  1. Crear un Dockerfile con las instrucciones necesarias
  2. Construir la imagen con docker build
  3. Ejecutar un contenedor con docker run

Nota: Dockerfile debe llamarse exactamente así (sin extensión) por convención, aunque técnicamente puede tener cualquier nombre.

2. Estructura básica de un Dockerfile

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"]

2.1 Orden de las instrucciones

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.

3. Instrucciones del Dockerfile

3.1 FROM

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

3.2 RUN

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"]

3.3 CMD

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;"]

3.4 ENTRYPOINT

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"]

3.5 COPY vs ADD

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/

3.6 WORKDIR

Establece el directorio de trabajo para las instrucciones siguientes.

WORKDIR /ruta/al/directorio

Ejemplo:

WORKDIR /app
RUN pwd  # Output: /app

3.7 ENV

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

3.8 EXPOSE

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

3.9 VOLUME

Crea un punto de montaje para volúmenes persistentes o compartidos.

VOLUME ["/data"]

Ejemplo:

VOLUME /var/lib/mysql
VOLUME ["/app/data", "/app/config"]

3.10 USER

Establece el usuario (y grupo) para las siguientes instrucciones.

USER <usuario>[:<grupo>]

Ejemplo:

USER nobody
USER 1000:1000

3.11 ARG

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

4. Buenas prácticas para Dockerfiles

4.1 Minimizar el tamaño de la imagen

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/*

4.2 Ordenar instrucciones para aprovechar el caché

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 . .

4.3 Usar multi-stage builds para imágenes de producción

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;"]

4.4 Seguridad en Dockerfiles

5. Ejemplos comunes de Dockerfiles

5.1 Aplicación Python (Flask)

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"]

5.2 Aplicación Node.js

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"]

5.3 Servidor Nginx

FROM nginx:alpine

COPY nginx.conf /etc/nginx/nginx.conf
COPY static /usr/share/nginx/html

EXPOSE 80 443

CMD ["nginx", "-g", "daemon off;"]

5.4 Base de datos PostgreSQL

FROM postgres:13

ENV POSTGRES_USER=myuser
ENV POSTGRES_PASSWORD=mypassword
ENV POSTGRES_DB=mydb

COPY init.sql /docker-entrypoint-initdb.d/

EXPOSE 5432

6. Comandos útiles relacionados con Dockerfile

6.1 Construir una imagen

docker build -t nombre-imagen:tag .

Opciones comunes:

6.2 Ejecutar un contenedor

docker run -d -p 8080:80 --name mi-contenedor nombre-imagen

Opciones comunes:

6.3 Otros comandos útiles

Comando 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

7. El archivo .dockerignore

Similar a .gitignore, permite excluir archivos y directorios del contexto de construcción.

7.1 Ejemplo de .dockerignore

# 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/

7.2 Beneficios

8. Multi-stage builds

Técnica avanzada que permite usar múltiples etapas en un Dockerfile para crear imágenes más pequeñas y seguras.

8.1 Ejemplo completo

# 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"]

8.2 Beneficios

9. Solución de problemas comunes

9.1 Problemas de caché

Síntoma: Los cambios no se reflejan en builds posteriores.

Solución:

9.2 Permisos de archivos

Síntoma: La aplicación no puede acceder a archivos dentro del contenedor.

Solución:

9.3 Tamaño de imagen excesivo

Síntoma: Las imágenes son demasiado grandes.

Solución:

9.4 Problemas de red

Síntoma: El contenedor no puede conectarse a servicios externos.

Solución:

10. Conclusión

Dockerfile 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.

Recursos adicionales