APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

AzureでRustを使う

はじめに

こんにちは、ACS事業部の髙井です。みなさんRustは使っていますか?

母語の次に学ぶべき言語はRustと言われていますよね。
むしろ母語をRustにすべきとも言われています(どこで?)

それは冗談にしてもTURBOPACKが話題になっていたり、Rustによるエコシステム高速化の波は確実にあり、Rustの注目度はどんどん上昇中です。 この際、せっかくなので母語にしましょう。

ということで今日はいろんなAzure PaaSにRustアプリケーションをデプロイしていきたいと思います。

※Rust言語自体の解説というより、RustアプリケーションをAzure PaaSに載せる観点の趣旨であることは最初に申し添えておきます!

RustとAzure

巷では AWS loves Rust という言葉をよく聞きます。とくにAWS LambdaとRustの組み合わせはサーバレスでよく利用されているようです。

aws.amazon.com

そういうのを聞くと「ならばあえてAzureで」と意気込むのが真のAzuristというものではないでしょうか。

さて、AzureのPaaSを考えていくと、

  • Azure App Service (Web Apps)
  • Azure Functions
  • Azure Container Instances (ACI)
  • Azure Container Apps (ACA)
  • Azure Kubernetes Service (AKS)

といったサービスがあります。

どれかひとつを選ぶなら、いったいどれを使うとよさそうかについては以前に別の記事を書きました。

techblog.ap-com.co.jp

今回も「漢は黙ってACA」と言い放ち、ACAだけ紹介してもいいのですが、それでは味気ないので全部紹介していきましょう。

サンプルアプリケーション

サンプルのアプリケーションはRust製Webフレームワークであるactix-webを利用してみましょう。

actix-webはめっちゃいい感じのフレームワークです。こちらの記事なんかが参考になります。

logmi.jp

さて、GitHubに公開されているexample集のなかに、いかにもbasicっぽい名前のものがあるのでこちらを使います1

github.com

ルートページにアクセスすると、静的ファイルにリダイレクトされる仕様になっているようです。

こちらはコンテナ化はされていないので、していきます。

アプリケーションコードの書き換え

まず、この部分にある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を利用します。

learn.microsoft.com

注意点としてはカスタムコンテナーを利用する場合は、価格レベル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
  }
}

上記のように、defaultExecutablePathenableForwardingHttpRequestを設定すれば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へのデプロイ

こちらはチームメンバーが書いた素晴らしい記事があるのでそちらを見ればすべてがわかります。

techblog.ap-com.co.jp

Azure Kubernetes Serviceへのデプロイ

さて、AKSはKubernetes自体の知識も必要ですし、準備がそこそこ大変です。

が、逆に考えると普通のKubernetesに載せるだけですので、Azure独自の取り回しのようなことはしなくてよいです。

ということでAKSの標準的なデプロイをしましょう。もちろんこちらも以前にチームメンバーの誰かがブログを書いてい……ない!
なんてこった、ちょっと詰まりやすい周辺事項ばかり記事になっててシンプルなデプロイに関するブログがありませんでした。

仕方がないので、こちらの公式ドキュメントをご参考ください。

learn.microsoft.com

と言いたいところですが、簡単に書いておきましょう。

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を使えば今回紹介したようなごくごくシンプルなシングルコンテナー構成にとどまらず、マイクロサービスの構築までいけちゃうってのはすごいことです。

ということで、今回はこれくらいにしておきます。髙井先生の次回作にご期待ください。では。

本記事の投稿者: 髙井 比文
AKSをメインにしたインフラとアプリの領域際をご支援することが多いです。Azureは11冠です。
Hifumi Takai - Credly