Rustアプリケーションをデプロイするには?
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機能を使って実行することができる。
コンテナ・イメージを使うことで、サーバー・アーキテクチャーのメンテナンスを気にすることなく、アプリのロジックを拡張することができる。
構築と展開
このチュートリアルに従うには、お使いのコンピューターに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関連関数を提供し、serde
、serde_derive
、serde_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_derive
crate の実装です。
ここでは、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の内容の内訳は以下の通り:
FROM rustlang/rust:nightly
ディレクティブは、Dockerfileのベースイメージを指定します。Dockerはこのイメージをリポジトリから取得し、その上でプログラムをビルドします。WORKDIR /usr/src/myapp
ディレクティブは、コンテナ内のアプリケーションの作業ディレクトリを設定する。COPY . .
ディレクティブは、作業ディレクトリの内容をすべてコンテナのカレント作業ディレクトリにコピーする。RUN cargo build --release
ディレクティブは、コンテナ内にアプリケーションをビルドするためのコマンドを実行する。EXPOSE 8000
ディレクティブは、コンテナのポート8000を
リクエストの着信用に 公開する。CMD["./target/release/back4app-rust-deployment"]
はプログラム(ビルド時の実行ファイル)を実行します。
Dockerfileを書いたら、Back4appのコンテナサービスにコンテナをデプロイします。
Back4appにコンテナをデプロイする
コンテナをデプロイするには、Back4appでアカウントを作成する必要がある。
Back4appアカウントを作成する手順は以下の通りです。
- Back4appのウェブサイトを見る
- ページ右上のサインアップボタンをクリックしてください。
- サインアップフォームに必要事項を記入し、送信するとアカウントが作成されます。
Back4appアカウントの作成が完了したら、ログインし、ランディングページの右上にある「NEW APP」
ボタンをクリックしてください。
アプリの構築方法を選択するオプションが表示されます。Container as a Service
オプションを選択します。
次に、GithubアカウントをBack4appアカウントに接続し、アカウント内のリポジトリまたは特定のプロジェクトへのアクセスを設定します。
デプロイしたいアプリケーション(このチュートリアルのもの)を選択し、selectをクリックします。
選択ボタンをクリックすると、ブランチ名、ルートディレクトリ、環境変数など、アプリに関する情報を入力するページに移動します。
配備プロセスが自動的に開始されます、
Back4app AI エージェントでデプロイする
開発ワークフローを強化するために、Back4app AIエージェントを使用してアプリをデプロイすることもできます:
このリンク からGitHubアカウントにBack4appコンテナアプリをインストールし、上の画像の手順に従って設定してください。
アプリのセットアップが完了したら、AIエージェントでアプリのデプロイを進めることができます。
提供されたリンクをたどって、アプリのデプロイメントの進捗状況を監視してください。
結論
Dockerコンテナ化されたRustアプリケーションをBack4appでビルドしてデプロイする方法を学びました。
アプリをBack4appにデプロイすることで、バックエンドのインフラ管理を簡素化できます。
Back4Appは、データの管理、アプリケーションのスケーリング、パフォーマンスのモニタリングのための強力なツールを提供します。
サーバーを管理するのではなく、優れたアプリケーションを構築したいと考えている開発者にとっては素晴らしい選択だ。