Shuttle で Rust のアプリケーションをデプロイしてみる

2024年2月11日 engineering

こんにちは、 @kz_morita です。

Rust のアプリケーションをデプロイできるプラットフォームである、 Shuttle というサービスが気になっているので触ってみます。

無料でどこまで使えるか?

Pricing ページをみると以下のことは無料で可能そうです。

  • 1 ユーザーまで
  • 3 プロジェクトまでデプロイ可能
  • DB Size 1 GB まで
  • Log の保持 1 日まで
  • Network (egress) 1GB まで
  • 1 日 20 デプロイまで
  • 1 デプロイ 10分まで

サンプルやちょっとしたアプリケーションのデプロイでは十分遊べそうです。

Pro プランになると、1 ユーザーあたり 月 $20 ( + リソースのUsageによる従量課金) で使うことができそうです。

Shuttle の Setup

まずは、ログインする必要があります。GitHub のアカウントでログインが可能です。

ログインするとダッシュボードのような画面が表示されます。

表示に従い、Setup をすすめます。

こちらのドキュメント も参考にしました。

$ cargo install cargo-shuttle

自分の環境だと、clap_mangen という package のビルドに rustc のバージョンが低かったようでエラーが出ました。

error: failed to compile `cargo-shuttle v0.38.0`, intermediate artifacts can be found at `/tmp/cargo-installBAhEdS`.
To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path.

Caused by:
  package `clap_mangen v0.2.20` cannot be built because it requires rustc 1.74 or newer, while the currently active rustc version is 1.72.1
  Try re-running cargo install with `--locked`

いい機会なので rustc のアップデートもやろうかなと思います。

$ rustup update

$ rustc --version
rustc 1.76.0 (07dca489a 2024-02-04)

アップデートできたので再度インストールしたら無事インストールできました。

$ cargo install cargo-shuttle

以下のコマンドを打つと API key を求められるので、ログイン後のダッシュボード画面のようなところからコピーして入力します。

$ cargo shuttle login

ちなみにこの API Key は、~/.config/shuttle/config.toml に記載されていました。デプロイなどの際にここを見に行ってるのだと思います。

プロジェクト生成

次にプロジェクトの生成などを行います。 対話式の I / F で聞かれるので答えていきます。

$ cargo shuttle init
 $ cargo shuttle init
What do you want to name your project?
It will be hosted at ${project_name}.shuttleapp.rs, so choose something unique!
✔ Project name · shuttle-sample-app

Where should we create this project?
✔ Directory · {your project directory}

Shuttle works with a range of web frameworks. Which one do you want to use?
✔ Framework · axum

Creating project "shuttle-sample-app" in "{your project directory}"

Hint: Check the examples repo for a full list of templates:
      https://github.com/shuttle-hq/shuttle-examples
Hint: You can also use `cargo shuttle init --from` to clone templates.
      See https://docs.shuttle.rs/getting-started/shuttle-commands
      or run `cargo shuttle init --help`

✔ Claim the project name "shuttle-sample-app" by starting a project container on Shuttle? · yes

Project "shuttle-sample-app" is ready
Your project will sleep if it is idle for 30 minutes.
To change the idle time refer to the docs: https://docs.shuttle.rs/getting-started/idle-projects

Run `cargo shuttle deploy --allow-dirty` to deploy your Shuttle service.
Run `cargo shuttle run` to run the app locally.

上記を実行すると以下のような状態になりました。

$ tree . -L 2
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    ├── CACHEDIR.TAG
    └── debug/

3 directories, 4 files

main.rs の中身は以下のようになっていました。

use axum::{routing::get, Router};

async fn hello_world() -> &'static str {
    "Hello, world!"
}

#[shuttle_runtime::main]
async fn main() -> shuttle_axum::ShuttleAxum {
    let router = Router::new().route("/", get(hello_world));

    Ok(router.into())
}

Framework に axum を選んだので基本的なセットアップ内容と、shuttle 用の attribute macro の shuttle_runtime::mainShuttleAxum というもので初期化された main 関数があることが確認できます。

実行とデプロイ

以下コマンドで、ローカルで実行できます。

$ cargo shuttle run

無事実行できると、localhost:8000 で Hello, world! が返ってくることが確認できます。

続けて、以下コマンドでデプロイすることができます。

$ cargo shuttle deploy --allow-dirty

デプロイコマンドを実行すると、ダッシュボード画面にも反映されていることが確認できます。

Deploy が終わると実際に URI にリクエストして確認することができます。

自分の場合は以下のような URI でした。

https://shuttle-sample-app.shuttleapp.rs

(Project名がそのままサブドメインになっているので、project 名は重複禁止もしくは連番みたいな仕組みで URL になるのかも)

アプリケーションを止めたいときは、以下コマンドもしくはダッシュボードから行えます。

$ cargo shuttle stop

Resource について

shuttle では、Database として、以下に対応されています。

  • Shuttle AWS RDS
  • Shuttle Shared Databases
  • Shuttle Persist
  • Shuttle Turso
  • Shuttle Qdrant

Shuttle AWS RDS は、プロジェクトごとの専用インスタンスで RDS を使用できます。

対して Shuttle Shared Databases は、ユーザー間で共通の DB となるみたいです。ほかユーザーのDBにアクセスはできないものの共有インスタンスとなります。

Shuttle Persist は、serde::Serialize, serde::Deserialize を実装したデータをファイルシステム上の KVS に永続化することができる仕組みです。

Shuttle Turso は、SQLite のフォークである、libSQL をベースにしたエッジホスト型の分散データベースです。

Shuttle Qdrant は、ベクトルDB の Qdrant に接続できるようになります。

色々な DB へのアダプターが用意されていてかなりすごいなと。

さらにすごいのが 実際の接続方法の簡単さです。実装者がやることとしては annotation を追加するだけのようです。

GitHub にサンプルコードがあるのでそこから引用しますが、Shared Databases の PostgreSQL を使用する場合以下のようなシンプルな記述で使用可能です。

#[shuttle_runtime::main]
async fn axum(#[shuttle_shared_db::Postgres] pool: PgPool) -> shuttle_axum::ShuttleAxum {
    sqlx::migrate!()
        .run(&pool)
        .await
        .map_err(CustomError::new)?;

    let state = MyState { pool };
    let router = Router::new()
        .route("/todos", post(add))

        .route("/todos/:id", get(retrieve))
        .with_state(state);

    Ok(router.into())
}

annotation を書くだけで DB を使用できるの非常に便利そうだなと思いました。

まとめ

今回は、shuttle という rust のサーバーレスプラットフォームを触ってみました。かなり便利だったのでちょっとしたアプリケーションをデプロイする際など便利そうです。 プロトタイピング目的などであれば、非常に有用だなと思いました。

この記事をシェア