2019년 1월 18일 금요일

[AWS] EC2 용량 증량, EC2 사용중에 용량 변경하여 적용하기!!!

[AWS] EC2 용량 증량, EC2 사용중에 용량 변경하여 적용하기!!!

개요

  • 용량 증설을 위한 EC2의 EBS(ELASTIC BLOCK STORE) 설정 변경 법
    • EC2 사용중 용량이 가득차서 작업 진행이 안될때 아래와 같이 처리 함
    • 주의! 과금 - EBS 용량이 늘어난 만큼 과금이 더 나온다는 것!

현상

  • 작업중인 기기에 용량이 남아있지 않다고 에러 발생

no left space on device … 류

  • 데이터베이스 Mongodb가 작동 중지를 함

처리

EBS 설정 변경

  • 증설할 EC2에 속하는 EBS 식별값을 확인!

    • EC2 인스턴스 창에서 눌러서는 EBS 가 뭔지 설정 보는 창에서 확인을 할수가 없었다.
  • 그래서 왼쪽 메뉴에서 ELASTIC BLOCK STORE 에서 볼륨으로 이동

    • EC2가 적용될 거 같은 EBS 항목을 행을 누르게 되면 __연결정보__에 링크가 담겨 나옴

  • 이 링크를 누르면 EC2인스턴스로 이동!
  • 이를 통해 연결된 EBS를 확인할 수 있음
  • EBS 용량을 늘릴 해당 행을 마우스 우클릭(또는 해당 EBS 열이 선택된 상태에서 작업 버튼 클릭) 후 볼륨수정 클릭
    • 크기 용량 수치(Giga) 를 수정한다.
      • 주의! 이 변경으로 바로 용량변화는 일어나지 않는다…,
        용량 적용된 EC2에 접속하여 다음 과정을 수행함

EC2 용량 변경 설정

  • 실제 용량 확인

$ df –h

  • 아직 용량 변화를 확인 할 수 없다.

  • 파티션 용량 확인

$ lsblk

  • 파티션에 용량이 어떻게 적용되었는지 확인 할 수 있다.

  • 상위 파티션 xvda 가 위 EBS 설정에서 변경된 값을 확인

  • 파티션 용량 증설

$ sudo growpart /dev/xvda 1

  • 하위 파티션 xvda 1 에 용량을 증설함

  • 파티션 용량 확인

$ lsblk
$ df –h

  • 파티션 용량이 증설 및 현재 용량까지 증설된 것을 확인

  • 주의! 용량이 100%로 가득찬 경우 이 위 명령어도 수행이 안된다! 결국 조금의 용량을 확보하기위해 파일 정리 삭제를 하여 위 작업이 진행될 수 있도록 처리를 해줘야 함
  • 이 방법 외에는 EC2 이미지를 떠서 EC2를 중단하고 다시 만들고 설정하는 방법도 있는 것으로 보여지는데… 위 과정이 속편한 것 같다.

참고자료

2019년 1월 13일 일요일

[AngularJS] scrollTo 페이지 내에서 스크롤 이동 디렉티브

[AngularJS 1] scrollTo 페이지 내에서 스크롤 이동 디렉티브

개요

클릭시 페이지 내에서 스크롤 이동하는 scrollTo 디렉티브 구현!

코드 내용

JS 구문, AngularJS의 디렉티브 내용과 HTML 에서 이를 속성으로 적용하는 방법

JS

angular.module('app', [])
  .directive('scrollTo', function ($location, $anchorScroll) {
    return function(scope, element, attrs) {
    element.bind('click', function(event) {
   event.stopPropagation();
   scope.$on('$locationChangeStart', function(ev) {
     ev.preventDefault();
   });
   var location = attrs.scrollTo;
   $location.hash(location);
   $anchorScroll();
  });
 };
  });

HTML 적용

    <ul>
      <li><a href="" id="top" scroll-to="section1">Section 1</a></li>
      <li><a href="" scroll-to="section2">Section 2</a></li>
      <li><a href="" scroll-to="section3">Section 3</a></li>
      <li><a href="" scroll-to="section4">Section 4</a></li>
    </ul>

~

    <a href="" scroll-to="top" class="back">Back to top</a>
    <h1 id="section1">Hi, I'm a help screen.</h1>

~

    <a href="" scroll-to="top" class="back">Back to top</a>
    <h1 id="section2">Hi, I'm a help screen.</h1>

~

    <a href="" scroll-to="top" class="back">Back to top</a>
    <h1 id="section3">Hi, I'm a help screen.</h1>

~

    <a href="" scroll-to="top" class="back">Back to top</a>
    <h1 id="section4">Hi, I'm a help screen.</h1>


추가 논의 할 점

스크롤 이동시 부드럽게 움직이는 것은 어떻게 연출할까?

2019년 1월 12일 토요일

[AngularJS] $http 이용하여 비동기 POST 요청 csv 파일 부터 엑셀(xlsx) 파일 다운로드 구현!

[AngularJS 1] $http 이용하여 비동기 POST 요청 csv 파일 부터 엑셀(xlsx) 파일 다운로드 구현!

개요

비동기 POST 요청에 의한 파일 다운로드 처리 구현 방식
이때 파일 형식 csv과 엑셀 처리 방식을 조사

구현

기본 CSV 형, xlsx 형

기본 CSV 처리

$http({
    url: '/path/to/your/API',
    method: 'POST',
    params: {},
    headers: {
        'Content-type': 'application/pdf',
    },
    responseType: 'arraybuffer'
}).success(function (data, status, headers, config) {
    // TODO when WS success
    var file = new Blob([data], {
        type: 'application/csv'
    });
    //trick to download store a file having its URL
    var fileURL = URL.createObjectURL(file);
    var a = document.createElement('a');
    a.href = fileURL;
    a.target = '_blank';
    a.download = 'yourfilename.pdf';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
}).error(function (data, status, headers, config) {
    //TODO when WS error
});

출처: https://code.i-harness.com/ko-kr/q/d8e789

  • 비동기 요청으로 파일 다운로드 할 경우가 있는데 위코드를 이용하여
    보이지 않는 a 태그와 응답값의 링크를 만들어서 클릭을 한 것으로 처리 하는 방식으로
    되어 있는 것을 확인(이를 tricky 하다고 함 ㅋㅋ)

  • 잘 보면 Blob 이라는 객체를 이용해서 실제 API 서버 응답값을 이용하여 처리 함.
    더불어 다운로드 이름 정하는 부분으로 a 속성 값을 컨트롤 함.

xlsx 처리

위 csv 처리로 xlsx 처리가 되지 않음. 엑셀 파일 처리 방식

$http({
    url: '/path/to/your/API',
    method: 'POST',
    params: {},
    headers: {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    },
    responseType: 'arraybuffer'
}).success(function (res, status, headers, config) {
    var file = new Blob([res.data], {
       type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    });
    var fileURL = URL.createObjectURL(file);
    var a = document.createElement('a');
    a.href = fileURL;
    a.target = '_blank';
    // 파일 이름 정의 
    a.download = 'DATA-' + moment(startDate).format('YYMMDDThhmmss') + '-' + moment(endDate).format('YYMMDDThhmmss') + '.xlsx';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
}).error(function (data, status, headers, config) {
    //TODO when WS error
});

참고: https://stackoverflow.com/questions/34993292/how-to-save-xlsx-data-to-file-as-a-blob

  • 참고 글에서 atob 함수와 자체 구현한 s2ab 함수를 사용해서 다운로드 처리하는 부분이 있었으나 시도했을때 파일 형식이 맞지 않아 파일이 열리지 않았음

  • 내용 중에 type: ‘application/vnd.openxmlformats-officedocument.spreadsheetml.sheet’ 타입 처리와 결과 데이터 자체를 별다른 처리 없이 수행하는 것으로 처리 하여 위 코드 구현

결론

  • 응답 파일을 Blob 으로 변환

  • URL.createObjectURL 이용하여 가상의 객체 링크를 생성

  • document.createElement 이용하여 가상의 a 태그 생성

  • a 속성 href 생성한 링크, target 으로 ‘blank’ 속성 지정

  • a 속성으로 download 로 파일 명 지정!!

  • a 태그 click 메소드 호출로 다운로드 하도록 트리거!

  • 생성한 a 태그 결과 document.body.removeChild 이용 해당 생성 a 태그 내용 삭제

  • 이 방법 외에 더 효율이며 정석적인 처리 방식은 있는가?

2019년 1월 10일 목요일

[AWS] Lambda 이미지 리사이징 함수 구현

[AWS] Lambda 이미지 리사이징 함수 구현

[AWS] Lambda 이미지 리사이징 함수 구현

이미지 리사이징 함수 구현을 AWS Lambda로 구현해 본다.
이미지 리사이징이라함은 AWS S3에 업로드한 이미지 객체에 대해서 thumbnail 이미지를 만드는 것이다.
썸네일 이미지의 기준 사이즈를 가로 100px을 기준으로 한다.
참고자료는 다음과 같다.

Lambda 콘솔에서 자유롭게 하려 했으나 자습서 내용에는 AWS CLI 로 기술되어 있기에 AWS CLI를 우선적으로 설치한다.

AWS CLI 설치법

Lambda 사용법

Node.js 배포

  • 자습서 자료: https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/nodejs-create-deployment-pkg.html
    Node.js 배포 패키지 생성에 대해
    위 내용은 결국 Lambda 올릴경우 패키지를 설치한 형태로 업로드가 되야함 디렉토리를 생성하고
    이 하위에 필요 패키지를 npm으로 설치한다. node_modules 생성 후 원하는 Lambda 함수 작동 코드를 index.js를 생성한다. 이를 압축하여 Lambda 콘솔에 업로드함.

예를들면 다음과 같다.
디렉터리는 다음의 구조를 갖게 됩니다.

index.js
node_modules/async
node_modules/async/lib
node_modules/async/lib/async.js
node_modules/async/package.json`

폴더의 내용을 압축하여 (배포 패키지) 업로드 후 테스트 수행 하고 문제 없을 시 트리거 등 실제 원하는
이벤트와 연결하여 사용!!!

테스트를 수행하여 제대로 동작 하는 것을 확인을 꼭 해야함! 안그럴 경우 트리거 또는 실전 연결하여 람다를 활용할 경우 문제 상황을 제대로 파악하기 어렵다… 왜냐하면 따로 로그 파악이 어려워서… cloudWatch 인가 이거 잘 이용하면 파악 된다던데…

S3 관련 과정은 다음과 같다.

사용 사례

위 과정을 통해 진행되며 이 포스트에서는 “2.1단계 배포 패키지 생성” 이후를 설명한다.
자세히 잘 설명 되어 있는데 디테일한 설정들이 많고 자기 상황에 맞는 부분을 정확히 수정해야하기 때문에
정신 바짝 차리고 해당 단계를 수정해 봐야한다.

aws cli 명령어 - 현재 lambda 함수 리스트

$ aws lambda list-functions --profile adminuser

명령어를 수행하면 현재 만들어진 람다의 함수 목록이 조회됨.

aws cli 명령어 - 배포

$ aws lambda create-function \
--region ap-northeast-2 \
--function-name CreateThumbnail \
--zip-file fileb:///Users/slicequeue/workplace/nodejs/lambda/ePROImageResizer.zip \
--role arn:aws:iam::075583837999:role/pro-lambda-s3-execution-role \
--handler CreateThumbnail.handler \
--runtime nodejs \
--profile adminuser \
--timeout 10 \
--memory-size 1024

이러한 명령어는 .zip 파일 업로드 뿐 아니라 역할 설정(이는 자습서 내용에서 실행 역할 생성 부분에 언급된 역할 생성 후 arn 값을 따로 기록해 두라고 되어 있는 부분에 내용임), handler 및 실행 환경 내용(nodejs) 등 기타 설정 내용이 믿음직 스럽게 담겨있다.
람다 콘솔에서 해보려고 하면 잘 설정이 안될때가 많았음.

Node.js 람다 이미지 리사이징 수행 코드

이미지 리사이징 수행 Node.js 코드는 aws 에서 예제로 되어 있는 코드를 변경하여 구현하였다.
자습서에 나와있는 코드는 버킷을 달리 두고 한쪽 원본 이미지가 들어오는 버킷에서 이미지가 업로드 된 경우
이미지 썸네일을 만들고 이후에 썸네일용 버킷에 옮겨 담는 예제이다.

nodejs 전체 코드 내용은 다음과 같다.

createThumbnail.js

// 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;

var PREFIX_THUMB = 'thumb-';

// 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    = PREFIX_THUMB + srcKey;
    
    console.log('>>', dstKey);

 //! 이부분 기존 코드 부분 같은 버킷에 위치하는 것으로 하고 싶기에 삭제
    // 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].toLowerCase();
    if (imageType != "jpg" && imageType != "png" && imageType != "jpeg") {
        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
                    //,ACL:'public-read'
                },
                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");
        }
    );
};

기존 코드에는 몇가지 제한사항이 있었다. jpg 파일 확장자가 어떨때는 JPG, JPEG 등 다른 값으로 들어올 때가 있었다. 이때 동작을 하지 않도록 파일 확장자 검사 부분을 수정하였다.

    var imageType = typeMatch[1].toLowerCase();
    if (imageType != "jpg" && imageType != "png" && imageType != "jpeg") {
        callback('Unsupported image type: ${imageType}');
        return;
    }

더불어 버킷을 두개를 운영해야하는 것을 원치 않아 하나의 버킷에서 동작하도록 버킷의 특정 폴더 내에서 이미지 업로드를 통해 객체가 생성될 경우 이미지 썸네일을 만들고 이를 다른 폴더로 저장시키는 코드로 수정하였다.

var PREFIX_THUMB = 'thumb-';
~

var dstKey    = PREFIX_THUMB + srcKey;

위의 변경 사항은 아래 Lambda의 트리거 연결 과정에서 추가 설정을 통해 코드가 제대로 동작 하도록 한다.

앞서 설명한 zip 파일로 만들어 배포를 수행 하였다.
필요 패키지는 gm, async 를 설치해야 하며 파일 구성은 다음과 같다.

CreateThumbnail.js 
/node_modules/gm 
/node_modules/async

주의! 이 파일 폴더 목록을 포함하여 그 위치에서 압축 수행해야함!
이 파일을 포함하는 폴더 자체를 압축하면 안됨!

이 nodejs 배포용 zip 파일을 업로드 하게 되면 Lambda 콘솔 페이지에서 함수 부분에 코드 편집 창 부분에 소스코드가 깔끔하게 올라와 진 것을 확인 할 수 있다! 뿌듯!

테스트

업로드 후에 기능이 제대로 되는지 확인을 해야함
테스트는 Lambda 콘솔의 상단 메뉴에 테스트 부분이 있고 옆에 테스트 종류를 나타내는 드롭다운 메뉴가 있음
이 드롭다운을 클릭하여 테스트 생성을 하게 되면 창에 해당 템플릿을 선택 할 수 있다.

여기서 기존에 업로드한 이미지 객체와 버킷 정보를 담아 생성을 하면 다음과 같다.

{
  "Records": [
    {
      "eventVersion": "2.0",
      "eventSource": "aws:s3",
      "awsRegion": "ap-northeast-2",
      "eventTime": "1970-01-01T00:00:00.000Z",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "EXAMPLE"
      },
      "requestParameters": {
        "sourceIPAddress": "127.0.0.1"
      },
      "responseElements": {
        "x-amz-request-id": "EXAMPLE123456789",
        "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
      },
      "s3": {
        "s3SchemaVersion": "1.0",
        "configurationId": "testConfigRule",
        "bucket": {
          "name": "smcepro.com",
          "ownerIdentity": {
            "principalId": "EXAMPLE"
          },
          "arn": "arn:aws:s3:::smcepro.com"
        },
        "object": {
          "key": "symptom-images/KakaoTalk_Photo_2017-10-12-01-29-31.jpeg",
          "size": 1024,
          "eTag": "0123456789abcdef0123456789abcdef",
          "sequencer": "0A1B2C3D4E5F678901"
        }
      }
    }
  ]
}

테스트 설정에서 아래 부분 버킷 이름과 오브젝트 이름에서 키값을 잘 설정해 줘야 테스트가 진행된다.

"bucket": {
          "name": "smcepro.com",
          "ownerIdentity": {
            "principalId": "EXAMPLE"
~
"object": {
          "key": "symptom-images/KakaoTalk_Photo_2017-10-12-01-29-31.jpeg",
          "size": 1024,
          "eTag": "0123456789abcdef0123456789abcdef",
          "sequencer": "0A1B2C3D4E5F678901"
        }

요청 송신시 제대로 요청이 될 경우 콘솔 페이지 부분에서 오류가 나지 않으며 실제 버킷에 가보면 리사이징 된 thumb- 폴더에 제대로 객체가 리사이징 된 결과물이 업로드 되어 있다.
이제 제대로 S3의 버킷에 특정 폴더에 이미지 파일이 객체로 생성될 때 그때 이벤트를 후킹하여 트리거 되도록 설정해보자!

함수 트리거 연결

이는 Lambda 콘솔의 함수 페이지에서 상단에 보여지는
함수에 엮여 있는 역할과 트리거 들에 대해 효과적으로 시각화되어 표현된다.
앞서서 배포 aws cli lambda 배포 명령어를 통해 역할들이 잘 지정되어 있다.

AWS 람다 이미지

이미 추가 해둔 것이긴 하지만 왼쪽편에 트리거 추가가 잘 나와있다. 자습서에는 이 부분도 cli로 처리할 것 같은데 그냥 콘솔 화면에서 처리해 보자!

트리거에 S3 를 클릭하면 우리가 원하는 이벤트 유형과 접두사 부분이 보여진다.

  • 버킷: 원하는 버킷을 선택한다.
  • 접두사: 우리는 원하는 특정 폴더의 생성 이벤트를 감지하고 싶기 때문에 “해당폴더이름/” 으로 접두사를 설정하자.
  • 접미사: 원하는 파일 형식의 끝값이 생성되는 오브젝트의 키값으로 오는 경우 지정 할 수 있으나 .jpg .jepg, .png 등등 다수가 있기 때문에 위 코드에 해당 형식 검사에 있으므로 생략한다. (여러개 접미사 지정은 어떻게 하지… 띄어쓰기 콤마로 될려나!?..)
  • 하단부 트리거 활성화: 체크를 한다. 아무래도 활성화를 해야지만이 제대로 연결되서 배포가 되겠지? 우리는 테스트로 문제 없는 것을 확인 했기 때문에 문제 없다고 판단.
  • 이 멘트 상단 “Lambda는 Amazon S3이(가) 이 트리거에서 Lambda 함수를 호출하는 데 필요한 권한을 추가합니다. Lambda 권한 모델에 대해 자세히 알아보기.” 요부분이 있다. 얼마나 고마운지~

이렇게 설정이 끝나면 꼭 상단에 저장 을 눌러야지만 생성이 된다.
생성을 마치고 실제 S3의 해당 버킷에 가서 속성에 이벤트 설정 부분을 가보면 해당 이벤트가 생성된 것을 확인 할 수 있다.

주의! 위 설정이 엉키거나 생성 후 삭제를 하다가 잘 못된 경우 이 부분이 삭제되지 않고 남을 때가 있어서 트리거 생성이 겹쳐서 안되는 에러가 발생 될 경우가 있다. 이경우 버킷에 가서 직접 이 이벤트를 삭제하고 다시 트리거를 설정하면 다시 생성 된다.

실전 배치가 끝났다. 제대로 동작하는 지는 lambda 대쉬보드에서 확인하자! 실제 서비스로 이미지 업로드를 수행하여 테스트를 하면 대쉬보드에서 그래프로 모니터링이 된다.

[Android] WebView 화면 시스템 글꼴 크기에 영향 없이 폰트 내용 나오도록 설정

[Android] WebView 화면 시스템 글꼴 크기에 영향 없이 폰트 내용 나오도록 설정