Compartir comentarios
Las respuestas se generan en base a la documentación.

Vista general de Dockerfile

Dockerfile

Todo comienza con un Dockerfile.

Docker compila imágenes leyendo las instrucciones de un Dockerfile. Un Dockerfile es un archivo de texto que contiene las instrucciones para compilar tu código fuente. La sintaxis de las instrucciones del Dockerfile está definida por la referencia de especificación en la referencia de Dockerfile.

Aquí tienes los tipos de instrucciones más comunes:

InstrucciónDescripción
FROM <imagen>Define una base para tu imagen.
RUN <comando>Ejecuta cualquier comando en una nueva capa encima de la imagen actual y confirma el resultado. RUN también tiene una forma de shell para ejecutar comandos.
WORKDIR <directorio>Establece el directorio de trabajo para cualquier instrucción RUN, CMD, ENTRYPOINT, COPY y ADD que le sigan en el Dockerfile.
COPY <origen> <destino>Copia nuevos archivos o directorios desde <origen> y los añade al sistema de archivos del contenedor en la ruta <destino>.
CMD <comando>Te permite definir el programa predeterminado que se ejecuta una vez que inicias el contenedor basado en esta imagen. Cada Dockerfile solo tiene un CMD, y solo se respeta la última instancia de CMD cuando existen varias.

Los Dockerfiles son entradas cruciales para las compilaciones de imágenes y pueden facilitar compilaciones de imágenes automatizadas y multicapa basadas en tus configuraciones únicas. Los Dockerfiles pueden comenzar siendo simples y crecer con tus necesidades para soportar escenarios más complejos.

Nombre de archivo

El nombre de archivo predeterminado para un Dockerfile es Dockerfile, sin extensión de archivo. El uso del nombre predeterminado te permite ejecutar el comando docker build sin tener que especificar banderas de comando adicionales.

Algunos proyectos pueden necesitar Dockerfiles distintos para propósitos específicos. Una convención común es nombrarlos como <algo>.Dockerfile. Puedes especificar el nombre del archivo Dockerfile utilizando la bandera --file para el comando docker build. Consulta la referencia de CLI de docker build para obtener información sobre la bandera --file.

Note

Recomendamos usar el nombre predeterminado (Dockerfile) para el Dockerfile principal de tu proyecto.

Imágenes de Docker

Las imágenes de Docker constan de capas. Cada capa es el resultado de una instrucción de compilación en el Dockerfile. Las capas se apilan secuencialmente y cada una es una diferencia (delta) que representa los cambios aplicados a la capa anterior.

Ejemplo

Así es como se ve un flujo de trabajo típico para compilar aplicaciones con Docker.

El siguiente código de ejemplo muestra una pequeña aplicación "Hello World" escrita en Python, que utiliza el framework Flask.

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

Para distribuir y desplegar esta aplicación sin Docker Build, tendrías que asegurarte de que:

  • Las dependencias de tiempo de ejecución requeridas estén instaladas en el servidor.
  • El código Python se suba al sistema de archivos del servidor.
  • El servidor inicie tu aplicación utilizando los parámetros necesarios.

El siguiente Dockerfile crea una imagen de contenedor, que tiene todas las dependencias instaladas y que inicia automáticamente tu aplicación.

# syntax=docker/dockerfile:1
FROM ubuntu:22.04

# install app dependencies
RUN apt-get update && apt-get install -y python3 python3-pip
RUN pip install flask==3.0.*

# install app
COPY hello.py /

# final configuration
ENV FLASK_APP=hello
EXPOSE 8000
CMD ["flask", "run", "--host", "0.0.0.0", "--port", "8000"]

Aquí tienes un desglose de lo que hace este Dockerfile:

Sintaxis de Dockerfile

La primera línea que se debe añadir a un Dockerfile es una directiva del analizador # syntax. Aunque es opcional, esta directiva le indica al constructor de Docker qué sintaxis utilizar al analizar el Dockerfile, y permite que las versiones anteriores de Docker con BuildKit habilitado utilicen un frontend de Dockerfile específico antes de comenzar la compilación. Las directivas del analizador deben aparecer antes de cualquier otro comentario, espacio en blanco o instrucción de Dockerfile en tu Dockerfile, y deben ser la primera línea en los Dockerfiles.

# syntax=docker/dockerfile:1
Tip

Recomendamos utilizar docker/dockerfile:1, que siempre apunta a la última versión de la sintaxis de la versión 1. BuildKit busca automáticamente actualizaciones de la sintaxis antes de compilar, asegurándose de que estás utilizando la versión más reciente.

Imagen base

La línea que sigue a la directiva de sintaxis define qué imagen base utilizar:

FROM ubuntu:22.04

La instrucción FROM establece tu imagen base como la versión 22.04 de Ubuntu. Todas las instrucciones que siguen se ejecutan en esta imagen base: un entorno Ubuntu. La notación ubuntu:22.04 sigue el estándar nombre:etiqueta para nombrar imágenes de Docker. Cuando compilas imágenes, utilizas esta notación para nombrar tus imágenes. Hay muchas imágenes públicas que puedes aprovechar en tus proyectos importándolas en tus pasos de compilación utilizando la instrucción FROM del Dockerfile.

Docker Hub contiene un gran conjunto de imágenes oficiales que puedes utilizar para este propósito.

Configuración del entorno

La siguiente línea ejecuta un comando de compilación dentro de la imagen base.

# install app dependencies
RUN apt-get update && apt-get install -y python3 python3-pip

Esta instrucción RUN ejecuta una shell en Ubuntu que actualiza el índice de paquetes APT e instala las herramientas de Python en el contenedor.

Comentarios

Observa la línea # install app dependencies. Esto es un comentario. Los comentarios en los Dockerfiles comienzan con el símbolo #. A medida que tu Dockerfile evoluciona, los comentarios pueden ser fundamentales para documentar cómo funciona tu Dockerfile para futuros lectores y editores del archivo, incluyéndote a ti mismo en el futuro.

Note

Es posible que hayas notado que los comentarios se denotan utilizando el mismo símbolo que la directiva de sintaxis en la primera línea del archivo. El símbolo solo se interpreta como una directiva si el patrón coincide con una directiva y aparece al principio del Dockerfile. De lo contrario, se trata como un comentario.

Instalación de dependencias

La segunda instrucción RUN instala la dependencia flask requerida por la aplicación Python.

RUN pip install flask==3.0.*

Un requisito previo para esta instrucción es que pip esté instalado en el contenedor de compilación. El primer comando RUN instala pip, lo que garantiza que se pueda usar el comando para instalar el framework web flask.

Copia de archivos

La siguiente instrucción utiliza la instrucción COPY para copiar el archivo hello.py desde el contexto de compilación local al directorio raíz de nuestra imagen.

COPY hello.py /

Un contexto de compilación es el conjunto de archivos a los que puedes acceder en las instrucciones de Dockerfile como COPY y ADD.

Después de la instrucción COPY, el archivo hello.py se añade al sistema de archivos del contenedor de compilación.

Configuración de variables de entorno

Si tu aplicación utiliza variables de entorno, puedes establecer variables de entorno en tu compilación de Docker utilizando la instrucción ENV.

ENV FLASK_APP=hello

Esto establece una variable de entorno de Linux que necesitaremos más adelante. Flask, el framework utilizado en este ejemplo, utiliza esta variable para iniciar la aplicación. Sin esto, flask no sabría dónde encontrar nuestra aplicación para poder ejecutarla.

Puertos expuestos

La instrucción EXPOSE marca que nuestra imagen final tiene un servicio escuchando en el puerto 8000.

EXPOSE 8000

Esta instrucción no es obligatoria, pero es una buena práctica y ayuda a que las herramientas y los miembros del equipo entiendan lo que hace esta aplicación.

Inicio de la aplicación

Finalmente, la instrucción CMD establece el comando que se ejecuta cuando el usuario inicia un contenedor basado en esta imagen.

CMD ["flask", "run", "--host", "0.0.0.0", "--port", "8000"]

Este comando inicia el servidor de desarrollo de flask escuchando en todas las direcciones en el puerto 8000. El ejemplo aquí utiliza la versión "exec form" de CMD. También es posible utilizar "shell form":

CMD flask run --host 0.0.0.0 --port 8000

Existen diferencias sutiles entre estas dos versiones, por ejemplo, en cómo capturan señales como SIGTERM y SIGKILL. Para obtener más información sobre estas diferencias, consulta Shell and exec form.

Compilación

Para compilar una imagen de contenedor utilizando el ejemplo de Dockerfile de la sección anterior, utilizas el comando docker build:

$ docker build -t test:latest .

La opción -t test:latest especifica el nombre y la etiqueta de la imagen.

El punto único (.) al final del comando establece el contexto de compilación en el directorio actual. Esto significa que la compilación espera encontrar el Dockerfile y el archivo hello.py en el directorio desde donde se invoca el comando. Si esos archivos no están allí, la compilación falla.

Después de compilar la imagen, puedes ejecutar la aplicación como un contenedor con docker run, especificando el nombre de la imagen:

$ docker run -p 127.0.0.1:8000:8000 test:latest

Esto publica el puerto 8000 del contenedor en http://localhost:8000 en el host de Docker.

Tip

Para mejorar el análisis estático, la navegación de código y el escaneo de vulnerabilidades de tus Dockerfiles en Visual Studio Code, consulta la extensión Docker DX.