localstackでローカルにS3を建てる

先日、localstackの存在を知った。このライブラリはAWSの各サービスをローカルで再現できるもので、AWSを使った機能を開発環境下でテストするのに役立つ。

github.com

一部のサービスは有料版でないと使えないが、今回は無料で使えるS3の機能を試してみた。

localstackは既に公式Docker imageが用意されているので、docker-compose.yml を作成すればすぐに使える。

version: "3"
services:
  localstack:
    image: localstack/localstack:0.11.3
    container_name: localstack
    ports:
      - 4566:4566
      - 8080:8080
    environment:
      - DEFAULT_REGION=ap-northeast-1
      - SERVICES=s3
      - DATA_DIR=/tmp/localstack/data
    volumes:
      - /Users/naoya-otani/.localstack:/tmp/localstack/ 

ポート 4566 は、localstack上で動く全てのAWSサービスのデフォルトのエンドポイントのポート ( EDGE_PORT 環境変数で設定を変更できる)。 ポート 8080GUIダッシュボードのデフォルトのエンドポイントである。 SERVICES には使いたいサービス名を記載する。
今回はS3なので、データの永続化もしておきたい。 DATA_DIR はlocalstackの中でデータを保持するディレクトリを指すが、このディレクトリはlocalstackコンテナ内のものなので、 volumes においてこのディレクトリとホスト側のディレクトリをマウントする必要がある。

docker-compose up -d で起動したら、 http://localhost:4566 をエンドポイントとしてローカルのS3にアクセスできる。
ローカルのS3も、aws-cliコマンドで操作することができる。 --endpoint-url オプションに上記のエンドポイントを指定することで、localstackのS3に対してコマンドを実行することができる。 AWS_ACCESS_KEY_IDAWS_ACCESS_SECRET_KEY は任意の値で良い。ただし、 --endpoint-url をつけ忘れて間違ってリモートのS3にコマンド実行してしまう事故を防ぐため、まずlocalstack用のprofileを作成しておく方が良いだろう。(以下では両方とも値を dummy にしている)

$ cat >> ~/.aws/credentials << EOF
[localstack]
aws_access_key_id = dummy
aws_secret_access_key = dummy
EOF

$ cat >> ~/.aws/config << EOF
[profile localstack]
region = ap-northeast-1
output = json
EOF

$ aws configure list --profile localstack
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile               localstack           manual    --profile
access_key     ****************ummy shared-credentials-file    
secret_key     ****************ummy shared-credentials-file    
    region           ap-northeast-1      config-file    ~/.aws/config

profileを作成したら、localstackにS3のバケットを作成する。リモートのS3を操作する場合と同様、 s3api list-buckets コマンドでバケットを確認できる。

$ aws s3 mb s3://sample-bucket --endpoint-url=http://localhost:4566 --profile localstack
make_bucket: sample-bucket
$ aws s3api list-buckets --endpoint-url=http://localhost:4566 --profile localstack 
{
    "Buckets": [
        {
            "Name": "sample-bucket",
            "CreationDate": "2020-08-02T11:42:51.547110Z"
        }
    ],
    "Owner": {
        "DisplayName": "webfile",
        "ID": "xxxxxxxxxxxxxxxxxxxxxxxxxx"
    }
}

sample-bucket にファイルをアップロードする。 s3 ls コマンドでファイルが確認できれば成功。

$ aws s3 cp sample.txt s3://sample-bucket/sample-dir/ --endpoint-url=http://localhost:4566 --profile localstack
upload: ./sample.txt to s3://sample-bucket/sample-dir/sample.txt 
$ aws s3 ls s3://sample-bucket/sample-dir/ --endpoint-url=http://localhost:4566 --profile localstack
2020-08-02 21:27:04         15 sample.txt