AWS
S3
LocalStack

LocalStackをDockerコンテナ内で使う場合に、S3のバケット名がサブドメインになって接続できなくて困った話(解決済み)

はじめに

LocalStackは、AWSの各サービスをローカルで再現するためのフェイク環境です。
公式のDockerイメージを使うと便利です。

localstackは、AWS Summit Tokyo 2017での@twadaの講演で聞いたことがありましたが、今回初めて使いました。

Dockerコンテナ内でLocalStackを使う

下記のように、Dockerコンテナを構成していたとします。

# docker-compose.yml
version: '3'
services:
  app:
    build: .
    env_file: .env
    volumes:
      - .:/app
      - ~/.aws:/root/.aws
    working_dir: /app
    links:
      - localstack
  localstack:
    image: localstack/localstack
    ports:
      - '8080:8080'
      - '4572:4572' # For S3

appコンテナから任意のBucketにアクセスしようとすると、エンドポイントがhttp://{Bucket}.localstack:4572/となり、下記のようにエラーが発生します。

Aws\S3\Exception\S3Exception: Error executing "CreateBucket" on "http://{Bucket}.localstack:4572/"; 
AWS HTTP error: cURL error 6: Could not resolve host: {Bucket}.localstack (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)

解決方法

サブドメイン付きのホストが名前解決できないのが原因ですが、/etc/hostsに追記するのは適切ではありません。
パス形式のURLにすることが最適です。
パス形式にすることで、エンドポイントがhttp://localstack:4572/{Bucket}となります。

Amazon S3 バケットの使用 - Amazon Simple Storage Service #バケットへのアクセス

パス形式のURLでは、バケット名は (リージョン固有のエンドポイントを使用しない限り) ドメインの一部にはなりません。
例:
- 米国東部 (バージニア北部) リージョンエンドポイント、http://s3.amazonaws.com/bucket
- リージョン固有のエンドポイント、http://s3-aws-region.amazonaws.com/bucket

PHPの場合は、use_path_style_endpointtrueにします。
https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.S3.S3Client.html#___construct

use_path_style_endpoint: (bool) Set to true to send requests to an S3 path style endpoint by default. 
Can be enabled or disabled on individual operations by setting '@use_path_style_endpoint\' to true or false. 
Note: you cannot use it together with an accelerate endpoint.

おわりに

@twadaが講演の中でおっしゃっていますが、LocalStackのようなFake Objectを使うことで、テストのために、依存ライブラリをインストールする必要がなくなり、テストもスッキリしますし、素早く開発が行えます。

今回のように、つまづくポイントがあったら、一つ一つ記事にしていきたいと思います。
ではでは。