¿Cómo desplegar una aplicación Rust?
Rust ha sido el lenguaje más admirado en la encuesta de desarrolladores de StackOverflow durante más de 4 años debido a las múltiples características que ofrece a quienes lo adoptan.
Mozilla creó Rust para que fuera fiable, eficaz y fácil de usar para los desarrolladores. Rust tiene una sintaxis similar a la de lenguajes como C++ y C, cuyos desarrolladores son el principal objetivo del lenguaje.
Rust también se centra en la seguridad de la memoria y la concurrencia con modelos que evitan los escollos asociados a los que se enfrentan los desarrolladores que utilizan otros lenguajes.
Aprenderás a construir APIs en Rust para aprovechar los beneficios de este artículo. Aprenderás creando, conteniendo y desplegando una aplicación Rust en el servicio gratuito de contenedorización de Back4app.
Contents
- 0.1 Ventajas de utilizar Rust
- 0.2 Limitaciones del uso de Rust
- 0.3 Opciones de implantación de Rust
- 0.4 El proceso de implantación de aplicaciones de Rust
- 1 ¿Qué es Back4app?
- 1.1 Construcción e implantación
- 1.2 La función POST Handler
- 1.3 La función GET Handler
- 1.4 La función PUT Handler
- 1.5 Función DELETE Handler
- 1.6 Asignación de funciones de gestión a rutas
- 1.7 Contenedorización de aplicaciones Rust con Docker
- 1.8 Desplegando un Contenedor en Back4app
- 1.9 Implementación con el agente de IA de Back4app
- 1.10 Conclusión
Ventajas de utilizar Rust
El uso de Rust en tus proyectos tiene muchas ventajas. Estas son algunas de las más importantes:
Abstracciones de coste cero
Rust proporciona abstracciones de alto nivel sin imponer costes adicionales en tiempo de ejecución. Esto insinúa que las abstracciones que utilices en tu código (funciones, iteradores o genéricos) no hacen que tus programas sean más lentos.
El compilador de Rust optimiza manualmente las abstracciones del código compilado de bajo nivel. Rust tiende un puente entre el control expresivo, de bajo nivel y de grano fino sobre el rendimiento.
El enfoque Fearless Concurrency para la seguridad de memoria en programas concurrentes
Rust adopta un “enfoque intrépido” de la concurrencia caracterizado por la seguridad y la eficiencia. El modelo de concurrencia de Rust aprovecha su modelo de propiedad y la comprobación de tipos para evitar carreras de datos en tiempo de compilación.
Esta función permite escribir aplicaciones multihilo sin los inconvenientes de la concurrencia de estados compartidos, como los bloqueos y las condiciones de carrera.
Sistema tipográfico avanzado y modelo de propiedad
El sistema de tipos de Rust y sus reglas de propiedad son características únicas que ayudan a reforzar la seguridad de la memoria.
El modelo de propiedad utiliza el verificador de préstamos para garantizar que cada dato tiene un único propietario y gestiona su ciclo de vida para evitar problemas como punteros colgantes y fugas de memoria.
Compatibilidad e integración entre plataformas
Rust es una gran elección si quieres crear aplicaciones multiplataforma. Puedes escribir código una vez y compilarlo en múltiples plataformas sin cambios significativos en la base de código existente.
Rust se integra bien con otros lenguajes de programación, especialmente con C, lo que lo hace adecuado para tareas de ensamblaje web y sistemas embebidos.
Limitaciones del uso de Rust
Es probable que te encuentres con algunos contratiempos a la hora de crear aplicaciones de producción con Rust.
Algunas de ellas pueden ser la pronunciada curva de aprendizaje de Rust, el mayor tiempo de compilación debido a las comprobaciones de memoria y de otro tipo, y su nuevo y pequeño ecosistema.
Hay algunos inconvenientes que puede encontrar al construir productos de grado de producción con Rust. He aquí algunos de ellos:
La curva de aprendizaje de la programación en Rust es pronunciada
En comparación con otros lenguajes populares (Go, Python, JavaScript, etc.), se necesita mucho tiempo para dominar Rust y crear aplicaciones de producción con este lenguaje.
Esto no debería hacerte rehuir el uso de Rust. Al dominar Rust, serás realmente productivo construyendo y desplegando aplicaciones, y obtendrás todos los beneficios de usar Rust.
Los programas Rust tardan mucho en compilarse
Las comprobaciones de memoria y concurrencia en tiempo de compilación, junto con otros factores, dan lugar a largos tiempos de compilación para los programas Rust.
Dependiendo del tamaño de la aplicación, los largos tiempos de compilación pueden provocar cuellos de botella en las fases de desarrollo o producción.
Rust tiene un ecosistema de bibliotecas más pequeño
Rust es relativamente nuevo en comparación con muchos otros lenguajes populares, y existe un ecosistema limitado de bibliotecas que puedes utilizar.
Muchas bibliotecas (crates) aún están en producción, y puedes consultar sitios web como AreWeWebYet para obtener una visión general de las crates listas para producción que puedes utilizar para crear aplicaciones web en Rust.
Opciones de implantación de Rust
Rust ya está ganando una amplia adopción, por lo que hay muchas opciones de despliegue que puede elegir para sus aplicaciones.
La mayoría de las opciones de despliegue de Rust son plataformas basadas en IaaS o CaaS. Puedes elegir una en función de las especificaciones de tu proyecto.
Infraestructura como servicio (IaaS) como AWS
Los proveedores de infraestructura como servicio (IaaS) le proporcionan la infraestructura para desplegar y gestionar sus aplicaciones en máquinas virtuales en la nube.
Puede utilizar los servicios que ofrecen las plataformas IaaS para desplegar sus aplicaciones Rust en máquinas virtuales que ejecuten sistemas operativos como Linux, Windows, macOS y otros sistemas operativos compatibles con Rust.
He aquí una lista de las plataformas IaaS más populares:
- Amazon Web Services
- Digital Ocean
- Google Cloud
- Linode
- Microsoft Azure
Containerización como servicio como Back4app Containers
Los proveedores de servicios de contenedorización (CaaS) le ayudan a facilitar el despliegue de su aplicación con tecnologías de contenedorización.
Para desplegar su aplicación en plataformas compatibles con la contenedorización, deberá agrupar su aplicación y todas sus dependencias en un contenedor aislado.
Los contenedores están aislados y son portátiles, pero tendrás que trabajar dentro de los límites de las características del proveedor de CaaS.
Algunos proveedores de IaaS ofrecen funciones de CaaS. Asimismo, hay plataformas que solo proporcionan funcionalidades CaaS flexibles de forma aislada.
He aquí una lista de algunas plataformas CaaS:
- Oracle Container Service
- Back4app
- Mirantix
- Docker Enterprise
El proceso de implantación de aplicaciones de Rust
En esta sección, aprenderás cómo puedes desplegar tu aplicación Rust en la plataforma CaaS de Back4app.
¿Qué es Back4app?
Back4app es una plataforma en la nube que puede aprovechar para crear y desplegar todo tipo de servicios backend para sus aplicaciones móviles, web y de otros tipos.
Back4app proporciona un agente de IA que puedes utilizar para agilizar el despliegue de tu aplicación en la plataforma. Puedes utilizarlo para gestionar tus repositorios de GitHub, desplegar código en la nube fácilmente y gestionar tus aplicaciones en ejecución.
En los servidores backend de Back4app, se pueden desplegar y ejecutar contenedores personalizados a través de la funcionalidad CaaS.
Utilizando sus imágenes contenedoras, puede ampliar la lógica de su aplicación sin preocuparse de mantener la arquitectura de su servidor.
Construcción e implantación
Debes tener Rust instalado en tu ordenador para seguir este tutorial. Puedes visitar la página de instalaciones de Rust para conocer las diferentes opciones de instalación disponibles.
Una vez que hayas instalado Rust, crea una sesión de terminal y ejecuta este comando para inicializar un nuevo proyecto Rust
mkdir back4app-rust-deployment && cd back4app-rust-deployment && cargo init
Cuando ejecutes el comando, deberías ver un archivo cargo.
toml en el nuevo directorio que acabas de crear. Utilizarás el cargo.
toml para gestionar las dependencias.
A continuación, añada estas directivas a la sección [dependencies]
de su archivo Cargo.toml
para instalar estas dependencias cuando compile su aplicación.
[dependencies]
actix-web = "4.0"
serde = { version = "1.0", features = ["derive"] }
serde_derive = { version = "1.0" }
serde_json = "1.0"
lazy_static = "1.4"
La crate actix-web
proporciona enrutamiento y otras funciones relacionadas con HTTP, las crates serde
, serde_derive
y serde_json
proporcionan funciones para las diferentes operaciones JSON y la crate lazy_static
proporciona el almacenamiento de datos en memoria para la API en tiempo de ejecución.
Añada estas importaciones al principio de su archivo [main.rs](<http://main
.rs>):
use serde::{Serialize, Deserialize};
use actix_web::{web, App, HttpServer, HttpResponse, Error};
use std::sync::Mutex;
extern crate lazy_static;
use lazy_static::lazy_static;
Puede utilizar una estructura para definir la estructura de datos de su API en función de los campos que necesite. A continuación se muestra una estructura que representa a una persona con un ID, un nombre de usuario y un correo electrónico.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Person {
pub id: i32,
pub username: String,
pub email: String,
}
Las #[derive(Serialize, Deserialize, Debug, Clone)]
son implementaciones de la crate serde_derive
para la estructura Persona
para acceder y usar sus funciones.
A continuación se muestra cómo puede utilizar la crate lazy_static
para configurar un almacén de datos en memoria para su API basado en el tipo struct Person
:
lazy_static! {
static ref DATA_STORE: Mutex<Vec<Person>> = Mutex::new(Vec::new());
}
Has creado un almacenamiento compartido inicializado perezosamente y a prueba de hilos para la estructura Personas. Lo utilizarás en tus funciones manejadoras para almacenar y recuperar datos.
La función POST Handler
La función POST request handler acepta una representación JSON de la estructura Persona
como entrada. A continuación, devolverá una respuesta HTTP y un error al cliente bajo petición.
Añade este bloque de código a tu archivo [main.rs](
) para implementar la funcionalidad del manejador de peticiones POST.
async fn create_person(new_person: web::Json<Person>) -> Result<HttpResponse, Error> {
let mut data_store = DATA_STORE.lock().unwrap();
let new_id = data_store.len() as i32 + 1;
let mut person = new_person.into_inner();
person.id = new_id;
data_store.push(person.clone());
Ok(HttpResponse::Ok().json(person))
}
La función create_person
es una función asíncrona que accede al almacén de datos compartido, genera un nuevo ID para la estructura Persona
, convierte la representación JSON Persona
en una estructura y la introduce en el almacén de datos.
Tras una solicitud correcta, la función proporciona al cliente los datos introducidos en la base de datos junto con un código de estado 200.
La función GET Handler
Aquí una función GET handler demuestra la lectura de todos los datos en el almacén de datos y devolverlos al cliente como JSON.
Añade este bloque de código a tu proyecto para implementar una función GET handler
async fn get_people() -> Result<HttpResponse, Error> {
let data_store = DATA_STORE.lock().unwrap();
let people: Vec<Person> = data_store.clone();
Ok(HttpResponse::Ok().json(people))
}
La función get_people
es una función asíncrona que accede al almacén de datos y escribe el contenido al cliente como respuesta.
Si la solicitud tiene éxito, la función responde con el código de estado 200
al cliente con todos los datos del almacén de datos.
La función PUT Handler
Su función manejadora de peticiones PUT debe actualizar una entrada en el almacén de datos basándose en un campo del objeto.
A continuación le mostramos cómo puede implementar una función manejadora PUT para su API:
async fn update_person(
id: web::Path<i32>,
person_update: web::Json<Person>,
) -> Result<HttpResponse, Error> {
let mut data_store = DATA_STORE.lock().unwrap();
if let Some(person) = data_store.iter_mut().find(|p| p.id == *id) {
*person = person_update.into_inner();
Ok(HttpResponse::Ok().json("Person updated successfully"))
} else {
Ok(HttpResponse::NotFound().json("Person not found"))
}
}
La función update_person
toma el ID y la nueva entrada de la solicitud. A continuación, recorre el almacén de datos y sustituye la entrada por la nueva, si existe.
Función DELETE Handler
La función de solicitud DELETE tomará un argumento; el campo ID de la solicitud realizada. Al ejecutarse la función, eliminará la entrada con el ID del almacén de datos.
Añade esta implementación de la función DELETE a tu programa.
// DELETE
pub async fn delete_person(id: web::Path<i32>) -> Result<HttpResponse, Error> {
let mut data_store = DATA_STORE.lock().unwrap();
if let Some(index) = data_store.iter().position(|p| p.id == *id) {
data_store.remove(index);
Ok(HttpResponse::Ok().json("Deleted successfully"))
} else {
Ok(HttpResponse::NotFound().json("Person not found"))
}
}
La función delete_person
elimina la entrada con el ID especificado del almacén de datos. Dependiendo del estado de la operación, la función devuelve al cliente una cadena y un código de estado.
Asignación de funciones de gestión a rutas
Después de definir los puntos finales, tendrá que asignar rutas a las funciones de control para acceder a la funcionalidad de las funciones de control.
A continuación se explica cómo asignar rutas a funciones de controlador:
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/person", web::post().to(create_person))
.route("/people", web::get().to(get_people))
.route("/person/{id}", web::put().to(update_person))
.route("/person/{id}", web::delete().to(delete_person))
})
.bind("0.0.0.0:8000")?
.run()
.await
}
La función principal
es una función asíncrona que configura el servidor después de asignar las rutas a las funciones manejadoras.
La función HttpServer::new
instancia un servidor HTTP, la función App::new()
crea una nueva instancia de aplicación, y la función route
asigna rutas a la función handler.
La función bind
especifica la dirección de la nueva aplicación, y la función run
ejecuta la aplicación.
Contenedorización de aplicaciones Rust con Docker
Docker es la tecnología de contenedorización más popular del mercado. Puedes contenerizar tus aplicaciones Rust con Docker para portabilidad y desplegarlas en Back4app con unos pocos clics.
Ejecute este comando para crear un nuevo Dockerfile en su proyecto:
touch Dockerfile
Abra el Dockerfile y añada estas instrucciones de compilación al Dockerfile:
# Use Rust Nightly as the base image
FROM rustlang/rust:nightly
# Set the working directory inside the container
WORKDIR /usr/src/myapp
# Copy the current directory contents into the container
COPY . .
# Build the application
RUN cargo build --release
# Expose port 8000
EXPOSE 8000
# Define the command to run the application
CMD ["./target/release/back4app-rust-deployment"]
Estas instrucciones especifican la imagen base y las instrucciones de compilación para contenerizar su aplicación Rust con Docker.
He aquí un desglose del contenido del Dockerfile:
- La directiva
FROM rustlang/rust:nightly
especifica la imagen base para el Dockerfile. Docker extrae esta imagen del repositorio y construye tus programas sobre ella. - La directiva
WORKDIR /usr/src/myapp
establece el directorio de trabajo para tu aplicación dentro del contenedor. - La directiva
COPY . .
copia todo el contenido de su directorio de trabajo en el directorio de trabajo actual del contenedor. - La directiva
RUN cargo build --release
ejecuta el comando para construir tu aplicación en el contenedor. - La directiva
EXPOSE 8000
expone el puerto8000
del contenedor para peticiones entrantes. - El
CMD ["./target/release/back4app-rust-deployment"]
ejecuta el programa (el ejecutable de la operación de compilación).
Una vez que hayas escrito el Dockerfile, puedes proceder a desplegar el contenedor en el servicio de contenedores de Back4app.
Desplegando un Contenedor en Back4app
Necesitas crear una cuenta en Back4app para desplegar contenedores.
Estos son los pasos para crear una cuenta Back4app.
- Visite el sitio web de Back4app
- Haga clic en el botón Inscribirse situado en la esquina superior derecha de la página.
- Rellene el formulario de inscripción y envíelo para crear la cuenta.
Ahora que has creado con éxito una cuenta Back4app, inicia sesión y haz clic en el botón NUEVA APP
situado en la esquina superior derecha de la página de destino.
Se te presentarán opciones para elegir cómo quieres construir tu aplicación. Elija la opción Contenedor como servicio
.
Ahora, conecta tu cuenta de Github a tu cuenta de Back4app y configura el acceso a los repositorios de tu cuenta o a un proyecto específico.
Elija la aplicación que desea desplegar (la de este tutorial) y haga clic en Seleccionar.
Al hacer clic en Seleccionar, el botón te llevará a una página en la que podrás rellenar información sobre tu aplicación, incluido el nombre de la rama, el directorio raíz y las variables de entorno.
El proceso de despliegue se inicia automáticamente,
Implementación con el agente de IA de Back4app
Para potenciar tu flujo de trabajo de desarrollo, también puedes desplegar tu aplicación utilizando el agente Back4app AI, como puedes ver en la siguiente imagen:
Sigue este enlace para instalar la app contenedora Back4app en tu cuenta de GitHub, y sigue los pasos de la imagen superior para configurarla.
Una vez completada la configuración de la aplicación, puede proceder a desplegarla con el agente de IA.
Siga el enlace proporcionado para supervisar el progreso de despliegue de su aplicación.
Conclusión
Has aprendido a construir y desplegar una aplicación Rust contenida en Docker en Back4app.
Desplegar sus aplicaciones en Back4app es una excelente manera de simplificar la gestión de la infraestructura de backend.
Back4App proporciona potentes herramientas para gestionar sus datos, escalar su aplicación y supervisar su rendimiento.
Es una opción excelente para los desarrolladores que buscan crear grandes aplicaciones en lugar de gestionar servidores.