Comment déployer une application Rust ?

How to Deploy an Rust Application_
How to Deploy an Rust Application_

Depuis plus de quatre ans, Rust est le langage le plus admiré dans l’enquête StackOverflow auprès des développeurs, en raison des nombreuses fonctionnalités qu’il offre à ceux qui l’adoptent.

Mozilla a créé Rust pour qu’il soit fiable, performant et convivial pour les développeurs. La syntaxe de Rust est similaire à celle de langages comme le C++ et le C, dont les développeurs sont la cible principale.

Rust se concentre également sur la sécurité de la mémoire et la concurrence avec des modèles qui évitent les pièges associés auxquels les développeurs utilisant d’autres langages sont confrontés.

Vous apprendrez à construire des API en Rust pour exploiter les avantages de cet article. Vous apprendrez en créant, en conteneurisant et en déployant une application Rust sur le service de conteneurisation gratuit de Back4app.

Avantages de l’utilisation de la Rust

L’utilisation de Rust dans vos projets présente de nombreux avantages. En voici quelques-uns :

Abstractions à coût zéro

Rust fournit des abstractions de haut niveau sans imposer de coûts d’exécution supplémentaires. Cela signifie que les abstractions que vous utilisez dans votre code (fonctions, itérateurs ou génériques) ne rendent pas vos programmes plus lents.

Le compilateur Rust optimise manuellement les abstractions pour le code de bas niveau compilé. Rust comble le fossé entre le contrôle expressif, de bas niveau et à grain fin et la performance.

L’approche Fearless Concurrency pour la sécurité de la mémoire dans les programmes simultanés

Rust adopte une “approche intrépide” de la concurrence, caractérisée par la sécurité et l’efficacité. Le modèle de concurrence de Rust s’appuie sur son modèle de propriété et sur la vérification de type pour éviter les courses de données au moment de la compilation.

Cette fonctionnalité vous permet d’écrire des applications multithreads sans les inconvénients de la concurrence des états partagés, tels que les blocages et les conditions de course.

Système de type avancé et modèle de propriété

Le système de types de Rust et ses règles de propriété sont des caractéristiques uniques qui contribuent à renforcer la sécurité de la mémoire.

Le modèle de propriété utilise le vérificateur d’emprunts pour s’assurer que chaque donnée a un propriétaire unique et gère son cycle de vie afin d’éviter les problèmes tels que les pointeurs pendants et les fuites de mémoire.

Compatibilité et intégration multiplateforme

Rust est un excellent choix si vous souhaitez créer des applications multiplateformes. Vous pouvez écrire du code une seule fois et le compiler sur plusieurs plateformes sans apporter de modifications importantes à la base de code existante.

Rust s’intègre bien à d’autres langages de programmation, en particulier le langage C, ce qui le rend adapté à l’assemblage web et aux tâches liées aux systèmes embarqués.

Limites de l’utilisation de Rust

Vous rencontrerez certainement des difficultés lors de la création d’applications de production avec Rust.

Parmi ceux-ci, on peut citer la courbe d’apprentissage abrupte de Rust, le temps de compilation plus long dû à la mémoire et à d’autres vérifications, et son écosystème nouveau et restreint.

Il y a quelques inconvénients que vous pouvez rencontrer en construisant des produits de qualité avec Rust. En voici quelques-uns :

La courbe d’apprentissage de la programmation en Rust est abrupte

Comparé à d’autres langages populaires (Go, Python, JavaScript, etc.), il faut beaucoup de temps pour maîtriser Rust et créer des applications de qualité avec ce langage.

Cela ne devrait pas vous faire hésiter à utiliser Rust. En maîtrisant Rust, vous deviendrez vraiment productif en construisant et en déployant des applications, et vous bénéficierez de tous les avantages de l’utilisation de Rust.

Les programmes Rust ont un temps de compilation long

Les vérifications de la mémoire et de la concurrence au moment de la compilation, associées à plusieurs autres facteurs, entraînent des temps de compilation longs pour les programmes Rust.

En fonction de la taille de l’application, les longs temps de compilation peuvent entraîner des goulets d’étranglement dans les phases de développement ou de production.

Rust a un écosystème de bibliothèques plus petit

Rust est relativement nouveau par rapport à de nombreux autres langages populaires, et il existe un écosystème limité de bibliothèques que vous pouvez utiliser.

De nombreuses bibliothèques (crates) sont encore en production, et vous pouvez consulter des sites web comme AreWeWebYet pour avoir une vue d’ensemble des crates prêts pour la production que vous pouvez utiliser pour construire des applications web en Rust.

Options de déploiement de la Rust

Rust étant déjà largement adopté, il existe de nombreuses options de déploiement pour vos applications.

La plupart des options de déploiement de Rust sont des plateformes basées sur IaaS ou CaaS. Vous pouvez choisir l’une d’entre elles en fonction des spécifications de votre projet.

Infrastructure en tant que service (IaaS) comme AWS

Les fournisseurs d’infrastructure en tant que service (IaaS) mettent à votre disposition l’infrastructure nécessaire au déploiement et à la gestion de vos applications fonctionnant sur des machines virtuelles dans le nuage.

Vous pouvez utiliser les services fournis par les plateformes IaaS pour déployer vos applications Rust sur des machines virtuelles fonctionnant sous des systèmes d’exploitation tels que Linux, Windows, macOS et d’autres systèmes d’exploitation pris en charge par Rust.

Voici une liste des plateformes IaaS les plus répandues :

  • Amazon Web Services
  • Digital Ocean
  • Google Cloud
  • Linode
  • Microsoft Azure

Conteneurisation en tant que service comme Back4app Containers

Les fournisseurs de services de conteneurisation (CaaS) vous aident à faciliter le déploiement de votre application grâce aux technologies de conteneurisation.

Afin de déployer votre application sur des plateformes qui prennent en charge la conteneurisation, vous devez regrouper votre application et toutes ses dépendances dans un conteneur isolé.

Les conteneurs sont isolés et portables, mais vous devrez travailler dans les limites des fonctionnalités du fournisseur de CaaS.

Certains fournisseurs IaaS proposent des fonctions CaaS. Il existe également des plateformes qui ne proposent que des fonctions CaaS flexibles et isolées.

Voici une liste de quelques plateformes CaaS :

  • Oracle Container Service
  • Back4app
  • Mirantix
  • Docker Enterprise

Le processus de déploiement de l’application Rust

Dans cette section, vous apprendrez comment déployer votre application Rust sur la plateforme CaaS de Back4app.

Qu’est-ce que Back4app ?

Back4app est une plateforme cloud que vous pouvez utiliser pour créer et déployer tous types de services backend pour vos applications mobiles, web et autres.

Back4app fournit un agent d’intelligence artificielle que vous pouvez utiliser pour rationaliser le déploiement de votre application sur la plateforme. Vous pouvez l’utiliser pour gérer vos dépôts GitHub, déployer facilement du code sur le cloud et gérer vos applications en cours d’exécution.

Sur les serveurs backend de Back4app, des conteneurs personnalisés peuvent être déployés et exécutés via la fonctionnalité CaaS.

En utilisant les images de vos conteneurs, vous pouvez étendre la logique de votre application sans vous soucier de la maintenance de l’architecture de votre serveur.

une capture d'écran de l'agent AI de Back4app

Construction et déploiement

Vous devez avoir installé Rust sur votre ordinateur pour suivre ce tutoriel. Vous pouvez consulter la page d’installation de Rust pour connaître les différentes options d’installation disponibles.

Une fois Rust installé, créez une session de terminal et exécutez la commande suivante pour initialiser un nouveau projet Rust

mkdir back4app-rust-deployment && cd back4app-rust-deployment && cargo init

Lorsque vous exécutez la commande, vous devriez voir un fichier cargo.toml dans le nouveau répertoire que vous venez de créer. Vous utiliserez le fichier cargo.toml pour gérer les dépendances.

Ensuite, ajoutez ces directives à la section [dependencies] de votre fichier Cargo.toml pour installer ces dépendances lorsque vous compilez votre application.

[dependencies]
actix-web = "4.0"
serde = { version = "1.0", features = ["derive"] }
serde_derive = { version = "1.0" }
serde_json = "1.0"
lazy_static = "1.4"

Le crate actix-web fournit le routage et d’autres fonctions liées à HTTP, les crates serde, serde_derive et serde_json fournissent des fonctions pour les différentes opérations JSON et le crate lazy_static fournit le stockage de données en mémoire pour l’API en cours d’exécution.

Ajoutez ces importations au début de votre fichier [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;

Vous pouvez utiliser une structure pour définir la structure des données de votre API en fonction des champs dont vous avez besoin. Voici une structure qui représente une personne avec un identifiant, un nom d’utilisateur et un courriel.

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Person {
    pub id: i32,
    pub username: String,
    pub email: String,
}

Les #[derive(Serialize, Deserialize, Debug, Clone)] sont des implémentations du crate serde_derive pour la structure Person afin d’accéder et d’utiliser ses fonctions.

Voici comment vous pouvez utiliser la caisse lazy_static pour mettre en place un magasin de données en mémoire pour votre API, basé sur le type de structure Person:

lazy_static! {
    static ref DATA_STORE: Mutex<Vec<Person>> = Mutex::new(Vec::new());
}

Vous avez créé un stockage partagé à sécurité thread et initialisé paresseusement pour la structure People. Vous l’utiliserez dans vos fonctions de gestion pour stocker et récupérer des données.

La fonction POST Handler

La fonction de traitement des requêtes POST accepte en entrée une représentation JSON de la structure Personne. Elle renvoie ensuite une réponse HTTP et une erreur au client sur demande.

Ajoutez ce bloc de code à votre fichier [main.rs] () pour mettre en œuvre la fonctionnalité de traitement des requêtes 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 fonction create_person est une fonction asynchrone qui accède au magasin de données partagé, génère un nouvel identifiant pour la structure Person, convertit la représentation JSON Person en une structure et l’introduit dans le magasin de données.

Lorsque la demande a abouti, la fonction fournit au client les données introduites dans la base de données ainsi qu’un code d’état 200.

La fonction GET Handler

Ici, une fonction de traitement GET permet de lire toutes les données du magasin de données et de les renvoyer au client sous forme de JSON.

Ajoutez ce bloc de code à votre projet pour mettre en œuvre une fonction de traitement GET

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 fonction get_people est une fonction asynchrone qui accède au magasin de données et écrit le contenu au client en tant que réponse.

Si la demande aboutit, la fonction répond au client avec le code d’état 200 et toutes les données contenues dans le magasin de données.

La fonction PUT Handler

Votre fonction de traitement des requêtes PUT doit mettre à jour une entrée dans le magasin de données sur la base d’un champ de l’objet.

Voici comment vous pouvez mettre en œuvre une fonction de traitement PUT pour votre 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 fonction update_person prend en compte l’identifiant et la nouvelle entrée de la requête. Elle parcourt ensuite le magasin de données et remplace l’entrée par la nouvelle si elle existe.

La fonction DELETE Handler

La fonction de requête DELETE prend un argument : le champ ID de la requête effectuée. Lors de l’exécution de la fonction, l’entrée correspondant à l’ID est supprimée de la base de données.

Ajoutez cette implémentation de la fonction de traitement DELETE à votre programme.

// 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 fonction delete_person supprime de la base de données l’entrée portant l’identifiant spécifié. Selon l’état de l’opération, la fonction renvoie au client une chaîne de caractères et un code d’état.

Mapping the Handler Functions to Routes

Après avoir défini les points de terminaison, vous devez mapper les routes vers les fonctions de traitement pour accéder à la fonctionnalité de ces fonctions.

Voici comment vous pouvez assigner des itinéraires aux fonctions de traitement :

#[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 fonction principale est une fonction asynchrone qui met en place le serveur après avoir fait correspondre les routes aux fonctions de traitement.

La fonction HttpServer::new instancie un serveur HTTP, la fonction App::new() crée une nouvelle instance d’application, et la fonction route associe des routes à la fonction handler.

La fonction bind spécifie l’adresse de la nouvelle application, et la fonction run exéc ute l’application.

Conteneuriser des applications Rust avec Docker

Docker est la technologie de conteneurisation la plus populaire sur le marché. Vous pouvez conteneuriser vos applications Rust avec Docker pour la portabilité et les déployer sur Back4app en quelques clics.

Exécutez cette commande pour créer un nouveau fichier Docker dans votre projet :

touch Dockerfile

Ouvrez le fichier Docker et ajoutez ces instructions de construction au fichier Docker :

# 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"]

Ces instructions spécifient l’image de base et les instructions de construction pour conteneuriser votre application Rust avec Docker.

Voici un aperçu du contenu du fichier Docker :

  1. La directive FROM rustlang/rust:nightly spécifie l’image de base pour le fichier Docker. Docker extrait cette image du référentiel et construit vos programmes dessus.
  2. La directive WORKDIR /usr/src/myapp définit le répertoire de travail de votre application dans le conteneur.
  3. La directive COPY . . copie tout le contenu de votre répertoire de travail dans le répertoire de travail actuel du conteneur.
  4. La directive RUN cargo build --release exécute la commande de construction de votre application dans le conteneur.
  5. La directive EXPOSE 8000 expose le port 8000 du conteneur aux requêtes entrantes.
  6. Le CMD ["./target/release/back4app-rust-deployment"] exécute le programme (l’exécutable issu de l’opération de construction).

Une fois que vous avez écrit le fichier Docker, vous pouvez déployer le conteneur sur le service de conteneurs de Back4app.

Déployer un conteneur sur Back4app

Vous devez créer un compte sur Back4app pour déployer des conteneurs.

Voici les étapes pour créer un compte Back4app.

  1. Visitez le site web de Back4app
  2. Cliquez sur le bouton Inscription dans le coin supérieur droit de la page.
  3. Remplissez le formulaire d’inscription et envoyez-le pour créer le compte.

Maintenant que vous avez créé un compte Back4app, connectez-vous et cliquez sur le bouton NEW APP situé dans le coin supérieur droit de la page d’accueil.

Des options vous sont proposées pour choisir la manière dont vous souhaitez construire votre application. Choisissez l’option Conteneur en tant que service.

Choisir un service back4app

Maintenant, connectez votre compte Github à votre compte Back4app et configurez l’accès aux dépôts de votre compte ou d’un projet spécifique.

Configurez votre compte GitHub pour donner à Back4app l'accès à l'importation d'un repo

Choisissez l’application que vous souhaitez déployer (celle de ce tutoriel) et cliquez sur select.

sélection et configuration des repo accessibles

En cliquant sur select, le bouton vous amènera à une page où vous pourrez remplir des informations sur votre application, y compris le nom de la branche, le répertoire racine et les variables d’environnement.

Le processus de déploiement démarre automatiquement,

Déploiement avec l’agent Back4app AI

Pour optimiser votre flux de développement, vous pouvez également déployer votre application en utilisant l’agent Back4app AI, comme vous pouvez le voir dans l’image ci-dessous :

Inviter l'agent AI à exécuter une commande de déploiement

Suivez ce lien pour installer l’application conteneur Back4app dans votre compte GitHub, et suivez les étapes de l’image ci-dessus pour la configurer.

Une fois la configuration de l’application terminée, vous pouvez procéder au déploiement de votre application avec l’agent IA.

Le déploiement de votre conteneur a été initialisé avec un message

Suivez le lien fourni pour contrôler la progression du déploiement de votre application.

Une capture d'écran du tableau de bord de votre conteneur pour surveiller le déploiement.

Conclusion

Vous avez appris à construire et déployer une application Rust conteneurisée par Docker sur Back4app.

Déployer vos applications sur Back4app est un excellent moyen de simplifier la gestion de l’infrastructure backend.

Back4App fournit des outils puissants pour la gestion de vos données, la mise à l’échelle de votre application et le contrôle de ses performances.

C’est un excellent choix pour les développeurs qui cherchent à créer de grandes applications plutôt qu’à gérer des serveurs.


Leave a reply

Your email address will not be published.