はじめに
サーバーレスアーキテクチャ(Serverless)は、インフラの管理を意識せずにコードを実行できる強力なソリューションです。Azure におけるサーバーレスの代表格である Azure Functions と、スケーラブルなストレージサービスである Azure Blob Storage を組み合わせることで、効率的なファイル処理パイプラインを構築できます。
本記事では、外部URLから画像を取得し、Azure Blob Storage へ保存する機能を Azure Functions で実装する手順を解説します。
Azure リソースの準備
実装の前に、Azure ポータルで必要なリソースを作成します。
1. Function App の作成
- リソースグループ: 任意の名前(例:
func-storage-rg) - 関数アプリ名: 一意の名前(例:
img-processor-func) - 公開: コード
- ランタイムスタック: .NET
- バージョン: 6 以上の LTS 推奨
- 地域: East Asia など
- プラン: 従量課金(サーバーレス)
2. ストレージコンテナの作成
Function App に紐付けたストレージアカウント、または新規作成したアカウント内に、ファイルを保存するためのコンテナを作成します。
- コンテナ名:
web-images - パブリックアクセスレベル: 私的(匿名アクセスなし)
プロジェクトの実装
必要な NuGet パッケージの導入
Azure Functions で依存関係注入(DI)と Blob 操作を行うため、以下のパッケージをインストールします。
dotnet add package Azure.Storage.Blobs
dotnet add package Microsoft.Azure.Functions.Extensions
dotnet add package Microsoft.Extensions.DependencyInjection
サービスレイヤーの実装
Blob Storage への操作を抽象化するためのインターフェースとクラスを定義します。
public interface IImageStorageService
{
Task SaveImageStreamAsync(string sourceUrl, string targetName);
Task SaveContentAsync(string data, string fileName);
}
public class BlobStorageService : IImageStorageService
{
private readonly BlobServiceClient _client;
private const string ContainerName = "web-images";
public BlobStorageService(BlobServiceClient client)
{
_client = client;
}
public async Task SaveImageStreamAsync(string sourceUrl, string targetName)
{
var container = _client.GetBlobContainerClient(ContainerName);
var blob = container.GetBlobClient(targetName);
using var httpClient = new HttpClient();
var stream = await httpClient.GetStreamAsync(sourceUrl);
await blob.UploadAsync(stream, new BlobHttpHeaders { ContentType = "image/jpeg" });
}
public async Task SaveContentAsync(string data, string fileName)
{
var container = _client.GetBlobContainerClient(ContainerName);
var blob = container.GetBlobClient(fileName);
using var ms = new MemoryStream(Encoding.UTF8.GetBytes(data));
await blob.UploadAsync(ms, new BlobHttpHeaders { ContentType = "text/plain" });
}
}
HTTP トリガーの実装
HTTP リクエストを受け取り、サービスを呼び出す関数を作成します。
public class UploadEndpoint
{
private readonly IImageStorageService _storageService;
public UploadEndpoint(IImageStorageService storageService)
{
_storageService = storageService;
}
[FunctionName("UploadImageFromUrl")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
ILogger log)
{
string jsonBody = await new StreamReader(req.Body).ReadToEndAsync();
var data = JsonConvert.DeserializeObject<UploadRequest>(jsonBody);
if (string.IsNullOrEmpty(data?.Url) || string.IsNullOrEmpty(data?.FileName))
{
return new BadRequestObjectResult("Invalid parameters.");
}
await _storageService.SaveImageStreamAsync(data.Url, data.FileName);
return new OkObjectResult(new { message = "Successfully uploaded." });
}
}
public class UploadRequest
{
public string Url { get; set; }
public string FileName { get; set; }
}
依存関係注入の設定 (Startup)
FunctionsStartup を使用して、BlobServiceClient と独自サービスをコンテナに登録します。
[assembly: FunctionsStartup(typeof(MyFunctionApp.Startup))]
namespace MyFunctionApp
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var connectionString = Environment.GetEnvironmentVariable("AzureWebJobsStorage");
builder.Services.AddSingleton(x => new BlobServiceClient(connectionString));
builder.Services.AddTransient<IImageStorageService, BlobStorageService>();
}
}
}
動作確認
ローカル環境またはデプロイ後に Postman などのツールを使用してテストを行います。
- エンドポイントに対して POST リクエストを送信します。
- リクエストボディに以下の JSON を含めます。
{
"Url": "https://example.com/sample-image.jpg",
"FileName": "stored-image.jpg"
}
実行後、Azure ポータルのストレージコンテナを確認し、指定したファイル名で画像が保存されていれば成功です。
まとめ
Azure Functions を使用することで、ファイルアップロードや画像処理といった特定のタスクを軽量なコードで実装できます。従量課金モデルを利用すれば、実行時間分のみのコストで運用できるため、バッチ処理や API 連携に非常に適しています。