Como describí acá, una forma de optimizar la imagen de Docker de tu aplicación Rust, es mediante las construcciones en múltiples etapas. En la primera etapa, construyes la aplicación y obtienes el binario, y en la segunda etapa construyes la imagen final que contiene solo el binario generado previamenete. De esta manera, obtendrás una imagen de Docker más pequeña. El Dockerfile
para la construcción de múltiples etapas se muestra a continuación:
FROM rust:latest AS builder
WORKDIR /app
COPY Cargo.toml .
RUN mkdir src && echo "fn main() {}" > src/main.rs
RUN cargo build --release
COPY src src
RUN touch src/main.rs
RUN cargo build --release
RUN strip target/release/hello_rocket
FROM gcr.io/distroless/cc-debian12 as release
WORKDIR /app
COPY --from=builder /app/target/release/hello_rocket .
ENV ROCKET_ADDRESS=0.0.0.0
ENV ROCKET_PORT=8000
EXPOSE 8000
CMD ["./hello_rocket"]
Otra opción es usar GitLab CI. A través de este artículo, aprenderás como usar GitLab CI para construir una imagen de Docker optimizada de tu aplicación.
GitLab CI#
Primero, crea un repositorio de GitLab para tu proyecto.
En seguida, crea el ejemplo de Hello, world!
con Rocket, en tu entorno local.
Crea un nuevo proyecto:
$ cargo new hello_rocket
Cámbiate al directorio del proyecto:
$ cd hello_rocket
Reemplaza el contenido de src/main.rs
con lo siguiente:
#[macro_use] extern crate rocket;
#[get("/")]
fn index() -> &'static str {
"Hello, world!"
}
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![index])
}
Edita el archivo Cargo.toml
y agrega la dependencia correspondiente:
[package]
name = "hello_rocket"
version = "0.1.0"
edition = "2021"
[dependencies]
rocket = "=0.5.0-rc.3"
El código anterior mostrará el texto Hello, world!
en el navegador. Ahora, sincroniza tu repositorio con el código de tu aplicación
Crea un Dockerfile
en tu repositorio, con el siguiente contenido:
FROM gcr.io/distroless/cc-debian12
WORKDIR /app
COPY /target/release/hello_rocket .
ENV ROCKET_ADDRESS=0.0.0.0
ENV ROCKET_PORT=8000
EXPOSE 8000
CMD ["./hello_rocket"]
Estoy usando una imagen distroless para evitar obtener algún error al ejecutar el contenedor.
Antes de crear el archivo de configuración de GitLab CI, .gitlab-ci.yml
, ve a Settings
⇾ CI/CD
y agrega las siguientes variables:
CI_REGISTRY_USER
. Escribe tu usuario de Docker Hub en el campoValue
CI_REGISTRY_PASSWORD
. En el campoValue
, escribe la constraseña de usuario de Docker HubCI_REGISTRY
. Escribedocker.io
en el campoValue
CI_REGISTRY_IMAGE
. En el campoValue
, escribeindex.docker.io/username/hello-rocket
username
es tu usuario de Docker Hub. hello-rocket
es el nombre del repositorio de Docker Hub donde la imagen estará disponible.
Y finalmente, crea el archivo .gitlab-ci.yml
en tu repositorio, con el siguiente contenido:
stages:
- build
- deploy
build-app:
image: rust:latest
stage: build
script:
- cargo build --release
- strip target/release/hello_rocket
artifacts:
paths:
- target/
docker-build:
# Official docker image.
image: docker:latest
stage: deploy
services:
- docker:dind
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script:
- docker build --pull -t "$CI_REGISTRY_IMAGE" .
- docker push "$CI_REGISTRY_IMAGE"
dependencies:
- build-app
En el primer trabajo (build-app
) de tu pipeline de CI/CD:
- La aplicación es construida (
cargo build --release
) - Se remueve la información innecesaria del binario, reduciendo su tamaño y haciendo que sea más difícil realizar ingeniería inversa
- Con artefactos de trabajo, el contenido del directorio
target
se almacena y se pasa al siguiente trabajo
En el segundo trabajo (docker-build
), se construye la imagen de Docker, usando un Dockerfile
, y se publica en Docker Hub. Para este ejemplo, publicarás la imagen de Docker que contiene tu aplicación en Docker Hub, y puedes reemplazar las instrucciones si estás publicando directamente en cualquier plataforma en la nube. Para usar los artefactos, debes especificar el primer trabajo como dependencia.
Cuando se inicia el segundo trabajo, se descargan los artefactos del trabajo anterior, y con la siguiente instrucción, se copian a la imagen de Docker que se generará con el Dockerfile
:
COPY /target/release/hello_rocket .
Después de que el pipeline de CI/CD termine, podrías usar la imagen de Docker Hub para iniciar un contenedor y ejecutar la aplicación.
$ docker run -p 8000:8000 --name hello-rocket username/hello-rocket
Y puedes ir a localhost:8000
en el navegador.
Conclusión#
A través de este artículo, aprendiste a usar GitLab CI y artefactos de trabajo para construir una imagen de Docker optimizada de tu aplicación.