2
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Organization

Docker + DynamoDB local + C++ の環境構築と実践まで

環境構築

今回使うものはこちら

  • Docker
  • Dynamodb local
  • AWS CLI バージョン 2
  • vcpkg
  • AWS SDK for C++

また、C++ のビルド環境には VC++ を使用します。

Docker の導入

Docker は、コンテナを用いてアプリケーションをすばやく構築、テスト、デプロイできるソフトウェアプラットフォームです。

ダウンロード

Docker のサイトからインストーラをダウンロードしましょう。
※この記事では、Docker Desktop for Windows を使用します。

インストール

Docker Desktop requires Windows 10 Pro/Enterprise (16299+) or Windows 10 Home (18362.1040+).
インストール中に、上のようなエラーメッセージが出る場合は、Windows Update を確認してみてください。アップデート後に、もう一度インストールを試してみましょう。

WSL 2 installation is imcomplete.

上のダイアログメッセージが出る場合は、Linux カーネル更新プログラムのインストールが必要です。以下からパッケージをダウンロードしましょう。

バージョン確認

コマンドラインからDocker のバージョンを確認してみましょう。インストールに成功していれば、以下のような出力が得られるはずです。

> docker --version
Docker version 20.10.0, build 7287ab3

DynamoDB local の導入

ダウンロード可能なバージョンの Amazon DynamoDB (DynamoDB local)では、DynamoDB ウェブサービスにアクセスせずに、アプリケーションを開発してテストすることができます。代わりに、データベースはコンピュータ上で自己完結型となります。

イメージを取得する

Docker を使って、DynamoDB local イメージを取得しましょう。

Amazon が公開している DynamoDB local のDocker イメージがありますので、
docker pull コマンドを使って取得します。

> docker pull amazon/dynamodb-local

コンテナを起動する

Docker を使って、DynamoDB local を起動しましょう。
docker run コマンドを使って起動します。

> docker run -p 8000:8000 amazon/dynamodb-local

これで DynamoDB local のコンテナが起動しました。わかりやすくポート番号は8000を使用しました。

コンテナを確認する

docker ps コマンドを使うと、現在起動しているコンテナのリストが出力されます。

> docker ps
CONTAINER ID   IMAGE                   COMMAND                  CREATED         STATUS         PORTS                    NAMES
607c8a202aac   amazon/dynamodb-local   "java -jar DynamoDBL…"   2 seconds ago   Up 7 seconds   0.0.0.0:8000->8000/tcp   frosty_goldstine

コンテナを終了する

docker kill コマンドを使うと、起動しているコンテナを終了させることができます。このとき、コンテナIDを指定します。

> docker kill 607c8a202aac

AWS CLI バージョン 2 の導入

AWS CLI には、DynamoDB local を操作するためのコマンドラインツールが含まれています。
※今回はテーブル情報の読み出しのためだけに利用したいと思います。(C++ からのリクエストが正しく通っているかを確認するため。)

事前にインストールしておきましょう。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2-windows.html

初回設定

1度だけこちらの4項目を設定しておきましょう。

それぞれ、設定内容はダミーでもよいですが、忘れないように覚えておく必要があります。もし忘れてしまったら設定しなおしましょう。

> aws configure
AWS Access Key ID [****************XXXX]: (ローカルで使用するのでダミーのキーIDでよい)
AWS Secret Access Key [****************XXXX]: (ローカルで使用するのでダミーのアクセスキーでよい)
Default region name [us-west-2]:(ローカルで使用するのでダミーのリージョンでよい)
Default output format [json]:

動作確認(DynamoDB local のテーブルリストを取得する)

DynamoDB local にアクセスして、動作確認をしてみましょう。
まだテーブルを作っていないので、以下のような JSON が取得できるはずです。

> aws dynamodb list-tables --endpoint-url http://localhost:8000
{
    "TableNames": []
}

AWS SDK for C++ の導入

今回は、C++ からDynamoDB local にアクセスするので、AWS SDK for C++ というライブラリを使用します。

vcpkg をインストールする

vcpkg は、C++ のコマンド ライン パッケージ マネージャーです。 これにより、Windows、Linux、および macOS でのサードパーティ ライブラリの取得とインストール作業を大幅に簡素化できます。

github から取得し、ブートストラップを実行しましょう。

> git clone https://github.com/microsoft/vcpkg
> ./vcpkg/bootstrap-vcpkg.bat

AWS SDK for C++ を取得する

vcpkg を使って、ライブラリを取得しましょう。

> ./vcpkg/vcpkg install aws-sdk-cpp:x64-windows

VC++ にインテグレートする

vcpkg を VC++ にインテグレートします。
これによって、先ほどダウンロードしたAWS SDK for C++ のためのインクルードパスの設定や、.lib のリンクを自動で行ってくれるようになります。

> ./vcpkg/vcpkg integrate install

※ただし、コーディング中のインテリセンスを働かせるためには、手動でインクルードパスを通す必要がありました。

また、インテグレートを解除したい場合は、以下のコマンドを使います。

> ./vcpkg/vcpkg integrate remove

コーディング

主要なデータベース操作と、対応する AWS SDK for C++ の関数名を挙げておきます。
AWS のサイトにもサンプルコードがあるので、参考にしてみてください。

用途 関数名
テーブル追加 Aws::DynamoDB::DynamoDBClient::CreateTable
テーブル削除 Aws::DynamoDB::DynamoDBClient::DeleteTable
アイテム取得 Aws::DynamoDB::DynamoDBClient::GetItem
アイテム追加 Aws::DynamoDB::DynamoDBClient::PutItem
アイテム更新 Aws::DynamoDB::DynamoDBClient::UpdateItem
アイテム削除 Aws::DynamoDB::DynamoDBClient::DeleteItem

C++ Code Samples for Amazon DynamoDB
https://docs.aws.amazon.com/code-samples/latest/catalog/code-catalog-cpp-example_code-dynamodb.html

テーブル作成(create-table)

#include <aws/core/Aws.h>
#include <aws/core/utils/Outcome.h> 
#include <aws/dynamodb/DynamoDBClient.h>
#include <aws/dynamodb/model/AttributeDefinition.h>
#include <aws/dynamodb/model/CreateTableRequest.h>
#include <aws/dynamodb/model/KeySchemaElement.h>
#include <aws/dynamodb/model/ProvisionedThroughput.h>
#include <aws/dynamodb/model/ScalarAttributeType.h>
#include <iostream>

// ここで、予め設定しておいたアクセスキーを使います
const Aws::String AWS_ACCESS_KEY_ID     = "XXXXXXXXXXXXXXXXXXXX";
const Aws::String AWS_SECRET_ACCESS_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

Aws::SDKOptions options;
Aws::InitAPI(options);

// 作成したいテーブルの名前を決める
const Aws::String table("Game");
// ここで、予め設定しておいたリージョン名を使います
const Aws::String region("us-west-2");

// エンドポイントを指定する
Aws::Client::ClientConfiguration clientConfig;
clientConfig.requestTimeoutMs = 1000;
clientConfig.region = region;
clientConfig.endpointOverride = "http://localhost:8000";

const Aws::DynamoDB::DynamoDBClient dynamoClient(Aws::Auth::AWSCredentials(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY), clientConfig);

// テーブル作成リクエスト
Aws::DynamoDB::Model::CreateTableRequest req;

Aws::DynamoDB::Model::AttributeDefinition haskKey;
// "Name"という名前の属性を定義する、"Name"は文字列型である
haskKey.SetAttributeName("Name");
haskKey.SetAttributeType(Aws::DynamoDB::Model::ScalarAttributeType::S);
req.AddAttributeDefinitions(haskKey);

// "Name" をハッシュキー(パーティションキー)として扱うようにスキーマを定義する
Aws::DynamoDB::Model::KeySchemaElement keyscelt;
keyscelt.WithAttributeName("Name").WithKeyType(Aws::DynamoDB::Model::KeyType::HASH);
req.AddKeySchema(keyscelt);

// 適当なキャパシティユニットを設定する
Aws::DynamoDB::Model::ProvisionedThroughput thruput;
thruput.WithReadCapacityUnits(5).WithWriteCapacityUnits(5);
req.SetProvisionedThroughput(thruput);

// テーブル名を指定する
req.SetTableName(table);

// テーブル作成リクエストをDynamoDB local に送信する(この関数はブロックするので注意!)
const Aws::DynamoDB::Model::CreateTableOutcome& result = dynamoClient.CreateTable(req);
if (result.IsSuccess())
{
    std::cout << "Table \"" << result.GetResult().GetTableDescription().GetTableName() <<
        " created!" << std::endl;
}
else
{
    std::cout << "Failed to create table: " << result.GetError().GetMessage();
}

Aws::ShutdownAPI(options);

AWS CLI を使って、テーブルが作成できているかの確認をしてみましょう。
うまく作成できていれば、以下のような JSON が取得できるはずです。

> aws dynamodb list-tables --endpoint-url http://localhost:8000
{
    "TableNames": [
        "Game"
    ]
}

アイテム追加(put-item)

#include <aws/core/Aws.h>
#include <aws/core/utils/Outcome.h> 
#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/dynamodb/DynamoDBClient.h>
#include <aws/dynamodb/model/AttributeDefinition.h>
//#include <aws/dynamodb/model/CreateTableRequest.h>
#include <aws/dynamodb/model/PutItemRequest.h>
#include <aws/dynamodb/model/PutItemResult.h>
#include <iostream>

//(途中省略...)

Aws::DynamoDB::Model::PutItemRequest req;
// 対象のテーブル名を指定する
req.SetTableName(table);

Aws::DynamoDB::Model::AttributeValue av;

// "Name" が 文字列型"Switch"
av.SetS("Switch");
req.AddItem("Name", av);

// "State" が 文字列型"off"
av.SetS("off");
req.AddItem("State",av);

// アイテム追加リクエストをDynamoDB local に送信する(この関数はブロックするので注意!)
const Aws::DynamoDB::Model::PutItemOutcome result = dynamoClient.PutItem(req);
if (!result.IsSuccess())
{
    std::cout << result.GetError().GetMessage() << std::endl;
    return 1;
}
std::cout << "Done!" << std::endl;

//(途中省略...)

AWS CLI を使って、テーブルの内容を出力してみましょう。
aws dynamodb scan コマンドにテーブル名を渡すと、以下のようにテーブルの内容を JSON で取得できます。

> aws dynamodb scan --table-name Game --endpoint-url http://localhost:8000
{
    "Items": [
        {
            "State": {
                "S": "off"
            },
            "Name": {
                "S": "Switch"
            }
        }
    ],
    "Count": 1,
    "ScannedCount": 1,
    "ConsumedCapacity": null
}

おわりに

非常に長い道のりでしたが、DynamoDB local を C++ から操作することができました。AWS SDK for C++ は扱いやすく、DynamoDB を操作するための一通りのAPI が揃っています。これを導入すれば、C++ プログラマにとっては DynamoDB の敷居が一気に下がるのではないでしょうか。

DynamoDB local は 簡単にレコードを追加したり、削除したりできるので、プロトタイピングにもおススメですね。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
2
Help us understand the problem. What are the problem?