S3などにファイルアップロードしますが、ローカル環境の場合はS3に接続してファイルアップロードするわけにもいきません。
そこでローカルでファイルアップロード環境を構築できるMinioを構築していきましょう!
Docker環境
minioのイメージは下記になります
タグは今の最新のものを取り入れるなど指定しておきましょう!
そうすると、環境の差異を防げます。
それでは、docker-compose.ymlにMinioの情報を記載していきます。
全体像
追加するのは下記になります。
minio:
image: minio/minio:latest
container_name: minio
ports:
- "9999:9999"
- "9002:9002"
environment:
MINIO_ROOT_USER: access_key
MINIO_ROOT_PASSWORD: secret_key
entrypoint: /bin/bash
command: -c "/opt/bin/minio server /export --address :9999 --console-address :9002"
create-bucket:
container_name: minio-create-bucket
image: minio/mc:latest
entrypoint: [ "" ]
command:
- /bin/sh
- -c
- |
until (mc config host add minio http://minio:9999 access_key secret_key) do echo 'wait until add host' && sleep 1; done;
mc mb minio/public
mc policy set public minio/public
mc mb minio/private
mc policy set private minio/private
mc policy set private minio/private
environment:
MINIO_ROOT_USER: access_key
MINIO_ROOT_PASSWORD: secret_key
depends_on:
- minio
Minioの環境
minio:
image: minio/minio:latest
container_name: minio
ports:
- "9999:9999"
- "9002:9002"
environment:
MINIO_ROOT_USER: access_key
MINIO_ROOT_PASSWORD: secret_key
entrypoint: /bin/bash
command: -c "/opt/bin/minio server /export --address :9999 --console-address :9002"
まずはMinioそのものを起動します
接続情報は環境変数で定義されています。
environment:
MINIO_ROOT_USER: access_key
MINIO_ROOT_PASSWORD: secret_key
使用するポート番号を指定して起動させます。
command: -c "/opt/bin/minio server /export --address :9999 --console-address :9002"
この設定だと
--address :9999
はAPIに利用するエンドポイント。http://minio:9999で利用する。ホストマシンで実行されているWebブラウザ。- Minioのコンソール画面は
localhost:9002
に設定。
http://localhost:9002/loginを開くと、Minioのログイン画面が表示される。
ここでMINIO_ROOT_USER
とMINIO_ROOT_PASSWORD
を入力すればログインができる。
MINIO_ROOT_USER: access_key
MINIO_ROOT_PASSWORD: secret_key
Minio Clientを使用して、初期バケットを作成する
Minioのログイン画面が表示されて、バケット作成など可能ですが、はじめはバケットがあります。
Dockerはコマンド一つで開発環境を構築できるので、Minioのアップロード先のバケットも一緒に構築したいですよね
そこで登場しているのがMinio Clientになります。
create-bucket:
container_name: minio-create-bucket
image: minio/mc:latest
entrypoint: [ "" ]
command:
- /bin/sh
- -c
- |
until (mc config host add minio http://minio:9999 access_key secret_key) do echo 'wait until add host' && sleep 1; done;
mc mb minio/public
mc policy set public minio/public
mc mb minio/private
mc policy set private minio/private
mc policy set private minio/private
environment:
MINIO_ROOT_USER: access_key
MINIO_ROOT_PASSWORD: secret_key
depends_on:
- minio
Minio ClientとMinioを接続
Object Storage を追加するには、以下のコマンドを実行します。
mc config host add <ALIAS> <COS-ENDPOINT> <ACCESS-KEY> <SECRET-KEY>
<ALIAS>
– コマンドで Object Storage を参照するためのショート・ネーム<COS-ENDPOINT>
– Object Storage インスタンスのエンドポイント。エンドポイントについて詳しくは、エンドポイントおよびストレージ・ロケーションを参照してください。<ACCESS-KEY>
– サービス資格情報に割り当てられたアクセス・キー<SECRET-KEY>
– サービス資格情報に割り当てられた秘密鍵
今回だと下記のような構成になります
mc config host add minio http://minio:9999 access_key secret_key
ALIAS
minio(dockerコンテナ)COS-ENDPOINT
http://minio:9999ACCESS-KEY
access_keySECRET-KEY
secret_key
mb
– バケットの作成
バケット作成時は、バケットの エイリアスと名前を指定します。
mc mb minio/public
アクセスポリシーの設定
mc policy set
コマンドは、バケットの匿名(つまり、認証されていない、または公開されている)アクセスポリシーを設定します。
アクセスポリシーは下記の箇所で設定をしています
mc policy set public minio/public
publicポリシーを設定しています。これによりダウンロードおよびアップロードアクセス可能なディレクトリを指定してます。
指定されたに割り当てるポリシーの必須ALIAS
名。次のいずれかの値を指定します。
none
-への匿名アクセスを無効にしALIAS
ます。download
-へのダウンロード専用アクセスを有効にしますALIAS
。upload
-へのアップロード専用アクセスを有効にしALIAS
ます。public
-へのダウンロードおよびアップロードアクセスを有効にしますALIAS
。
必須コマンドが指定されたを適用するバケットまたはバケットプレフィックスへのフルパスPERMISSION
。
MinIOまたは他のS3互換サービスのエイリアスと、バケットまたはバケットプレフィックスへのフルパスを指定します。例えば:
mc set public play/mybucket
バケットプレフィックスを指定して、そのプレフィックスのみにポリシーを設定します。たとえば、次のコマンドは、 mybucket/downloads
とmybucket/uploads
プレフィックスに個別の匿名バケットポリシーを設定します。
mc set download play/mybucket/downloads mc set upload play/mybucket/uploads
まとめ
- Minioでアップロード先のエイリアスとエンドポイント、コンソール画面を用意
- Minio Clientでバケット作成し、ポリシーをセットする
設定ファイルを更新
Minioの準備ができたところで、Laravel側で利用できるようにしていきます。
.envに情報を追加
.envにMinioの接続情報を記述します。
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=
MINIO_ROOT_USER=access_key
MINIO_ROOT_PASSWORD=secret_key
MINIO_DEFAULT_REGION=us-east-1
MINIO_USE_PATH_STYLE_ENDPOINT=true
MINIO_ENDPOINT=http://minio:9999
FILESYSTEM_DRIVER=local
AWS_UPLOADS_PUBLIC_BUCKET=public
AWS_UPLOADS_PRIVATE_BUCKET=secret
filesystems.phpを更新
先ほど.envで定義した接続情報をfilesystems.phpに反映します。
filesystems.phpはLaravelのファイル保存などの設定を管理する場所です。
publicバケットとprivateバケットにdisksをわける場合
<?php
// 共通の接続情報
$s3base = [
'driver' => 's3',
'key' => env('MINIO_ROOT_USER', env('AWS_ACCESS_KEY_ID')),
'secret' => env('MINIO_ROOT_PASSWORD', env('AWS_SECRET_ACCESS_KEY')),
'region' => env('MINIO_DEFAULT_REGION', env('AWS_DEFAULT_REGION')),
'url' => env('MINIO_URL', env('AWS_URL')),
'endpoint' => env('MINIO_ENDPOINT', env('AWS_ENDPOINT')),
'use_path_style_endpoint' => (bool) env("MINIO_USE_PATH_STYLE_ENDPOINT", env('AWS_USE_PATH_STYLE_ENDPOINT', false)),
];
return [
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| Here you may specify the default filesystem disk that should be used
| by the framework. The "local" disk, as well as a variety of cloud
| based disks are available to your application. Just store away!
|
*/
'default' => env('FILESYSTEM_DRIVER', 'local'),
/*
|--------------------------------------------------------------------------
| Filesystem Disks
|--------------------------------------------------------------------------
|
| Here you may configure as many filesystem "disks" as you wish, and you
| may even configure multiple disks of the same driver. Defaults have
| been setup for each driver as an example of the required options.
|
| Supported Drivers: "local", "ftp", "sftp", "s3"
|
*/
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
's3_public' => [
...$s3base,
'bucket' => env('AWS_UPLOADS_PUBLIC_BUCKET'),
],
's3_private' => [
...$s3base,
'bucket' => env('AWS_UPLOADS_PRIVATE_BUCKET'),
],
],
/*
|--------------------------------------------------------------------------
| Symbolic Links
|--------------------------------------------------------------------------
|
| Here you may configure the symbolic links that will be created when the
| `storage:link` Artisan command is executed. The array keys should be
| the locations of the links and the values should be their targets.
|
*/
'links' => [
public_path('storage') => storage_path('app/public'),
],
];
シンプルにminio用のdisksを用意する場合
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| Here you may specify the default filesystem disk that should be used
| by the framework. The "local" disk, as well as a variety of cloud
| based disks are available to your application. Just store away!
|
*/
'default' => env('FILESYSTEM_DRIVER', 'local'),
/*
|--------------------------------------------------------------------------
| Filesystem Disks
|--------------------------------------------------------------------------
|
| Here you may configure as many filesystem "disks" as you wish, and you
| may even configure multiple disks of the same driver. Defaults have
| been setup for each driver as an example of the required options.
|
| Supported Drivers: "local", "ftp", "sftp", "s3"
|
*/
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
],
'minio' => [
'driver' => 's3',
'key' => env('MINIO_ACCESS_KEY_ID'),
'secret' => env('MINIO_SECRET_ACCESS_KEY'),
'region' => env('MINIO_DEFAULT_REGION'),
'bucket' => env('MINIO_BUCKET'),
'url' => env('MINIO_URL'),
'endpoint' => env('MINIO_ENDPOINT'),
'use_path_style_endpoint' => env('MINIO_PATH_STYLE_ENDPOINT'),
]
],
/*
|--------------------------------------------------------------------------
| Symbolic Links
|--------------------------------------------------------------------------
|
| Here you may configure the symbolic links that will be created when the
| `storage:link` Artisan command is executed. The array keys should be
| the locations of the links and the values should be their targets.
|
*/
'links' => [
public_path('storage') => storage_path('app/public'),
],
];
S3のRepositoryを作成
ファイルアップロードの設定ができたところで、S3でアップロードする用のRepository層を作成します。
インターフェース
<?php
use App\Exceptions\S3Exception;
use Illuminate\Http\UploadedFile;
use Symfony\Component\HttpFoundation\StreamedResponse;
interface S3Repository
{
/**
* ファイルをS3にアップロードする
* @param string $path
* @param UploadedFile $file アップロードするファイル
* @return string ファイルの保存先のパス
* @throws S3Exception
*/
public function upload(string $path, UploadedFile $file): string;
/**
* S3上のファイルを削除する。
* @param string $path
* @return bool
* @throws S3Exception
*/
public function delete(string $path): bool;
/**
* S3上のファイルをダウンロードする
* @param string $path ファイルパス
* @param string $file_name ファイル名
* @throws S3Exception
* @return StreamedResponse
*/
public function download(string $path, string $file_name): StreamedResponse;
}
実装クラス
<?php
use App\Exceptions\S3Exception;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\StreamedResponse;
class S3RepositoryImpl implements S3Repository
{
private const DISK_NAME = 's3_public';
/**
* {@inheritDoc}
*/
public function upload(string $path, UploadedFile $file): string
{
try {
$s3_path = Storage::disk(self::DISK_NAME)->putFile($path, $file);
} catch (S3Exception $e) {
throw new S3Exception(S3Exception::CODE_FAILED_TO_CONNECT, null, $e);
}
if ($s3_path === false) {
throw new S3Exception(S3Exception::CODE_UPLOAD_FAILED, trans('message.error.s3.failed_to_upload'));
}
return $s3_path;
}
/**
* {@inheritDoc}
*/
public function delete(string $path): bool
{
try {
return $is_success = Storage::disk(self::DISK_NAME)->delete($path);
} catch (S3Exception $e) {
throw new S3Exception(S3Exception::CODE_FAILED_TO_CONNECT, null, $e);
}
if ($is_success === false) {
throw new S3Exception(S3Exception::CODE_DELETE_FAILED, trans('message.error.s3.failed_to_delete'));
}
}
/**
* {@inheritDoc}
*/
public function download(string $path, string $file_name): StreamedResponse
{
try {
return Storage::disk(self::DISK_NAME)->download($path, $file_name);
} catch (S3Exception $e) {
throw new S3Exception(S3Exception::CODE_FAILED_TO_CONNECT, null, $e);
}
}
}
コメント