순서대로 해봅시다.

1) IAM 정책 및 역할 생성

1. IAM 정책 생성

  • 정책 선택
  • 정책 생성 선택
  • JSON 선택 및 아래 정책 입력
  • 정책 검토 선택
  • 정책 이름 **ResizingImagePolicy ** 또는 원하는 이름 선택 (설명 옵션)
  • 정책 생성 선택
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceLinkedRole",
                "lambda:GetFunction",
                "lambda:EnableReplication",
                "cloudfront:UpdateDistribution",
                "s3:GetObject",
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "logs:DescribeLogStreams"
            ],
            "Resource": "*"
        }
    ]
}

2. IAM 역할 생성

  • 역할 선택
  • 역할 만들기 선택
  • 신뢰 할 수 있는 유형의 개체 선택 - AWS 서비스
  • 사용 사례 선택 - Lambda
  • 다음:권한 선택
  • 권한 정책 설정
  • 정책 필터에 1. 정책 생성을 통해 생성된 정책 검색 (ResizingImagePolicy) 후 선택
  • 다음:태그 선택 (skip)
  • 다음:검토 선택
  • 역할 이름 **ResizingImageRole ** 또는 원하는 이름 선택 (설명 옵션)
  • 역할 만들기

3. 역할 신뢰 관계(정책) 수정

  • 역할에서 만든 ResizingImageRole 선택
  • 신뢰 관계 선택
  • 신뢰 관계 편집 선택
  • 아래 json 입력
  • 신뢰 정책 업데이트 선택
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "edgelambda.amazonaws.com",
          "lambda.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

2) S3 생성

1. 버킷 생성

  • 버킷 만들기 선택
  • 원하는 버켓 이름 입력
  • 리전은 상관 없음 (저는 seoul로 선택)
  • 생성 선택

3) Lambda 함수 생성

1. Lambda@Edge 로 생성

중요! 반드시 버지니아 북부(us-east-1)에서 생성할 것!!

  • 왼쪽 상단 지역 - 버지니아 북부 선택
  • Lambda - 함수 생성 선택
  • 새로 작성 선택
  • 함수이름 resize-image 또는 원하는 함수명 입력
  • 런타임 Node.js 12.x 선택
  • 권한 아래 실행 역할을 선택하거나 생성하여 클릭
  • 기존 역할 사용 선택
  • 전에 만든 ResizingImageRole 검색 후 선택
  • 함수 생성

2. 함수 제한 시간 수정

  • 생성된 함수 하단의 기본 설정 - 편집 선택
  • 제한 시간 3초 -> 10초 변경

4) Cloud9을 활용한 Lambda 함수 작성

Cloud9은 AWS에서 제공하는 유료IDE 서비스

1. Cloud9을 통한 인스턴스 생성

  • 왼쪽 상단 지역 - 버지니아 북부 선택
  • Cloud9 - Create environment 선택
  • Name에 resize-image 또는 원하는 이름 입력 (Description 은 옵션)
  • Next step 선택
  • Environment type - Create a new EC2 instance for environment 선택
  • Instance type - t2.micro 선택
  • Platform - Amazon Linux 선택
  • Cost-saving setting - After 30 minutes 선택
  • Next step 선택
  • Create environment 선택

2. 생성된 인스턴스를 통해 lambda 함수 수정

  • 우측에 사람인 모양 람다 클릭
  • Remote Functions - **resize-image ** 더블 클릭
  • import 선택
  • 아래 터미널에서 명령어를 통한 npm init, 라이브러리 설치
  • cd resize-image
  • npm init -y
  • npm i sharp
  • 아래 코드 복사 붙여넣기

아래 코드 S3 내 region, BUCKET 내 이름은 내가 설정한 지역, 이름으로 변경

  • command+s 또는 control+s 로 저장

  • 우측 상단에 새로고침 버튼 클릭

  • Local Functions 의 resize-image 우클릭

  • Deploy 선택

'use strict';

const querystring = require('querystring'); // Don't install.
const AWS = require('aws-sdk'); // Don't install.
const Sharp = require('sharp');

const S3 = new AWS.S3({
  region: 'ap-northeast-2'
});
const BUCKET = 'resize-image';

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

  // Required width or height value.
  if (!params.w && !params.h) {
    return callback(null, response);
  }

  // Extract name and format.
  const { uri } = request;
  const [, imageName, extension] = uri.match(/\/?(.*)\.(.*)/);

  // Init variables
  let width;
  let height;
  let format;
  let quality; // Sharp는 이미지 포맷에 따라서 품질(quality)의 기본값이 다릅니다.
  let s3Object;
  let resizedImage;

  // Init sizes.
  width = parseInt(params.w, 10) ? parseInt(params.w, 10) : null;
  height = parseInt(params.h, 10) ? parseInt(params.h, 10) : null;

  // Init quality.
  if (parseInt(params.q, 10)) {
    quality = parseInt(params.q, 10);
  }

  // Init format.
  format = params.f ? params.f : extension;
  format = format === 'jpg' ? 'jpeg' : format;

  // For AWS CloudWatch.
  console.log(`parmas: ${JSON.stringify(params)}`); // Cannot convert object to primitive value.
  console.log(`name: ${imageName}.${extension}`); // Favicon error, if name is `favicon.ico`.

  try {
    s3Object = await S3.getObject({
      Bucket: BUCKET,
      Key: decodeURI(imageName + '.' + extension)
    }).promise();
  } catch (error) {
    console.log('S3.getObject: ', error);
    return callback(error);
  }

  try {
    resizedImage = await Sharp(s3Object.Body)
      .resize(width, height)
      .toFormat(format, {
        quality
      })
      .toBuffer();
  } catch (error) {
    console.log('Sharp: ', error);
    return callback(error);
  }

  const resizedImageByteLength = Buffer.byteLength(resizedImage, 'base64');
  console.log('byteLength: ', resizedImageByteLength);

  // `response.body`가 변경된 경우 1MB까지만 허용됩니다.
  if (resizedImageByteLength >= 1 * 1024 * 1024) {
    return callback(null, response);
  }

  response.status = 200;
  response.body = resizedImage.toString('base64');
  response.bodyEncoding = 'base64';
  response.headers['content-type'] = [
    {
      key: 'Content-Type',
      value: `image/${format}`
    }
  ];
  return callback(null, response);
};

5) Lambda 함수 새 버전 게시

1. 람다 함수 새 버전 게시하기

  • 좌측 상단 버지니아 선택
  • Lambda - resize-image 선택
  • 구분자 - 버전 - $LATEST 선택
  • 작업 - 새 버전 발행 선택 (버전 설명은 옵션)
  • 게시 선택
  • 작업 선택
  • 새 버전 발행 선택 (버전 설명은 옵션임)

6) CloudFront 에 Lambda 연결하기

1. CloudFront의 Distribution 생성하기

  • CloudFront - Distributions - Create Distribution 선택
  • Web - Get Started 선택
  • Origin Domain Name - 전에 생성한 S3 검색 후 선택 (Origin ID 자동으로 추가됨)
  • Restrict Bucket Access - Yes 선택 (항상 Cloud Front URL 로 S3액세스 하도록)
  • Origin Access Identity - Create a New Identity 선택
  • Grant Read Permissions on Bucket - Yes, Update Bucket Policy 선택 (CloudFront 가 S3 버킷 정책에 엑세스하여 업데이트)
  • Cache and origin request settings - Use legacy cache settings 선택
  • Cache Based on Selected Request Headers - None(Improves Caching) 선택
  • Forward Cookies - None(Improves Caching) 선택
  • Query String Forwarding and Caching - Forward all, cache based on whitelist 선택
  • Query String WhiteList - w,h,f,q 를 순서대로 순서대로 적을 것
    (w, enter, h, enter, f, enter, q, enter)
  • Compress Objects Automatically - Yes 선택
  • Create Distribution 선택 후 생성

2. Lambda 의 ARN 추출하기

  • Lambda - resize-image 선택
  • 구분자 - 버전 - 1 선택
  • 상단의 ARN 복사

3. CloudFront - Lambda 연결하기

Lambda Function Associations 을 통해 CloudFront + Lambda 연결

  • CloudFront - Distributions - 생성된 Distribution 선택
  • Behaviors 선택
  • 생성된 Default 클릭 후 Edit 선택
  • 최하단의 Lambda Function Associations 수정
    • CloudFront Event - Origin Response 선택
    • Lambda Function ARN - 추출한 ARN 붙여넣기
    • Yes, Edit 선택

4. CloudFront - Lambda 연결 확인하기

  • Lambda - resize-image 선택
  • 구분자 - 버전 - 1 선택
  • 디자이너 클릭
  • CloudFront - Lambda 가 연결 되어 있으면 정상적으로 진행된 것임

7) S3에 이미지 업로드 후 불러오기

  • 아래 이미지를 로컬에 저장 (image.png)
  • S3 버켓에 업로드 하기
  • CloudFront - Distributions - 생성된 Distribution 선택
  • General - Domain Name 복사

profile
Be proud of yourself.

1개의 댓글

comment-user-thumbnail
2020년 10월 5일

좋은 글 감사드립니다~! 하지만 진행마지막에 테스트도중 오류를 발견하였는데요!
"The Lambda function associated with the CloudFront distribution is invalid or doesn't have the required permissions. We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation." 라는 오류가 발생했는데 혹시 아실까요..?

답글 달기