LocalStackのS3バケットにDockerコンテナからMountpoint for Amazon S3で接続する
こんにちは。エンジニアのmackeyです。今回は、Mountpoint for Amazon S3を使用するアプリケーションの開発時に役立つ知識を紹介したいと思います。
背景
AWSのS3を用いるアプリケーションを開発していた際に、Mountpoint for Amazon S3(以下Mountpointと省略する場合あり)が一般公開され、アプリケーションの要件的にマッチしていたため採用することにしました。ただ、ローカル環境のテスト用にLocalStackを用いていたため、MountpointでLocalStackのS3バケットをマウントできないか試してみることにしました。その結果、LocalStackに対してもうまく動作することがわかったので、この記事では最小構成のサンプルでやり方を紹介したいと思います。
Docker環境の準備
今回使用するコードはこちらのGitHubリポジトリにアップロードしています。
実行環境はMacOSを想定しており、アプリケーション側のコードにはPythonを用いることにします。
全体構成
.
├── cmd
│ ├── read_file.py
│ └── write_file.py
├── compose.yml
├── Dockerfile
├── init_localstack.sh
└── mount_localstack_s3.sh
各設定ファイルの説明
version: "3.8"
services:
app:
build: .
privileged: true
volumes:
- .:/app
localstack:
image: localstack/localstack:3.2.0
ports:
- "127.0.0.1:5566:4566" # LocalStack Gateway
- "127.0.0.1:5510-5559:4510-4559" # external services port range
environment:
# LocalStack configuration: https://docs.localstack.cloud/references/configuration/
- DEBUG=${DEBUG:-0}
volumes:
- "./init_localstack.sh:/etc/localstack/init/ready.d/init_localstack.sh"
Dockerコンテナとしては、LocalStack用のコンテナ(localstack)と、それに接続するためのアプリケーション用のコンテナ(app)の二つを用意します。
注目すべき点は、6行目の privileged: true です。
Mountpoint uses the Linux FUSE subsystem to mount its file system. Running a FUSE file system inside a Docker container requires giving the container elevated root-level privileges to the host instance.
https://github.com/awslabs/mountpoint-s3/tree/main/docker#docker-permissions-and-aws-container-services
とある通り、Dockerコンテナ上でMountpointを使用するには、特権モードで実行する必要があります。ホストコンピュータへのアクセス権限が付与されることになるので、コンテナ上ではありますが信頼できない外部リソースにはアクセスしないなど、セキュリティ面には十分注意を払ってください。
#!/bin/bash
echo "Start LocalStack init..."
awslocal s3 mb s3://bucket-test
LocalStackにS3バケットを作成するためにのスクリプトです。compose.ymlの18行目でこのファイルをマウントしており、LocalStackの起動時に実行されます。
(起動時スクリプトの詳細は https://docs.localstack.cloud/references/init-hooks/ を参照)
FROM --platform=linux/arm64 python:3.12-slim
RUN apt update && apt upgrade -y
# Install Mountpoint for Amazon S3
RUN apt-get install -y wget fuse libfuse2 sudo
RUN wget https://s3.amazonaws.com/mountpoint-s3-release/latest/arm64/mount-s3.deb
RUN sudo apt-get install ./mount-s3.deb
WORKDIR /app
CMD bash mount_localstack_s3.sh && bash
アプリケーションコンテナのDockerfileです。pythonのDockerイメージにMountpointをインストールしています。
MacOSで実行しているため、arm64向けの設定になっているのでご注意ください。(環境ごとのインストール方法の詳細はhttps://github.com/awslabs/mountpoint-s3/blob/main/doc/INSTALL.md を参照)
#!/bin/bash
MOUNT_DIRECTORY="/mnt/s3"
BUCKET_NAME="bucket-test"
echo "Start mount s3 bucket..."
mkdir -p $MOUNT_DIRECTORY
mount-s3 \
--allow-delete --allow-overwrite \
--force-path-style --endpoint-url http://localstack:4566 --no-sign-request \
$BUCKET_NAME $MOUNT_DIRECTORY
コンテナ起動時にMountpointを実行してS3バケットをマウントするためのスクリプトです。mount-s3を実行する際のオプションが重要なので、一つずつ解説します。(オプションの詳細は https://github.com/awslabs/mountpoint-s3/blob/main/doc/CONFIGURATION.md を参照)
まず、以下はファイル操作に関するオプションです。
- --allow-delete : ファイルの削除を可能にする
- --allow-overwrite : 既存のファイルを上書き可能にする(アップデートで追加されたオプションです)
そして、以下はLocalStackのバケットをマウントする際に必要なオプションです。
- --force-path-style : Path-Styleでリクエストを送る
- --endpoint-url : S3のエンドポイントを指定する
- --no-sign-request : AWS認証を無効にする
LocalStackにおけるPath-StyleとVirtual Hosted-Styleに関しては、https://docs.localstack.cloud/user-guide/aws/s3/#path-style-and-virtual-hosted-style-requests を参照してください。今回の場合、Virtual Hosted-Styleだとうまくいかなかったので、force-path-styleを指定して、endpoint-urlには http://localstack:4566 を指定しています。
動作検証
appコンテナで実行するPythonスクリプトの準備
openを使用したファイル操作を行うスクリプトを準備しておきます。
import sys
S3_MOUNT_PATH = "/mnt/s3"
if len(sys.argv) < 2:
print("Usage: python write_file.py <text>")
sys.exit(1)
with open(S3_MOUNT_PATH + "/test.txt", "w") as f:
f.write(" ".join(sys.argv[1:]) + "\n")
ファイルを書き込むためのスクリプトです。
S3_MOUNT_PATH = "/mnt/s3"
with open(S3_MOUNT_PATH + "/test.txt", "r") as f:
print(f.read())
ファイルを読み込むためのスクリプトです。
実行してみる
$ docker compose build
(省略)
$ docker compose up -d localstack
[+] Running 1/2
⠧ Network mountpoint-s3-test_default Created 1.7s
✔ Container mountpoint-s3-test-localstack-1 Started 1.6s
まずはLocalStackコンテナの起動です。コンテナのログを見ると、この時点でS3バケットが作成されていることを確認できます。
$ docker compose run --rm app
Start mount s3 bucket...
bucket bucket-test is mounted at /mnt/s3
root@5218519f757d:/app# python cmd/write_file.py Hello, MountPoint!
root@5218519f757d:/app# python cmd/read_file.py
Hello, MountPoint!
root@5218519f757d:/app# python cmd/write_file.py Overwrite file!
root@5218519f757d:/app# python cmd/read_file.py
Overwrite file!
root@5218519f757d:/app# ls /mnt/s3
test.txt
root@5218519f757d:/app# cat /mnt/s3/test.txt
Overwrite file!
appコンテナを起動すると、まずDockerfileのCMDで指定した mount_localstack_s3.sh が実行され、バケットがマウントされます。
その後、Pythonのスクリプトを実行し、S3バケットへの書き込みと読み込みと上書きが成功していることが確認できます。
また、lsやcatが使えることも確認できます。
おわりに
今回は、LocalStackのS3バケットにDockerコンテナからMountpoint for Amazon S3で接続する方法を紹介しました。
記事投稿時点ではWeb上ではこの方法を紹介する記事はなさそうだったので、お役に立てば幸いです。