ローカルDocker環境でS3Mockを利用する
AWS 環境で動作させているシステムの開発をしていて、ローカルの Docker 環境に S3 と同じ API で動作するモックがあったらいいなと思って調べたら、当然のようにありました。
S3 のモックサーバー候補
とりあえず見つかったのは以下です。
上2つが有力候補。 3つ目の Fake S3 は古いバージョンはオープンソースだけど新しいバージョンは有料っぽい? 後ろ2つは adobe/S3Mock が似たようなプロジェクトとして紹介してました。
今回は findify/S3Mock を試した後に、結局 adobe/S3Mock を利用しました。
実際のプロジェクトでは TypeScript を使っているのですが、ここでは Javascript で解説します。
なぜ adobe/S3Mock にしたか?
findify/S3Mock でデフォルトのバケットをコンテナ作成時に最初から作成しておく方法がすぐに分からなかったからです。 もちろん API を呼んで CreateBucket することはできます。
dokcer-compose.yml の用意
docker-compose の設定は以下のようにしました。 Node.js 環境も dokcer-compose で用意しておきます。
version: '3.7'
services:
# Node.js環境。開発時のnpmコマンド実行はここで行う。
node:
image: node:12.18.3-alpine3.12
volumes:
- ./:/project:delegated
tty: true
working_dir: /project
environment:
# AWS-SDKを動作させるのにダミーでいいので設定しておく必要がある
AWS_REGION: ap-northeast-1
AWS_ACCESS_KEY_ID: local
AWS_SECRET_ACCESS_KEY: dummy
s3:
image: adobe/s3mock
environment:
- initialBuckets=my-bucket
initialBuckets を指定することでコンテナ作成時にバケットも作成することができます。inisitalBuckets と複数形になっていますが、リストで複数作成させることができるようです。
- initialBuckets=my-bucket1,my-bucket2,my-bucket3
Node.js 環境の用意
コンテナを起動しておきましょう。
$ docker-compose up -d
node コンテナに入って作業します。alpine 版を使ってるので bash が入っていなくて sh を指定します1。
$ docker-compose exec node sh
ここからは node コンテナ内でのコマンド実行の場合は、先頭を $ ではなく # で表します。
package.json を作成します。中身は適当でいいです。
# npm init
AWS SDK をインストールします。
$ npm install aws-sdk
AWS SDK でのアクセス
適当に index.js とかの名前でファイルを作成しましょう。 まずは s3 クライアントオブジェクトを作成します。
const AWS = require('aws-sdk');
const s3 = new AWS.S3({
apiVersion: '2006-03-01',
// docker-compose環境の中ではサービス名がそのままホスト名として使える。s3コンテナの9090番ポートを指定。
endpoint: 'http://s3:9090',
// S3Mock使う時は <バゲット名>.hostname:9090 でなく hostname:9090/<バゲット名> になってもらわないと困る
s3ForcePathStyle: true,
});
endpoint と s3ForcePathStyle を指定する必要があります。
S3 の URL は昔は https://s3-<リージョン >.amazonaws.com/<バケット名>
というパス形式と呼ばれるものが使われていました。
今は https://<バケット名>.s3-<リージョン>.amazonaws.com/
という仮想ホスト形式が使われています。
しかし S3Mock を使うときに仮想ホスト形式になってもらってはアクセスできないので、パス形式を利用するように指定しています。
9090 番ポートは HTTP 用で、9191 番ポートが HTTPS 用だそうです。HTTP しか試してませんが。
あとは普通に使ってもらえば大丈夫です。
-
alpine を使っているのは、本番環境の Fargate 用コンテナをサイズの小さい alpine で作るつもりでいて、開発環境も同じに合わせたかったからです。debian を使った方が色々とカスタマイズが楽だと思います。
↩