インフラ担当の柴田です。
さて、突然ですがDynamoDBを使った開発をどうやっていますか? DynamoDBがないと開発できないのですが、AWS上にDynamoDBを用意してローカルから接続する場合クレデンシャルの取り扱いが面倒くさいですよね。 かといって、毎回AWS環境にデプロイしないと確認できないのも面倒くさい。AWS Cloud9?いやほら、オフラインじゃ使えないじゃないですか……
ということで、今更なところはありますがDynamoDB Localを使ってローカル開発環境を構築してみました。
DynamoDB Local
DynamoDB Localはローカルで実行可能なDynamoDBで、JARファイルやDockerイメージが配布されています。 公式のDockerイメージがあるので、簡単に試して見ることができるのが良いですね。
Visual Stdio Code (VSCode)のRemote Containersと組み合わせる
VS CodeのRemote Containers便利ですよね。 私は最近簡単なコードはPythonで書くのですが、プロジェクト毎にコンテナ上に開発環境を作れるので、 Pythonの仮想環境機能を使わなくても環境やPythonのバージョンを分離できるのが楽で愛用しています。
そこで今回はRemote Containersに用意されているPythonの設定とDynamoDB Localのコンテナイメージを利用して環境を構築してみました。
作業用フォルダーをVSCodeで開いた後、少し手抜きをするためにまず、Remote ContainersのReopen in Container
を選びます。
コンテナ定義が無い状態でReopen in Container
を選択すると、「Add Development Container Configuration File」とコンテナ定義の追加メニューが表示されますので、
「Show All Definitions...」を選びテキストの入力エリアに「python」と入力して「Python3」を選び、使いたいバージョンを選択していくだけで簡単にPythonの開発環境が用意できます。
細かい利用方法や設定についてはVSCodeのドキュメント「Developing inside a Container using Visual Studio Code Remote Development」もあわせてご確認下さい。VSCodeのドキュメントでは「Open Folder in Container」ではじめていますが、コンテナで開くフォルダの選択の有無ぐらいの違いです。
これだけではPythonは使えますが、まだDynamoDB Localが使えないのでDynamoDB Localの設定をしていきます。
先ほどのReopen in Container
によって.devcontainer
というフォルダーが作成されるはずなので、.devcontainer
フォルダーの中にdocker-compose.yml
というファイルを作成して以下の内容を入力します。
Pythonのコードを書く用のコンテナのapp
サービスと、dynamodb-localを動かすコンテナdynamodb-local
サービスを定義しています。
app
サービスのargs
キーは同じく.devcontainer
フォルダーにあるdevcontainer.json
のbuild.args
プロパティと同じ内容を入力します。また、AWS_ACCESS_KEY_ID
とAWS_SECRET_ACCESS_KEY
は任意の値で問題ないので、変更は不要です。
version: "3" services: app: container_name: petstore build: context: . dockerfile: Dockerfile args: - VARIANT=3.9 - INSTALL_NODE="false" - NODE_VERSION="lts/*" working_dir: /workspaces/petstore volumes: - ..:/workspaces/petstore:cached ports: - 8080:8000 environment: AWS_ACCESS_KEY_ID: "DUMMYIDEXAMPLE" AWS_SECRET_ACCESS_KEY: "DUMMYEXAMPLEKEY" AWS_DEFAULT_REGION: "ap-northeast-1" tty: true dynamodb-local: command: "-jar DynamoDBLocal.jar -sharedDb -optimizeDbBeforeStartup -dbPath ./data" image: "amazon/dynamodb-local:latest" container_name: dynamodb-local ports: - "8000:8000" volumes: - "./docker/dynamodb:/home/dynamodblocal/data" working_dir: /home/dynamodblocal
次に、devcontainer.json
を以下の様に書き換えます。VSCodeにインストールしている拡張機能や、「Add Development Container Configuration File」で選んだオプション等によって内容は変わってきます。
ポイントはbuild
プロパティは削除してdockerComposeFile
プロパティでdocker-compose.yml
指定するのと、service
プロパティを使ってdocer-compose.yml
で定義したサービス名を指定することで、VSCodeで接続するコンテナを指定します。
{ "name": "Python 3", "dockerComposeFile": "docker-compose.yml", "service": "app", "workspaceFolder": "/workspaces/petstore", // Set *default* container specific settings.json values on container create. "settings": { "python.pythonPath": "/usr/local/bin/python", "python.linting.enabled": true, "python.linting.pylintEnabled": true, "python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8", "python.formatting.blackPath": "/usr/local/py-utils/bin/black", "python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf", "python.linting.banditPath": "/usr/local/py-utils/bin/bandit", "python.linting.flake8Path": "/usr/local/py-utils/bin/flake8", "python.linting.mypyPath": "/usr/local/py-utils/bin/mypy", "python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle", "python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle", "python.linting.pylintPath": "/usr/local/py-utils/bin/pylint" }, // Add the IDs of extensions you want installed when the container is created. "extensions": [ "ms-python.python" ], // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], // Use 'postCreateCommand' to run commands after the container is created. // "postCreateCommand": "pip3 install --user -r requirements.txt", // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. //"remoteUser": "vscode" }
入力が終わったら、Remote ContainersのRebuild Container
を選べば、コンテナが再ビルドされ、PythonのコンテナとDynamoDB Localのコンテナが立ち上がります。
これで、DynamoDB Localを使った開発環境が構築できました。
DynamoDB Localにテーブルを作ってみる
今回はPynamoDBというPythonのライブラリを利用します。PynamoDBについては改めて紹介できればと思いますが、DynamoDBをO/Rマッパー風に操作できるライブラリーです。
最初に、pipを使ってPynamoDBのパッケージを導入していきます。
pip3 install pynamodb pynamodb-attributes
つづいてDynamoDBに作るテーブルのモデルを作成します。作業フォルダーにdynamodb.py
というファイルを作成して以下の内容を入力します。
from unicodedata import category, name from enum import Enum from pynamodb.models import Model from pynamodb.attributes import UnicodeAttribute, ListAttribute, MapAttribute from pynamodb_attributes import UnicodeEnumAttribute, IntegerAttribute class Status(str, Enum): available = "available" pending = "pending" sold = "sold" class _Category(MapAttribute): id = IntegerAttribute() name = UnicodeAttribute() class _Tag(MapAttribute): id = IntegerAttribute(hash_key=True) name = UnicodeAttribute() class _Pet(Model): class Meta: table_name = "pet_table" id = IntegerAttribute(hash_key=True, null=True) category = _Category(null=True) name = UnicodeAttribute() photoUrls = ListAttribute(of=UnicodeAttribute) tags = ListAttribute(of=_Tag, null=True) status = UnicodeEnumAttribute(Status, null=True) class PetRepo: def __init__(self) -> None: self.model = _Pet
その後、先ほど作ったモデルを呼び出して、テーブルを作成するコードを作成します。作業フォルダにcreate.py
というファイルを作って以下の内容を入力します。
from dynamodb import PetRepo DDB_LOCAL_HOST = "http://dynamodb-local:8000" if __name__ == "__main__": repo: PetRepo = PetRepo() model_meta_class = getattr(repo.model, "Meta") setattr(model_meta_class, "host", DDB_LOCAL_HOST) setattr(model_meta_class, "billing_mode", "PAY_PER_REQUEST") repo.model.create_table(wait=True)
DDB_LOCAL_HOST = "http://dynamodb-local:8000"
がDynamoDB Localに接続するための設定で、docker-compose.yml
で定義したDynamoDB Localのサービス名とポートを指定します。
最後に、create.py
を実行すればDynamoDB Local上に、テーブルが作成されます。
なお、このコードはJX通信社エンジニアブログさんの記事で紹介されていた、手法を参考にしてみました。
テーブルの確認
さて、本当にテーブルができたのかを確認していきましょう。 今回はコンテナの中では無く、ホスト側(私の場合はMacになります)から確認してみようと思います。
私の場合はMacにAWS CLIが導入されてるのでそれを使います。最初にテスト用のprofileを作ります。
以下のコマンドで、local
というプロファイルを作成します。Access Key ID
やSecret Access Key
は何でも大丈夫です。Default region name
はap-northeast-1
にします。これは、アプリケーションのコンテナを作ったときにap-northeast-1
をデフォルトのリージョンに指定しているので、DynamoDBのテーブルがap-northeast-1
に作成されているためです。
$ aws configure --profile local AWS Access Key ID [None]: dummy AWS Secret Access Key [None]: dummy Default region name [None]: ap-northeast-1 Default output format [None]: json
profileの作成が完了しましたら、以下の様にdynamodb list-tables
を使うことで、テーブルの一覧が取得できます。--endpoint-url
でlocalhostを指定する事でDynamoDB Localへ接続しています。
$ aws --profile local dynamodb list-tables --endpoint-url http://localhost:8000 { "TableNames": [ "pet_table" ] }
まとめ
駆け足になってしまいましたが、DynamoDB Localを利用した開発環境の雰囲気は伝わりましたでしょうか。
ローカルでDynamoDBを実行できるということは、AWSを使わずにテストができるようになるなど利点がありますので、 これからは積極的に使っていきたいと思います。