Desarrolla tu aplicación Rust
Prerrequisitos
- Has instalado la última versión de Docker Desktop.
- Has completado las guías en el Centro de aprendizaje de Docker Desktop para conocer los conceptos de Docker.
- Tienes un cliente git. Los ejemplos de esta sección utilizan un cliente git basado en la línea de comandos, pero puedes utilizar cualquier cliente.
Resumen
En esta sección, aprenderás cómo utilizar volúmenes y redes en Docker. También utilizarás Docker para compilar tus imágenes y Docker Compose para hacer todo mucho más fácil.
Primero, veremos cómo ejecutar una base de datos en un contenedor y cómo utilizar volúmenes y redes para persistir tus datos y permitir que tu aplicación se comunique con la base de datos. Luego, lo reuniremos todo en un archivo Compose que te permitirá configurar y ejecutar un entorno de desarrollo local con un solo comando.
Ejecuta una base de datos en un contenedor
En lugar de descargar PostgreSQL, instalarlo, configurarlo y luego ejecutar la base de datos PostgreSQL como un servicio, puedes utilizar la Imagen Oficial de Docker para PostgreSQL y ejecutarla en un contenedor.
Antes de ejecutar PostgreSQL en un contenedor, crea un volumen que Docker pueda administrar para almacenar tus datos y configuración persistentes. Utiliza la función de volúmenes con nombre (named volumes) que proporciona Docker en lugar de utilizar montajes de tipo bind (bind mounts).
Ejecuta el siguiente comando para crear tu volumen.
$ docker volume create db-data
Ahora crea una red que tu aplicación y la base de datos utilizarán para comunicarse entre sí. La red se llama red puente definida por el usuario (user-defined bridge network) y te proporciona un servicio de resolución DNS útil que puedes utilizar al crear tu cadena de conexión.
$ docker network create postgresnet
Ahora puedes ejecutar PostgreSQL en un contenedor y conectarlo al volumen y a la red que creaste anteriormente. Docker descargará la imagen desde Hub y la ejecutará localmente por ti.
En el siguiente comando, la opción --mount sirve para iniciar el contenedor con un volumen. Para obtener más información, consulta
Volúmenes de Docker.
$ docker run --rm -d --mount \
"type=volume,src=db-data,target=/var/lib/postgresql" \
-p 5432:5432 \
--network postgresnet \
--name db \
-e POSTGRES_PASSWORD=mysecretpassword \
-e POSTGRES_DB=example \
postgres:18
Ahora, asegúrate de que tu base de datos PostgreSQL esté en funcionamiento y de que puedas conectarte a ella. Conéctate a la base de datos PostgreSQL en ejecución dentro del contenedor.
$ docker exec -it db psql -U postgres
Deberías ver una salida como la siguiente.
psql (15.3 (Debian 15.3-1.pgdg110+1))
Type "help" for help.
postgres=#
En el comando anterior, iniciaste sesión en la base de datos PostgreSQL pasando el comando psql al contenedor db. Presiona ctrl-d para salir de la terminal interactiva de PostgreSQL.
Obtén y ejecuta la aplicación de muestra
Para la aplicación de muestra, utilizarás una variante del backend de la aplicación react-rust-postgres de Awesome Compose.
Clona el repositorio de la aplicación de muestra utilizando el siguiente comando.
$ git clone https://github.com/docker/docker-rust-postgresEn el directorio del repositorio clonado, ejecuta
docker initpara crear los archivos de Docker necesarios. Consulta el siguiente ejemplo para responder a las preguntas dedocker init.$ docker init 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! ? What application platform does your project use? Rust ? What version of Rust do you want to use? 1.70.0 ? What port does your server listen on? 8000En el directorio del repositorio clonado, abre el
Dockerfileen un IDE o editor de texto para actualizarlo.docker initse encargó de crear la mayoría de las instrucciones en el Dockerfile, pero tendrás que actualizarlo para tu aplicación específica. Además de un directoriosrc, esta aplicación incluye un directoriomigrationspara inicializar la base de datos. Agrega un montaje de tipo bind para el directoriomigrationsen la etapa de compilación en el Dockerfile. El siguiente es el Dockerfile actualizado.# syntax=docker/dockerfile:1 # Los comentarios se proporcionan a lo largo de este archivo para ayudarte a empezar. # Si necesitas más ayuda, visita la guía de referencia de Dockerfile en # https://docs-docker.esdocu.com/reference/dockerfile/ ################################################################################ # Crea una etapa para compilar la aplicación. ARG RUST_VERSION=1.70.0 ARG APP_NAME=react-rust-postgres FROM rust:${RUST_VERSION}-slim-bullseye AS build ARG APP_NAME WORKDIR /app # Compila la aplicación. # Aprovecha un montaje de caché en /usr/local/cargo/registry/ # para las dependencias descargadas y un montaje de caché en /app/target/ para # las dependencias compiladas, lo que acelerará las compilaciones posteriores. # Aprovecha un montaje de tipo bind al directorio src para evitar tener que copiar el # código fuente dentro del contenedor. Una vez compilado, copia el ejecutable a un # directorio de salida antes de que se desmonte el /app/target montado en caché. RUN --mount=type=bind,source=src,target=src \ --mount=type=bind,source=Cargo.toml,target=Cargo.toml \ --mount=type=bind,source=Cargo.lock,target=Cargo.lock \ --mount=type=cache,target=/app/target/ \ --mount=type=cache,target=/usr/local/cargo/registry/ \ --mount=type=bind,source=migrations,target=migrations \ <<EOF set -e cargo build --locked --release cp ./target/release/$APP_NAME /bin/server EOF ################################################################################ # Crea una nueva etapa para ejecutar la aplicación que contenga las dependencias de # ejecución mínimas para la aplicación. A menudo se utiliza una imagen base diferente # de la etapa de compilación donde se copian los archivos necesarios desde la etapa de # compilación. # # El siguiente ejemplo utiliza la imagen debian bullseye como base para ejecutar la aplicación. # Al especificar la etiqueta "bullseye-slim", también utilizará la versión más reciente # de esa etiqueta cuando compiles tu Dockerfile. Si la reproducibilidad es importante, # considera utilizar un digest # (por ejemplo, debian@sha256:ac707220fbd7b67fc19b112cee8170b41a9e97f703f588b2cdbbcdcecdd8af57). FROM debian:bullseye-slim AS final # Crea un usuario sin privilegios bajo el cual se ejecutará la aplicación. # Consulta https://docs-docker.esdocu.com/develop/develop-images/dockerfile_best-practices/#user ARG UID=10001 RUN adduser \ --disabled-password \ --gecos "" \ --home "/nonexistent" \ --shell "/sbin/nologin" \ --no-create-home \ --uid "${UID}" \ appuser USER appuser # Copia el ejecutable desde la etapa de compilación "build". COPY --from=build /bin/server /bin/ # Expone el puerto en el que escucha la aplicación. EXPOSE 8000 # Lo que debe ejecutar el contenedor cuando se inicia. CMD ["/bin/server"]En el directorio del repositorio clonado, ejecuta
docker buildpara compilar la imagen.$ docker build -t rust-backend-image .Ejecuta
docker runcon las siguientes opciones para ejecutar la imagen como un contenedor en la misma red que la base de datos.$ docker run \ --rm -d \ --network postgresnet \ --name docker-develop-rust-container \ -p 3001:8000 \ -e PG_DBNAME=example \ -e PG_HOST=db \ -e PG_USER=postgres \ -e PG_PASSWORD=mysecretpassword \ -e ADDRESS=0.0.0.0:8000 \ -e RUST_LOG=debug \ rust-backend-imageHaz curl a la aplicación para verificar que se conecta a la base de datos.
$ curl http://localhost:3001/usersDeberías obtener una respuesta como la siguiente.
[{ "id": 1, "login": "root" }]
Usa Compose para desarrollar localmente
Cuando ejecutas docker init, además de un Dockerfile, también se crea un archivo compose.yaml.
Este archivo Compose es muy conveniente ya que no tienes que escribir todos los parámetros que se pasan al comando docker run. Puedes hacer eso de forma declarativa usando un archivo Compose.
En el directorio del repositorio clonado, abre el archivo compose.yaml en un IDE o editor de texto. docker init se encargó de crear la mayoría de las instrucciones, pero tendrás que actualizarlo para tu aplicación específica.
Debes actualizar los siguientes elementos en el archivo compose.yaml:
- Descomentar todas las instrucciones de la base de datos.
- Agregar las variables de entorno bajo el servicio server.
El siguiente es el archivo compose.yaml actualizado.
# Los comentarios se proporcionan a lo largo de este archivo para ayudarte a empezar.
# Si necesitas más ayuda, visita la guía de referencia de Docker Compose en
# https://docs-docker.esdocu.com/reference/compose-file/
# Aquí las instrucciones definen tu aplicación como un servicio llamado "server".
# Este servicio se construye a partir del Dockerfile en el directorio actual.
# Puedes añadir otros servicios de los que dependa tu aplicación aquí, como una
# base de datos o un caché. Para ver ejemplos, consulta el repositorio Awesome Compose:
# https://github.com/docker/awesome-compose
services:
server:
build:
context: .
target: final
ports:
- 8000:8000
environment:
- PG_DBNAME=example
- PG_HOST=db
- PG_USER=postgres
- PG_PASSWORD=mysecretpassword
- ADDRESS=0.0.0.0:8000
- RUST_LOG=debug
# La siguiente sección comentada es un ejemplo de cómo definir una base de datos
# PostgreSQL que tu aplicación puede utilizar. `depends_on` le dice a Docker Compose que
# inicie la base de datos antes que tu aplicación. El volumen `db-data` persiste los
# datos de la base de datos entre reinicios del contenedor. El secreto `db-password` se utiliza
# para establecer la contraseña de la base de datos. Debes crear `db/password.txt` y añadir
# la contraseña que elijas antes de ejecutar `docker compose up`.
depends_on:
db:
condition: service_healthy
db:
image: postgres:18
restart: always
user: postgres
secrets:
- db-password
volumes:
- db-data:/var/lib/postgresql
environment:
- POSTGRES_DB=example
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
expose:
- 5432
healthcheck:
test: ["CMD", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db-data:
secrets:
db-password:
file: db/password.txtTen en cuenta que el archivo no especifica una red para esos dos servicios. Cuando utilizas Compose, este crea automáticamente una red y conecta los servicios a ella. Para más información, consulta Redes en Compose.
Antes de ejecutar la aplicación con Compose, ten en cuenta que este archivo Compose especifica un archivo password.txt para contener la contraseña de la base de datos. Debes crear este archivo, ya que no está incluido en el repositorio fuente.
En el directorio del repositorio clonado, crea un nuevo directorio llamado db y dentro de ese directorio crea un archivo llamado password.txt que contenga la contraseña para la base de datos. Utilizando tu IDE o editor de texto favorito, añade el siguiente contenido al archivo password.txt.
mysecretpasswordSi tienes algún otro contenedor ejecutándose de las secciones anteriores, detenlos ahora.
Ahora, ejecuta el siguiente comando docker compose up para iniciar tu aplicación.
$ docker compose up --build
El comando pasa la bandera --build para que Docker compile tu imagen y luego inicie los contenedores.
Ahora prueba tu endpoint de la API. Abre una nueva terminal y realiza una solicitud al servidor utilizando los comandos curl:
$ curl http://localhost:8000/users
Deberías recibir la siguiente respuesta:
[{ "id": 1, "login": "root" }]Resumen
En esta sección, vimos cómo configurar tu archivo Compose para ejecutar tu aplicación Rust y la base de datos con un solo comando.
Información relacionada:
Pasos siguientes
En la siguiente sección, veremos cómo configurar un flujo de trabajo de CI/CD utilizando GitHub Actions.