PythonでlocalStack(Docker)のS3オブジェクトを取得する
AWSリソースをローカル環境で使うことができるlocalStackを試しに使ってみました。
環境
機種 : MacBook Pro 2021(M1 Max)
OS : Monterey(12.2.1)
Python version(Docker): 3.11.2
pip version(Docker): 22.3.1
awscli-local version: 0.20
各種インストール
localStackのインストール
localStackを記載ある方法通りインストールします。が、Dockerコンテナを立てるので、なくてもまぁいい。
$ brew install localstack
awscli-localのインストール
awscli-localをインストールします。awsコマンドを使ってもlocalStackのリソースへアクセスできますが、毎度endpoint-urlを指定せねばなりません。awscli-localコマンドだと長ったらしいコマンドにならずに済みます。
$ pip install awscli-local
$ pip list | grep aws
awscli-local 0.20
DockerでlocalStackを構築する
DockerコンテナでlocalStack環境を構築します。良さげなdocker-compose.ymlのサンプルがあったのでありがたく、参考に使わせてもらいました。
以下は自分で追記しました。後ほど、Python環境のDockerコンテナからアクセスできるようにネットワークの設定をしています。
+ networks:
+ - sample-app-network
+
+networks:
+ sample-app-network:
次のようなdocker-compose.ymlになります。
version: "3.8"
services:
localstack:
container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}"
image: localstack/localstack
ports:
- "127.0.0.1:4566:4566" # LocalStack Gateway
- "127.0.0.1:4510-4559:4510-4559" # external services port range
environment:
- DEBUG=${DEBUG-}
- LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR-}
- DOCKER_HOST=unix:///var/run/docker.sock
volumes:
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"
networks:
- sample-app-network
networks:
sample-app-network:
起動します。
docker compose up -d
localStackでS3バケットとオブジェクトを作成する
ドキュメントを見つつ、localStackにS3バケットとオブジェクトを作成していきます。
余談ですが、普段はs3コマンド(aws s3 ...
)を利用しているのですが、ドキュメントではs3apiコマンドを利用していて、「何が違うんだってばよ!」と思い調べてみました。
以下の通り、s3apiコマンドよりs3コマンドのほうが高レベルな操作が可能なようでした。
S3バケットを作成します。
$ awslocal s3 mb s3://first-sample-test
make_bucket: first-sample-test
$ awslocal s3 ls
2023-02-23 21:53:41 first-sample-test
ファイルのアップロードしてみます。次のようなhtmlファイルを作成しました。
<p>hello world, localstack!</p>
CLIで先程作成したS3バケットにアップロードします。
$ awslocal s3 mv hello.html s3://first-sample-test/
move: ./hello.html to s3://first-sample-test/hello.html
$ awslocal s3 ls s3://first-sample-test/
2023-02-23 21:58:51 31 hello.html
試しにcurlしてみたら、取得できました。仕組みはいまいちよく分かっていない。。。
$ curl http://localhost:4566/first-sample-test/hello.html
<p>hello world, localstack!</p>
dockerでpython環境を構築する
先程作成したdocker-compose.ymlにPython環境を追記します。
...
networks:
- sample-app-network
+ python3:
+ restart: always
+ image: python:3.11.2
+ container_name: "my-python"
+ tty: true
+ volumes:
+ - "./src/:/root/src/"
+ networks:
+ - sample-app-network
networks:
sample-app-network:
また、S3オブジェクトにアクセスするためのpythonファイルを作成します。ディレクトリ構成は次の通り。
./
├── docker-compose.yml
└── src
└── s3_sample.py
今回はシンプルにファイルを取得して、printするだけです。region_name
は文字列であればどんな値を入れておいても取得できるぽいです(localStackがそういうものなのかなぁ。。。)
import boto3
s3 = boto3.client(
's3',
region_name='dummy',
# endpoint_url='http://localhost:4566'
# dockerコンテナ内で実行する場合はこちらを利用する
endpoint_url='http://localstack:4566'
)
response = s3.get_object(Bucket='first-sample-test', Key='hello.html')
body = response['Body'].read().decode('utf-8')
print(body)
起動します。
$ docker compose up -d
コンテナ内に入ってS3へ接続するときに使うboto3をインストールしておきます。
$ docker compose exec python3 bash
$ pip install boto3
pythonでS3ファイルを取得する
コンテナ内に入ったまま、s3_sample.pyのある場所へ移動します。AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEYが必要ですが、文字列を設定しておけばなんでも良いみたいでした。
$ cd root/src/
$ export AWS_ACCESS_KEY_ID=ACCESSKEY123
$ export AWS_SECRET_ACCESS_KEY=SECRETKEY123
$ python s3_sample.py
<p>hello world, localstack!</p>
感想
AWSのS3に接続してファイルを取得するという処理のコードを書いていたのですが、開発中だと他の人も同じファイルを参照していたら、ファイル名をいちいち変更して開発したりしていたので、そういうバッティングすることがあればlocalStackを用いて開発してもよいかもしれません。
設定がガバガバでも疎通できるので、慣れると便利ですが逆にガバガバなため、設定の不備などを見落としてしまうんじゃないかなと思いました(今回だとIAMやリージョン名など)。
まだまだ使いこなせていないので、時折触ってみようと思います
Discussion