Atlassian LocalStackを使ってみた

4月に見つけたからずっと気になっていたので、軽く試してみました。

LocalStackとは

LocalStackはAWS環境をローカルに作ってしまおうというツールです。

atlassian / localstackGit repository hosted by Bitbucket.

開発はJIRAやBitbucket、Confluenceで有名なAtlassianが行っています。
私自身が上記ツールの導入/運用を行っていたり、Atlassianユーザグループの会にも参加しているため親近感がありました。

凄いことをやっているのに日本ではマイナーな感じがありましたが、最近一気に知名度が上がったような気がしています。
(会社で共有しても誰も反応しないレベルだった..)

先日のAWS Summit Tokyo 2017でt_wadaさんが紹介されていたのが大きいのかなと思っています。

著名人が広めるより前に知っていると、少しドヤ顔したくなりますね(笑)

前提条件

  • OSはWindows10
  • Bash on Ubuntu on Windows + wsl-terminal
  • Vagrant1.9.5 + VirtualBox 5.1.22

VM上のDockerに対して、LocalStack環境を作成します。
Vagrant, VirtualBoxの初期環境構築方法は以下の記事を参照してください。

VagrantとDockerでConfluenceを立ち上げてみた

VMの作成

LocalStack環境を作成します。

Vagrantfile

/mnt/c/Users/syoum/vagrant/localstack にVagrantfileを作成します。

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  # Docker入りのubuntuイメージ
  config.vm.box = "williamyeh/ubuntu-trusty64-docker"
  config.vm.box_version = "1.12.1.20160830"

  # 4567-4581ポートはLocalStackで使用するポート
  # 9080ポートはLocalStackのダッシュボード用。8080は競合するのでVMでは9080でフォワーディング
  ACCEPT_PORTS = (4567..4581).to_a.push(9080)
  ACCEPT_PORTS.each do |port|
    config.vm.network "forwarded_port", guest: port, host: port, host_ip: "127.0.0.1"
  end
  config.vm.network "private_network", ip: "192.168.33.10"

  # provider
  config.vm.provider "virtualbox" do |vb|
    vb.memory = "1024"
  end

  # provisioning. atlassianlabs/localstackのダッシュボードは8080ポートなので、9080からフォワーディング
  config.vm.provision "shell", inline: <<-SHELL
    docker run -d --restart=always \
               --name="localstack" \
               -p 4567-4581:4567-4581 \
               -p 9080:8080 \
               atlassianlabs/localstack
  SHELL
end
syoumはユーザ名です。自身の名称に変更してください。

実行とプロビジョニング

$ wcmd vagrant up --provision

エラーが出なければOKです。

動作確認

個人的な都合でDynamoDBとS3の確認をしました。
Windowsのwsl-terminalからAWS CLIを使って操作します。

DynamoDB

エンドポイントは http://localhost:4569 です。
ポート番号は SERVICES ホスト名は HOSTNAME の設定値で変更できるようですね。

dynamodb – AWS CLI 1.11.115 Command ReferenceDynamoDB automatically spreads the data and traffic for your tables over a sufficient number of servers to handle your throughput and storage requirements, while maintaining consistent and fast performance. All of your data is stored on solid state disks (SSDs) and automatically replicated across multiple Availability Zones in an AWS region, providing built-in high availability and data durability.

テーブル一覧の取得

初期状態なので何もありません。

$ aws --endpoint-url=http://localhost:4569 dynamodb list-tables
{
    "TableNames": []
}

テーブルの作成

jumeaux-viewer という名前のテーブルを作成してみます。
primary key を hashkey に設定します。

$ aws --endpoint-url=http://localhost:4569 dynamodb create-table \
      --table-name jumeaux-viewer \
      --attribute-definitions \
          AttributeName=hashkey,AttributeType=S \
      --key-schema AttributeName=hashkey,KeyType=HASH \
      --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1

上手くいくと、以下の様に結果が返却されます。

{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:ddblocal:000000000000:table/jumeaux-viewer",
        "AttributeDefinitions": [
            {
                "AttributeName": "hashkey",
                "AttributeType": "S"
            }
        ],
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "WriteCapacityUnits": 1,
            "LastIncreaseDateTime": 0.0,
            "ReadCapacityUnits": 1,
            "LastDecreaseDateTime": 0.0
        },
        "TableSizeBytes": 0,
        "TableName": "jumeaux-viewer",
        "TableStatus": "ACTIVE",
        "KeySchema": [
            {
                "KeyType": "HASH",
                "AttributeName": "hashkey"
            }
        ],
        "ItemCount": 0,
        "CreationDateTime": 1498914600.725
    }
}

テーブルの確認

もう一度テーブル一覧を取得して jumeaux-viewer が作成されたことを確認します。

$ aws --endpoint-url=http://localhost:4569 dynamodb list-tables
{
    "TableNames": [
        "jumeaux-viewer"
    ]
}

アイテム一覧の取得

scanで全件走査します。

$ aws --endpoint-url=http://localhost:4569 dynamodb scan \
      --table-name jumeaux-viewer
{
    "Count": 0,
    "Items": [],
    "ScannedCount": 0,
    "ConsumedCapacity": null
}

まだ登録していないので0件です。

アイテムの登録

put-itemで登録します。

$ aws --endpoint-url=http://localhost:4569 dynamodb put-item \
      --table-name jumeaux-viewer \
      --item '{
          "hashkey": {"S": "xxxxx"},
          "name": {"S": "tadashi-aikawa"}
      }'

何もエラーが表示されていなければ登録完了です。

アイテムの確認

scanコマンドで登録されていることを確認できます。

$ aws --endpoint-url=http://localhost:4569 dynamodb scan \
      --table-name jumeaux-viewer
{
    "Count": 1,
    "Items": [
        {
            "hashkey": {
                "S": "xxxxx"
            },
            "name": {
                "S": "tadashi-aikawa"
            }
        }
    ],
    "ScannedCount": 1,
    "ConsumedCapacity": null
}

S3

エンドポイントは http://localhost:4572 です。

s3 – AWS CLI 1.11.115 Command ReferenceEvery command takes one or two positional path arguments. The first path argument represents the source, which is the local file/directory or S3 object/prefix/bucket that is being referenced. If there is a second path argument, it represents the destination, which is is the local file/directory or S3 object/prefix/bucket that is being operated on.

バケット一覧取得

lsコマンドを使います。

$ aws --endpoint-url=http://localhost:4572 s3 ls

バケットは作成していないので何も返却されません。

バケット作成

mamansoft-jumeaux-viewer というバケットを作成します。

$ aws --endpoint-url=http://localhost:4572 s3 mb s3://mamansoft-jumeaux-viewer/
make_bucket: mamansoft-jumeaux-viewer

バケット確認

もう一度lsコマンドを使います。

$ aws --endpoint-url=http://localhost:4572 s3 ls
2006-02-04 01:45:09 mamansoft-jumeaux-viewer

作成したバケットが表示されました。

オブジェクトの登録

以下のような mimizou.txt を作成します。

$ cat mimizou.txt
ぴぎーー!!
pigi---!!

これをcpコマンドで登録します。

$ aws --endpoint-url=http://localhost:4572 s3 cp mimizou.txt s3://mamansoft-jumeaux-viewer/20170702/
upload: ./mimizou.txt to s3://mamansoft-jumeaux-viewer/20170702/mimizou.txt

オブジェクトの確認

--recursive オプションを付けて mamansoft-jumeaux-viewer バケットの中身を全て表示します。

$ aws --endpoint-url=http://localhost:4572 s3 ls s3://mamansoft-jumeaux-viewer --recursive
2017-07-02 19:30:06         25 20170702/mimizou.txt

登録されていることを確認できました。

オブジェクトの取得

せっかくなので s3api を使います。

s3api – AWS CLI 1.11.115 Command ReferenceFirst time using the AWS CLI? See the User Guide for help getting started.

$ aws --endpoint-url=http://localhost:4572 \
      s3api get-object mimizou.txt \
      --bucket mamansoft-jumeaux-viewer \
      --key 20170702/mimizou.txt
{
    "ContentType": "text/plain",
    "LastModified": "Sun, 02 Jul 2017 10:30:06 GMT",
    "ContentLength": 25,
    "ETag": "\"b9b91cdb49d33fe4fbf7fff8663901f6\"",
    "Metadata": {}
}

mimizou.txt がs3から取得できていればOKです。

AWS SDK

AWS SDKを使用している場合でもエンドポイントURLを切り替えればLocalStackを使用する事ができます。

  • Pythonの場合は endpoint_url
  • JavaScriptの場合は endpoint

Sandbox環境での確認やテスト実行時に切り替えることで活用しましょう。

ダッシュボードの表示

http://localhost:9080/ からダッシュボードを表示することができます。

まだプロトタイプ感が漂いますが、徐々にリッチになっていくのではないでしょうか。

注意

何点か注意があります。

LocalStackのデータは永続化されない

コンテナ終了時にデータは全て初期化されます。
削除されると困る場合は気をつけて使いましょう。

S3のキーにマルチバイト文字を使用できない

確認したのは日本語だけですが、恐らくASCII以外の文字に対応していないと思われます。
不具合かもしれませんのでGitHubにIssueを登録しておきました。

`s3api put-object` failed when specifying to `–key` non-ascii string · Issue #142 · atlassian/localstackHi. Thanks for your great product! When I used s3api, I found the following error. Is localstack support non-ascii key string? OK $ aws –endpoint-url=http://localhost:4572 s3api put-object \ -…

反応あるといいのですが、スルーされてしまったら 『英語を使いましょう』 という風に乗り切るのが良さそうですね。

Preflightに対応していない

こちらの方が厳しいです。S3は勿論のことDynamoDBにもアクセスができません。

Added initial implementation of S3 OPTIONS preflight request mocking – Issue #20Still needs to take into account CORS settings. @w_hummer I’ll be happy to follow up with improved CORS handling later in the week. Please advise on what automated tests you want included with this – only had time to skim over the existing automated tests and didn’t see anywhere obvious to slot in.

上記プルリクエストがマージされれば解決しそうです。
ただ、本課題のスコープはS3なのでDynamoDBは解決しないかもしれません。

s3apiでCORS設定変更できるようになった場合は以下を実施する予定です。

        $ cat > cors.json << 'EOF'
        {
        "CORSRules": [
            {
            "AllowedHeaders": ["*"],
            "AllowedMethods": ["GET", "PUT", "POST", "DELETE"],
            "AllowedOrigins": ["*"],
            "MaxAgeSeconds": 3000
            }
        ]
        }
        EOF

        $ aws --endpoint-url=http://localhost:4572 \
            s3api put-bucket-cors \
            --bucket mamansoft-jumeaux-viewer \
            --cors-configuration file://cors.json
    

総括

AWS環境をローカルに作ってしまうAtlassian製ツールのLocalStackを使ってみました。
Preflightに対応していない問題が解決すれば、Sandbox環境やmiddleなテストに利用できそうです。

オマケ

LocalStackを使いたいと思った私の開発物です。まだαとβの中間くらいですが宣伝がてら紹介しておきます。

tadashi-aikawa/jumeaux

jumeaux - Check difference between two responses of API.

tadashi-aikawa/jumeaux-viewer

jumeaux-viewer - Viewer for jumeaux.

Atlassian LocalStackを使ってみた” に対して1件のコメントがあります。

  1. 権フリークス より:

    すげえ、なんかわからないけどすごい

コメントを残す