Deploy de aplicación Rocket desde GitLab a Heroku
Tags: rust, git
Published: 2019-04-19 21:25:03

En este artículo voy a describir los pasos a seguir para hacer deploy de una aplicación desarrollada con Rust, desde un repositorio de **[GitLab](https://gitlab.com)** hacia **[Heroku](https://heroku.com)**.

## .gitignore
Cuando se realizan pruebas desde el entorno local de desarrollo, se generan algunos archivos temporales durante la compilación, por lo que para evitar que estos se sincronicen con el repositorio, se debe crear el archivo `.gitignore`. El archivo debe contener lo siguiente:

```
# Generated by Cargo
# will have compiled files and executables
/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk
```

Este archivo también puede crearse en **[gitignore.io](https://gitignore.io/)**. En la barra de búsqueda se escribe el nombre del lenguaje de programación (Rust) y al dar click en **Create** se genera el `.gitignore` correspondiente, el cual debe descargarse y agregarse al repositorio.

![gitignore.io](https://thepracticaldev.s3.amazonaws.com/i/ar6n3tv92ib3p4t6r5a5.png)

## Heroku
**[Heroku](https://heroku.com/)** tiene soporte para lenguajes y tecnologías como Node.js, Ruby, Java, PHP, Python y Go, y para lenguajes como Rust a través de paquetes de construcción (build packs) desarrollados por la comunidad.

Después de crear la aplicación en Heroku, se realiza la configuración correspondiente.

En el apartado `Settings` se realiza la siguiente configuración:

* Se agrega la URL del paquete de construcción correspondiente, que para Rust es `https://github.com/emk/heroku-buildpack-rust.git`.
![Buildpacks](https://thepracticaldev.s3.amazonaws.com/i/5pwan62x1dt5lay21muj.png)

La URL desde donde se puede acceder a la aplicación tiene el formato `https://nombre-aplicacion.herokuapp.com`.

* Desde la [configuración de la cuenta](https://dashboard.heroku.com/account) se copia la API Key.
![Heroku API Key](https://thepracticaldev.s3.amazonaws.com/i/0sp74uby8nvx7hzflcbx.png)

## GitLab

### GitLab CI
**GitLab** cuenta con un sistema propio de integración continua. Tiene soporte para múltiples lenguajes, como Java, PHP, Ruby, C y Rust. Es de código abierto y está disponible para **GitLab Community Edition** y **GitLab Enterprise Editiion**, de acuerdo a la información disponible en el [sitio](https://about.gitlab.com/product/continuous-integration/).

En la configuración del repositorio se debe agregar el valor de la API Key, para ello:

* Ir a `Settings` > `CI/CD`.
* En la sección `Variables` dar click en `Expand`.
* Agregar la variable `HEROKU_API_KEY` y asignar el valor de la API Key copiado anteriormente.
* Marcar la variable como `Protected`.
![API Key](https://thepracticaldev.s3.amazonaws.com/i/n9jifw1zepiv9w6an3wd.png)

### Repositorio
Se crean los archivos `Rocket.toml`, `RustConfig` y `Procfile` en el repositorio.

En el archivo `Procfile` se indica la versión de Rust que deberá usar Heroku para el deployment, ya que por defecto descarga la versión Stable y para Rocket se necesita Nightly.

```
VERSION = nightly
```

En el archivo Rocket.toml se configura la dirección de la aplicación, tal y como se indica en la [documentación oficial](https://rocket.rs/guide/configuration/#rockettoml).

```toml
[global]
limits = { forms = 32768, json = 32768 }

[development]
address = "localhost"
port = 8000
log = "normal"

[staging]
address = "0.0.0.0"
port = 8000
log = "normal"

[production]
base_url = "https://nombre-aplicacion.herokuapp.com"
log = "critical"
```

Por último, en el archivo `Procfile` se escribe la instrucción que iniciará la aplicación.

```
ROCKET_PORT=$PORT ROCKET_ENV=prod ./target/release/nombre-binario
```

Heroku asigna el puerto de manera dinámica, es por eso que este no se especifica en el archivo `Rocket.toml`, ya que el puerto se obtiene con `ROCKET_PORT=$PORT`, además se indica que la aplicación se ejecuta en entorno de producción mediante `ROCKET_ENV=prod` y la ruta del binario correspondiente `./target/release/nombre-binario`, según lo indicado en `Cargo.toml`.

En seguida se crea el archivo `.gitlab-ci.yml`, correspondiente a la configuración del sistema de integración continua de **GitLab**, el cual debe contener lo siguiente:

```
stages:
  - build
  - production

variables:
  CARGO_HOME: $CI_PROJECT_DIR/cargo

rust-nightly:
  stage: build
  image: rustlang/rust:nightly
  script:
    - cargo build --verbose
    - cargo test --verbose
  cache:
    paths:
      - target/
      - cargo/
  allow_failure: false

production:
  image: ruby:2.2
  stage: production
  script:
    - gem install dpl
    - dpl --provider=heroku --app=nombre-aplicacion --api-key=$HEROKU_API_KEY --strategy=git
  only:
    - master
```

Se especifica las etapas de las tareas que debe ejecutar, que son `build` y `production`, correspondientes a las pruebas de construcción y el deploy hacia Heroku, se indica la versión de Rust que se está usando, Rocket ocupa Nightly. Por último se coloca el nombre de la aplicación creada en Heroku y la variable correspondiente a la API Key. Además, se genera la cache del proyecto, para evitar tener que se descarguen y compilen todas las dependencias si no existe una actualización.

Una vez que se ha agregado este archivo, se realizará el primer test al proyecto. Con cada cambio que se envíe al repositorio se realizará un test nuevo. Los tests se pueden ver en tiempo real desde `https://gitlab.com/usuario/nombre-repositorio/-/jobs`.
![GitLab CI Jobs](https://thepracticaldev.s3.amazonaws.com/i/a9sts4s1mk8mfwceb05c.png)

Una vez que se realiza la configuración, se envía un pequeño cambio al repositorio, para que se realicen las pruebas y posteriormente el deploy a Heroku.

En esta URL se puede ver un ejemplo: https://slides-gallery.herokuapp.com/ y el repositorio de GitLab [aquí](https://gitlab.com/mattdark/reveal.js-gallery).

Espero que este tutorial les haya servido.