Docker + MinIO + PHPを使い、S3と互換性のあるローカル環境をつくろう!

こんにちは。
株式会社アドグローブ ソリューション事業部の前田 直です。

以前、別の前田さんが記事を書いていましたので差別化を図るためにスポーツ選手の表記名のように下の名前の一部を記載してみました。

ちなみに私が特に好きなスコアボード表記は、高橋由伸氏の「高橋 由」です。
よろしくお願いいたします。

さて、今回は「Docker + MinIO + PHPを使い、S3と互換性のあるローカル環境をつくろう!」というお題でお送りします。

目次

はじめに

開発を進めるとき、まずはローカル環境で作業を始めることが多いですよね。加えて作業時に開発環境がまだ整っていない場合も多々あるかと思います。
ですが、ローカルではテストできない…なんて状況だと困ってしまいますよね。そこで今回は、「ローカル環境でしっかりチェックできるように環境を整える」というテーマでお話ししたいと思います。

使用環境

  • Windows10
  • Docker Desktop version 4.13.1 (90346)
  • PHP 8.1, 7.2
  • Lumen 8.0, CodeIgniter3.1

MinIOとは

MinIOは、Amazon S3とAPI互換性があるオブジェクトストレージシステムです。
Dockerコンテナとして起動することができるため、S3の機能を擬似的にローカル環境で再現することが可能となっています。

作成されるファイルのツリー

myproject/
│
├── .env
├── compose.yml
└── docker-local/
    ├── Dockerfile
    └── minio/
        └── data/
            └── 各bucket (例: test-bucket/ など)
  • .env: 環境変数を設定。今回はプロジェクト名(${COMPOSE_PROJECT_NAME})のみ。
  • compose.yml: Docker Compose の設定ファイル。MinIOのサービスを定義。
  • Dockerfile: PHP周りの環境構築用。今回は割愛します。

Docker Composeで環境を構築

以前の記事でもMinIOについて触れられていましたが、改めてフォーカスします。
PHP周りの環境構築についてはこの記事では割愛しますので、詳しく知りたい方は下記をご参照ください。 blog.adglobe.co.jp

compose.y(a)mlファイルを作成し、MinIOのDocker環境を定義します。

services:
  minio:
    image: minio/minio:RELEASE.2024-10-29T16-01-48Z
    container_name: ${COMPOSE_PROJECT_NAME}-minio
    ports:
      - "9000:9000" # API用
      - "9001:9001" # コンソール画面用
    environment:
      - MINIO_ROOT_USER=user
      - MINIO_ROOT_PASSWORD=password
    entrypoint: sh
    command: -c "
      mkdir -p /export/test-bucket;
      minio server /export --address :9000 --console-address :9001;"
    volumes:
      - ./docker-local/minio/data:/export
image(イメージ)

MinIOのバージョン更新により正常に動作しなくなることがあるため、指定することをお勧めします。
今回は記事作成時点の最新バージョンであるRELEASE.2024-10-29T16-01-48Zを指定しました。
作成される際の最新バージョンは公式で確認してください。

ports(ポート)

ホスト側のポート:コンテナ側のポート を指定しています。

  • APIアクセス時のポート: 9000
  • コンソール画面のポート: 9001
environment(環境変数)
  • MINIO_ROOT_USER
  • MINIO_ROOT_PASSWORD

コンソール画面でのログイン時と、API実行時のcredentials情報として使用します。

command(コマンド)

デフォルトのバケット作成とMinIOサーバーの起動を記述しています。

  • APIアクセス時のポートを指定: --address :9000
  • コンソール画面のポートを指定: --console-address :9001
volumes(ボリュームパス)

ホスト側のディレクトリパス:コンテナ側のディレクトリパス を指定しています。
指定しておくことでストレージの永続化が行なわれます。

コンテナ起動

docker compose up

コンソール画面確認

コンソール画面(http://localhost:9001)を確認していきます。

ログイン画面

MINIO_ROOT_USERとMINIO_ROOT_PASSWORDで設定したユーザ名とパスワードでログインします。

ログイン後

compose.y(a)mlで指定したバケットが作成されたことを確認できました。
ここまででMinIOの準備は完了です!

PHPでのファイルのアップロード/ダウンロード

環境構築ができたので実際に使ってみましょう。
今回はAWS SDK for PHP 開発者ガイドに沿って、ファイルのアップロード/ダウンロードといった基本的な操作を紹介します。

前提条件

AWS SDK for PHPが使用できる状態であること

S3クライアントの作成

use Aws\S3\S3Client;

$config = [
    'region' => 'ap-northeast-1', // アジアパシフィック (東京)
    'version' => 'latest',
];

// ローカル環境の場合はMinIOを使用する
if (ローカル環境の場合) {
    $config['endpoint'] = 'http://host.docker.internal:9000';
    $config['use_path_style_endpoint'] = true;
    $config['credentials'] = [
        'key'    => MINIO_ROOT_USERの値,
        'secret' => MINIO_ROOT_PASSWORDの値,
    ];
}

$s3Client = new S3Client($config);
// ストリーム ラッパーを使用する場合のみ記述する
$s3Client->registerStreamWrapper();

Amazon S3 AWS SDK for PHP使用時(基本)

docs.aws.amazon.com

新規で実装を行う場合はこちらを採用するのが良いと思われます。

ファイルアップロード(putObject)
$bucketName = 'test-bucket'; // 作成したバケット名
$keyName = "dirName/testFile.txt";
$uploadFilePath = '/dirName/uploadFile.txt';

try {
    $this->s3client->putObject([
        'Bucket' => $bucketName, // バケット名
        'Key' => $keyName, // S3の保存先(パス/ファイル名)
        'SourceFile' => $uploadFilePath, // アップロード対象ファイルのフルパス
    ]);
} catch (Exception $exception) {
    // エラー処理
}
ファイルダウンロード(getObject)
$bucketName = 'test-bucket'; // 作成したバケット名
$keyName = "dirName/testFile.txt";
$downloadFilePath = '/dirName/downloadFile.txt';

try {
    $this->s3client->getObject([
        'Bucket' => $bucketName, // バケット名
        'Key' => $keyName, // S3から取得するファイル(パス/ファイル名)
        'SaveAs' => $savePath, // 保存先ファイルパス(保存時のみ指定する)
    ]);
} catch (Exception $exception) {
    // エラー処理
}

Amazon S3 ストリーム ラッパー使用時

docs.aws.amazon.com

既存システムにおいて、ファイルサーバーをS3化するケースなどで使用することが想定されます。
従来のコード(file_get_contentsなどの組み込み PHP 関数)が活用できるため、ソースコードの書き換え量を減らしたり、置換や書き換え漏れによる不具合を減らすことが期待できます。

S3クライアントの作成の項目でも触れましたが、使用するにはストリームラッパーを登録($s3Client->registerStreamWrapper();)してください。

ファイルアップロード(copy)

今回はfile_put_contentsではなく、copyコマンドで実装を行いました。

$uploadFilePath = '/dirName/uploadFile.txt'; // アップロード対象ファイルのフルパス
$s3FilePath = 's3://test-bucket/dirName/testFile.txt'; // S3の保存先のフルパス

try {
    // copy(ローカルのファイルパス, S3のファイルパス)
    copy($uploadFilePath, $s3FilePath);         
} catch (Exception $exception) {
    // エラー処理
}
ファイルダウンロード(file_get_contents)
$s3FilePath = 's3://test-bucket/dirName/testFile.txt'; // S3の保存先のフルパス
$data = file_get_contents($s3FilePath);

Laravelの場合

今回は使用していないのですが、Laravel Flysystemを使用し実装も可能ということだけ紹介しておきます。 readouble.com

気づき(Docker Compose V2について)

今回記事を書くにあたって調べ直したところ、Docker Compose V2はCompose V1と比べて変わっている点がありました。
しかし、メジャーバージョンアップを経ても気にすることなく使い続けられていたため、後方互換が優秀だなと感じました。
Docker Desktopに関しては一般提供とともにV2がデフォルトとなっています

変更点で気になったポイント

  • Composeファイルの推奨ファイル名が「compose.y(a)ml」となった
    docker-compose.y(a)mlcompose.y(a)ml
  • Composeファイルに記載していたversion情報が非推奨となった
  • docker-composeコマンドがdockerコマンドのサブコマンドに加わった
    docker-compose updocker compose up

皆さんご存知でしたか?または意識して使っていましたか?
Docker Compose V2の一般公開が2022年4月と2年以上経過しているので、ご存知の方にとっては今さらのことかと思います。
私は正直なところ、今までぼんやりと使っていたため、恥ずかしながら知りませんでした…!
これでまたひとつ賢くなってしまいましたね。

とりあえず動かすだけなら、多少曖昧な知識や間違いがあっても何とかなることもありますよね。ただ、今回は記事にするにあたって、いい加減なことは書けないので、改めて勉強し直す良い機会になりました。

まとめ

Dockerを使用したMinIOの環境構築をメインコンテンツとし、PHP周りに関してはざっくりと記載しました。
使用するフレームワークや新規開発・既存システムの改修によって書き方は変わってくると思います。 ご紹介した内容は基本的な部分と公式ドキュメントを元にしていますので、実際に試す際は、ケースに合わせて最適な方法を調べたり比較したりしてみてくださいね。 それでは、最後までお読みいただきありがとうございました!

余談(アドグローブの働き方について)

実は私は関西出身でして、元々は大阪オフィスの社員として働いておりました。
「人生で一度は首都圏に住んでみたい」という思いがあり、入社後しばらくして東京オフィス勤務をお願いしたところ、快く応じてもらえました!
業務によって出社が必要な場面もありますが、同じプロジェクトメンバーの中にも、沖縄からフルリモートで勤務している方がいて、遠方からでも働ける環境が整っています。
移籍当時はコロナ禍より前でリモートワークが普及する前でしたが、柔軟に対応いただけたのでUターン、Iターン、Jターンを考えている方にとってもアドグローブは良い環境かと思います。
今回挙げた技術内容はもちろん、アドグローブで働くことにご興味がある方は是非、下記に案内あります求人ページもご覧になっていただけると嬉しいです。


アドグローブでは、さまざまなポジションで一緒に働く仲間を募集しています!
詳細については下記からご確認ください。みなさまからのご応募お待ちしております。

採用情報