Rustアプリケーションをデプロイするには?

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

Rustは、StackOverflowの開発者アンケートで4年以上にわたって最も賞賛されている言語であり、その理由は採用者に複数の機能を提供するためである。

Mozillaは、信頼性が高く、パフォーマンスが高く、開発者に優しいRustを開発した。Rustは、C++やCのような言語と似た構文を持っており、開発者がこの言語の主なターゲットである。

Rustはまた、他の言語を使用する開発者が直面する関連する落とし穴を回避するモデルで、メモリ安全性と並行性に重点を置いている。

この記事では、RustでAPIを構築する方法を学び、その利点を活用します。Rustアプリケーションを作成し、コンテナ化し、Back4appの無料コンテナ化サービスでデプロイすることで学びます。

Rustを使う利点

プロジェクトでRustを使うことで得られる利点はたくさんあります。その中から重要なものをいくつか紹介しよう:

コストゼロの抽象化

Rustは、実行時の追加コストを課すことなく、高レベルの抽象化を提供する。これは、コードで使用する抽象化機能(関数、イテレータ、ジェネリクス)がプログラムを遅くすることはないということを意味している。

Rustコンパイラーは、コンパイルされた低レベルコードの抽象化を手動で最適化する。Rustは、表現力豊かな低レベルコードと、パフォーマンスに対するきめ細かな制御のギャップを埋める。

並行プログラムにおけるメモリ安全性のための大胆不敵な並行アプローチ

Rustは、安全性と効率性を特徴とする「大胆不敵なアプローチ」で並行処理を行います。Rustの並行性モデルは、オーナーシップ・モデルと型チェックを活用し、コンパイル時にデータ・レースを防止する。

この機能により、デッドロックや競合状態といった共有状態並行性の欠点なしに、マルチスレッド・アプリを書くことができる。

高度なタイプ・システムとオーナーシップ・モデル

Rustの型システムと所有権ルールは、メモリ安全性を強化するための独自の機能である。

オーナーシップ・モデルは、ボローン・チェッカーを使用して、各データの所有者が単一であることを確認し、そのライフサイクルを管理することで、ダングリング・ポインタやメモリ・リークのような問題を防止する。

クロスプラットフォームの互換性と統合

クロスプラットフォームのアプリケーションを作りたいなら、Rustは最高の選択だ。一度コードを書けば、既存のコードベースに大きな変更を加えることなく、複数のプラットフォームでコンパイルできる。

Rustは他のプログラミング言語、特にC言語とうまく統合できるため、ウェブアセンブリや組み込みシステムのタスクに適している。

Rust 使用の限界

Rustでプロダクション・グレードのアプリを構築している間に、いくつかの挫折に遭遇することになるだろう。

その中には、Rustの学習曲線が急であること、メモリやその他のチェックのためにコンパイルに時間がかかること、新しく小さなエコシステムであることなどが含まれる。

Rustを使用してプロダクショングレードの製品を作る際に遭遇する可能性のある欠点がいくつかあります。ここではそのいくつかをご紹介します:

Rustプログラミングの学習曲線は険しい

他の一般的な言語(Go、Python、JavaScriptなど)と比べると、Rustをマスターして本番レベルのアプリケーションを構築するにはかなりの時間がかかる。

だからといって、Rustの使用を敬遠する必要はない。Rustをマスターすれば、アプリのビルドやデプロイが実に生産的になり、Rustを使うことのあらゆるメリットを享受できる。

Rustプログラムのコンパイル時間が長い

コンパイル時のメモリと同時実行性のチェックは、他のいくつかの要因と相まって、Rustプログラムの長いコンパイル時間をもたらす。

アプリケーションの規模によっては、長いコンパイル時間が開発段階や生産段階でのボトルネックになる可能性がある。

Rustはライブラリのエコシステムが小さい

Rustは他の多くの一般的な言語に比べて比較的新しく、使えるライブラリーのエコシステムも限られている。

多くのライブラリ(クレート)はまだ制作中であり、AreWeWebYetのようなウェブサイトで、Rustでウェブ・アプリケーションを構築するために使用できる制作可能なクレートの概要をチェックすることができる。

Rust 展開オプション

Rustはすでに広く採用されているため、アプリには多くのデプロイオプションから選ぶことができる。

Rustの導入オプションのほとんどは、IaaSまたはCaaSベースのプラットフォームです。プロジェクトの仕様に応じて選択できます。

AWSのようなIaaS(インフラストラクチャー・アズ・ア・サービス

IaaS(Infrastructure as a Service)プロバイダーは、クラウド上の仮想マシン上で動作するアプリケーションをデプロイおよび管理するためのインフラを提供します。

IaaSプラットフォームが提供するサービスを利用して、Linux、Windows、macOS、その他のRust対応オペレーティングシステムを実行する仮想マシン上にRustアプリをデプロイできます。

人気のあるIaaSプラットフォームのリストはこちら:

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

Back4app Containersのようなサービスとしてのコンテナ化

コンテナ化サービス(CaaS)プロバイダーは、コンテナ化技術を使ってアプリのデプロイを容易にする手助けをする。

コンテナ化をサポートするプラットフォームにアプリケーションをデプロイするには、アプリケーションとその依存関係をすべて、隔離されたコンテナにバンドルする。

コンテナは分離可能でポータブルだが、CaaSプロバイダーの機能の範囲内で作業しなければならない。

IaaSプロバイダーの中には、CaaS機能を提供しているところもある。また、柔軟なCaaS機能だけを単独で提供するプラットフォームもある。

以下は、いくつかのCaaSプラットフォームのリストである:

  • Oracle Container Service
  • Back4app
  • Mirantix
  • Docker Enterprise

Rust・アプリケーションの展開プロセス

このセクションでは、RustアプリをBack4appのCaaSプラットフォームにデプロイする方法をご紹介します。

Back4appとは?

Back4appはクラウドプラットフォームで、モバイル、ウェブ、その他のアプリケーションのあらゆるタイプのバックエンドサービスを作成し、デプロイすることができます。

Back4appは、プラットフォーム上でのアプリのデプロイを効率化するために使用できるAIエージェントを提供します。GitHubリポジトリの管理、クラウド上でのコードのデプロイ、実行中のアプリの管理などに利用できます。

Back4appのバックエンドサーバー上で、カスタムコンテナをデプロイし、CaaS機能を使って実行することができる。

コンテナ・イメージを使うことで、サーバー・アーキテクチャーのメンテナンスを気にすることなく、アプリのロジックを拡張することができる。

Back4app AIエージェントのスクリーンショット

構築と展開

このチュートリアルに従うには、お使いのコンピューターにRustがインストールされている必要があります。利用可能なインストールオプションについては、Rustのインストールページをご覧ください。

Rustをインストールしたら、ターミナル・セッションを作成し、以下のコマンドを実行して新しいRustプロジェクトを初期化する。

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

コマンドを実行すると、作成した新しいディレクトリにcargo.tomlファイルが表示されるはずです。cargo.tomlは、依存関係を管理するために使用します。

次に、これらのディレクティブをCargo.tomlファイルの[dependencies]セクションに追加して、アプリのビルド時にこれらの依存関係をインストールします。

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

actix-webクレートはルーティングとその他のHTTP関連関数を提供し、serdeserde_deriveserde_jsonクレートはさまざまなJSON操作の関数を提供し、lazy_staticクレートは実行時にAPIのインメモリデータストレージを提供する。

これらのインポートを[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;

構造体を使用すると、必要なフィールドに基づいてAPIのデータ構造を定義できます。以下は、ID、ユーザー名、電子メールを持つ人物を表す構造体です。

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

derive(Serialize, Deserialize, Debug, Clone)]は、Person構造体の関数にアクセスして使用するためのserde_derivecrate の実装です。

ここでは、lazy_staticクレートを使用して、Person構造体タイプに基づくAPI用のインメモリ・データ・ストアをセットアップする方法を説明します:

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

People構造体のために、スレッドセーフな共有ストレージを作成しました。これをハンドラ関数で使用して、データを格納したり取得したりします。

POSTハンドラ関数

POST リクエスト ハンドラ関数は、Person構造体の JSON 表現を入力として受け付けます。リクエストに応じて、HTTPレスポンスとエラーをクライアントに返します。

このコードブロックを[main.rs]()ファイルに追加して、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))
}

create_personは非同期関数で、共有データストアにアクセスし、Person構造体の新しいIDを生成し、JSON表現のPersonを構造体に変換してデータストアにプッシュする。

リクエストに成功すると、この関数はクライアントにデータベースに入力されたデータを200のステータスコードとともに提供する。

GETハンドラ関数

ここでは、GETハンドラー関数が、データストアにあるすべてのデータを読み込み、JSONとしてクライアントに返すことを示している。

以下のコードブロックをプロジェクトに追加して、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))
}

get_people関数は、データストアにアクセスし、その内容をレスポンスとしてクライアントに書き込む非同期関数です。

リクエストに成功すると、この関数はクライアントに200のステータスコードで、データストアにあるすべてのデータを応答する。

PUTハンドラ関数

PUTリクエストハンドラ関数は、オブジェクトのフィールドに基づいてデータストアのエントリを更新する必要があります。

あなたのAPIにPUTハンドラ関数を実装する方法を説明しよう:

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"))
    }
}

update_person関数はリクエストからIDと新しいエントリーを受け取ります。そして、データストアをトラバースし、エントリが存在すれば新しいものに置き換えます。

DELETEハンドラ関数

DELETEリクエスト関数は1つの引数を取る。関数を実行すると、そのIDを持つエントリがデータストアから削除されます。

このDELETEハンドラ関数の実装をあなたのプログラムに追加する。

// 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"))
    }
}

delete_person関数は、指定された ID のエントリーをデータストアから削除します。操作の状態に応じて、関数は文字列とステータスコードをクライアントに返します。

ハンドラ関数のルートへのマッピング

エンドポイントを定義した後、ハンドラ関数の機能にアクセスするために、ハンドラ関数にルートをマッピングする必要があります。

ハンドラ関数にルートを割り当てる方法を説明します:

#[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
}

main関数は非同期関数で、ルートをハンドラー関数にマッピングした後にサーバーをセットアップする。

HttpServer::new関数はHTTPサーバーをインスタンス化し、App::new()関数は新しいアプリのインスタンスを作成し、route関数はルートをハンドラー関数にマッピングする。

bind関数は新しいアプリのアドレスを指定し、run関数はアプリを実行する。

DockerでRustアプリをコンテナ化する

Dockerは市場で最も人気のあるコンテナ化技術です。RustアプリをDockerでコンテナ化し、数クリックでBack4appにデプロイすることができます。

このコマンドを実行して、プロジェクトに新しいDockerfileを作成する:

touch Dockerfile

Dockerfileを開き、以下のビルド手順を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"]

この説明では、RustアプリケーションをDockerでコンテナ化するためのベースイメージとビルド手順を指定します。

Dockerfileの内容の内訳は以下の通り:

  1. FROM rustlang/rust:nightlyディレクティブは、Dockerfileのベースイメージを指定します。Dockerはこのイメージをリポジトリから取得し、その上でプログラムをビルドします。
  2. WORKDIR /usr/src/myappディレクティブは、コンテナ内のアプリケーションの作業ディレクトリを設定する。
  3. COPY . .ディレクティブは、作業ディレクトリの内容をすべてコンテナのカレント作業ディレクトリにコピーする。
  4. RUN cargo build --releaseディレクティブは、コンテナ内にアプリケーションをビルドするためのコマンドを実行する。
  5. EXPOSE 8000ディレクティブは、コンテナのポート8000をリクエストの着信用に 公開する。
  6. CMD["./target/release/back4app-rust-deployment"]はプログラム(ビルド時の実行ファイル)を実行します。

Dockerfileを書いたら、Back4appのコンテナサービスにコンテナをデプロイします。

Back4appにコンテナをデプロイする

コンテナをデプロイするには、Back4appでアカウントを作成する必要がある。

Back4appアカウントを作成する手順は以下の通りです。

  1. Back4appのウェブサイトを見る
  2. ページ右上のサインアップボタンをクリックしてください。
  3. サインアップフォームに必要事項を記入し、送信するとアカウントが作成されます。

Back4appアカウントの作成が完了したら、ログインし、ランディングページの右上にある「NEW APP」ボタンをクリックしてください。

アプリの構築方法を選択するオプションが表示されます。Container as a Serviceオプションを選択します。

back4appサービスの選択

次に、GithubアカウントをBack4appアカウントに接続し、アカウント内のリポジトリまたは特定のプロジェクトへのアクセスを設定します。

GitHubアカウントを設定し、Back4appにリポジトリをインポートするためのアクセスを許可する。

デプロイしたいアプリケーション(このチュートリアルのもの)を選択し、selectをクリックします。

アクセス可能なレポの選択と設定

選択ボタンをクリックすると、ブランチ名、ルートディレクトリ、環境変数など、アプリに関する情報を入力するページに移動します。

配備プロセスが自動的に開始されます、

Back4app AI エージェントでデプロイする

開発ワークフローを強化するために、Back4app AIエージェントを使用してアプリをデプロイすることもできます:

AIエージェントにデプロイコマンドを促す

このリンク からGitHubアカウントにBack4appコンテナアプリをインストールし、上の画像の手順に従って設定してください。

アプリのセットアップが完了したら、AIエージェントでアプリのデプロイを進めることができます。

コンテナのデプロイが初期化されました。

提供されたリンクをたどって、アプリのデプロイメントの進捗状況を監視してください。

デプロイメントを監視するコンテナ・ダッシュボードのスクリーンショット

結論

Dockerコンテナ化されたRustアプリケーションをBack4appでビルドしてデプロイする方法を学びました。

アプリをBack4appにデプロイすることで、バックエンドのインフラ管理を簡素化できます。

Back4Appは、データの管理、アプリケーションのスケーリング、パフォーマンスのモニタリングのための強力なツールを提供します。

サーバーを管理するのではなく、優れたアプリケーションを構築したいと考えている開発者にとっては素晴らしい選択だ。


Leave a reply

Your email address will not be published.