nikkie-ftnextの日記

イベントレポートや読書メモを発信

LocalStackでローカル環境に簡単にAWSのサービスを用意! Dockerで動かし、boto3でS3を操作する例

はじめに

YAPC::Kyoto 2023のチケットを買ってくれ!1(本日1/31(火)まで) nikkieです。

直近でLocalStackという技術を触る機会がありました。
LocalStackはAWSのサービス(に相当するAPI群)をローカル開発環境で動かせます
環境構築からPythonスクリプトでローカルのS3を操作するまでをログとして残します。

目次

LocalStack

フューチャーさんのブログで存在を知りました。

フューチャーさんの記事は、AWS Lambdaの開発環境をLocalStackで動かす例を示しています。

LocalStack自体はPythonで実装されていて2PyPIにパッケージも登録されています

DockerでLocalStackを動かす

今回はDockerで動かすことにしました(pip install localstackは今後の素振り材料です)。

https://docs.localstack.cloud/getting-started/installation/#docker

$ docker run --rm -it \
    -p 4566:4566 \
    -p 4510-4559:4510-4559 \
    localstack/localstack

起動中のログより、以下のバージョンを動かしていました。

LocalStack version: 1.3.2.dev
LocalStack build date: 2023-01-28
LocalStack build git hash: 63e357fb

「Ready.」と出たら準備完了です。
curl -s http://localhost:4566/health | jq .で各種サービスがavailableになったことが確認できます。

ローカルのS3でboto3を素振り!

AWSのサービスの操作を提供するライブラリboto3、LocalStackに向けても使えます。

pip install boto3でインストールできます。
以下のバージョンで動かしています。

$ python -V
Python 3.10.2
$ pip list | grep boto
boto3           1.26.59
botocore        1.29.59

試しにS3にバケットを作り、ファイルを置いてみます(s3://awesome/foo/bar.txtが置かれます)。

import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="http://localhost:4566",
    aws_access_key_id="dummy",
    aws_secret_access_key="dummy",
)

BUCKET_NAME = "awesome"
s3.create_bucket(Bucket=BUCKET_NAME)

FILE_PATH = "foo/bar.txt"
s3.put_object(Bucket=BUCKET_NAME, Key=FILE_PATH, Body=b"LocalStack!")

client3はLocalStackのエンドポイントを指定し、aws_access_key_idaws_secret_access_keyにはダミーの文字列を指定します。

boto3でS3のバケット操作

バケットの作成はcreate_bucketメソッドです。
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.create_bucket
Parametersのうち、Bucketバケット名を指定)のみが必須です。

パケットにファイルを置くのはput_objectメソッドです。
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.put_object
必須のパラメータはBucketKey(S3に置くオブジェクトのキー)です。
オブジェクトのデータはBodybytesオブジェクト、またはfile-likeオブジェクト4として渡せます。

LocalStackのS3バケットに置いたファイルを確認

上で示したスクリプトs3_practice.py)を-iオプションを付けて実行します。
スクリプト実行後に立ち上がるPythonの対話モードで、s3://awesome/foo/bar.txtの内容を確認します。

>>> response = s3.get_object(Bucket=BUCKET_NAME, Key=FILE_PATH)
>>> response["Body"].read()
b'LocalStack!'

get_objectメソッドでオブジェクトを取得します。 https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.get_object
Parametersのうち、BucketKeyが必須です。

Responseの辞書では、キー"Body"がデータを指しています。
readメソッドで読み込みます5
書き込んだバイト列と同じですね!🙌

終わりに

ローカル環境にAWSのサービスを立てられるLocalStackを触りました。
Dockerで動かし、boto3を使ってS3を操作しています。
バケットを作り、オブジェクトを置き、その内容を読み出しました。

ローカル環境に簡単にAWSを用意できるのは開発が捗りそうな印象です。
AWS Lambdaで動かしているBot6がありますが、他のAWSサービスと連携させる開発はまずサービスの用意が必要ですし、一発で正しく構築できないことが多いので数回作り直すイメージがあります。
ですが、LocalStackでローカル環境に用意すれば、試行錯誤に必要な準備が劇的に簡単になります!
素振り中も、例えばバケットができたあとに実装ミスでエラーが送出されたら、LocalStackを止めて再度docker runして操作をリセット。
修正したスクリプトを最初から流し直しました。

ブログにまとめるにあたって、boto3のドキュメントの読み方もなんとなく分かりました。
すごく文字がありますが、ParametersのREQUIREDさえ確認すれば使い出せます。
ResponseやExampleも参考になりますね。

参考記事

P.S. boto3のClient API

ここで示したスクリプトboto3.clientとClient APIを使うものです。
boto3にはもう1つResource APIがあります(boto3.resource)。

  • Client APIは低レベル
  • Resource APIは高レベル

Resource APIが廃止という情報を見かけ、今回のスクリプトはClient APIを使って実装しています。

2023/01/19 追記:「Resource API」廃止についての情報