본문 바로가기

Compute/Lambda

AWS Lambda를 이용하여 S3 업로드된 파일 meta-data 변경

오늘은 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를 이용하여 헤더 값 변경 후 다른 버킷에 업로드 하는 테스트를 완료. 비슷한 워크플로우를 이용하여 썸네일 등 작업이 가능.