# Vista general de Dockerfile


<!-- vale Docker.We = NO -->

## 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](/reference/dockerfile/).

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

| Instrucción                                                | Descripción                                                                                                                                                                                                                      |
| :--------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`FROM <imagen>`](/reference/dockerfile/#from)           | Define una base para tu imagen.                                                                                                                                                                                                  |
| [`RUN <comando>`](/reference/dockerfile/#run)            | 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>`](/reference/dockerfile/#workdir) | Establece el directorio de trabajo para cualquier instrucción `RUN`, `CMD`, `ENTRYPOINT`, `COPY` y `ADD` que le sigan en el Dockerfile.                                                                                          |
| [`COPY <origen> <destino>`](/reference/dockerfile/#copy) | Copia nuevos archivos o directorios desde `<origen>` y los añade al sistema de archivos del contenedor en la ruta `<destino>`.                                                                                                   |
| [`CMD <comando>`](/reference/dockerfile/#cmd)            | 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`](/reference/cli/docker/buildx/build/#file)
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.

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

```dockerfile
# 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](#sintaxis-de-dockerfile)
- [Imagen base](#imagen-base)
- [Configuración del entorno](#configuracion-del-entorno)
- [Comentarios](#comentarios)
- [Instalación de dependencias](#instalacion-de-dependencias)
- [Copia de archivos](#copia-de-archivos)
- [Configuración de variables de entorno](#configuracion-de-variables-de-entorno)
- [Puertos expuestos](#puertos-expuestos)
- [Inicio de la aplicación](#inicio-de-la-aplicacion)

### Sintaxis de Dockerfile

La primera línea que se debe añadir a un Dockerfile es una [directiva del analizador `# syntax`](/reference/dockerfile/#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](/build/buildkit/#primeros-pasos)
utilicen un [frontend de Dockerfile específico](/build/buildkit/frontend/) antes de
comenzar la compilación. Las [directivas del analizador](/reference/dockerfile/#parser-directives)
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.

```dockerfile
# 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:

```dockerfile
FROM ubuntu:22.04
```

La [instrucción `FROM`](/reference/dockerfile/#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](https://hub.docker.com/search?badges=official)
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.

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

Esta [instrucción `RUN`](/reference/dockerfile/#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](#sintaxis-de-dockerfile) 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.

```dockerfile
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`](/reference/dockerfile/#copy) para copiar el
archivo `hello.py` desde el contexto de compilación local al directorio raíz de nuestra imagen.

```dockerfile
COPY hello.py /
```

Un [contexto de compilación](/build/concepts/context/) 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`](/reference/dockerfile/#env).

```dockerfile
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`](/reference/dockerfile/#expose) marca que
nuestra imagen final tiene un servicio escuchando en el puerto `8000`.

```dockerfile
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`](/reference/dockerfile/#cmd) establece el
comando que se ejecuta cuando el usuario inicia un contenedor basado en esta imagen.

```dockerfile
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":

```dockerfile
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](/reference/dockerfile/#shell-and-exec-form).

## Compilación

Para compilar una imagen de contenedor utilizando el ejemplo de Dockerfile de la
[sección anterior](#ejemplo), utilizas el comando `docker build`:

```console
$ 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](/build/concepts/context/) 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:

```console
$ 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](https://marketplace.visualstudio.com/items?itemName=docker.docker).

