linux node app 백그라운드 실행

1
nohup npm start &
  • ec2에서 24시간 돌아가는 웹 앱을 돌릴일이 생겼다
  • 그런데 처음에 그냥 마지막에 &만 붙여주면 되겠지 하고
  • npm start & 명령을 치고 리모트를 종료했더니, 리모트를 종료하는 순간 앱 실행도 멈췄다
  • 왜 그런가 했더니 단순히 &을 붙이고 실행한 프로세스는 터미널이 종료하면 같이 꺼진다고 한다

nohup

  • 리눅스에서는 특별한 패키지 설치없이도 완전한? 백그라운드 실행을 가능하게해주는 명령이 있다
1
2
nohup npm start &
exit
  • 이렇게 실행하고 exit을 눌러 나와주면 터미널이 자동으로 닫힌다
  • 하지만 앱은 계속해서 실행되고 있다
  • exit 은 nohup이랑 관계없고, 그냥 터미널을 종료하는 명령이다
  • nohup 명령 후 아무키나 누르면 다시 터미널을 사용할 수 있는 상태가 된다

참고

ec2 web app https 적용하기

  • 웹에서 위치정보를 활용하고 싶어서 geolocation을 사용했는데,
  • geolocation은 localhost 또는 https에서만 동작했다
  • 위치정보를 활용하는 이 앱을 다른사람들에게 배포하기 위해서는 https를 사용했어야 했다
  • 삽질을 많이했는데, 어떻게 하는지 정리한다. 할게 쫌 많고, 중간중간 대기시간이 길다
  • 처음부터 끝까지 무료로 하는 법이다
  • 따라하면 ec2에서 express로 돌아가는 웹앱에 https를 적용할 수 있다

내가 시도한 환경

  • aws 프리티어
  • ec2 (아마존 리눅스 2)
  • 탄력적 IP
  • 주의사항 ; 탄력적 IP는 1개까지 무료다. 탄력적 IP를 사용하면 연결된 ec2 인스턴스를 종료해서는 안된다. 인스턴스는 매월 750시간 무료다. 이 인스턴스를 제외하고 다른 인스턴스를 실행하면 비용이 생길 수 있다

해야할일 목록…

  • express 웹 앱준비
  • ec2 보안그룹 인바운드 설정 (http, https, 앱에서 사용하는 포트 열기)
  • ec2에 탄력적 IP 할당
  • ACM(AWS Certificate Manager)에서 SSL/TLS 인증서 발급요청
  • freenom에서 도메인 얻기
  • cloudflare 가입하고 사이트 추가
  • freenom dns 설정 및 SSL/TLS 인증서 발급 완료
  • freenom에서 cloudflare로 네임서버 변경
  • aws 애플리케이션 로드 밸런서 생성
  • cloudflare dns 설정

따라하기

express 웹 앱 준비

terminal
1
2
3
express https-web-app --view=ejs
cd https-web-app
npm i
  • 간단하게 익스프레스 제너레이터로 웹앱을 생성한다
  • 새로 생성하거나 기존에 있는 웹앱을 ec2 인스턴스에 올려준다
terminal
1
export PORT=8080&& node ./bin/www
  • 앱을 실행한다
  • 나는 익스프레스 제너레이터로 만들었기때문에 process.env.PORT로 8080값을 줘서 8080포트로 앱이 실행되도록 하였다

ec2에 탄력적 IP 할당

  • ec2 > 탄력적 IP 주소 > 탄력적 IP 주소 할당
  • 방금 앱을 실행한 인스턴스를 선택하고 할당해준다
  • 주의 : 탄력적 IP를 할당한 이상 연결된 EC2가 종료되어 탄력적 IP에 아무것도 연결되어 있지 않으면 비용이 발생한다
  • 또, 탄력적 IP는 1개까지 무료이다. EC2도 이제부터 매일 돌아가게됨(750시간 무료)으로 사실상 실행할 수 있는 인스턴스는 1개로 제한된다

ec2 보안그룹 인바운드 설정 (http, https, 앱에서 사용하는 포트 열기)

  • 앱이 실행되고있는 ec2 인스턴스 보안그룹으로 들어가 인바운드 규칙을 편집한다
  • http와 https를 어디서나 접근가능하게 한다
  • 또 앱을 실행 포트도 어디선 접근가능하게 한다. 나의 경우 8080포트이다

freenom에서 도메인 얻기

  • 내가 도메인을 얻을 때 이사이트가 엄청나게 느리기때문에 많은 인내가 필요하다..

  • 수시로 404 not found가 뜬다…

  • 새로고침을 몇번했는지 모르곘다

  • freenom에서 나는 처음 도메인을 얻어봤다

  • 그런데 여기서 삽질한 것이

  • 당연히 회원가입을 먼저하고 도메인을 얻는 것인줄 알았으나,

  • 도메인을 얻는 과정에서 체크아웃을 하면서 회원가입을 진행해야 정상 진행된다

  • 원하는 도메인을 입력한다
  • FREE 라벨이 붙은것중에서 원하는 것을 선택한다

  • 원하는 도메인을 선택하면, 체크아웃 버튼이 생긴다
  • 체크아웃버튼을 눌러준다

  • 기간을 선택하고 Continue버튼을 누른다

  • 여기서 드디어 회원가입을 진행한다..
  • 나는 왼쪽 이메일 인증을 선택하였다
  • 이메일 입력하고 버튼을 누르면, 해당 메일로 인증 url이 날라오는데 클릭해서 다음을 진행한다

  • 이렇게 회원가입폼이 나오는데 빨간부분을 채워주고 동의체크하고 완료한다
  • 이렇게 무료로 도메인 얻기에 성공했다
  • 이제 aws로 돌아와서 무료로 인증서를 발급받아보자

ACM(AWS Certificate Manager)에서 SSL/TLS 인증서 발급요청

  • ACM(AWS Certificate Manager)에서 인증서 요청 > 공인 인증서 요청 으로 들어간다

  • 도메인 이름을 추가한다
  • 나는 이 인증서에 다른 이름 추가 버튼을 통해 *.domainname 도 추가해줬다

  • 검증 방법으로 DNS 검증을 선택한다
  • 다음 검토 화면은 그냥 확인

  • 마지막 단계 검증 화면에서 조금 기다리면 이런 화면이 나온다
  • 도메인 이름 옆에 펼치기 버튼을 클릭해주면 이름 유형 값이라는 게 나오는데
  • 이 값들을 freenom dns 설정에서 레코드로 추가해줄 것이다

freenom dns 설정 및 SSL/TLS 인증서 발급 완료

  • freenom 사이트로 돌아와서 로그인하고
  • 상단 메뉴에 Services > My domains 클릭
  • Manage Domain 버튼을 클릭하고 Manage Freenom DNS를 클릭한다

  • 위같은 화면이 나오면 아까 ACM에서 봤던 이름과 값들을 채워준다
  • 주의 : 타입을 CNAME으로 한다
  • 위와같이 매칭시켜주면된다
  • 나는 *.domainname으로 추가 이름을 지정해줬는데 이 경우에는 이름과 값이 완전히 똑같기 때문에 한개의 레코드만 설정해주면된다
  • *이 아니고, www. 같은 이름을 추가한 경우에는
  • 레코드를 하나 더 추가하고 똑같이 매칭시켜서 입력해주면 된다
  • 저장한다

  • 이제 ACM으로 돌아와서 인증서 상태가 발급 완료로 변할때까지 기다리면서 유튜브 한편을 보고온다
  • 나는 약 5-10분정도 기다린 것 같다
  • 만약에 20분이 넘도록 검증 보류 상태라면 뭔가 잘못 따라한 것이다
  • 이제 DNS 네임서버를 cloudflare로 바꿀 것이다

cloudflare 가입하고 사이트 추가

  • 회원가입한다

  • 회원가입을 완료하면, 사이트를 추가할 수 있는데, 내 도메인을 입력한다

  • 다음화면에서 Free를 선택하고 넘어간다

  • 넘어오면 이렇게 스캔하는 화면이 나온다

  • 스캔이 완료되면 이런화면이 나오는데, 비어있다면,
  • 아까 freenom에서 dns 설정한것처럼 똑같이 타입을 cname으로 하여 이름, 값을 넣어준다
  • 완료했다면 다음화면을 넘어간다

  • 그러면 네임 서버를 바꾸라는 말이 나온다
  • 이제 freenom사이트로 돌아가서 네임서버를 변경해보자

freenom에서 cloudflare로 네임서버 변경

  • 상단 메뉴에 Services > My domains 클릭

  • Manage Domain 버튼을 클릭하고 Management Tools > Nameservers를 클릭한다

  • 네임 서버를 변경해준다

  • 성공하면, cloudflare화면으로 돌아와서 완료를 눌러준다

  • 이런화면이 나오는데 나는 항상 https 옵션을 켜주고 완료해주었다

  • 해당 사이트의 개요화면으로 넘어가는데 만약에 이런화면이 나오는데 1~5분정도 기다리면,

  • 이런 화면으로 바뀐다
  • 이제 aws로 돌아와 로드 밸런서를 생성해줄 것이다

aws 애플리케이션 로드 밸런서 생성

  • ec2 > 로드 밸런서 > 로드 밸런서 생성 > 애플리케이션 로드 밸런서 생성

  • 이름을 정해주고, 리스너에서 https를 추가해준다

  • 가용영역 체크하고 다음으로 넘어간다

  • 발급받은 도메인 인증서를 선택하고 다음으로 넘어간다

  • ce2 인스턴스가 속해있는 보안그룹을 선택한다

  • 적당히 이름을 짓고,
  • 포트에서 내 앱이 사용하고있는 포트를 입력하고 다음으로 넘어간다

  • 내 앱이 실행되고있는 인스턴스를 선택하고
  • 등록된 항목에 추가 버튼을 누른다
  • 그러면 3이라고 표시한 주황색 박스에 해당 인스턴스가 추가되는 걸 확인할 수 있다
  • 검토화면에서 다음버튼

  • 로드밸런서 메인화면으로 넘어와지면 생성된 로드밸런서의 DNS이름을 복사한다
  • 이제 cloudflare dns 설정만 하면 끝이다!

cloudflare dns 설정

  • cloudflare에 와서 위처럼 새로운 레코드를 추가하고 타입은 CNAME, 이름은 @, 대상은 방금 복사한 로드밸런서 DNS이름을 넣어주고 저장을 누르면 완료다

  • 이제 자신의 도메인으로 접속을 해보면…
  • https..!

여기서 잠깐..!

  • 처음에 npm start로 웹 앱을 실행시켰는데
  • 이러면 ec2 리모트를 종료하는 순간 앱도 같이 종료된다
  • nohup export PORT=8080&& node ./bin/www & 이런식으로 실행해야 ec2 리모트를 종료해도 웹 앱이 계속 살아 있다
  • 참고 ; linux node app 백그라운드 실행

참고

ubuntu ec2 remote-ssh 튕김

  • 아마존 리눅스는 안튕기는데 ubuntu는 튕긴다…
  • vscode remote - ssh 를 통해 리모트했다
  • 처음에 연결이 잘되지만 한 1분 정도사용하면 튕긴다

윈도우에서 aws ec2 keypair 설정

  • 윈도우 10에서 aws ec2를 리모트할 때 .pem파일의 권한을 아무나 볼 수 없게 설정해줘야 한다
  • 관리자만 볼 수 있도록 설정해야 리모트를 할 수 있다
  • 속성 > 보안탭 > 고급 > 상속사용안함 > 명시적 사용 권한 > SYSTEM, Administrators 남기고 다 삭제 > 확인 > 확인
  • SYSTEM, Administrators만 남은걸 확인한다

aws 아마존 리눅스2 인스턴스 생성 및 리모트

  • ec2 인스턴스를 하나 만들고, vscode로 원격접속해보겠다

따라하기

준비물

  • ec2 keypair
  • vscode

ec2 인스턴스 생성하기

 ec2 > 인스턴스 > 인스턴스 시작 버튼 클릭
 AMI 선택
 인스턴스 유형 선택. 기본값 사용. 검토 및 시작 버튼 클릭
 시작하기 버튼 클릭
 키페어를 생성하거나 기존 키페어 사용

  • 예전에는 인스턴스 하나 생성하는 것도 겁이 났었는데, 지금은 옵션 안보고 그냥 기본값으로 생성..

ec2 인스턴스 리모트하기

  • ssh 클라이언트로 푸티 putty가 대표적이다
  • 근데 나는 푸티는 잘 안쓰고… vscode의 Remote - SSH 확장도구를 사용한다
  • vscode를 관리자권한으로 실행한다. (열려있는 vscode가 있다면 모두 종료하고 관리자 권한으로 새로 실행한다)

 확장도구가 안깔린 경우 설치한다

  • Ctrl + Shift + P 를 눌러 커맨드창을 열고 remote를 입력하고,
  • Remete-SSH: Connect to Host... 를 누른다

 Configure SSH Hosts... 클릭

 Users\user.ssh\config 클릭

.ssh\config
1
2
3
4
5
# Read more about SSH config files: https://linux.die.net/man/5/ssh_config
Host ec2-asdf
HostName ec2-0-00-000-000.ap-northeast-2.compute.amazonaws.com
User ec2-user
IdentityFile "C:\key\KeyPair.pem"
  • config 파일을 채워줘야하는데,

  • 브라우저로 ec2 인스턴스 화면으로 돌아가서 우클릭 연결을 누른다

  • 위 화면에서 복사를 해서 붙여넣어주면된다
  • HostName에 ec2-0-00-000-000.ap-northeast-2.compute.amazonaws.com
  • User에 @앞에 있는 유저명을 적어주면된다. 나는 ec2-user가 기본값이 였다
  • Host에는 그냥 자기가 원하는 식별문자를 적어주면된다. 나는 아무렇게나 ec2-asdf로 했다
  • IdentityFile에는 키페어 .pem 파일의 경로를 적어주면된다. 절대경로를 사용했다
  • Ctrl + S 로 저장한다
  • 참고 : HostNameec2-0-00-000-000.ap-northeast-2.compute.amazonaws.com 이 값은 인스턴스를 중지했다가 다시켜면 바뀐다. 다음번에 접속할 때 탄력적 IP를 사용하는게 아니라면 계속 수정하면서 접속해야한다

  • Ctrl + Shift + P 를 눌러 커맨드창을 열고 Remote-SSH: Connect to Host를 실행하고
  • 방금 설정한 호스트가 보일 것이다. 클릭한다
  • 그러면 새창이 열린다
1
2
3
4
5
6
[14:56:31.053] > @         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
> @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
> Permissions for 'C:\\key\\KeyPair.pem' are too open.
> It is required that your private key files are NOT accessible by others.
> This private key will be ignored.
> Load key "C:\\key\\a.pem": bad permissions

  • 운영체제를 고르라고하는데 당연히 리눅스를 선택한다

  • 이렇게 vscode로 리모트에 성공했다

  • 폴더를 열어보자. 나는 홈디렉터리를 열어보겠다
  • 그러면 창이 리로드 되면서 좌측 탐색기가 업데이트된다
terminal
1
2
3
mkdir a b c

ls
  • mkdir 로 a,b,c 3개의 디렉터리를 생성한다

  • 그러면 좌측 탐색기도 업데이트되는게 보일 것이다. 끝!

rds sqldump 하기

cmd
1
2
3
4
5
6
7
8
mysqldump -h database-1.aaaaaaaaaaaa.ap-northeast-2.rds.amazonaws.com ^
-u root ^
-p12341234 ^
--port=3306 ^
--single-transaction ^
--routines ^
--triggers ^
--databases TestDB > aaaa.sql
  • 윈도우 cmd에서 aws rds mysqldump를 해보았다

윈도우 따라하기

  • cmd를 관리자 권한으로 실행한다
cmd
1
cd C:\Program Files\MariaDB 10.5\bin
  • mysqldump.exe가 있는 경로까지 이동한다. (나는 로컬에 마리아 디비가 설치되어 있어서..)
cmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysqldump -h {rds 엔드포인트} ^
-u root ^
-p{rds 비밀번호} ^
--port=3306 ^
--single-transaction ^
--routines ^
--triggers ^
--databases {db명} > {백업파일위치}

mysqldump -h database-1.aaaaaaaaaaaa.ap-northeast-2.rds.amazonaws.com ^
-u root ^
-p12341234 ^
--port=3306 ^
--single-transaction ^
--routines ^
--triggers ^
--databases TestDB > aaaa.sql
  • 자신에 맞게 설정하고 명령을 붙여넣는다

RDS 비공개하는 방법

  • 내 RDS 지키기
  • 내가 지정한 IP에서만 접근가능하도록 설정하자

따라하기

  • 설정하고싶은 RDS 화면에 들어간다
  • 연결 & 보안 > 보안 > vpc 보안 그룹
  • 을 눌러서 현재 rds에 적용되어 있는 보안그룹 설정으로 들어간다
  • 인바운드 규칙 > 인바운드 규칙 편집으로 들어간다
  • 아마 이런식으로 위치무관으로 되어있을 수 있는데
  • 이 규칙으로 인해 모든 컴퓨터에서 접근가능하게 해준다
  • 이 규칙을 이제 내 컴퓨터에서만 접근가능하도록 고쳐보자
    1. MySQL/Aurora 를 선택해서 포트를 제한한다
    1. 소스 유형에 내 IP 를 선택한다
    1. 내 공인 IP 주소로 바뀌었는지 확인한다
  • 이렇게하면 내 IP에서 MySQL 접근 포트인 3306 포트로만 접근을 허용하는 세팅이 된 것이다
  • 규칙 저장을 눌러 적용시켜준다
  • 끝!

sam template.yaml 익히는 빠른 방법

  • 브라우저에서 aws console 통해 람다 수정해보고
  • 작업 > 내보내기 > aws sam 파일 다운로드 하기
  • 여기서 aws sam 파일template.yaml이다

익히는 법

  • 처음에 할때는 gui만큼 쉬운게 없다
  • sam을 시작하면 yaml을 어떻게 건드려야할지 감이 안올 것이다
  • 그럴때는 역으로 브라우저에서 내가 설정할 권한들을 설정하고 저장한다
  • 그리고 작업 > 내보내기 > aws sam 파일 다운로드를 통해 어떻게 yaml이 수정되었는지 확인해보면 된다

sam에서 노드 모듈을 레이어로 빼기

  • 람다는 가벼운게 최고다
  • 노드 모듈은 따로 빼버리기!

Lambda Layer

  • nodejs로 치면 node_modules이다
  • 람다 함수에서 노드 모듈같은 종속성을 람다 함수 밖에으로 뺄 수 있음
  • 왜 쓰냐?
      1. 공통적으로 쓰이는 패키지들을 묶어서 관리할 수 있음
      1. 람다함수가 커지면 브라우저로 aws console에서 코드 조회를 못함

따라하기

외부 모듈을 사용해보기

  • sam template.yaml에서 layer설정할 수 있다
  • 지난번에 만든 hello world에서 이어서 진행해 보겠다
hello-world/app.js
1
2
3
// const axios = require('axios')
// const url = 'http://checkip.amazonaws.com/';
let response;
hello-world/app.js
1
2
3
const axios = require('axios');
const url = 'http://checkip.amazonaws.com/';
let response;
  • 맨 윗 2줄 주석 해제한다
hello-world/app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
exports.lambdaHandler = async (event, context) => {
try {
// const ret = await axios(url);
response = {
statusCode: 200,
body: JSON.stringify({
message: 'hello world',
// location: ret.data.trim(),
}),
};
} catch (err) {
console.log(err);
return err;
}

return response;
};
hello-world/app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
exports.lambdaHandler = async (event, context) => {
try {
const ret = await axios(url);
response = {
statusCode: 200,
body: JSON.stringify({
message: 'hello world',
location: ret.data.trim(),
}),
};
} catch (err) {
console.log(err);
return err;
}

return response;
};
  • 여기도 2곳 주석을 해제한다

package.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"name": "hello_world",
"version": "1.0.0",
"description": "hello world sample for NodeJS",
"main": "app.js",
"repository": "https://github.com/awslabs/aws-sam-cli/tree/develop/samcli/local/init/templates/cookiecutter-aws-sam-hello-nodejs",
"author": "SAM CLI",
"license": "MIT",
"dependencies": {
"axios": "^0.18.0"
},
"scripts": {
"test": "mocha tests/unit/"
},
"devDependencies": {
"chai": "^4.2.0",
"mocha": "^6.1.4"
}
}
  • 필요없는 devDependencies 를 없앤다
  • test 할때 필요한 패키지인데, 우리는 안쓸거다
package.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"name": "hello_world",
"version": "1.0.0",
"description": "hello world sample for NodeJS",
"main": "app.js",
"repository": "https://github.com/awslabs/aws-sam-cli/tree/develop/samcli/local/init/templates/cookiecutter-aws-sam-hello-nodejs",
"author": "SAM CLI",
"license": "MIT",
"dependencies": {
"axios": "^0.18.0"
},
"scripts": {
"test": "mocha tests/unit/"
}
}
  • 없애면 이런 모양이 된다

cmd
1
2
cd hello-world
npm i
  • app.js가 있는 hello-world 디렉터리로 와서 종속성을 설치한다
1
2
3
4
5
6
7
8
9
10
11
12
13
.
├── .aws-sam/
├── events
│ └── event.json
├── hello-world
│ ├── node_modules/
│ ├── tests/
│ ├── .npmignore
│ ├── app.js
│ └── package.json
├── .gitignore
├── README.md
└── template.yaml
  • node_modules 폴더가 생기면서 현재 디렉터리 구조는 이렇게 된다
  • hello-world/tests 폴더를 삭제한다. 우리는 안쓴다
  • events 폴더를 삭제한다. 우리는 안쓴다
  • .aws-sam 폴더를 삭제한다. 이 폴더가 있으면 local start-api 했을때 .aws-sam를 우선 참조하기때문에 소스 코드에 변경사항이 발생해도 반영되지 않는다
1
2
3
4
5
6
7
8
9
.
├── hello-world
│ ├── node_modules/
│ ├── .npmignore
│ ├── app.js
│ └── package.json
├── .gitignore
├── README.md
└── template.yaml
  • 현재까지 디렉터리 구조는 이렇게 된다

cmd
1
2
cd ..
sam local start-api --skip-pull-image
cmd log
1
2
3
4
5
6
7
C:\tmp\hello-world\hello-world>cd ..

C:\tmp\hello-world>sam local start-api --skip-pull-image
Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM
CLI if you update your AWS SAM template
2020-09-21 14:49:47 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
  • 이렇게 location에 자신의 공인 IP가 뜨면 성공이다

  • 주석 해제한 소스 코드는

  • axios라는 모듈로 http://checkip.amazonaws.com/ 에서 공인 ip를 얻어와 response 객체에 location이라는 이름으로 담아서 반환한 것이다

  • http://checkip.amazonaws.com/ 에 접속해 보면 알 수 있듯이 자신의 공인 ip를 알려주는 api다

  • 여기까지 axios라는 모듈을 이용해봤다

  • 이제 sam build & sam deploy 를 통해 aws에 올려보자

cmd
1
sam build & sam deploy
  • 배포가 완료되면 엔드 포인트를 통해서 aws에 올린 람다를 실행해보자
  • 그러면 이상한 아이피가 나온다
  • 이게 aws 컴퓨터중에서 현재 람다가 실행된 컴퓨터의 공인 ip 주소이다
  • 여기까지 잘 작동되는 것이 확인 되었다

외부 모듈을 layer로 빼기

  • 이제 브라우저를 열고 aws console > lambda > HelloWorldFunction 으로 가서 함수가 어떻게 생겻는지 확인한다
  • 함수 안에 노드 모듈이 포함되어 있는 것을 확인할 수 있다
  • 이제 이 글의 핵심인 node_modules 폴더를 layer로 빼볼것이다
  • 레이어를 만드는 방법이 여러가지가 있지만 나는 내 방식을 설명해 보겠다
  • 나는 cmd명령을 사용할 것이다

  • template.yaml에서 빨간 네모 부분을 추가한다
template.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
hello-world

Sample SAM Template for hello-world

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3

Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
Layers:
- !Ref DependencyLayer
CodeUri: hello-world/
Handler: app.lambdaHandler
Runtime: nodejs12.x
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
DependencyLayer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: HelloWorldFunction-layer
Description: Dependencies for HelloWorldFunction
ContentUri: opt/
CompatibleRuntimes:
- nodejs12.x
RetentionPolicy: Retain

Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: 'API Gateway endpoint URL for Prod stage for Hello World function'
Value: !Sub 'https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/'
HelloWorldFunction:
Description: 'Hello World Lambda Function ARN'
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: 'Implicit IAM Role created for Hello World function'
Value: !GetAtt HelloWorldFunctionRole.Arn
  • 최종코드는 이러하다
  • 눈여겨 봐야할 것은
  • Resources아래에 DependencyLayer라는 이름으로 layer정의하고
  • ContentUri: opt/ 를 지정한다. 이 opt 디렉터리에 우리가 layer로 따로뺄 패키지가 들어가게 될것이다
  • 이제 배치파일을 2개 만들거다
layer.bat
1
2
3
4
5
6
7
echo layer process

set functionDir=HelloWorldFunction

echo y|rmdir /s opt\nodejs
mkdir opt\nodejs
move .aws-sam\build\%functionDir%\node_modules opt\nodejs
  • layer.bat을 sam project 최상위에 만들고 내용은 위와같이 한다
  • set functionDir=HelloWorldFunction 에서는 template.yaml에서 지정한 함수명을 적어주면 된다. template.yaml을 안거드렸으면 HelloWorldFunction이니까 그대로 사용하면 된다
template.yaml
1
2
3
Resources:
HelloWorldFunction: // <- 이름과 매칭되도록
Type: AWS::Serverless::Function
deploy.bat
1
2
3
echo deploy

sam build & layer.bat & sam deploy
  • 또 deploy.bat을 sam project 최상위에 만들고 내용은 위와같이 한다
  • build하고 방금 만든 layer.bat으로 배포될 빌드 디렉터리에서 node_modules을 opt 디렉터리로 옮기고
  • deploy한다

  • 결과는 이렇게 된다
  • 1.2. 디렉터리 구조를 봐보면 node_modules 폴더가 없다
  • 3.4. yaml에서 지정한 layer 등록되어 있는 것을 확인할 수 있다
  • 당연하게도 이 함수는 잘 동작한다
  • 여기까지 batch파일을 활용해서 노드모듈을 레이어로 빼는 방법을 알아보았다
  • 여기까지 프로젝트 파일