はじめに
入社して初めて参画するプロジェクトでAzure Functionsに触れるため、似たようなサービスであるAWSのLambdaと画像リサイズファンクションの開発を通して様々なことを初心者目線で比較していきます。
サーバーレスコンピューティングサービス比較の際の参考指針や.NETを使用した画像リサイズファンクション作成ガイドラインとしてご活用ください。
初Qiita投稿なのでお手柔らかにお願いします。
1. Azure FunctionsとAWS Lambdaの概要
1.1. 概要
まず、Azure FunctionsとAWS Lambdaについての概要を公式ドキュメントから引用します。
Azure Functions公式ドキュメント概要
Azure Functions は、記述するコードと管理するインフラストラクチャを減らし、コストを節約できるサーバーレス ソリューションです。 クラウド インフラストラクチャによって、アプリケーションの実行を維持するために必要な最新のリソースがすべて提供されるので、サーバーのデプロイや管理について心配する必要はありません。
ユーザーは自分にとって最も生産性の高い言語で最も重要なコードに集中し、残りは Azure Functions が処理をします。
AWS Lambda は、サーバーをプロビジョニングまたは管理せずにコードを実行できるようにするコンピューティングサービスです。
Lambda は可用性の高いコンピューティングインフラストラクチャでコードを実行し、コンピューティングリソースに関するすべての管理を行います。これには、サーバーおよびオペレーティングシステムのメンテナンス、容量のプロビジョニングおよび自動スケーリング、さらにログ記録などが含まれます。Lambda で必要なことは、サポートするいずれかの言語ランタイムにコードを与えることだけです。
Azure Functions、AWS Lambdaはどちらもパブリッククラウド上でコードをサーバーレスで実行できるサーバーレスコンピューティングサービスです。FaaS(Function as a Service)と呼ばれたりもします。
サーバーレスとはサーバーの存在を意識することなくサービスを利用できるという考え方です。サーバーの構築や管理、リソースの割り当てをパブリッククラウド(Azure、AWS)側で行ってくれるため運用、保守のコストを削減することができます。そのため、サーバーレスコンピューティングの場合はプログラムに集中するだけで問題ありません。
Azure Functions、AWS Lambdaは基本的に「あらかじめ設定したイベントが起きたら、プログラムを実行する」という使い方をします。イベントのことをトリガーと言います。ほかのサービスをトリガーとして実行されることが多いです。
トリガーには以下のようなものがあります。
トリガー概要 | 対象サービス(Azure) | 対象サービス(AWS) |
---|---|---|
ストレージにファイルが置かれた際に自動でプログラムを実行する | Blob Storage | S3 |
キューサービスにリクエストが入ったら順番にプログラムを実行する | Queue Storage / Service Bus Queue | SQS |
取得したメトリクスから条件に合わせてプログラムを実行する | Application Insights | CloudWatch |
他にもさまざまな機能、トリガーが存在します。以下を参考にしてください。
Azure Functions:Azure Functions でのトリガーとバインドの概念
AWS Lambda:他のサービスで AWS Lambda を使用する
1.2. 両者の違い
Azure FunctionsとAWS Lambdaは似たようなサービスなので両者に大きな違いはありませんが、細かい違いを5種類あげます。
1. 実行環境
Azure Functionsはサーバーレス環境だけでなくPaaS上でも動かすことができます。
サービス | 実行環境概要 |
---|---|
Azure Functions | ・サーバーレス環境とApp Service Planと呼ばれるPaaS上で動かすことができる ・使用中のApp Service Planがあればその上で追加料金なしで動かすことができる |
AWS Lambda | ・サーバーレスな環境でのみ動かすことができる |
2. タイムアウト時間
サービス | タイムアウト時間概要 |
---|---|
Azure Functions | ・従量課金プランではタイムアウトまでの時間を10分まで設定することができる ・Premiumプランを選択するとタイムアウトまでの時間を無制限に選択することができる |
AWS Lambda | ・タイムアウトまでの時間を15分まで設定することができる |
3. 対応プログラミング言語
基本的には同じですがAWS LambdaはGOとRubyをサポートしています。
サービス | プログラミング言語 |
---|---|
Azure Functions | JavaScript、Java、Python、C#、F#、PowerShell |
AWS Lambda | JavaScript、Java、Python、C#、F#、PowerShell、GO、Ruby |
4. 同時実行
どちらのサービスも、同じ関数の処理を同時に複数実行することができますが、リソースの使い方に違いがあります。
サービス | 同時実行概要 |
---|---|
Azure Functions | ・複数の実行を共通のリソース上で同時実行できる ・リソースの奪い合いになるため、全体的なパフォーマンスに悪影響を及ぼすことがある |
AWS Lambda | ・複数の実行に対して個別のリソースを確保するため、パフォーマンスが安定する ・関数の同時実行数は同一アカウントの同一リージョン内につき、デフォルトでは1000までと制限されている |
5. コスト
どちらのサービスも、基本的な料金はほとんど変わりません。
ただし、AWS Lambdaは月当たりの実行時間が延びると単価が下がるという特徴を持ちます。リクエスト100万件あたりの料金は変わりません。
サービス | 期間コスト | リクエストコスト | 無料枠 |
---|---|---|---|
Azure Functions | GB-秒あたり 0.000016USD | リクエスト100万件あたり 0.20USD | 1 か月100万件の無料リクエストと、40万 GB-sのコンピューティングタイム |
AWS Lambda | GB-秒あたり 0.0000166667USD | リクエスト100万件あたり 0.20USD | 1 か月100万件の無料リクエストと、40万 GB-sのコンピューティングタイム |
料金に関する詳しい概要に関しては以下を参考にしてください。
Azure Functions:Azure Functions 料金
AWS Lambda:AWS Lambda 料金
2. 開発フローとその比較
2.1. 開発プロダクトに関する概要
この記事では画像リサイズファンクションをAzureとAWSに実装し開発の各段階を比較していきます。画像リサイズファンクションはストレージサービスに画像がアップロードされたことをトリガーとして、画像をリサイズし別のストレージにアップロードする機能です。
1920x1440の富士山の画像を1/2の960x720のサイズに変更する機能です。
以下がAzureとAWSでの画像リサイズファンクションのアーキテクチャ図です。
ストレージサービスはAzureではAzure Blob Storage、AWSではS3を使用しました。どちらも一般的によく使用されるストレージサービスでドキュメントファイルや画像を格納することができます。
比較を公平にするために以下の内容を統一しました。また、今回の業務と合わせるために開発言語には.NETを使用しています。
- 統合開発環境:Visual Studio 2022
- 開発言語:.NET 6(C#)
- 画像リサイズ処理:ImageSharpライブラリ
- サーバーレスコンピューティングの性能や設定:デフォルト値からの変更なし
.NETでの画像処理にはSystem.Drawingクラスを使用するのが一般的ですがWindows以外で使用することは非推奨になっています。Lambda上でSystem.Drawingクラスを使用できなかったため、この記事ではImageSharpライブラリを使用します。
2.2. 開発
2.2.1. Azure Functionsでの開発
手順1. プロジェクトの作成
プロジェクトはVisual StudioのAzure Functionsテンプレートを用いて作成しました。
使用するトリガー(今回はBlob Trigger)を指定してテンプレートを作成するとBlob TriggerをAzure Functionsで実装するために必要なファイルやパッケージを自動的に準備してくれます。
手順2. 必要パッケージのインストール
実装に必要なパッケージをVisual StudioのNuGetパッケージ管理でインストールします。
テンプレートを使用するとBlob Triggerを実装するための以下の基本的なパッケージを自動でインストールするように設定ファイルに記述してくれます。
パッケージ | 概要 |
---|---|
Microsoft.NET.Sdk.Functions | Azure Functionsを開発する際に使用するSDK |
Microsoft.Azure.WebJobs.Extensions.Storage | Blob Triggerを実装するときに使うパッケージ |
今回は画像リサイズ処理で使用するImage SharpパッケージのみをNuGetパッケージ管理でインストールしました。
手順3. 実装
実装したコードは以下の通りです。
public class TestResizeFunction
{
[FunctionName("TestResizeFunction")]
public async Task RunAsync(
// Blob Storageのsampleが監視対象
[BlobTrigger("sample/{name}")]Stream myBlob, string name, ILogger log)
{
// Blob Storageから取得したデータをログに出力
log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");
// Blob Storageから取得したデータを画像リサイズ
Stream output = ResizeImage(myBlob);
// リサイズした画像の送信先を指定
BlobContainerClient container = new(System.Environment.GetEnvironmentVariable("AzureWebJobsStorage"), "sample-output");
string fileName = "resized-" + name;
BlobClient blobClient = container.GetBlobClient(fileName);
// 現在の位置がストリームの末尾にあるためアップロードする前に、位置をストリームの開始位置に設定する
output.Position = 0;
// リサイズした画像をBlob Storageにアップロード
await blobClient.UploadAsync(output, true);
log.LogInformation("Image upload successful.");
}
private Stream ResizeImage(Stream input)
{
// Stream→Image
Image img = Image.Load(input);
// リサイズ処理
img.Mutate(x => x.Resize(img.Width / 2, img.Height / 2));
Stream output = new MemoryStream();
// Image→Stream
img.Save(output, img.Metadata.DecodedImageFormat);
return output;
}
}
.NETではBlob Storageから取得するデータ、Blob Storageへアップロードするデータの型はStream
でなければなりません。そのため、リサイズ処理を施すにはStream
からImage
へ型を変換する必要があります。
手順4. Azureクラウド環境の準備
今回の開発プロダクトのためにAzureには以下のリソースを準備しました。
リソース | 概要 |
---|---|
リソースグループ | プロダクトリソース管理サービス |
ストレージアカウント | 画像を格納するストレージ |
関数アプリ | Azure Functions管理サービス |
手順5. デプロイ
実装したコードをAzureにデプロイする方法はいくつかあります。
- Azure CLIからデプロイ
- Visual Studio、Visual Studio Codeからデプロイ
- Zipにしてデプロイ
- ...etc.
今回はZipにしてAzureにデプロイしました。
詳しくは以下の記事を参考にしてください。
Azure App ServiceではFTPデプロイよりZipデプロイを使おう
- .NET CLIを使用してアプリケーションとその依存関係をフォルダーに発行します。
dotnet publish -c Release -p:UseAppHost=false
- プロジェクト内の bin\Release\net6.0\publish にファイル一式が作成されるので、
下記コマンドをPowerShellで実行し、Zipアーカイブを作成します。Compress-Archive -Path * -DestinationPath {ファイル名}.zip
- AzureポータルからApp Serviceの[高度なツール]> [移動]を押下し、Kuduサイトで[Tools]> [Zip Push Deploy]からZipをアップロードします。
手順6. Azure上で動作
デプロイが完了したらデプロイした関数の[Developer]> [統合]からトリガーになるBlob Storageとの接続方法を編集します。
この記事では自動で作成される<ストレージアカウント名>_STORAGE
をアタッチしました。
監視対象のBlob Storageに画像を格納すると出力対象のBlob Storageに画像が格納されていることを確認できました。
2.2.2. AWS Lambdaでの開発
手順1. プロジェクトの作成
Azureと同じくVisual Studio上で開発を行いますが、Visual StudioにはLambdaのテンプレートはありません。かわりに、.NET SDKでLambdaを開発するためのLambda Templateをインストールして使用します。
.NET SDKがインストールされていれば以下のコマンドでインストールできます。
dotnet new -i Amazon.Lambda.Templates
Templateから以下のコマンドでプロジェクトを作成します。
dotnet new lambda.EmptyFunction -n <任意のプロジェクト名>
作成されたテンプレートには.csproj
ファイルが含まれているので、そのファイルを指定してVisual Studioの[プロジェクトやソリューションを開く(P)]でプロジェクトとして認識されます。
.NETをRuntimeとしてAWS Lambdaを開発するための基本的な環境準備に関しては以下の記事を参考にしてください。
【準備編】.NET6.0でAWS Lambda開発
手順2. 必要パッケージのインストール
.NET SDKのテンプレートにはLambdaを開発する必要最低限のパッケージしか自動インストールする記述がないため、自身でNuGetパッケージ管理からS3トリガーに関するパッケージなどをインストールする必要があります。
今回の実装では以下のパッケージを使用しました。
パッケージ | 概要 |
---|---|
Amazon.Lambda.Core | Lambda開発基本パッケージ |
Amazon.Lambda.Serialization.SystemTextJson | Lambda Templateデフォルトパッケージ JSON入力を.NETクラスに変換できるようにする |
Amazon.Lambda.S3Events | S3関連のパッケージ |
AWSSDK.S3 | S3関連の依存パッケージ |
AWSSDK.SecurityToken | AWSのサービス間通信に関するパッケージ |
SixLabors.ImageSharp | 画像処理パッケージ |
手順3. 実装
実装したコードは以下の通りです。
public class Function
{
private static AmazonS3Client _s3Client;
public Function() : this(null)
{
}
// S3バケットクライアント
internal Function(AmazonS3Client s3Client)
{
_s3Client = s3Client ?? new AmazonS3Client();
}
public async Task<string> Handler(S3Event evt, ILambdaContext context)
{
try
{
if (evt.Records.Count <= 0)
{
context.Logger.LogLine("Empty S3 Event received");
return string.Empty;
}
// S3バケット名の取得
var bucket = evt.Records[0].S3.Bucket.Name;
// ファイル名の取得
var key = HttpUtility.UrlDecode(evt.Records[0].S3.Object.Key);
context.Logger.LogLine($"Request is for {bucket} and {key}");
// S3からデータの取得
var objectResult = await _s3Client.GetObjectAsync(bucket, key);
// 取得したデータをStream型へ
var stream = objectResult.ResponseStream;
// 画像リサイズ処理
var output = ResizeImage(stream);
// アップロード内容の作成
PutObjectRequest request = new PutObjectRequest()
{
Key = "resized-" + key,
BucketName = "sample-bucket-1753-resized",
InputStream = output
};
// リサイズ画像のアップロード
var responseResult = await _s3Client.PutObjectAsync(request);
context.Logger.LogLine("Image upload successful.");
return objectResult.Key;
}
catch (Exception e)
{
context.Logger.LogLine($"Error processing request - {e.Message}");
return string.Empty;
}
}
private Stream ResizeImage(Stream input)
{
// Stream→Image
Image img = Image.Load(input);
// リサイズ処理
img.Mutate(x => x.Resize(img.Width / 2, img.Height / 2));
Stream output = new MemoryStream();
// Image→Stream
img.Save(output, img.Metadata.DecodedImageFormat);
return output;
}
}
基本的なコードはAWSの公式チュートリアルの「チュートリアル: Amazon S3 トリガーを使用して Lambda 関数を呼び出す」を参考にしています。
AWSの公式チュートリアル「チュートリアル: Amazon S3 トリガーを使用してサムネイル画像を作成する」のように、画像リサイズチュートリアルがありますが.NETを用いた実装は載っていないため今回の実装を参考にしてみてください。
.NET SDKのLambda Templateのlambda.EmptyFunction
を使用してプロジェクトを作成し、それをベースに改良していく場合はテンプレート内のaws-lambda-tools-defaults.json
ファイルの"function-handler": "XXXX"
の内容を適切に修正する必要があります。
手順4. AWSクラウド環境の準備
今回の開発プロダクトのためにAWSには以下のリソースを準備しました。
リソース | 概要 |
---|---|
S3 | 画像を格納するストレージサービス 監視対象と出力対象の2つ作成 |
IAM | LambdaやS3へのアクセスポリシーを持ったロールの作成サービス |
Lambda | サーバーレスコンピューティングサービス |
手順5. デプロイ
AWSへのデプロイはAWS CLIを使用しました。
IAMからアクセスキーとシークレットアクセスキーを入手してローカルPCでターミナルでaws config
と入力しAWSへの認証情報を設定します。
デプロイは.csproj
ファイルがある階層で以下のコマンドを入力します。
dotnet restore
dotnet lambda deploy-function
Function NameとIAM Role Nameを聞かれるので任意の名前を入力してください。
成功すればAWSのコンソール上に作成した関数が表示されます。
手順6. AWS上で動作
トリガーのS3に画像を格納すると出力対象のS3に画像が格納されていることを確認できました。
2.3. 比較
比較ではAzureとAWSの各サービスを使用した"個人的"感想を述べていきます。
使用してみた感触、良かった点と難しいと感じた点に関して記述していきます。
理解が乏しい部分もあると思いますので、ご指摘があればコメントをお願いします。
感触 | 概要 |
---|---|
◎ | 理解が容易で取り組みやすかった |
△ | 理解に時間がかかり思うように進まなかった |
比較1. 全体を通しての.NETでの実装難易度
サービス | 感触 | よかった点 | 難しいと感じた点 |
---|---|---|---|
Azure Functions | ◎ | ・Visual Studioとの相性が良くローカル環境での開発がスムーズな点 ・ドキュメントの種類が豊富な点 |
・ドキュメントの内容が難しい点 |
Lambda | ◎ | ・チュートリアルが多数存在し、内容の理解がしやすかった点 | ・処理内容に関するドキュメントが少なかった点 |
全体でみるとどちらのサービスを使用しても十分な開発ができると感じました。
比較2. プロジェクト作成の比較
サービス | 感触 | よかった点 | 難しいと感じた点 |
---|---|---|---|
Azure Functions | ◎ | ・.NET(C#)であればVisual Studioのテンプレートで基本的には作成できる点 | ・テンプレートで使用可能な言語として.NET(C#)以外が少ない点 |
Lambda | △ | ・開発するのに十分なプロジェクトをテンプレートから作成できた点 | ・IDEから作成することができず、作成するのに必要な準備も多かった点 |
比較3. パッケージ管理の比較
サービス | 感触 | よかった点 | 難しいと感じた点 |
---|---|---|---|
Azure Functions | ◎ | ・基本的にNuGetからインストールすることができた点 | ・特になし |
Lambda | ◎ | ・基本的にNuGetからインストールすることができた点 | ・特になし |
パッケージ管理に関してはどちらも同じ使用感でした。Lambdaの方が依存関係の影響で必要なパッケージ数が多かったですが必要なパッケージをNuGetの方で管理してくれるため特に気になることはありませんでした。
比較4. クラウド環境の準備に関する比較
サービス | 感触 | よかった点 | 難しいと感じた点 |
---|---|---|---|
Azure Functions | △ | ・リソースグループに使用するリソースをまとめられるため、システム単位で管理するのが容易な点 | ・ストレージアカウントの中でBlob Storageを作成しなければならなかったりと、リソースが少し複雑な点 |
Lambda | ◎ | ・必要リソースがそれぞれ明確に分かれているのでリソースが明確でわかりやすい点 | ・LambdaやS3へアクセスするためのIAMポリシーを適切に設定しなければならない点 |
比較5. デプロイに関する比較
サービス | 感触 | よかった点 | 難しいと感じた点 |
---|---|---|---|
Azure Functions | ◎ | ・デプロイ手法が多様な点 | ・特になし |
Lambda | ◎ | ・デプロイ手法が多様な点 | ・特になし |
デプロイに関しても同じ使用感でした。認証がうまくいけばCLIからのデプロイが簡単だと感じました。
比較5. クラウド上での操作比較
サービス | 感触 | よかった点 | 難しいと感じた点 |
---|---|---|---|
Azure Functions | △ | ・サービス間の接続方法をAzureポータル上で設定できるのが直感的でわかりやすい点 | ・Azureポータル上からデプロイした関数をいじることができない点 |
Lambda | ◎ | ・コードの詳細確認やテストがしやすい点 ・.NETではできなかったがPythonのコードなどをコンソール上から編集することができる点 |
・特になし |
3. まとめ
この記事では、Azure FunctionsとAWS Lambdaでの画像リサイズファンクションの実装を通して開発フローで感じたことを比較してきました。
両者の大きな違いとして、Azureはローカルでの開発がスムーズで、LambdaはAWS上での操作が分かりやすいと感じました。どちらのサーバーレスコンピューティングサービスを使用しても十分な開発は行うことができるため、プロダクトに合わせて選択することが重要です。この記事が参考指針の1つになれれば幸いです。
この記事を通してAzure FunctionsとLambdaでの基本的なファンクションの開発を経験することができました。この経験を業務でも生かせるよう努めていきたいと思います。
4. 参照
多くの文献を参考にさせていただきました。ありがとうございます。
- Azure Functions の Azure Blob Storage トリガー 公式ドキュメント
- Azure Functions における Azure Blob Storage の出力バインド 公式ドキュメント
- クイックスタート: .NET 用 Azure Blob Storage クライアント ライブラリ 公式ドキュメント
- Azure App ServiceではFTPデプロイよりZipデプロイを使おう
- チュートリアル: Amazon S3 トリガーを使用して Lambda 関数を呼び出す
- チュートリアル: Amazon S3 トリガーを使用してサムネイル画像を作成する
- 【準備編】.NET6.0でAWS Lambda開発
- 【開発編】.NET6.0でAWS Lambda開発
- 【デプロイ編】.NET6.0でAWS Lambda開発