AWS Lambda
개발자 안내서

2.1단계: 배포 패키지 생성

[Filter View] 목록에서 Lambda 함수에 사용할 언어를 선택합니다. 배포 패키지를 생성하는 데 필요한 특정 지침과 코드가 표시된 해당 섹션이 나타납니다.

Node.js

배포 패키지는 Lambda 함수 코드 및 종속성이 포함되어 있는 .zip 파일입니다.

  1. 폴더(examplefolder)를 생성한 다음 하위 폴더(node_modules)를 생성합니다.

  2. Node.js 플랫폼을 설치합니다. 자세한 내용은 Node.js 웹 사이트를 참조하십시오.

  3. 종속 항목을 설치합니다. 이 코드 예제는 다음 라이브러리를 사용합니다.

    • Node.js에서 JavaScript용 AWS SDK 사용

    • gm, GraphicsMagick(node.js용)

    • 비동기 유틸리티 모듈

    AWS Lambda 실행 시간에는 Node.js에 이미 JavaScript용 AWS SDK가 있으므로 다른 라이브러리만 설치하면 됩니다. 명령 프롬프트를 열고 examplefolder로 이동한 후 Node.js의 일부인 npm 명령을 사용하여 라이브러리를 설치합니다.

    npm install async gm
  4. 텍스트 편집기를 열고 다음 코드를 복사합니다.

    // dependencies var async = require('async'); var AWS = require('aws-sdk'); var gm = require('gm') .subClass({ imageMagick: true }); // Enable ImageMagick integration. var util = require('util'); // constants var MAX_WIDTH = 100; var MAX_HEIGHT = 100; // get reference to S3 client var s3 = new AWS.S3(); exports.handler = function(event, context, callback) { // Read options from the event. console.log("Reading options from event:\n", util.inspect(event, {depth: 5})); var srcBucket = event.Records[0].s3.bucket.name; // Object key may have spaces or unicode non-ASCII characters. var srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " ")); var dstBucket = srcBucket + "resized"; var dstKey = "resized-" + srcKey; // Sanity check: validate that source and destination are different buckets. if (srcBucket == dstBucket) { callback("Source and destination buckets are the same."); return; } // Infer the image type. var typeMatch = srcKey.match(/\.([^.]*)$/); if (!typeMatch) { callback("Could not determine the image type."); return; } var imageType = typeMatch[1]; if (imageType != "jpg" && imageType != "png") { callback('Unsupported image type: ${imageType}'); return; } // Download the image from S3, transform, and upload to a different S3 bucket. async.waterfall([ function download(next) { // Download the image from S3 into a buffer. s3.getObject({ Bucket: srcBucket, Key: srcKey }, next); }, function transform(response, next) { gm(response.Body).size(function(err, size) { // Infer the scaling factor to avoid stretching the image unnaturally. var scalingFactor = Math.min( MAX_WIDTH / size.width, MAX_HEIGHT / size.height ); var width = scalingFactor * size.width; var height = scalingFactor * size.height; // Transform the image buffer in memory. this.resize(width, height) .toBuffer(imageType, function(err, buffer) { if (err) { next(err); } else { next(null, response.ContentType, buffer); } }); }); }, function upload(contentType, data, next) { // Stream the transformed image to a different S3 bucket. s3.putObject({ Bucket: dstBucket, Key: dstKey, Body: data, ContentType: contentType }, next); } ], function (err) { if (err) { console.error( 'Unable to resize ' + srcBucket + '/' + srcKey + ' and upload to ' + dstBucket + '/' + dstKey + ' due to an error: ' + err ); } else { console.log( 'Successfully resized ' + srcBucket + '/' + srcKey + ' and uploaded to ' + dstBucket + '/' + dstKey ); } callback(null, "message"); } ); };

    참고

    이 코드 샘플은 Node.js 실행 시간 v8.10, v6.10 또는 v4.3과 호환됩니다. 자세한 내용은 프로그래밍 모델(Node.js) 단원을 참조하십시오.

  5. 앞의 코드를 검토하고 다음 사항을 확인합니다.

    • 이 함수는 파라미터로 받은 이벤트 데이터에서 원본 버킷 이름과 객체 키 이름을 알고 있습니다. 객체가 .jpg인 경우, 코드는 썸네일을 만들고 대상 버킷에 저장합니다.

    • 이 코드는 대상 버킷이 존재하고 해당 이름이 원본 버킷 이름과 resized 문자열이 이어진 것이라고 가정합니다. 예를 들어 이벤트 데이터에서 식별된 원본 버킷이 examplebucket인 경우 코드는 사용자에게 examplebucketresized 대상 버킷이 있다고 가정합니다.

    • 생성하는 썸네일의 경우 코드는 resized- 문자열과 소스 객체 키 이름이 연결된 키 이름을 가져옵니다. 예를 들어 소스 객체 키가 sample.jpg인 경우 코드는 키가 resized-sample.jpg인 썸네일 객체를 만듭니다.

  6. 파일을 examplefolderCreateThumbnail.js로 저장합니다. 이 단계를 완료한 후에는 다음과 같은 폴더 구조를 갖게 됩니다.

    CreateThumbnail.js /node_modules/gm /node_modules/async
  7. CreateThumbnail.js 파일과 node_modules 폴더를 CreateThumbnail.zip으로 압축합니다.

    이것은 Lambda 함수 배포 패키지입니다.

다음 단계

2.2단계: 실행 역할 생성(IAM 역할)

Java

다음은 수신하는 Amazon S3 이벤트를 읽고 썸네일을 생성하는 Java 코드의 예입니다. 이는 aws-lambda-java-core 라이브러리에 제공된 RequestHandler 인터페이스를 구현합니다. 따라서 Lambda 함수를 만들 때 클래스를 핸들러로 지정합니다(example.S3EventProcessorCreateThumbnail). 인터페이스를 사용하여 핸들러를 제공하는 방법에 대한 자세한 내용은 핸들러를 생성하기 위해 사전 정의된 인터페이스 활용(Java) 단원을 참조하십시오.

핸들러가 입력 유형으로 사용하는 S3Event 유형은 수신하는 Amazon S3 이벤트에서 정보를 쉽게 읽을 수 있는 방법을 제공하는 aws-lambda-java-events 라이브러리의 사전 정의된 클래스 중 하나입니다. 핸들러는 문자열을 출력으로 반환합니다.

package example; import java.awt.Color; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLDecoder; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.imageio.ImageIO; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.S3Event; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.event.S3EventNotification.S3EventNotificationRecord; import com.amazonaws.services.s3.model.GetObjectRequest; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.S3Object; public class S3EventProcessorCreateThumbnail implements RequestHandler<S3Event, String> { private static final float MAX_WIDTH = 100; private static final float MAX_HEIGHT = 100; private final String JPG_TYPE = (String) "jpg"; private final String JPG_MIME = (String) "image/jpeg"; private final String PNG_TYPE = (String) "png"; private final String PNG_MIME = (String) "image/png"; public String handleRequest(S3Event s3event, Context context) { try { S3EventNotificationRecord record = s3event.getRecords().get(0); String srcBucket = record.getS3().getBucket().getName(); // Object key may have spaces or unicode non-ASCII characters. String srcKey = record.getS3().getObject().getKey() .replace('+', ' '); srcKey = URLDecoder.decode(srcKey, "UTF-8"); String dstBucket = srcBucket + "resized"; String dstKey = "resized-" + srcKey; // Sanity check: validate that source and destination are different // buckets. if (srcBucket.equals(dstBucket)) { System.out .println("Destination bucket must not match source bucket."); return ""; } // Infer the image type. Matcher matcher = Pattern.compile(".*\\.([^\\.]*)").matcher(srcKey); if (!matcher.matches()) { System.out.println("Unable to infer image type for key " + srcKey); return ""; } String imageType = matcher.group(1); if (!(JPG_TYPE.equals(imageType)) && !(PNG_TYPE.equals(imageType))) { System.out.println("Skipping non-image " + srcKey); return ""; } // Download the image from S3 into a stream AmazonS3 s3Client = new AmazonS3Client(); S3Object s3Object = s3Client.getObject(new GetObjectRequest( srcBucket, srcKey)); InputStream objectData = s3Object.getObjectContent(); // Read the source image BufferedImage srcImage = ImageIO.read(objectData); int srcHeight = srcImage.getHeight(); int srcWidth = srcImage.getWidth(); // Infer the scaling factor to avoid stretching the image // unnaturally float scalingFactor = Math.min(MAX_WIDTH / srcWidth, MAX_HEIGHT / srcHeight); int width = (int) (scalingFactor * srcWidth); int height = (int) (scalingFactor * srcHeight); BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = resizedImage.createGraphics(); // Fill with white before applying semi-transparent (alpha) images g.setPaint(Color.white); g.fillRect(0, 0, width, height); // Simple bilinear resize // If you want higher quality algorithms, check this link: // https://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.drawImage(srcImage, 0, 0, width, height, null); g.dispose(); // Re-encode image to target format ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageIO.write(resizedImage, imageType, os); InputStream is = new ByteArrayInputStream(os.toByteArray()); // Set Content-Length and Content-Type ObjectMetadata meta = new ObjectMetadata(); meta.setContentLength(os.size()); if (JPG_TYPE.equals(imageType)) { meta.setContentType(JPG_MIME); } if (PNG_TYPE.equals(imageType)) { meta.setContentType(PNG_MIME); } // Uploading to S3 destination bucket System.out.println("Writing to: " + dstBucket + "/" + dstKey); s3Client.putObject(dstBucket, dstKey, is, meta); System.out.println("Successfully resized " + srcBucket + "/" + srcKey + " and uploaded to " + dstBucket + "/" + dstKey); return "Ok"; } catch (IOException e) { throw new RuntimeException(e); } } }

Amazon S3는 Event 호출 유형을 사용해 Lambda 함수를 호출하며, 여기에서 AWS Lambda는 코드를 비동기식으로 실행합니다. 반환하는 항목은 중요하지 않습니다. 하지만 이 경우 반환 유형을 지정해야 하는 인터페이스를 구현하므로 이 예제에서는 핸들러가 String을 반환 유형으로 사용합니다.

위의 코드(S3EventProcessorCreateThumbnail.java라는 파일에 위치)를 사용하여 배포 패키지를 생성합니다. 다음 종속성을 추가했는지 확인합니다.

  • aws-lambda-java-core

  • aws-lambda-java-events

이는 aws-lambda-java-libs에서 확인할 수 있습니다.

자세한 내용은 Java로 Lambda 함수를 작성하기 위한 프로그래밍 모델 단원을 참조하십시오.

배포 패키지는 .zip 파일 또는 독립 실행형 .jar일 수 있습니다. 익숙한 빌드 및 패키징 도구를 사용하여 배포 패키지를 생성할 수 있습니다. Maven 빌드 도구를 사용하여 독립 실행형 .jar을 생성하는 방법의 예는 IDE 없이 Maven을 사용하여 .jar 배포 패키지 만들기(Java)Maven 및 Eclipse IDE를 사용하여 .jar 배포 패키지 생성(Java)을 참조하십시오. Gradle 빌드 도구를 사용하여 .zip 파일을 생성하는 방법의 예는 .zip 배포 패키지 만들기(Java) 단원을 참조하십시오.

배포 패키지가 생성되었는지 확인한 후 다음 단계로 진행하여 IAM 역할(실행 역할)을 만듭니다. Lambda 함수를 생성할 때 이 역할을 지정합니다.

다음 단계

2.2단계: 실행 역할 생성(IAM 역할)

Python

이 단원에서는 예제 Python 함수를 만들고 종속 항목을 설치합니다. 코드 샘플은 Python 실행 시간 버전 3.6 또는 2.7과 호환됩니다. 이 단계에서는 3.6 실행 시간을 사용하지만 둘 중 하나를 사용할 수 있습니다.

  1. 텍스트 에디터를 열고 다음 코드를 복사합니다. 해당 코드는 다음과 같이 크기가 조정된 이미지를 동일한 이미지 이름을 가진 다른 버킷에 업로드합니다.

    source-bucket/image.png -> source-bucketresized/image.png

    참고

    from __future__ 문을 사용하여 Python 2 또는 3과 호환 가능한 코드를 작성할 수 있습니다. 실행 시간 버전 3.6을 사용하는 경우에는 포함할 필요가 없습니다.

    from __future__ import print_function import boto3 import os import sys import uuid from PIL import Image import PIL.Image s3_client = boto3.client('s3') def resize_image(image_path, resized_path): with Image.open(image_path) as image: image.thumbnail(tuple(x / 2 for x in image.size)) image.save(resized_path) def handler(event, context): for record in event['Records']: bucket = record['s3']['bucket']['name'] key = record['s3']['object']['key'] download_path = '/tmp/{}{}'.format(uuid.uuid4(), key) upload_path = '/tmp/resized-{}'.format(key) s3_client.download_file(bucket, key, download_path) resize_image(download_path, upload_path) s3_client.upload_file(upload_path, '{}resized'.format(bucket), key)
  2. 파일을 CreateThumbnail.py로 저장합니다.

  3. 소스 코드가 로컬 호스트에 있으면 복사합니다.

    scp -i key.pem /path/to/my_code.py ec2-user@public-ip-address:~/CreateThumbnail.py

  4. SSH를 통해 64비트 Amazon Linux 인스턴스에 연결합니다.

    ssh -i key.pem ec2-user@public-ip-address

  5. 다음 단계에 따라 Python 3.6 및 virtualenv를 설치합니다.

    1. sudo yum install -y gcc zlib zlib-devel openssl openssl-devel

    2. wget https://www.python.org/ftp/python/3.6.1/Python-3.6.1.tgz

    3. tar -xzvf Python-3.6.1.tgz

    4. cd Python-3.6.1 && ./configure && make

    5. sudo make install

    6. sudo /usr/local/bin/pip3 install virtualenv

  6. pip3을 통해 설치된 가상 환경을 선택합니다.

    /usr/local/bin/virtualenv ~/shrink_venv

    source ~/shrink_venv/bin/activate

  7. 가상 환경에 라이브러리를 설치합니다.

    pip install Pillow

    pip install boto3

    참고

    AWS Lambda에는 Python용 AWS SDK(Boto 3)가 포함되어 있기 때문에 배포 패키지에 이를 포함시킬 필요가 없지만 선택적으로 로컬 테스트에 포함시킬 수 있습니다.

  8. liblib64 사이트 패키지 콘텐츠를 .zip 파일에 추가합니다. 다음 단계에서는 Python 실행 시간 버전 3.6을 사용한다고 가정합니다. 버전 2.7을 사용했다면 그에 따라 업데이트해야 합니다.

    cd $VIRTUAL_ENV/lib/python3.6/site-packages

    zip -r9 ~/CreateThumbnail.zip .

    참고

    숨겨진 파일을 모든 포함하려면 다음 zip -r9 ~/CreateThumbnail.zip 옵션을 사용합니다.

  9. python 코드를 .zip 파일에 추가합니다.

    cd ~

    zip -g CreateThumbnail.zip CreateThumbnail.py

다음 단계

2.2단계: 실행 역할 생성(IAM 역할)

이 페이지에서: