Azurite と Docker Compose  で Azure Blob Storage をローカルでエミュレートする方法

### 前書き
本番環境ではAzure Blob Storageをオブジェクトストレージとして使用していますが、ローカル開発環境ではクラウド環境と切り離して開発したいと考え、Azure StorageのエミュレーターであるAzuriteを利用しました。
AzuriteをDockerComposeで構築する際に、Blobコンテナの作成までをCompose内で自動化しているケースがパッと見つかれなかったので本記事を作成しました。


### 対応方針
1. **Azurite（Azure Storage Emulator）** をDocker Composeで立ち上げて、Azure Blob Storageの代替として使う。  
2. 起動時に **Azurite** の初期設定として、あらかじめBlobコンテナを作成する。  
3. Laravelのソースコードで、本番とローカルを環境変数だけで切り替えられるようにする。 

### 実装

#### 1. ライブラリのインストール

まず、Azure Blob Storage にアクセスするためのライブラリを Laravel プロジェクトに導入します。

```bash
composer require microsoft/azure-storage-blob
```

#### 2. `.env` の設定
クラウドのAzure Blob Storageではなく、ローカルのAzuriteに接続するための設定例です。`AZURE_BLOB_CONNECTION_STRING`のAccountKeyについて、Base64形式でないと後続の「az storage container create」がエラーになったため、ダミーのBase64形式としています。

```bash
AZURE_BLOB_CONNECTION_STRING="DefaultEndpointsProtocol=http;AccountName=localblobaccount;AccountKey=Eby8vdM02xNo72UNZ4lCUQ==;BlobEndpoint=http://azurite:10000/localblobaccount"
AZURE_BLOB_ENDPOINT=http://localhost:10000/localblobaccount/local-container/
AZURE_BLOB_CONTAINER_NAME=local-container
```

#### 3. `docker-compose.yml` でAzuriteコンテナと初期設定のコンテナを追加
下記の例では `azurite` というサービスでAzuriteを起動し、`azurite-init` というサービスでBlobコンテナを作成するコマンドを実行しています。

```yaml
version: '3.8'
services:
  # ...（他のサービス設定など）

  #*# Azurite (Azure Storage Emulator) #*#
  azurite:
    container_name: azurite_${APP_NAME}
    image: mcr.microsoft.com/azure-storage/azurite:latest
    ports:
      - "10000:10000"
    volumes:
      - azurite-store:/data
    environment:
      AZURITE_ACCOUNTS: localblobaccount:Eby8vdM02xNo72UNZ4lCUQ==
    restart: always

  # Azurite上にcontainerを作成
  azurite-init:
    container_name: azurite_init_${APP_NAME}
    image: mcr.microsoft.com/azure-cli
    depends_on:
      - azurite
    entrypoint:
      - "/bin/sh"
    command:
      - "-c"
      - |
        echo 'Waiting for azurite...'
        sleep 3
        az storage container create \
            --name local-container \
            --account-name localblobaccount \
            --account-key Eby8vdM02xNo72UNZ4lCUQ== \
            --blob-endpoint http://azurite:10000/localblobaccount \
            --public-access blob
        echo 'Done.'

volumes:
  azurite-store:
```

上記では、`azurite-init` コンテナで `az storage container create ...` コマンドを実行し、Azurite上に `local-container` というBlobコンテナを作成しています。`--public-access blob` を指定しているため、特定のパスを直接URLで開くことが可能になります。


#### 4. Laravelコントローラでファイルアップロード処理
以下は例として、ローカルの `neko.jpg` をAzuriteにアップロードするコードです。`createBlockBlob` メソッドでBlobへアップロードしています。

```php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use MicrosoftAzure\Storage\Blob\BlobRestProxy;
use MicrosoftAzure\Storage\Blob\Models\CreateBlockBlobOptions;
use Illuminate\Support\Str;

class BlobSampleController extends Controller
{
    public function uploadLocalImage()
    {
        // 環境変数から直接取得
        $connectionString = env('AZURE_BLOB_CONNECTION_STRING');
        $blobEndpoint     = env('AZURE_BLOB_ENDPOINT');
        $containerName    = env('AZURE_BLOB_CONTAINER_NAME');

        // Blobクライアントの生成
        $blobClient = BlobRestProxy::createBlobService($connectionString);

        // ローカルの画像ファイル（例：project_root/neko.jpg）を読み込み
        $localFilePath = base_path('neko.jpg');
        $content = fopen($localFilePath, 'r');

        // アップロード先パスとファイル名をランダム生成（例：XXX/image/YYY.jpg）
        $uploadPath = Str::random(10) . '/image/';
        $fileName   = Str::random(10) . '.jpg';

        // Blobの作成オプション（ここでは MIME タイプを設定）
        $options = new CreateBlockBlobOptions();
        $options->setContentType('image/jpeg');

        // アップロード実行
        $blobClient->createBlockBlob(
            $containerName,
            $uploadPath . $fileName,
            $content,
            $options
        );

        // 成功レスポンス（URL を含む）
        return response()->json([
            'message'  => 'アップロード成功',
            'blob_url' => $blobEndpoint . $uploadPath . $fileName,
        ]);
    }
}

```

実装後、Laravelプロジェクトを起動して `uploadLocalImage()` を呼び出すと、Azuriteに対して画像がアップロードされます。JSONレスポンスに含まれる `blob_url` にアクセスすると、実際にアップロードされた画像をブラウザから確認できます。

### 参考
- [ローカルでの Azure Storage の開発に Azurite エミュレーターを使用する](https://learn.microsoft.com/ja-jp/azure/storage/common/storage-use-azurite?tabs=docker-hub%2Cblob-storage)  
- [【Laravel】Azure Blob Storageを使ってみる - Qiita](https://qiita.com/mattun_evo/items/33938a9f6b2f4f12c7bc)  
- [Azure Blob Storage を扱う Python アプリの開発環境を Docker で作る - Qiita](https://qiita.com/hoto17296/items/27ef0e945bd8d0b398f2)  


どなたかの参考になれば嬉しいです！