AWS SDK for .NET에서 로컬 fake 서비스를 위해 S3의 동작 확인

fake-s3 또는 LocalStack 을 사용하여 로컬로 S3 동작 확인을 수행할 수 있지만 AWS SDK for .NET을 사용하는 경우 조금 번거로운 부분이 있으므로 기록해 둡니다.

설정 관련 자료


  • AWS 자격 증명 설정 - AWS SDK for .NET
  • AWS 리전 선택 - AWS SDK for .NET
  • 기타 애플리케이션 파라미터 설정 - AWS SDK for .NET
  • AWS SDK for .NET - 개발자 가이드

  • Access Key Management for .NET Applications – Part 1
  • 조금 오래되었습니다.


  • LocalStack의 S3에 연결하는 데 필요한 정보



    LocalStack을 docker-compose에서 다음과 같이 설정하고 시작한다고 가정합니다.
    version: '3'
    
    services:
      localstack-s3:
        image: atlassianlabs/localstack:latest
        environment:
          - SERVICES=s3:5000
          - DEFAULT_REGION=us-east-1
          - HOSTNAME=localstack-s3
        ports:
          - "5000:5000"
    

    Credential은 무엇이든 좋기 때문에 aws cli라면 다음과 같이 연결할 수 있습니다.
    $ aws --endpoint-url=http://localhost:5000 --region=us-east-1 s3 ls --profile my-profile
    

    물론 profile 보다는 accesskey, secret 를 지정해도 됩니다.

    따라서 다음을 설정할 수 있으면 C# 코드에서도 연결할 수 있을 것 같습니다.
  • region
  • endpoint
  • accesskey/secret

  • 또한 주의해야 할 것은 HTTP라는 점입니다.

    C# 코드로 설정을 작성하는 경우


    var config = new AmazonS3Config {ServiceURL = "http://localhost:5000", AuthenticationRegion = "us-east-1"};
    
    // accesskey/secret は foo/foo と適当に指定
    var client = new AmazonS3Client("foo", "foo", config);
    

    이것만으로 연결할 수 있습니다.

    config에서 설정을 작성하는 경우



    App.config
    <?xml version="1.0"?>
    <configuration>
        <configSections>
            <section name="aws" type="Amazon.AWSSection, AWSSDK.Core"/>
        </configSections>
        <aws region="us-east-1" endpointDefinition="endpoints.json">
        </aws>
        <appSettings>
            <add key="AWSAccessKey" value="foo"/>
            <add key="AWSSecretKey" value="foo"/>
        </appSettings>
    </configuration>
    

    endpointDefinition 에 관해서는 상기(일본어판이 낡으면 곤란하므로 일단 영어판을 참조)에 기재가 있습니다.
    단지 거기에서 링크 된 endpoints.json Github의 링크 대상 샘플에서는 작동하지 않습니다

    endpoints.json 버전 낮추기



    다음은 RegionEndpointProvider 라는 바로 endpoints.json 의 내용을 읽어들이기 위한 클래스입니다만, 이것에는 내부적으로 V2, V3 와 버젼이 나뉘어져 있습니다.
      // If the existing customer provided the endpoints.json file via
      // <aws endpointDefinition=""/>, it's in v2 format.  We we will create
      // a v2 provider which does a fall through during LoadEndpointDefinitions()
      // and loads from the override file provided by the user.
      //
      // Else, we are loading from the assembly resource.  In which case we use the 
      // latest provider.
      //
      // It's actually a bug that _regionEndpointProvider is a static member variable
      // since the IEndpointProvider should respect the AWSConfigs.EndpointDefinition
      // _at_ the time of the service client instantiation.  However, since this is
      // the existing behavior with v2 endpoint file format, we will preserve this behavior as is.
      if (!string.IsNullOrEmpty(AWSConfigs.EndpointDefinition))
      {
          _regionEndpointProvider = new RegionEndpointProviderV2();
      }
      else
      {
          _regionEndpointProvider = new RegionEndpointProviderV3();
      }
    

    코멘트와 코드에서 알 수 있듯이 사용자가 설정하는 endpoints.jsonV2 로 로드됩니다. 한편, 링크처의 endpoints.jsonV3 용의 것이 되어 있습니다.


    endpoints.json
      } ],
      "version" : 3
    }
    

    따라서 과거 커밋을 따라 V2에 대한 endpoints.json를 찾습니다.

    위를 사용하여 이번에는 us-east-1/s3 만 다시 씁니다.
    {
      "version": 2,
      "endpoints": {
        "*/*": {
          "endpoint": "{service}.{region}.amazonaws.com"
        },
        "cn-north-1/*": {
          "endpoint": "{service}.{region}.amazonaws.com.cn",
          "signatureVersion": "v4"
        },
        "us-gov-west-1/iam": {
          "endpoint": "iam.us-gov.amazonaws.com"
        },
        "us-gov-west-1/s3": {
          "endpoint": "s3-{region}.amazonaws.com"
        },
        "*/cloudfront": {
          "endpoint": "cloudfront.amazonaws.com"
        },
        "*/iam": {
          "endpoint": "iam.amazonaws.com"
        },
        "*/importexport": {
          "endpoint": "importexport.amazonaws.com"
        },
        "*/route53": {
          "endpoint": "route53.amazonaws.com"
        },
        "*/waf": {
          "endpoint": "waf.amazonaws.com"
        },
        "us-east-1/sdb": {
          "endpoint": "sdb.amazonaws.com"
        },
        "us-east-1/s3": {
    -     "endpoint": "s3.amazonaws.com"
    +     "endpoint": "localhost:5000"
        },
        "us-west-1/s3": {
          "endpoint": "s3-{region}.amazonaws.com"
        },
        "us-west-2/s3": {
          "endpoint": "s3-{region}.amazonaws.com"
        },
        "eu-west-1/s3": {
          "endpoint": "s3-{region}.amazonaws.com"
        },
        "ap-southeast-1/s3": {
          "endpoint": "s3-{region}.amazonaws.com"
        },
        "ap-southeast-2/s3": {
          "endpoint": "s3-{region}.amazonaws.com"
        },
        "ap-northeast-1/s3": {
          "endpoint": "s3-{region}.amazonaws.com"
        },
        "sa-east-1/s3": {
          "endpoint": "s3-{region}.amazonaws.com"
        }
      }
    }
    

    나중에 이것을 실행 디렉토리에 복사해야합니다.

    다만, 이것으로는 HTTPS 로의 접속이 되어 버리므로, 코드는 이하와 같이 할 필요가 있습니다.
    var client = new AmazonS3Client(new AmazonS3Config {UseHttp = true});
    
    // or 設定の有り無しで切り替えるなら以下のような感じ
    if (!string.IsNullOrEmpty(AWSConfigs.EndpointDefinition))
      new AmazonS3Client(new AmazonS3Config {UseHttp = true});
    else
      new AmazonS3Client(); // おそらく production は EC2 のインスタンスメタデータ等から接続するはず
    

    NUnit 등의 테스트 러너를 사용하는 경우



    위는 콘솔 어플리케이션 등의 실행 파일과 endpoints.json가 같은 장소에 존재하는 경우를 상정하고 있었습니다만, 테스트 러너가 다른 장소에 있는 경우가 있을 수 있습니다. (라고 할까, fake 를 사용하는 것은 그쪽이 많다고 생각합니다)

    다음과 같이 SetUp 단계에서 필요에 따라 테스트 실행 디렉토리로 경로를 바꾸면 잘 작동합니다. (xUnit의 경우는 조사하지 않고)
    public void OneTimeSetUp()
    {
      if (!string.IsNullOrEmpty(AWSConfigs.EndpointDefinition))
      {
        if (AWSConfigs.EndpointDefinition.Equals(new FileInfo(AWSConfigs.EndpointDefinition).Name))
        {
          AWSConfigs.EndpointDefinition =
            Path.Combine(TestContext.CurrentContext.TestDirectory, AWSConfigs.EndpointDefinition);
        }
      }
    }
    

    요약



    이번에는 S3를 소재로 했습니다만, LocalStack 등을 사용하면 DynamoDB나 다른 AWS Sevice의 Fake도 로컬로 실행할 수 있어 동작 확인이나 자동 테스트 환경에 편리하게 사용할 수 있습니다.

    이번 코드는 아래에 있습니다.
    htps : // 기주 b. 이 m / 다 ny1468 / ぉ ぁ w

    좋은 웹페이지 즐겨찾기