이두잉의 AWS 세상

오늘은 Lambda에 관한 포스팅을 하도록 하겠습니다.

Lambda를 이용하여 S3 업로드 시에 파일의 meta-data(헤더)를 변경해보도록 하겠습니다

meta-data를 통해 client가 vod(mp4) 파일을 스트리밍할 지, 강제로 다운로드 받을지 결정할 수 있습니다. 

App 서버에서 Client가 업로드 시 meta-data 수정 전/후 파일을 S3에 업로드 할 수 있지만, Lambda 학습할 겸 테스트 해봤습니다. 


1.Overview

Lambda는 AWS의 event trigger function 서비스입니다. S3 / SNS 등에서 Event가 발생되면 Lambda에 호출을 하고 Lambda는 node / python / java 등을 이용하여 작업을 합니다. 

Lambda와 S3를 연동해서 썸네일, 파일의 메타 데이터 변경이 가능합니다.

오늘은 S3 파일의 메타데이터를 변경하도록 하겠습니다. AOD 버킷에 업로드된 파일의 mp3 파일의 mime-type을 변경하여 Download 버킷에 업로드하도록 하겠습니다. 브라우저에서 AOD 접근 시에는 스트리밍이 되며, Download 접근 시에는 강제로 다운로드 되도록 하겠습니다.



2. Getting Started

먼저 S3 Bucket 2개를 만들어줍니다. 일반적으로 파일을 올릴 버킷과 Lambda를 거쳐서 헤더 값이 수정된 파일이 올라갈 버킷입니다.

Edit bucket policy를 통해 접근 권한을 두 버킷에 모두 줍니다.

ma2rix의 버킷의 경우 일반적인 파일 업로드 / ma2rix-lambda의 경우 lambda를 거친 수정된 파일이 업로드 되겠습니다.


 

Lambda 페이지로 이동합니다. Create 합니다. 예제 코드들이 있습니다.

S3-get-object 예제를 먼저 테스트 합니다.


어떤 Event가 발생했을 때 Lambda trigger 시킬 것이냐고 물어봅니다.

S3를 선택하고 해당 버킷을 선택합니다. 사용자가 업로드 시 사용하는 method Put과 MultipartUpload입니다.


그럼 소스코드를 넣는 곳이 나옵니다.

Lambda Function의 이름을 넣어주시구요. node.js 선택합니다.

직접 해당 창에 소스 코드 입력, 업로드, S3에서 파일을 가져올 수도 있습니다.

굳이 다른 모듈을 사용하지 않는 간단한 작업이라면 코드를 직접 입력합니다.

해당 예제 소스코드의 경우 파일이 업로드 되면 그 업로드 된 Content Type 헤더 값을 알려준 코드입니다.


콜백함수를 통해 event 발생 시 해당 핸들러가 동작하게 됩니다.

context의 경우 현재 Lambda 실행 환경을 알 수 있으며, context.succeed / context.fail / context.done method를 통해 Lambda function 실행 내용을 return 받을 수 있습니다.

콜백함수의 event context 객체입니다.

Event의 경우 S3에 파일 업로드 시 발생되는 이벤트 내용 / context의 경우 현재 Lambda 함수의 상태를 나타냅니다.

Received event: {

  "Records": [

    {

      "eventVersion": "2.0",

      "eventSource": "aws:s3",

      "awsRegion": "ap-northeast-1",

      "eventTime": "1970-01-01T00:00:00.000Z",

      "eventName": "ObjectCreated:Put",

      "userIdentity": {

        "principalId": "EXAMPLE"

      },

      "requestParameters": {

        "sourceIPAddress": "127.0.0.1"

      },

      "responseElements": {

        "x-amz-request-id": "C3D13FE58DE4C810",

        "x-amz-id-2": "FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD"

      },

      "s3": {

        "s3SchemaVersion": "1.0",

        "configurationId": "testConfigRule",

        "bucket": {

          "name": "ma2rix",

          "ownerIdentity": {

            "principalId": "EXAMPLE"

          },

          "arn": "arn:aws:s3:::ma2rix"

        },

        "object": {

          "key": "test.png",

          "size": 1024,

          "eTag": "d41d8cd98f00b204e9800998ecf8427e"

        }

      }

    }

  ]

}


Received context: {

  "awsRequestId": "acccbb0e-2a95-11e5-b233-f73a9f240845",

  "invokeid": "acccbb0e-2a95-11e5-b233-f73a9f240845",

  "logGroupName": "/aws/lambda/s3AddHeader",

  "logStreamName": "2015/07/15/47dee86189d549e9bf41b9d9f1199ba6",

  "functionName": "s3AddHeader",

  "memoryLimitInMB": "256"

}

END RequestId: acccbb0e-2a95-11e5-b233-f73a9f240845                                                                        REPORT RequestId: acccbb0e-2a95-11e5-b233-f73a9f240845 Duration: 797.87 ms Billed Duration: 800 ms  Memory Size: 256 MB Max Memory Used: 19 MB 


코드 밑에 보시면 handler 이름과 role을 기입하게 되어 있습니다. Role S3 권한을 주어야 합니다

메모리와 타임아웃도 정할 수 있습니다. 메모리가 증가할수록 Lambda 비용이 증가합니다. 생성 후 변경도 가능합니다.


 

next를 누르면 다음 장이 나옵니다. Enable event source, 지금부터 Lambda를 사용할 것이냐고 물어봅니다. 일단 테스트부터 합니다.


 

완료된 화면입니다. Test 버튼을 누르면 가상으로 해당 Event Lambda에게 던져주는 json 형식의 템플릿이 보입니다. S3 Put을 선택합니다.

sample 템플릿을 테스트할 때 json 파일의 세 가지 key 값에 주의합니다.

"awsRegion": "us-east-1"   // S3 Lambda가 존재하는 리전을 넣어줍니다. 리전이 일치해야 합니다.

"bucket": {
          "name": "sourcebucket",  //
사용할 버킷 이름을 맞춰줍니다.
          "ownerIdentity": {
            "principalId": "EXAMPLE"
          },

"object": {
          "key": "HappyFace.jpg",  //
파일 이름을 맞춰줍니다. 현재 샘플이기 때문에 S3 HappyFace.jpg 파일이 존재해야 합니다.
          "size": 1024,
          "eTag": "d41d8cd98f00b204e9800998ecf8427e"
        }



 

테스트 결과입니다.

이상 샘플코드를 이용하여 테스트해봤습니다.


이제 샘플 코드에 헤더 값 변경을 위해 putObject 함수를 추가시킵니다. 내용은 주석으로 표기해놨습니다.

console.log('Loading function');

var aws = require('aws-sdk'); //aws sdk 모듈 사용

var s3 = new aws.S3({ apiVersion: '2006-03-01' });

 

exports.handler = function(event, context) { //이벤트 발생 시 콜백 함백 함수 호출

    console.log('Received event:', JSON.stringify(event, null, 2)); //Event 값 확인

    console.log('Received context:', JSON.stringify(context, null, 2)); //Context 값 확인

    console.log(process.version + 'tttttttt');

    // Get the object from the event and show its content type

    var bucket = event.Records[0].s3.bucket.name; //Event 객체 내에 Bucket 확인

    var key = event.Records[0].s3.object.key; //Event 객체 내에 파일 이름 확인

    var params = { //Params 객체에 해당 내용 생성

        Bucket: bucket,

        Key: key

    };

    s3.getObject(params, function(err, data) { //s3.getObject method를 통해 params에 맞는 data를 가져옴

        if (err) { //getObject err

            console.log(err);

            var message = "Error getting object " + key + " from bucket " + bucket +

                ". Make sure they exist and your bucket is in the same region as this function.";

            console.log(message);

            context.fail(message);

        } else { //Success 시에 새로운 버킷에 헤더 값을 변경하여 Data 삽입

            console.log(data);

            var params2 = {

                    Bucket: 'ma2rix-lambda', //새로운 버킷 지정

                    Key: key, //동일한 파일 네임

                    //CopySource : 'ma2rix' + '/' + key,

                    Body: data.Body, //가져온 Data body

                    //ContentType: 'octet-stream',

                    ContentDisposition: 'attachment; filename="'+key+'"' //header 추가

            };

            s3.putObject(params2, function(err, data){ //params2를 새로운 버킷에 업로드

               if(err){

                    console.log(err, err.stack);

                    context.fail(err);

               }else{

                    //context.succeed('200');

                    console.log('tttttt'+JSON.stringify(context));

                    context.done(null, 'success'); //완료 시 context.succeed 호출

               }

            });

        }

    });

};

 

getObject 콜백 함수의 data는 다음과 같습니다.

{ AcceptRanges: 'bytes',

  LastModified: 'Tue, 14 Jul 2015 11:09:55 GMT',

  ContentLength: '442743',

  ETag: '"e227614ccedb9210f4c56523511ad230"',

  VersionId: 'l.TFB.Nm9Hp4ZfOT0I.WXw55SPhAmIhH',

  ContentType: 'image/png',

  Metadata: {},

  Body: <Buffer ff d8 ff e1 00 18 45 78 69 66 00 00 49 49 2a 00 08 00 00 00 00 00 00 00 00 00 00 00 ff ec 00 11 44 75 63 6b 79 00 01 00 04 00 00 00 46 00 00 ff e1 03 6f ...> }

 


실제로 기존 버킷에 mp3 파일을 업로드해하고 결과를 확인합니다.


기존 버킷(ma2rix)

새로 생성한 버킷(ma2rix-lambda)


3. Result

이상 S3 업로드 시 Lambda를 이용하여 헤더 값 변경 후 다른 버킷에 업로드 하는 테스트를 완료했습니다. 비슷한 워크플로우를 이용하여 썸네일 등 작업이 가능합니다.