본문 바로가기

개발 기록/AWS

Lambda@Edge 기반 CloudFront QRCode 생성기 만들기

반응형

추후 서비스에 동일 링크를 가리키는 QRCode를 다양한 사이즈로 활용할 수 있기에 미리 구상을 해보았다. 여러 QRCode 생성기를 찾아보았고 외국 사이트나 국내사이트는 nodejs 기반 qrcode 라이브러리를 S3에 업로드 하는 예제나 별도 node 기반 웹서버에서 바로 보여주는 예제는 많았다. 내가 원하는것은 원하는 사이즈를 특정 URL 호출을 통해 실시간으로 생성되도록 하는것이였다.

 

처음엔 생성된 QRCode를 S3에 업로드하여 이미지만 sharp라이브러리를 통해 리사이징을 고려했지만 S3에 불필요한 이미지 자원인것 같아 다이렉트로 생성된 QRCode 버퍼 정보를 response할 수 있도록 구상해보았다. 

 

참고한 것은 npm qrcode라이브러리 정보와 lambda@edge기반의 이미지 리사이징 방법을 활용하였다.

 

해당 예제는 리전을 버지니아로 하여 진행하였다.

 

* 참고 사이트

https://www.npmjs.com/package/qrcode

 

qrcode

QRCode / 2d Barcode api with both server side and client side support using canvas. Latest version: 1.5.1, last published: a month ago. Start using qrcode in your project by running `npm i qrcode`. There are 1618 other projects in the npm registry using qr

www.npmjs.com

 

https://heropy.blog/2019/07/21/resizing-images-cloudfrount-lambda/

 

AWS Lambda@edge로 실시간 이미지 리사이징(updated)

AWS Lambda@edge(CloudFront)로 실시간 이미지 리사이징 기능을 구현합니다. Cloud 9으로 람다 함수를 작성하고 CloudWatch로 로그를 확인합니다.

heropy.blog

 

처리 구상도는 다음과 같다.

위 구상도를 대략적으로 설명하자면 유저는 cloudfront url를 통해 qrcode 이미지를 요청하게 된다. 요청 받은 cloudfront는 origin response 이벤트에서 lambda 함수 이벤트를 발생시켜 유저가 원하는 사이즈의 qrcode 이미지를 응답하게 된다. 

S3 버킷은 cloudfront에 원본 도메인으로 연결되어야 하므로 설정용도로 사용된다고 보면 된다.

 

1. IAM 정책 및 역할 신규 추가

  1-1. IAM -> 정책 -> 정책생성 -> JSON 탭 클릭

 


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceLinkedRole",
                "lambda:GetFunction",
                "lambda:EnableReplication",
                "cloudfront:UpdateDistribution",
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "logs:DescribeLogStreams"
            ],
            "Resource": "*"
        }
    ]
}

 

* 정책 권한으로는 lambda 함수 관련 권한과 cloudwatch에 로깅할수 있는 권한이면 충분하다.

JSON편집으로 정책 입력
정책생성을 누른다.

 

 1-2 IAM -> 역할 -> 역할만들기 -> 사용자 지정 신뢰정책 클릭


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "edgelambda.amazonaws.com",
                    "lambda.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

 

 

2. S3 버킷 생성 및 설정

 * S3 버킷 리전은 서울로 만들어도 된다. @edge 리전이 버지니아이기 때문에 버지니아로 하였다.

 

2-1 버킷 생성

 

2-2 버킷 정책 편집 및 추가 (IAM에서 생성한 정책을 권한 부여 한다.)

 


{
	"Version": "2008-10-17",
	"Id": "PolicyForCloudFrontPrivateContent",
	"Statement": [
		{
			"Sid": "1",
			"Effect": "Allow",
			"Principal": {
				"AWS": "arn:aws:iam::{iam고유번호}:role/{qrcode 관련 신규 정책}"
			},
			"Action": "s3:GetObject",
			"Resource": "arn:aws:s3:::{S3버킷이름}/*"
		}
	]
}

 

3. CloudFront 생성 및 설정

* 필자는 뷰어 프로토콜 정책 및 캐시 키 및 원본 요청만 설정하였고 기본으로 설정하여 진행하였다.

 

* 캐시 키 및 원본 요청에 쿼리 문자열정보로 링크와 넓이 정보를 받을 수 있도록 반드시 설정하여야 한다.

 

4. Lambda 함수 생성 및 설정

* 함수 생성시 기존 실행 역할 변경을 만들어놓은 정책정보로 설정을 반드시 하여야 한다.

 

* 생성된 Lambda 함수는 구성탭 -> 일반구성을 편집하여 제한시간 10초, 메모리 256MB로 수정을 추천한다.

  (제한시간 3초일 경우 Timeout 발생할 수 있다.)

 

5. Cloud9을 통한 소스 배포

* cloud9은 EC2 사양으로 t3.small 하는것이 좋다.. micro 사양도 가능하지만 성능이 매우 낮아서 정상 동작이 안될수도 있다..

   리전은 버지니아로 하여 생성하여 한다.

 

 5-1. cloud9 인스턴스 생성

 

 

5-2. 프로젝트 생성 <cloud9 터미널 명령어>


// nodejs v16.17.0 설치
nvm install v16.17.0
nvm use v16.17.0

// node 버전 확인
node -v

// 프로젝트 디렉토리 생성
mkdir qrcode-test
cd qrcode-test

// node 프로젝트 초기화 및 관련 라이브러리 설치
npm init -y
npm i —save sharp
npm i —save qrcode

// index 파일 생성
touch index.js

 

5-3. 프로젝트 Index 파일 생성 <index.js 소스>


'use strict';

const querystring = require('querystring'); 
const QRCode = require('qrcode');
const Sharp = require('sharp');

exports.handler = async(event, context, callback) => {
  const { request, response } = event.Records[0].cf;
  
  // Parameters are w, link and indicate width, qrLink
  const params = querystring.parse(request.querystring);
  const { w, link } = params

  const width = parseInt(w, 60) || null;
  let format;
  let base64;
  let base64DataImage;
  let responseImage;
  
  // AWS CloudWatch. Parameter logging
  console.log(`parmas: ${JSON.stringify(params)}`);

  // required link parameter
  if (!link) {
    responseHandler(
      400,
      'Bad Request',
      'Required link Parameter', [{
        key: 'Content-Type',
        value: 'text/plain'
      }],
    );

    return callback(null, response);
  }

  try {
    // QR Code Image Buffer Create&base64
    var opts = {
      errorCorrectionLevel: 'H',
      type: 'image/png',
      margin: 1,
      width: width
    }
    base64 = await QRCode.toDataURL(params.link, opts);
    base64DataImage = new Buffer.from(base64.replace(/^data:image\/\w+;base64,/, ""), 'base64');
    format = base64.split(';')[0].split('/')[1];
    
    // Sharp base64 Image Convert
    responseImage = await Sharp(base64DataImage)
                          .rotate()
                          .toBuffer();
  }
  catch (error) {
    responseHandler(
      500,
      'Internal Server Error',
      'Fail to resize image.', [{
        key: 'Content-Type',
        value: 'text/plain'
      }],
    );
    return callback(null, response);
  }
  
  // QRCode Image Response Create
  responseHandler(
    200,
    'OK',
    responseImage.toString('base64'), [{
      key: 'Content-Type',
      value: `image/${format}`
    }],
    'base64'
  );

  
  function responseHandler(status, statusDescription, body, contentHeader, bodyEncoding) {
    response.status = status;
    response.statusDescription = statusDescription;
    response.body = body;
    response.headers['content-type'] = contentHeader;
    if (bodyEncoding) {
      response.bodyEncoding = bodyEncoding;
    }
  }
  
  console.log('Success qrcode image');

  return callback(null, response);
};

 

5-4. Lambda 함수에 배포

 

- 좌측 AWS 탭에 Lambda 클릭 후 해당 함수 클릭 및 우측 클릭 후 Upload Lambda 클릭

해당 람다 함수를 클릭 후 우측 클릭하면 다음과 같은 메뉴가 뜬다. (업로드 클릭)

- Directory -> No 클릭 후 배포

 

6. Lambda@Edge 배포 및 테스트

- 소스가 정상적으로 배포되었는지 확인

 

- 작업 -> Lambda@Edge배포 클릭

테스트 결과

https://{CloudFront도메인주소}/?w=100&link=www.naver.com

정상 생성되었다.

반응형