Help us understand the problem. What is going on with this article?

S3互換のオブジェクトストレージ MinioにAWS SDK for C++でアクセスするのにハマるポイント

More than 1 year has passed since last update.

AWS SDK for C++を利用した開発でMinioを利用する際にハマったのでメモ。

AWS SDK for C++とMinioについては下記をご参考ください。

C++初心者がMacでAWS SDK for C++を利用してAmazon DynamoDBにアクセスする - Qiita
https://qiita.com/kai_kou/items/fe9e3525d2023dc955a5

C++初心者がDockerで開発環境をつくってみた - Qiita
https://qiita.com/kai_kou/items/1f4b9a45a5d4d6788649

S3互換のオブジェクトストレージ MinioをDocker Composeで利用する - Qiita
https://qiita.com/kai_kou/items/9fe06d4d24928d9efa2a

実装

AWS SDK for C++のバージョンは1.6.0となります。(2019/02/18時点)

aws/aws-sdk-cpp: AWS SDK for C++
https://github.com/aws/aws-sdk-cpp

下記のサンプルのエンドポイントをMinioに変更して動作するようにします。
C++ Code Samples for Amazon S3 - AWS Code Sample
https://docs.aws.amazon.com/ja_jp/code-samples/latest/catalog/code-catalog-cpp-example_code-s3.html

put_object.cpp - AWS Code Sample
https://docs.aws.amazon.com/ja_jp/code-samples/latest/catalog/cpp-s3-put_object.cpp.html

put_object.cpp
/*
   Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.

   This file is licensed under the Apache License, Version 2.0 (the "License").
   You may not use this file except in compliance with the License. A copy of
   the License is located at

    http://aws.amazon.com/apache2.0/

   This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied. See the License for the
   specific language governing permissions and limitations under the License.
*/
#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/s3/model/PutObjectRequest.h>
#include <iostream>
#include <fstream>

/**
 * Put an object from an Amazon S3 bucket.
 */
int main(int argc, char** argv)
{
    if (argc < 4)
    {
        std::cout << std::endl <<
            "To run this example, supply the name of an S3 bucket, destination key, and file to upload."
            << std::endl << std::endl <<
            "Ex: put_object <bucketname> <keyname> <filename> <optional:region>" << std::endl;
        exit(1);
    }

    Aws::SDKOptions options;
    Aws::InitAPI(options);
    {
        const Aws::String bucket_name = argv[1];
        const Aws::String key_name = argv[2];
        const Aws::String file_name = argv[3];
        const Aws::String region(argc > 4 ? argv[4] : "");

        std::cout << "Uploading " << file_name << " to S3 bucket " <<
            bucket_name << " at key " << key_name << std::endl;

        Aws::Client::ClientConfiguration clientConfig;
        if (!region.empty())
            clientConfig.region = region;
        Aws::S3::S3Client s3_client(clientConfig);

        Aws::S3::Model::PutObjectRequest object_request;
        object_request.WithBucket(bucket_name).WithKey(key_name);

        // Binary files must also have the std::ios_base::bin flag or'ed in
        auto input_data = Aws::MakeShared<Aws::FStream>("PutObjectInputStream",
            file_name.c_str(), std::ios_base::in | std::ios_base::binary);

        object_request.SetBody(input_data);

        auto put_object_outcome = s3_client.PutObject(object_request);

        if (put_object_outcome.IsSuccess())
        {
            std::cout << "Done!" << std::endl;
        }
        else
        {
            std::cout << "PutObject error: " <<
                put_object_outcome.GetError().GetExceptionName() << " " <<
                put_object_outcome.GetError().GetMessage() << std::endl;
        }
    }
    Aws::ShutdownAPI(options);
}

上記サンプルで、Minioへアクセスするようにエンドポイントを指定してやればよいわけですが、いろいろとハマったのでポイントです。

エンドポイントの指定はendpointOverrideschemeを利用する

Aws::Client::ClientConfiguration にあるendpointOverride でエンドポイントが指定できます。HTTPアクセスの場合、scheme の指定も必要です。

AWS SDK for C++: Aws::Client::ClientConfiguration Struct Reference
https://sdk.amazonaws.com/cpp/api/LATEST/struct_aws_1_1_client_1_1_client_configuration.html

put_object.cpp_一部抜粋
    Aws::Client::ClientConfiguration clientConfig;
    if (!region.empty())
      clientConfig.region = region;
    clientConfig.scheme = Aws::Http::Scheme::HTTP;
    clientConfig.endpointOverride = endpoint;

公式のドキュメントをみるとauthenticationRegion の指定も必要とありますが、最新バージョン1.6.0 (2019/02/18時点)では定義されていませんので気をつけましょう。

古いドキュメント
AWS Client Configuration - AWS SDK for C++
https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/client-config.html

古いドキュメント
AWS SDK for C++: Aws::Client::ClientConfiguration Struct Reference
https://sdk.amazonaws.com/cpp/api/0.12.9/df/d19/struct_aws_1_1_client_1_1_client_configuration.html

S3Client 作成時にuseVirtualAdressing を無効にする

Minioのエンドポイントがlocalhost:9000 となり、useVirtualAdressing が有効の場合、アクセスすることができません。
useVirtualAdressing を指定するコンストラクタではCredentials などを渡す必要があるため、Aws::Auth::EnvironmentAWSCredentialsProvider().GetAWSCredentials()を利用します。アクセスキーとシークレットをパラメータにCredentials を作成してもOKです。

AWS SDK for C++: Aws::S3::S3Client Class Reference
https://sdk.amazonaws.com/cpp/api/LATEST/class_aws_1_1_s3_1_1_s3_client.html#ac8168b12d0e630dcdc5cd912d38d8787

VirtualAdressing (仮想ホスト形式)については下記が参考になります。

S3のバケットURL(仮想ホスト形式とパス形式) - Qiita
https://qiita.com/ryo0301/items/48120379b240ab071028

AWS CLIのS3接続先の選択動作とaddressing_styleオプション - おぎろぐはてブロ
https://iogi.hatenablog.com/entry/s3-addressing-style

put_object.cpp_一部抜粋
#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/core/auth/AWSAuthSigner.h>

()

    // 環境変数などから認証情報を取得する
    Aws::Auth::AWSCredentials cred = Aws::Auth::EnvironmentAWSCredentialsProvider().GetAWSCredentials();
    // useVirtualAdressingをfalseにする
    Aws::S3::S3Client s3_client(cred, clientConfig, Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, false);

こちらも過去バージョンだとS3Clientコストラクタのパラメータが一部異なるので注意しましょう。

古いドキュメント
AWS SDK for C++: Aws::S3::S3Client Class Reference
https://sdk.amazonaws.com/cpp/api/0.12.9/d7/db7/class_aws_1_1_s3_1_1_s3_client.html

まとめ

AWS SDK for C++のバージョンによって仕様が異なり、ネットで検索して得られる情報では解決できない可能性がありますので、最終的には実装や最新のドキュメントを確認するようにしましょう。

参考

C++初心者がMacでAWS SDK for C++を利用してAmazon DynamoDBにアクセスする - Qiita
https://qiita.com/kai_kou/items/fe9e3525d2023dc955a5

C++初心者がDockerで開発環境をつくってみた - Qiita
https://qiita.com/kai_kou/items/1f4b9a45a5d4d6788649

aws/aws-sdk-cpp: AWS SDK for C++
https://github.com/aws/aws-sdk-cpp

C++ Code Samples for Amazon S3 - AWS Code Sample
https://docs.aws.amazon.com/ja_jp/code-samples/latest/catalog/code-catalog-cpp-example_code-s3.html

put_object.cpp - AWS Code Sample
https://docs.aws.amazon.com/ja_jp/code-samples/latest/catalog/cpp-s3-put_object.cpp.html

AWS SDK for C++: Aws::Client::ClientConfiguration Struct Reference
https://sdk.amazonaws.com/cpp/api/LATEST/struct_aws_1_1_client_1_1_client_configuration.html

AWS SDK for C++: Aws::S3::S3Client Class Reference
https://sdk.amazonaws.com/cpp/api/LATEST/class_aws_1_1_s3_1_1_s3_client.html#ac8168b12d0e630dcdc5cd912d38d8787

S3のバケットURL(仮想ホスト形式とパス形式) - Qiita
https://qiita.com/ryo0301/items/48120379b240ab071028

AWS CLIのS3接続先の選択動作とaddressing_styleオプション - おぎろぐはてブロ
https://iogi.hatenablog.com/entry/s3-addressing-style

S3互換のオブジェクトストレージ MinioをDocker Composeで利用する - Qiita
https://qiita.com/kai_kou/items/9fe06d4d24928d9efa2a

kai_kou
2004年からWeb系のシステムエンジニアとして開発、運用、マネジメントを経験。現在はアイレット(クラウドパック)に所属。 べ、別にいいね貰えたからってモチベーションが上がって記事とコードの品質があがるわけじゃないんだからね///
https://twitter.com/k_aik_ou
cloudpack
Amazon Web Services (AWS) の導入設計、環境構築、運用・保守をサポートするマネジドホスティングサービス
https://cloudpack.jp/
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