NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

注目のタグ

    localstackを利用して、ローカル環境でJavaからDynamoDBとS3へアクセスしてみる

    はじめに

    はじめまして、入社1年目の川野です。
    主に、AWSを利用したアプリケーション開発や運用の業務をおこなってます。
    開発では、localstackを使ってローカルで検証しよう!とアドバイスをもらったものの、よく分からず・・・・
    先輩方に設定や環境構築など教えて頂きどうにか乗り越えることができましたが、疑問点も多かったので、 今回はlocalstackの設定やAWS SDK for javaの使用例をまとめていきます!

    localstackとは

    軽くlocalstackについて触れたいと思います。 localstackとは、AWS環境をローカルで再現できるプラットフォームです。
    ざっくり言うと、localstackにリクエストを送ると、AWSサービスと同様のレスポンスを返してくれるアプリケーションです。 一部有料のサービスや機能制限はありますが、多くのAWSサービスが無料でサポートされています。

    www.localstack.cloud

    環境準備

    さっそく、localstackの環境を準備をしていきましょう。 手順は下記2点です。

    • dockerコンテナ作成
    • AWS クレデンシャル設定

    dockerコンテナ作成

    まず、docker-composeを利用してlocalstackのイメージを取得し、dockerコンテナを作成・起動します。 docker-compose.ymlにコンテナの設定を書いていきます。

    version: '3.8'
    
    services:
      localstack:
        image: localstack/localstack:latest
        ports:
          - 4566:4566
        environment:
          - SERVICES=dynamodb,s3
          - PERSISTENCE=1
        volumes:
          - ./volume:/var/lib/localstack
    項目 内容
    version docker-composeのバージョン
    services dockerコンテナで起動するアプリケーション
    image コンテナの名前やタグ (コンテナ名:タグ)
    localstackの場合、タグでバージョンを指定
    ports 通信を行うポート番号 (localhostのポート番号 : コンテナのポート番号)
    environment アプリケーションの環境変数
    SERVICES 利用するAWSサービス (複数の場合はカンマ区切り)
    PERSISTENCE データ永続化フラグ
    volumes ローカルのデータとdockerコンテナのデータを同期させるためのパス


    docker-compose.ymlファイルを作成出来たら、保存したディレクトリへ移動し、

    docker conpose up 
    

    コマンドを実行することで、dockerコンテナを作成・起動できます。

    AWS クレデンシャル設定

    次に、AWSサービスにアクセスするためのクレデンシャルを用意していきます。
    ホームディレクトリに.awsディレクトリ、その配下にcredentialsファイルを作成しlocalstack用のクレデンシャルを追加します。値は「dummy」としていますが、半角英数字であれば大丈夫です。

    [localstack]
    aws_access_key_id = dummy
    aws_secret_access_key = dummy

    以上で、環境準備は完了です!

    AWS SDK for javaを利用して、AWSリソースへアクセスする

    今回はGradleプロジェクトを使用して、SDKをダウンロードしてきます。
    build.gradleのmaven依存関係に下記を追加します。ライブラリは2024年2月10日時点で最新バージョンです。

    dependencies {
        implementation 'software.amazon.awssdk:dynamodb:2.24.0'
        implementation 'software.amazon.awssdk:s3:2.24.0'
        implementation 'software.amazon.awssdk:regions:2.24.0'
    }

    SDKのバージョンは1.xと2.xがありますが、今回は 2.x を利用します。1.xを利用する場合と仕様が異なるので注意です。

    次に、Javaコード内でAWSサービスの設定を定義します。ここで、エンドポイントとクレデンシャルをlocalstack用にすることで、dockerコンテナ内のlocalstackと通信できるわけですね。

    Region REGION = Region.AP_NORTHEAST_1;
    String ENDPOINT_URL = "http://localhost:4566";
    ProfileCredentialsProvider provider = ProfileCredentialsProvider.create("localstack");
    

    クレデンシャルの設定方法はいくつかありますが、今回は、.aws/credentialsファイルで追記したlocalstackプロファイルを使って設定しています。

    DynamoDBへアクセスしてみる

    • DynamoDBクライアント設定

    各AWSサービスにアクセスするためには、それぞれに対してクライアントを定義する必要があります。 今回はlocalstack用の最低限の設定ですが、その他タイムアウトやリトライ回数など色々設定できます。

    DynamoDbClient ddbClient = DynamoDbClient.builder()
            .region(REGION)
            .credentialsProvider(provider)
            .endpointOverride(new URI(ENDPOINT_URL))
            .build();
    


    • テーブル作成

    DynamoDBテーブルを作成してみます。 CreateTableRequestインスタンスにテーブルの設定を定義する形です。 IaCで定義するYMLファイルと少し似ている気がします。

    String tableName = "sample-table";
    String tableKey = "name";
    Long readCapacity = 10L;
    Long writeCapacity = 10L;
    
    CreateTableRequest createTable = CreateTableRequest.builder()
            .tableName(tableName)
            .attributeDefinitions(AttributeDefinition.builder()
                    .attributeName(tableKey)
                    .attributeType(ScalarAttributeType.S)
                    .build())
            .keySchema(KeySchemaElement.builder()
                    .attributeName(tableKey)
                    .keyType(KeyType.HASH)
                    .build())
            .provisionedThroughput(ProvisionedThroughput.builder()
                    .readCapacityUnits(readCapacity)
                    .writeCapacityUnits(writeCapacity)
                    .build())
            .build();
    
    ddbClient.createTable(createTable);
    


    • データ挿入

    作成したテーブルにデータを挿入します。HashMap<String, AttributeValue>に項目名 (key) と値 (value) を追加していき、PutItemRequestインスタンスを生成します。

    String name = "sample name";
    String company = "sample company";
    
    HashMap<String, AttributeValue> item = new HashMap<>();
    item.put(tableKey, AttributeValue.fromS(name));
    item.put("company", AttributeValue.fromS(company));
    
    PutItemRequest putItem = PutItemRequest.builder()
            .tableName(tableName)
            .item(item)
            .build();
    
    ddbClient.putItem(putItem);
    


    • データ削除

    先ほど追加したデータを削除してみます。 削除対象のテーブルキーをHashMap<String, AttributeValue>に追加します。

    String deleteName = "sample name";
    HashMap<String, AttributeValue> deleteKey = new HashMap<>();
    deleteKey.put(tableKey, AttributeValue.fromS(deleteName));
    
    DeleteItemRequest deleteItem = DeleteItemRequest.builder()
            .tableName(tableName)
            .key(deleteKey)
            .build();
    
    ddbClient.deleteItem(deleteItem);
    

    S3へアクセスしてみる

    • S3クライアント設定

    S3用のクライアントを作っていきます。
    基本的にはDynamoDBのクライアントと同様に作成できますが、 現在、AWS S3 バケットのアドレスは仮想ホスト形式がデフォルトなのに対し、localstackはパス形式での指定なので、forcePathStyle(true)を設定する必要があります。

    S3Client s3Client = S3Client.builder()
            .region(REGION)
            .credentialsProvider(provider)
            .endpointOverride(new URI(ENDPOINT_URL))
            .forcePathStyle(true)
            .build();
    


    • バケット生成

    作成したクライアントを使って、S3 バケットを作っていきます。

    String bucketName = "bucket";
    
    CreateBucketRequest createBucket = CreateBucketRequest.builder()
            .bucket(bucketName)
            .build();
    
    s3Client.createBucket(createBucket);
    


    • オブジェクトのアップロード

    作成したバケットにファイルをアップロードします。 ファイルパスはアップロードしたいファイルのパスを指定してください。

    String objectKey = "sample";
    
    PutObjectRequest putObject = PutObjectRequest.builder()
            .bucket(bucketName)
            .key(objectKey)
            .build();
    
    File file = new File(アップロードするファイルのパス);
    
    s3Client.putObject(putObject, RequestBody.fromFile(file));
    


    • オブジェクト削除

    最後に、先ほど作成したオブジェクトを削除してみます。

    Stirng deleteObjectKey = "sample";
    
    DeleteObjectRequest deleteObject = DeleteObjectRequest.builder()
            .bucket(bucketName)
            .key(deleteObjectKey)
            .build();
    
    s3Client.deleteObject(deleteObject);
    

    おわりに

    今回は、localstackとAWS SDK for javaを使って、ローカルでDynamoDBとS3へのアクセスを再現してみました。
    まだまだ、localstackもAWS SDKにも使ってない機能がたくさんあるので、色々試してみたいです。ローカル環境なので気軽に試せる点もlocalstackの魅力かと思います。 興味のある方はぜひお試しを!

    執筆者:川野弘陽 駆け出しシステムエンジニア