Amazon Web Services 한국 블로그

.NET Core에서 AWS Lambda Layer 기능 활용하기

AWS Lambda Layer(계층)은 AWS Lambda 함수에 추가적인 코드 및 콘텐츠를 제공할 수 있게 해 줍니다. 계층은 Lambda 컴퓨팅 환경의 /opt 디렉토리로 추출되어 Lambda 함수에서 사용되는 추가 파일들로 구성됩니다.

Lambda 계층이 출시된 후 자주 듣는 질문 중 하나는 .NET Core Lambda 함수가 이 기능을 어떻게 활용할 수 있는가 하는 것입니다. .NET Core의 경우 계층을 활용하기 위해 극복해야 하는 몇 가지 과제가 있습니다. 먼저 .NET 런타임에 배포 번들 외부로부터 어셈블리를 로드할 것을 지시해야 합니다. 또 다른 큰 과제는 AWS의 모든 .NET Lambda 도구가 모든 .NET 어셈블리를 수집하는데 필요한 dotnet publish 명령을 실행할 때 publish 명령은 어느 어셈블리가 계층에 의해 제공되므로 포함되지 않아야 하는지 알아야 합니다.

다행스럽게도 .NET Core 도구에 있는 잘 알려지지 않은 일부 기능이 이 작업을 지원합니다. 그러나 이 기능의 사용방법이 조금 까다롭습니다. 이제 Amazon.Lambda.Tools .NET Core Global Tool의 버전 3.2.0에서는 계층을 생성하고 이를 Lambda 함수에 사용하는 절차를 간단하게 사용할 수 있습니다.계층을 사용할 때 가장 큰 이점은 함수를 배포할 때마다 Lambda에 업로드해야 하는 .zip 파일의 크기를 대폭 줄일 수 있다는 것입니다. 또한 아래의 패키지 최적화 섹션에 설명하겠지만 콜드 스타트 성능을 개선할 수 있는 기회가 됩니다.

런타임 패키지 스토어

Amazon.Lambda.Tools에서 계층을 생성하기 위해 사용하는 .NET Core 기술을 런타임 패키지 스토어라고 부릅니다(https://docs.microsoft.com/en-us/dotnet/core/deploying/runtime-store). 이 기술은 .NET Core 2.0의 일부로 소개되었습니다.

런타임 패키지 스토어를 생성하기 위해서 매니페스트 파일을 사용합니다. 프로젝트 파일(Lambda 프로젝트의 *.csproj 파일)도 매니페스트의 한 예입니다. 런타임 패키지 스토어를 생성하면, 매니페스트의 PackageReference 요소에 의해 식별된 모든 NuGet 패키지 및 해당 종속성이 Amazon.Lambda.Tools에서 Lambda 계층으로 변환시킬 디렉토리에 캡처됩니다.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
    <AWSProjectType>Lambda</AWSProjectType>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Amazon.Lambda.Core" Version="1.1.0" />
    <PackageReference Include="Amazon.Lambda.Serialization.Json" Version="1.4.0" />
  </ItemGroup>
</Project>

이는 Lambda 프로젝트의 모든 종속성에 대해 하나의 계층을 생성할 수 있음을 의미합니다. 그러므로 배포 시 해당 로컬 프로젝트를 위한 어셈블리만 업로드하면 됩니다. 또는 모든 공통 종속성을 포함한 .csproj 파일과 같은 형식으로 사용자 지정 매니페스트를 생성한 후 해당 매니페스트로부터 계층을 생성할 수도 있습니다. 그런 다음 모든 Lambda 프로젝트에서 해당 레이어를 참조하면 됩니다.

런타임 패키지가 Lambda 계층으로 변환되는 방식과 작동 방식에 대한 자세한 설명은 .NET Lambda 계층 설명서(https://github.com/aws/aws-extensions-for-dotnet-cli/blob/master/docs/Layers.md)를 참조하십시오.

Lambda Layer(계층) 생성

앞에서 언급되었듯이, 계층은 Lambda 프로젝트의 .csproj 파일로부터 생성할 수 있습니다. 계층을 생성하려면 프로젝트 디렉토리에서 다음 명령을 실행합니다.

dotnet lambda publish-layer LayerBlogDemoLayer --layer-type runtime-package-store --s3-bucket <s3-bucket>

이 명령은 LayerBlogDemoLayer라는 이름의 계층을 생성합니다. 유형은 runtime-package-store가 됩니다. 현재로는 runtime-package-store가 유일한 유효한 값이지만 향후 새 유형의 계층의 생성을 지원하기 위해 필수 필드로 지정되어 있습니다. 지정된 Amazon S3 버킷은 로컬에서 생성된 런타임 패키지 스토어를 업로드하는데 사용되며, Lambda는 이후 이 버킷을 이용해서 계층을 생성하게 됩니다.

publish-layer 명령의 출력은 다음과 같습니다.

...
... Progress: 100%
Upload complete to s3://normj-west2/LayerBlogDemoLayer-636888783824636933/artifact.xml
Create zip file of runtime package store directory
... zipping: dotnetcore\store\x64\netcoreapp2.1\artifact.xml
... zipping: dotnetcore\store\x64\netcoreapp2.1\amazon.lambda.core\1.0.0\lib\netstandard1.3\Amazon.Lambda.Core.dll
... zipping: dotnetcore\store\x64\netcoreapp2.1\amazon.lambda.core\1.1.0\lib\netstandard2.0\Amazon.Lambda.Core.dll
... zipping: dotnetcore\store\x64\netcoreapp2.1\amazon.lambda.serialization.json\1.4.0\lib\netstandard1.3\Amazon.Lambda.Serialization.Json.dll
... zipping: dotnetcore\store\x64\netcoreapp2.1\newtonsoft.json\9.0.1\lib\netstandard1.0\Newtonsoft.Json.dll
Uploading layer input zip file to S3
Uploading to S3. (Bucket: normj-west2 Key: LayerBlogDemoLayer-636888783824636933/packages.zip)
... Progress: 52%
... Progress: 100%
Upload complete to s3://normj-west2/LayerBlogDemoLayer-636888783824636933/packages.zip
Layer publish with arn arn:aws:lambda:us-west-2:123412341234:layer:LayerBlogDemoLayer:1

여기에서 두 가지 사항을 언급하고자 합니다. 첫째, Amazon S3로 로드된 artifact.xml 파일이 있습니다. 이 파일이 중요한 이유는 나중에 이 계층을 사용하여 Lambda 함수가 배포될 때 dotnet publish 명령에게 포함하지 않아야 할 어셈블리에 대해 알리기 위해 Amazon.Lambda.Tools에 의해 artifact.xml 파일이 다운로드되기 때문입니다. 이 파일의 사용은 사용자의 개입 없이 진행되지만 이 파일이 S3에 업로드되어야 하며 이 계층을 사용하는 한 해당 위치에 존재해야 한다는 점에 유의하시기 바랍니다. 계층을 다른 계정과 공유하려면 S3에서도 이 객체를 공유해야 합니다.

출력 정보 중 가장 중요한 정보는 계층의 새 버전에 대한 ARN으로서, 이는 마지막 줄에 표시됩니다. 이 값은 함수를 배포할 때 사용됩니다.

계층 검사

dotnet lambda help 명령을 실행하면 계층 관리를 위해 몇 가지 새로운 명령이 추가된 것을 볼 수 있습니다.

PS> dotnet lambda help
Amazon Lambda Tools for .NET Core applications (3.2.0)
Project Home: https://github.com/aws/aws-extensions-for-dotnet-cli, https://github.com/aws/aws-lambda-dotnet
...
Commands to publish and manage AWS Lambda Layers:
        publish-layer           Command to publish a Layer that can be associated with a Lambda function
        list-layers             Command to list Layers
        list-layer-versions     Command to list versions for a Layer
        get-layer-version       Command to get the details of a Layer version
        delete-layer-version    Command to delete a version of a Layer
...

계층을 검사하기 위해 get-layer-version 명령을 이용하면 어떤 어셈블리가 계층에 있으며 어디에 artifact.xml 파일이 저장되어 있는지 알려줍니다.

PS< dotnet lambda get-layer-version arn:aws:lambda:us-west-2:123412341234:layer:LayerBlogDemoLayer:1
Amazon Lambda Tools for .NET Core applications (3.2.0)
Project Home: https://github.com/aws/aws-extensions-for-dotnet-cli, https://github.com/aws/aws-lambda-dotnet

Layer ARN:               arn:aws:lambda:us-west-2:123412341234:layer:LayerBlogDemoLayer
Version Number:          1
Created:                 3/22/2019 12:06 PM
License Info:
Compatible Runtimes:     dotnetcore2.1
Layer Type:              .NET Runtime Package Store
.NET Runtime Package Store Details:
Manifest Location:       s3://normj-west2/LayerBlogDemoLayer-636888783824636933/artifact.xml
Packages Optimized:      False
Packages Directory:      /opt/dotnetcore/store
Manifest Contents
-----------------------
<StoreArtifacts>
  <Package Id="Amazon.Lambda.Core" Version="1.1.0" />
  <Package Id="Amazon.Lambda.Core" Version="1.0.0" />
  <Package Id="Amazon.Lambda.Serialization.Json" Version="1.4.0" />
  <Package Id="Newtonsoft.Json" Version="9.0.1" />
</StoreArtifacts>

계층을 통한 배포

함수를 배포할 때 계층을 사용하려면 --function-layers 스위치를 사용합니다. 여기에 publish-layer 명령에 의해 출력된 계층 버전 ARN 값을 지정해야 합니다. 여러 계층을 사용하려면 쉼표로 구분된 ARN 목록을 사용할 수 있습니다.

PS< dotnet lambda deploy-function LayerBlogDemo --function-layers arn:aws:lambda:us-west-2:123412341234:layer:LayerBlogDemoLayer:1
Amazon Lambda Tools for .NET Core applications (3.2.0)
Project Home: https://github.com/aws/aws-extensions-for-dotnet-cli, https://github.com/aws/aws-lambda-dotnet

Inspecting Lambda layers for runtime package store manifests
... arn:aws:lambda:us-west-2:626492997873:layer:LayerBlogDemoLayer:1: Downloaded package manifest for runtime package store layer
Executing publish command
Deleted previous publish folder
... invoking 'dotnet publish', working folder 'C:\temp\LayerBlogDemo\src\LayerBlogDemo\bin\Release\netcoreapp2.1\publish'
... Disabling compilation context to reduce package size. If compilation context is needed pass in the "/p:PreserveCompilationContext=false" switch.
... publish: Microsoft (R) Build Engine version 15.9.20+g88f5fadfbe for .NET Core
... publish: Copyright (C) Microsoft Corporation. All rights reserved.
... publish:   Restore completed in 46.95 ms for C:\temp\LayerBlogDemo\src\LayerBlogDemo\LayerBlogDemo.csproj.
... publish:   LayerBlogDemo -> C:\temp\LayerBlogDemo\src\LayerBlogDemo\bin\Release\netcoreapp2.1\rhel.7.2-x64\LayerBlogDemo.dll
... publish:   LayerBlogDemo -> C:\temp\LayerBlogDemo\src\LayerBlogDemo\bin\Release\netcoreapp2.1\publish\
Zipping publish folder C:\temp\LayerBlogDemo\src\LayerBlogDemo\bin\Release\netcoreapp2.1\publish to C:\temp\LayerBlogDemo\src\LayerBlogDemo\bin\Release\netcoreapp2.1\LayerBlogDemo.zip
... zipping: LayerBlogDemo.deps.json
... zipping: LayerBlogDemo.dll
... zipping: LayerBlogDemo.pdb
... zipping: LayerBlogDemo.runtimeconfig.json
Updating code for existing function LayerBlogDemo

배포 시작 시 Lambda 계층이 검사되고 artifact.xml 파일이 다운로드된 것을 볼 수 있습니다. 앞서 이 artifact.xml 파일은 dotnet publish 명령에 전달되고, 해당 명령은 Amazon.Lambda.* 및 Newtonsoft.Json NuGet 패키지를 포함하지 말 것을 지시했었습니다. 프로젝트의 어셈블리만 패키지 번들에 포함된 것을 볼 수 있습니다.

deploy-serverless 명령을 사용하여 AWS CloudFormation 템플릿을 통해 배포할 때 계층 속성을 설정합니다. deploy-serverless 명령은 *deploy-function* 명령에서 본 것과 동일하게 계층 검사를 수행합니다.

javascript
{
    "AWSTemplateFormatVersion" : "2010-09-09",
    "Transform" : "AWS::Serverless-2016-10-31",
    "Description" : "An AWS Serverless Application.",
    "Resources" : {
        "LayerBlogDemo" : {
            "Type" : "AWS::Serverless::Function",
            "Properties": {
                "Handler": "LayerBlogDemo::LayerBlogDemo.Function::FunctionHandler",
                "Runtime": "dotnetcore2.1",
                "Layers" : ["arn:aws:lambda:us-west-2:123412341234:layer:LayerBlogDemoLayer:1"],
                "CodeUri": "",
                "MemorySize": 256,
                "Timeout": 30,
                "Role": null,
                "Policies": [ "AWSLambdaBasicExecutionRole" ]
            }
        }
    }
}

패키지 최적화

런타임 패키지 스토어의 기능 중 하나는 스토어에 배치된 .NET 어셈블리를 사전 컴파일을 통해 대상 런타임에 맞게 최적화할 수 있다는 것입니다. 사전 컴파일은 플랫폼에 종속되지 않는 MSIL이라는 어셈블리 기계 코드를 네이티브 기계 코드로 컴파일하는 과정입니다. 사전 컴파일이 없으면 어셈블리는 .NET Core 프로세스로 처음 로드될 때 네이티브 기계 코드로 컴파일됩니다. 최적화를 사용하면 Lambda에서의 콜드 스타트 시간을 상당히 줄일 수 있습니다.

최적화된 런타임 패키지 스토어 계층을 생성하려면 Amazon Linux 환경에서 publish-layer 명령을 실행해야 합니다. Windows 또는 macOS에서 최적화된 런타임 패키지 스토어 계층의 생성을 시도하면 오류가 반환됩니다. Linux에서 계층을 생성하는 경우 배포가 Amazon Linux인지 확인하십시오. Amazon EC2는 Amazon Linux 및 .NET Core 2.1이 사전 설치된 AMI를 제공하며 AWS Toolkit for Visual Studio에서 이를 손쉽게 시작할 수 있습니다.

최적화된 계층을 사용할 때 장점 중 하나는 사전 컴파일의 이점을 얻기 위해 Amazon Linux 인스턴스에 계층을 한 번만 생성한 다음, 해당 계층 버전 ARN을 Windows 및 macOS에서 여러분이 개발 중인 모든 Lambda 함수와 공유할 수 있다는 것입니다.

publish-layer 명령에 계층을 최적화하도록 지시하려면 --enable-package-optimization 스위치를 true로 설정하면 됩니다.

AWS Toolkit for Visual Studio 업데이트

오늘 출시로 Lambda 계층을 Amazon.Lambda.Tools .NET Core Global Tool과 함께 사용할 수 있습니다. AWS에서는 다음 버전의 Visual Studio 2019에 대한 지원을 추가하도록 AWS Toolkit for Visual Studio의 업데이트를 마무리하는 중입니다. 이 업데이트가 출시되면 aws-lambda-tools-defaults.json 또는 serverless.template 파일에서 publish-layer 명령으로 생성한 계층을 참조할 수 있으며, Visual Studio로부터 생성한 배포는 deploy-functiondeploy-serverless 명령에서 본 것과 동일한 방식으로 계층을 처리하게 됩니다. AWS Toolkit for Visual Studio 출시 정보는 AWS의 .NET 블로그 또는 @awsfornet Twitter handle을 수시로 확인하시기 바랍니다.

요약

AWS에서는 Amazon.Lambda.Tools에서 동일한 경험을 제공할 수 있도록 관련한 다양한 작업이 진행하고 있습니다. GitHub 리포지토리에서 이 기능의 작동 방식에 대한 전체 설명서(https://github.com/aws/aws-extensions-for-dotnet-cli/blob/master/docs/Layers.md)를 읽어볼 것을 권장해 드립니다. FAQ와 계층을 CI 시스템용 packagepackage-ci 명령과 함께 사용하는 방법에 대한 세부 정보가 제공되고 있습니다.

저는 고객 여러분이 요청한 이 기능을 Lambda .NET 도구에 추가하게 되어 기쁘게 생각합니다. 계층을 사용하는 과정이 원활하기를 바라며 이 기능에 대한 여러분의 의견도 적극 환영합니다. 언제든지 .NET Lambda 리포지토리를 통해 연락주시기 바랍니다.

–Norm

이 글은 AWS Developer Blog의 AWS Lambda layers with .NET Core의 한국어 번역입니다.