19
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

NRI OpenStandiaAdvent Calendar 2023

Day 15

初学者がAzure FunctionsとAWS Lambdaに画像リサイズ処理を実装して比較してみた

Last updated at Posted at 2023-12-14

はじめに

入社して初めて参画するプロジェクトで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公式ドキュメント概要

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のサイズに変更する機能です。
image_change.jpg

以下がAzureとAWSでの画像リサイズファンクションのアーキテクチャ図です。
ストレージサービスはAzureではAzure Blob Storage、AWSではS3を使用しました。どちらも一般的によく使用されるストレージサービスでドキュメントファイルや画像を格納することができます。
azure_aws_architect.jpg

比較を公平にするために以下の内容を統一しました。また、今回の業務と合わせるために開発言語には.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テンプレートを用いて作成しました。
image.png
使用するトリガー(今回はBlob Trigger)を指定してテンプレートを作成するとBlob TriggerをAzure Functionsで実装するために必要なファイルやパッケージを自動的に準備してくれます。

手順2. 必要パッケージのインストール

実装に必要なパッケージをVisual StudioのNuGetパッケージ管理でインストールします。
image.png
テンプレートを使用すると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デプロイを使おう

  1. .NET CLIを使用してアプリケーションとその依存関係をフォルダーに発行します。
    dotnet publish -c Release -p:UseAppHost=false
    
  2. プロジェクト内の bin\Release\net6.0\publish にファイル一式が作成されるので、
    下記コマンドをPowerShellで実行し、Zipアーカイブを作成します。
    Compress-Archive -Path * -DestinationPath {ファイル名}.zip
    
  3. AzureポータルからApp Serviceの[高度なツール]> [移動]を押下し、Kuduサイトで[Tools]> [Zip Push Deploy]からZipをアップロードします。
    image.png

手順6. Azure上で動作

デプロイが完了したらデプロイした関数の[Developer]> [統合]からトリガーになるBlob Storageとの接続方法を編集します。
この記事では自動で作成される<ストレージアカウント名>_STORAGEをアタッチしました。
image.png
監視対象のBlob Storageに画像を格納すると出力対象のBlob Storageに画像が格納されていることを確認できました。
image.png
image.png

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のコンソール上に作成した関数が表示されます。
image.png

手順6. AWS上で動作

トリガーのS3に画像を格納すると出力対象のS3に画像が格納されていることを確認できました。
image.png
image.png

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. 参照

多くの文献を参考にさせていただきました。ありがとうございます。

19
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?