はじめに
こんにちは、ACS事業部の髙井です。みなさんRustは使っていますか?
母語の次に学ぶべき言語はRustと言われていますよね。
むしろ母語をRustにすべきとも言われています(どこで?)
それは冗談にしてもTURBOPACKが話題になっていたり、Rustによるエコシステム高速化の波は確実にあり、Rustの注目度はどんどん上昇中です。 この際、せっかくなので母語にしましょう。
ということで今日はいろんなAzure PaaSにRustアプリケーションをデプロイしていきたいと思います。
※Rust言語自体の解説というより、RustアプリケーションをAzure PaaSに載せる観点の趣旨であることは最初に申し添えておきます!
RustとAzure
巷では AWS loves Rust という言葉をよく聞きます。とくにAWS LambdaとRustの組み合わせはサーバレスでよく利用されているようです。
そういうのを聞くと「ならばあえてAzureで」と意気込むのが真のAzuristというものではないでしょうか。
さて、AzureのPaaSを考えていくと、
といったサービスがあります。
どれかひとつを選ぶなら、いったいどれを使うとよさそうかについては以前に別の記事を書きました。
今回も「漢は黙ってACA」と言い放ち、ACAだけ紹介してもいいのですが、それでは味気ないので全部紹介していきましょう。
サンプルアプリケーション
サンプルのアプリケーションはRust製Webフレームワークであるactix-webを利用してみましょう。
actix-webはめっちゃいい感じのフレームワークです。こちらの記事なんかが参考になります。
さて、GitHubに公開されているexample集のなかに、いかにもbasicっぽい名前のものがあるのでこちらを使います1。
ルートページにアクセスすると、静的ファイルにリダイレクトされる仕様になっているようです。
こちらはコンテナ化はされていないので、していきます。
アプリケーションコードの書き換え
まず、この部分にあるbind
を書き換えて外部からの呼び出しに対応させます。
use std::net::Ipv4Addr; // 中略 .bind((Ipv4Addr::UNSPECIFIED, 8080))?
これは、具体的には0.0.0.0
が入ると思えばよいです。
Dockerfileの作成
次に、Dockerfileを作成します。 後ほどAzure Functionsを利用する際に書き換えたりバイナリを利用したりもするので、ローカルでbuildしたものを利用していきます。
FROM debian:bullseye-slim COPY ./target/release/basics . COPY ./static/ /static CMD ["./basics"]
ローカルでのbuildは以下のコマンドで行います(Rust環境のインストールはされている前提です)。
cargo build --target-dir ./target --release
CIなど、Dockerfile内にビルド工程を含めたマルチステージにしたい場合は、以下のようにしてもよいです。 冪等にはなりますが、時間のかかる初回ビルドを毎回走らせることになることにご注意ください。
FROM rust:1.60.0 AS build-stage RUN USER=root cargo new --bin basics COPY ./ /basics RUN cargo build --release FROM debian:bullseye-slim AS production COPY --from=build-stage /basics/target/release/basics . COPY --from=build-stage /basics/static/ /static CMD ["./basics"]
作成したイメージはACRにpushしておきます。
ACR作成とpushの手順
# リソース名とリージョンの定義 RG_NAME=rg-sample ACR_NAME=acrsample LOCATION=japaneast # リソースグループ作成 az group create -l $LOCATION -n $RG_NAME # ACR作成 az acr create -n $ACR_NAME -g $RG_NAME -l $LOCATION --sku Basic # イメージビルド docker build -t $ACR_NAME.azurecr.io/sampleapp:0.1 . # ACRにログイン az acr login -n $ACR_NAME # イメージをプッシュ docker push $ACR_NAME.azurecr.io/sampleapp:0.1
Azure PaaSへのデプロイ
まず、Azure loves Rustではないらしく、App Service (Web Apps)やAzure Functionsではネイティブ言語としてはRustがサポートされていません。
そのため、Rustを利用するなら基本的にはコンテナ化して、コンテナ対応のPaaSにデプロイする流れとなります。
App Service (Web Apps)へのデプロイ
ネイティブサポートではないので、Web App for Containersを利用します。
注意点としてはカスタムコンテナーを利用する場合は、価格レベルBasic以上が必要です。
公式ドキュメントのApp Serviceの制限には書いていないのですが、料金ページを見ると地味に他のSKUには書いてあるカスタムコンテナーに関する記述がFreeには書かれていなかったりします。 Azure PortalからもFreeかつカスタムコンテナーという構成でデプロイ自体はできてしまうのでご注意ください(デプロイはできるけど疎通はできない)。
また、複数コンテナー機能がプレビューで利用可能ですが、Azure Container Appsが出現したことにより、この機能は永遠にプレビューのままなのではないかという噂2もあります。
Azure Functionsへのデプロイ
Azure Functionsの場合は、2通りのデプロイ方法があります。
- カスタムイメージ
- カスタムハンドラー
learn.microsoft.com learn.microsoft.com
カスタムイメージを利用する場合は、従量課金プランは利用できないので注意してください。
カスタムハンドラー用の設定
Azure Functionsを使う場合は、コードの書き換えとファイルの追加が必要になります。
デプロイにあたって必要なファイル一式はVisual Studio Codeの拡張機能を使って生成するのが楽チンです。
WindowsマシンならCtrl
+Shift
+P
、Macなら⌘⇧Pでメニューを開いて、Azure Functions: Create New Project...
することで生成できます。
さらに、カスタムハンドラーのエントリポイントを指定するためにhost.json
を編集します。
{ ... "customHandler": { "description": { "defaultExecutablePath": "target/release/basics", ... }, "enableForwardingHttpRequest": true } }
上記のように、defaultExecutablePath
とenableForwardingHttpRequest
を設定すればOKです。
ポートの設定
現状のアプリコードは8080番ポートを利用する前提ですが、Azure Functionsは3000番ポートがデフォルトなので書き換えていきます。
また、環境変数によっても変更できるようにしています。
use std::env; ... #[actix_web::main] async fn main() -> io::Result<()> { ... let port_key = "FUNCTIONS_CUSTOMHANDLER_PORT"; let port: u16 = match env::var(port_key) { Ok(val) => val.parse().expect("Custom Handler port is not a number!"), Err(_) => 3000, }; ... log::info!("starting HTTP server at http://localhost:{}", port); ... .bind((Ipv4Addr::UNSPECIFIED, port))?
デプロイ
以上の処理を完了すると、無事デプロイ可能な状態が揃います。
デプロイもVisual Studio Codeで可能です。以下の2つを順に実行してAzure環境にデプロイが可能です。
Azure Functions: Create Function App in Azure... (Advanced)
Azure Functions: Deploy to Function App...
Azure Container Instancesへのデプロイ
ACIはVisutal Studio Code経由でデプロイできないので、お手軽にやるならAzure Portalからやっていきましょう。
ACIは機能がシンプルで、公式ドキュメントのポートが一致しないため、コンテナー グループの IP アドレスにアクセスできないにもある通り、ポートマッピングには非対応です。
そのため、アプリケーション側で80を公開するか、ACIで8080等を公開するように設定する必要があります。
上記のイメージをそのまま利用する場合は、TCP/8080をデプロイ時にAzure Portalで記入すればOKです。
Azure Container Appsへのデプロイ
こちらはチームメンバーが書いた素晴らしい記事があるのでそちらを見ればすべてがわかります。
Azure Kubernetes Serviceへのデプロイ
さて、AKSはKubernetes自体の知識も必要ですし、準備がそこそこ大変です。
が、逆に考えると普通のKubernetesに載せるだけですので、Azure独自の取り回しのようなことはしなくてよいです。
ということでAKSの標準的なデプロイをしましょう。もちろんこちらも以前にチームメンバーの誰かがブログを書いてい……ない!
なんてこった、ちょっと詰まりやすい周辺事項ばかり記事になっててシンプルなデプロイに関するブログがありませんでした。
仕方がないので、こちらの公式ドキュメントをご参考ください。
と言いたいところですが、簡単に書いておきましょう。
AKSの簡易デプロイ手順
検証用に安価な構成で作成するなら以下のようなコマンドでデプロイすることになるでしょう。
#RG_NAME=rg-sample #ACR_NAME=acrsample #LOCATION=japaneast AKS_NAME=aks-sample # AKSのデプロイ az aks create \ -n $AKS_NAME \ -l $LOCATION \ -g $RG_NAME \ --attach-acr $ACR_NAME \ --node-count 1 \ --node-vm-size Standard_B2s # 資格情報の取得 az aks get-credentials -n $AKS_NAME -g $RG_NAME
ここまで出来ればローカルのkubectlからAKSを操作可能です。
マニフェストは簡素な構成にするなら以下のようになるかと思います。
apiVersion: apps/v1 kind: Deployment metadata: name: sampleapp spec: replicas: 1 selector: matchLabels: app: sampleapp template: metadata: labels: app: sampleapp spec: containers: - name: sampleapp image: <ACRの名称>.azurecr.io/sampleapp:latest # ACRの情報は書き換える ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: sampleapp spec: type: LoadBalancer ports: - port: 80 targetPort: 8080 selector: app: sampleap
上記のマニフェストをapplyしてkubectl get svc
で出てきたEXTERNAL-IP
にアクセスすれば疎通できているのが確認できるでしょう。
おわりに
以上で、シンプルなシングルコンテナーの例に過ぎませんが、だいたいコンテナイメージさえあれば主要なAzure PaaSでは簡単にRustアプリケーションがデプロイできることが分かりました。
Azure PaaSは本当に開発者寄りなので、「開発者がインフラのことを極力考えなくても済む」ような状態を目指して作っている印象です。
ということでぶっちゃけRustに限らずコンテナさえあればなんでも簡単にデプロイできます!我々がAzureやコンテナを中心に据えてご支援を提供している理由でもあります。
Azure loves Rustに留まらない Azure loves Developers💛って感じがしますね。
そしてACAを使えば今回紹介したようなごくごくシンプルなシングルコンテナー構成にとどまらず、マイクロサービスの構築までいけちゃうってのはすごいことです。
ということで、今回はこれくらいにしておきます。髙井先生の次回作にご期待ください。では。