S3互換オブジェクトストレージ”MinIO”と学ぶDocker Compose
MinIOとは?
互換性があるということは、S3とほぼ同じAPIを使用することができます。
またコンテナ上にサーバーを構築することができます。
つまりS3の擬似環境をコンテナで用意することができます。これは、本番環境ではS3を使うアプリケーションを開発環境でも同じように動作させたいという場合にとても便利です。
Laravelの場合は、LaravelのファイルシステムがサポートするS3ドライバを使用することで環境変数をMinIO用に設定するのみで使用することができます。環境に応じてアプリケーションコードを変える必要はありません。
またMinIOはDockerイメージがあるので簡単に環境を構築することができます。
Dockerのボリュームを用いることでMinIOストレージに保存したオブジェクトを永続的に保持できることはもちろん、0から動かしたい時にはボリュームを削除すればよいという点も嬉しいポイントです。(コンテナの良いところ!)
TL;DR
- Docker Composeのサービス名はコンテナの名前解決に使われる。
- AWS互換サービスのコンテナを構築すると、サービス名はAWSエンドポイントの役割として重要な要素になる。
やってみる
LaravelとMinIOの環境をDocker Composeで構築します。
コード
【docker-compose.yaml】
services:
# 省略
xxx-minio:
container_name: xxx-minio-container
image: minio/minio:RELEASE.2023-11-11T08-14-41Z # 任意のバージョンを指定。latestより特定バージョンの指定が推奨される。
volumes:
- "xxx/xxx:xxx/minio/data" # 任意の設定
ports:
- 9090:9090
environment:
MINIO_ROOT_USER: "minio_root"
MINIO_ROOT_PASSWORD: "minio_password"
command: server --console-address ":9090" /xxx/minio/data
【環境変数(Laravelで使用する.envファイル)】
MINIO_BUCKET=xxx-bucket
MINIO_DATA_PATH=./xxx/minio/data
# minio使用のため以下の値を設定(MINIO用の環境変数を別途設定するor以下に直接書く)
AWS_ACCESS_KEY_ID=minio_root
AWS_SECRET_ACCESS_KEY=minio_password
AWS_DEFAULT_REGION=${AWS_REGION}
AWS_BUCKET=${MINIO_BUCKET_NAME}
AWS_USE_PATH_STYLE_ENDPOINT=true # ステージング/本番ではfalseにする
AWS_ENDPOINT=http://xxx-minio:9000
AWS_URL=http://127.0.0.1:${MINIO_PORT}
Docker(Docker Compose)のおさらい
- サービス名:
xxx-minio:
Docker Composeで実行される各コンテナを定義するセクション・その名前です。
Docker Composeでは、サービス名がそのまま内部DNSによるホスト名として機能します。これにより、Docker Compose内で定義された異なるサービス(コンテナ)間の通信が容易になります。 - コンテナ名:
container_name: xxx-minio-container
Docker Composeで実行される各コンテナを識別するためにあります。
指定しなければ、デフォルトで「{プロジェクト名}{サービス名*}{*インスタンス番号}
」の形式で生成されますが、明示的に名前を指定することで開発時に分かりやすくなります。 - イメージ:
image: minio/minio:RELEASE.2023-11-11T08-14-41Z
コンテナで使用するDockerイメージを指定します。
DockerHubのイメージを使用する場合に使用するプロパティです。例えば今回の場合はDockerHubのこちらからMinIOのイメージを使用するため、このように指定しています。
-
ビルド:(今回の例では指定なし)
独自のDockerイメージを使用する場合にこちらのプロパティでDockerfileのパスを指定します。
※Docker Composeではimage
もしくはbuild
のどちらかを指定する必要があります。 -
ボリューム:
{ホスト側のボリュームディレクトリパス}:{コンテナ側のボリュームディレクトリパス}
を設定。 -
ポート
{ホスト側のポート}:{コンテナ側のポート}
を設定。
コンテナは独立しているため任意のポートを設定して基本的に問題はない(一般的なポートを使用する)
よくあるのが、ホスト側(自分のローカルマシン)のポートが他のプロジェクトと重複しているためにうまく動作しないということです。
これは自分のローカル環境に依存しているため、他の人の環境では動作するけれど自分の環境では動作しないということがよく起こります。
上記docker-compose.yaml
では直書きしていますが、環境変数で設定することで各開発者が任意のポートを使用することができます。 -
環境変数
コンテナの起動に必要な環境変数を指定します。
MinIOではユーザー名とパスワードの指定が必要です。DBコンテナでのユーザー名やパスワード、ホスト名の指定にもこちらが使われます。environment: MINIO_ROOT_USER: "minio_root" MINIO_ROOT_PASSWORD: "minio_password"
-
コマンド:
command: server --console-address ":9090" /xxx/minio/data
コンテナ起動時に実行するコマンドを指定できます。
今回の例ではMinIOサーバーを立ち上げるコマンドを実行しています。
(/xxx/minio/data
はコンテナ側のボリュームディレクトリを指定)
構築して気づいたこと(個人的な感想)
「http://{サービス名}:{コンテナのポート}
」がコンテナのエンドポイントになることを今回初めて知りました。
今回の例では、サービス名をxxx-minio
と指定しているのにエンドポイントにhttp://minio:9090
とするとコンテナのエンドポイントが間違っているため名前解決ができないというエラーが発生します。
Dockerコンテナのエンドポイントを使用する機会はなかなかないので勉強になりました。
今回の気づき
※AWS_ENDPOINTとAWS_URLはLaravelの話です。
AWS_ENDPOINTって何?
AWS_ENDPOINT
はAWSサービスへのカスタムエンドポイントを指定するために使われます。
LaravelからAWSサービスに直接アクセスする場合は設定の必要はありませんが、AWSの公式エンドポイント以外の場所を使う場合に指定します。
今回のMinIOのような互換サービスを利用する際は代表的な例の一つです。
AWS_URLって何?
AWS_URL
は、AWSのストレージ(主にS3)に保存されたオブジェクトにアクセスするためのパブリックURLのベースとなります。
形式の例としては https://[bucket-name].s3.amazonaws.com
のように、バケット名とS3のドメインを含めますが、Laravelでは基本的に指定は必須ではありません。
パブリックURLを提供するため、カスタムドメインやCDNを使用する場合やアプリケーション上でのファイルの利用、バケットポリシーとの連携など特定のユースケースにおいてAWS_URLの指定を活用することができます。
具体的につまづいたこと、学んだこと
サービス名をxxx-minio
としているにも関わらず、AWS_ENDPOINT
にhttp://minio:9000
を指定していました。(MinIOコンテナ構築の際に参考にした記事の多くがサービス名がminio
、AWS_ENDPOINT
にはhttp://minio:9000
が指定されており、そのまま記述したため)
そうするとMinIOサーバーは起動しましたが、アプリケーションからストレージ(MinIO)に接続(ファイルをアップロード)する際にDNSエラーが発生しました。
正しくはサービス名をエンドポイント名に反映させたhttp://xxx-minio:9000
となります。
コンテナのサービス名が名前解決に使われること、コンテナのエンドポイント、AWS_ENDPOINTについて整理することで問題を解決することができました。
あまり意識したことがなかった点なので今回を機にDocker ComposeとDockerコンテナについてさらに理解を深めることができてよかったです🐙
Discussion