AWS NAT 인스턴스의 가성비 확인

AWS의 Private Subnet에 있는 인스턴스가 외부와 통신하려면 NAT를 활용해야한다. 그렇다면 NAT인스턴스를 만들어 사용할지, NAT 게이트웨이(Gateway, 이하 GW)를 사용할지 결정해야 한다.

AWS VPC 와 서브넷

VPC의 NAT Gateway 가격은 서울리전에서 $0.059 이다. 1달이 월 720시간이라면 Multiple AZ를 고려해 2개를 설치하면 월 $84.96, 약 10만원의 추가부담이 생긴다.

NAT Instance로 구성한다면 EC2 1년 선결제 없는 경우의 예약 인스턴스 사용시 c5.large, m5.large, t3.large 정도의 가격이다.

NAT GW는 기본 5Gbps의 대역폭을 지원하고 45Gbps까지 확장가능하다. 또 관리 소요가 줄어들기 때문에 AWS에서는 GW를 활용할 것을 권고하고 있다. 하지만 이런 수치는 트래픽에 따라 달라질 것이라 우리 회사의 경우 가격 부담없이 사용할 수 있을지 확인해보고 싶었다. 특히 t3.nano를 적용했을 때의 성능이 활용할만한지 궁금했다. AWS홈페이지에 나와있듯 t3.nano의 네트워크 대역폭은 최대 5Gbps 이다.

참고:
AWS, NAT 인스턴스 및 NAT 게이트웨이 비교
AWS, Amazon EC2 인스턴스 유형

적용방법

먼저 Public 서브넷의 호스트를 Private으로 옮긴 후 t3.nano 로 만든 NAT인스턴스를 각 AZ의 Public Subnet에 설치했다. 인스턴스의 AMI는 AWS 매뉴얼(참고: AWS, NAT인스턴스)에 설명된 대로 AWS에서 제공하는 AMI를 사용했다.

NAT 인스턴스 전송속도

아래 수치들은 백엔드끼리 연결된 타사와의 트래픽이다(서비스 트래픽은 로드밸런서에 연결되어있다). 제휴사와의 트래픽 중 HTTPS 단일 호스트에 200 OK 로 제한한 결과다.
결론부터 말하자면 현재 우리 트래픽으로는 t3.nano NAT인스턴스 사용시에도 큰 차이가 나지 않았다. 특히 T3계열 네트워크 속도가 “최대5Gbps” 이고 경험상 때때로 네트워크가 지연되는 경우도 자주 봤지만(소위 튕기는 현상), 이번에는 편차면에서도 크게 차이가 없음을 확인할 수 있었다.

참고)

  • Group: Before / After – 적용 전후
  • Count : 요청 및 응답수 (50만건 전후)
  • AVG: 평균 (ms 단위)
  • Min: 최소값(ms 단위)
  • Max: 최대값(ms 단위)
  • STDDEV: 표준편차(ms 단위)

NAT 인스턴스 리소스 사용률

AWS의 T계열은 CPU사용률을 고려해야한다. 하지만 현재로써는 설치된 NAT인스턴스의 CPU사용률이 높지 않아 만약 더 저렴한 인스턴스 타입이 나온다면 전환하는 것도 가능할 것으로 보인다.

 

마지막으로 비용은 t3.nano, 표준 1년 선결제 예약인스턴스, GP 8GB EBS 를 사용해 인스턴스 대당 월 $3.5가량, 2대에 $7로 NAT GW의 $84.96에 비해 크게 비용을 아껴 구성할 수 있었다.

트래픽의 크기에 따라 다르겠으나 t3.nano 로 현재 트래픽에 대응되는 것을 확인했다. 비용면에서도 훨씬 저렴하기 때문에 소규모 스타트업이라면 적용해 보는 것을 추천한다.

AWS VPC 와 서브넷

AWS 의 VPC는 리전 내에 위치하고 서브넷은 AZ내에 위치한다.

한 VPC에 AZ에 대해 여러 서브넷을 둬서 고가용성(HA)를 확보할 수 있다.

서브넷의 통신 방법은 VPC의 라우팅 규칙(Route Tables)을 따른다.

라우팅 규칙은 아이피 대역(CIDR)에 따라 타깃을 설정할 수 있고, 서브넷에 붙이는(associate) 방식으로 서브넷의 통신 방법을 설정할 수 있다. 서브넷과 라우팅 규칙은 1:n 관계이다. 각 서브넷은 한개의 라우팅 규칙을 붙일 수 있고 한 라우팅 규칙은 여러 서브넷에 적용될 수 있다.

이 라우팅 규칙을 통해 VPC Peering이나 Public Subnet, Private Subnet의 설정을 할 수 있게 된다.

인터넷 게이트웨이(IGW) / Public Subnet / Private Subnet

IGW는 VPC와 인터넷을 이어주는 가상 게이트웨이이다.

라우팅 규칙을 통해 IGW에 연결된 서브넷은 Public Subnet, 그렇지 않은 서브넷은 Private Subnet이라 한다.

Private Subnet 내의 인스턴스들은 Public IP를 갖지 않고 인터넷에 직접 노출되어있지 않다. Private Subnet에서 인터넷에 아이피가 노출되지 않으면서 인터넷에 접속하려면 NAT를 사용해야 한다.

원격근무의 필수조건, AWS에 OpenVPN 구축기

근무중인 세븐핀테크는 설립 때부터 리모트 근무에 높은 가치를 두고 실천해오고 있다. 각 멤버는 인천 송도, 천안, 제주에서 근무하고 있다. 세븐핀테크는 주식 고수의 실시간 계좌를 열람하고 거래 알림을 받는 모바일 앱 월스트릿파이터를 개발, 운영하고 있다.

계좌까고 말해라 월스트릿파이터

집이나 도서관, 카페 등 본인이 편한 곳에서 근무하기 때문에 모든 사내 리소스는 물리적인 공간에 두지 않으며 클라우드(주로 AWS)에서 운영된다. 그러나 보안 면에서 아이피 주소 제한에 손이 많이가고 그에 따라 보안이 느슨해지는 이슈가 발생했다. 이슈의 해결을 위해 VPN 을 도입했다.

우리는 아래 사항에 중점을 두고 구축 작업을 진행했다.

  • AWS EC2에 OpenVPN을 사용해 구축
  • 사내 리소스에 접근할 때만 VPN을 통하기
  • Docker를 사용한 구축

AWS EC2

물리적인 사내 리소스가 있는 경우 VPN 구축작업은 사실 굉장히 쉽다. 최근에는 공유기나 NAS에 기본 기능으로 탑재되어 있는 경우도 많기 때문에 곧바로 사용할 수도 있다. 그러나 물리적인 이슈가 생겼을 때 사무실로 이동해야하는 불편함이 있을것이고 모든 리소스가 클라우드에 존재하는데 사무실을 거쳐 접근해야 한다면 성능에서도 불리할 것이다.

사내 리소스에 접근할 때만 VPN을 통하기

VPN클라이언트를 동작시켰을 때 모든 트래픽을 VPN을 통하게 한다면 AWS 데이터 트래픽 비용을 감당하기 어려울 것이다. 사내 리소스에 접근할 때만 VPN을 통하도록 Split Tunnel 방식으로 구축했다.

Docker OpenVPN

사내 리소스들은 대부분 Docker 기반으로 동작하고 있다. 사용률이 높지 않아 EC2 하나에 여러 컨테이너를 동작시키고 있다. OpenVPN도 Docker 로 잘 만들어진 이미지가 있다. 우리가 사용한 이미지는 kylemanna/docker-openvpn 이고 아래 주소들에서 확인할 수 있다.

이 이미지는 Config 파일 생성과 사용자 추가 삭제 등 관리에 필요한 커맨드들을 다수 제공하고 문서화가 잘 되어있는 장점이 있다.

설치법도 매우 간단해서 Medium 에는 5분만에 설치하는 글이 있을 정도다. (https://medium.com/@gurayy/set-up-a-vpn-server-with-docker-in-5-minutes-a66184882c45)

설치

아래 설치법은 프로젝트의 README 를 따라 거의 그대로 옮긴 것이다.

볼륨 만들기

아래 만들 설정파일과 인증서 파일들을 저장할 볼륨을 만든다.

OVPN_DATA="ovpn-data-test"

docker volume create --name $OVPN_DATA

ovpn_genconfig 를 사용해 기본값으로 서버만들기

docker run -v $OVPN_DATA:/etc/openvpn --log-driver=none --rm kylemanna/openvpn ovpn_genconfig -u udp://VPN.SERVERNAME.COM

루트인증서 생성

실행 중 발급기관 이름(CN)과 비밀번호를 물어본다. 비밀번호는 앞으로 사용자 추가 / 삭제에도 사용되므로 메모해둬야 한다.

docker run -v $OVPN_DATA:/etc/openvpn --log-driver=none --rm -it kylemanna/openvpn ovpn_initpki

init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /etc/openvpn/pki

Generating a 2048 bit RSA private key
............................................................................+++
....+++
writing new private key to '/etc/openvpn/pki/private/ca.key.XX'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
...
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:

CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/etc/openvpn/pki/ca.crt

Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
... 

Enter pass phrase for /etc/openvpn/pki/private/ca.key:
Check that the request matches the signature
...
Enter pass phrase for /etc/openvpn/pki/private/ca.key:

An updated CRL has been created.
CRL file: /etc/openvpn/pki/crl.pem

클라이언트 개인용 인증서 만들기

CLIENTNAME 을 CN 으로 하는 10년짜리 인증서가 만들어진다.

docker run -v $OVPN_DATA:/etc/openvpn --log-driver=none --rm -it kylemanna/openvpn easyrsa build-client-full CLIENTNAME nopass

Generating a 2048 bit RSA private key
......................................+++++
.....................................................................................................+++++
writing new private key to '/etc/openvpn/pki/private/CLIENTNAME.key.XXXXOGlPiN'
-----
Using configuration from /usr/share/easy-rsa/openssl-easyrsa.cnf
Enter pass phrase for /etc/openvpn/pki/private/ca.key:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'CLIENTNAME'
Certificate is to be certified until Nov 14 14:02:04 2028 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated

참고 – 사용자 제거

# crt 파일과 key는 보존
docker run --rm openvpn ovpn_revokeclient CLIENTNAME
# crt 파일과 key도 함께 제거
docker run --rm openvpn ovpn_revokeclient CLIENTNAME remove 

사용자에게 배포할 클라이언트 Config 파일 만들기

이 파일에 개인용 인증서가 포함되어 있어 중앙에서 배포할 때 편리하다.

docker run -v $OVPN_DATA:/etc/openvpn --log-driver=none --rm kylemanna/openvpn ovpn_getclient CLIENTNAME > CLIENTNAME.ovpn

서버실행

AWS Security Group 에서 UDP 1194 포트를 열어야 함에 유의한다.

docker run -v $OVPN_DATA:/etc/openvpn -d -p 1194:1194/udp --cap-add=NET_ADMIN kylemanna/openvpn

테스트

VPN 클라이언트를 사용해 클라이언트 Config 파일 설치 후, VPN 접속해본다.

VPN 접속 전후로 외부 아이피 주소가 달라지면 성공이다.

나는 주로 ifconfig.co 라는 서비스에서 외부 아이피 주소를 활용한다.

$ curl ifconig.co
0.0.0.0

설정 팁

구축을 위해 사용한 몇가지 설정을 소개한다. 이 설정들은 컨테이너 볼륨의 /etc/openvpn/openvpn.conf 수정내역에 대한 것이고, 이미지에는 vi가 설치되어있어 config 파일에 접근이 가능하다는 점을 알아두고 시작하면 좋다.

docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn vi /etc/openvpn/openvpn.conf

Split Tunnel 사용

OpenVPN 에서 Split Tunnel은 특정 아이피 대역을 VPN Gateway 를 통하도록 한다. 설치때 사용한 ovpn_genconfig 은 기본값으로 클라이언트의 모든 트래픽이 VPN 네트워크를 통하게 한다. 따라서 이를 변경해줘야 한다. AWS 내의 내부 자원이므로 아이피 대역은 VPC의 아이피 대역을 적어준다.

# push "redirect-gateway def1" # => 모든 트래픽이 VPN 을 통하는 설정, 주석처리 / 삭제
push "route 10.20.0.0 255.255.0.0 vpn_gateway" # VPC 대역에 접근할 때만 VPN 을 통하도록 클라이언트 접속 설정에 PUSH

다중 클라이언트 접속

한 클라이언트 CN으로 동시에 접속가능하게 하려면 duplicate-cn 을 사용한다. 모바일과 PC에서 동시에 접속하려면 필요할 것이다.

duplicate-cn

Route53의 Private DNS 설정

액세스 편의를 위해 내부 자원에 Private DNS 를 사용할 수 있다. Route53를 이용한 Private DNS는 VPC 대역 +2에 위치한다. 예를 들어 10.20.0.0, 255.255.0.0 이라면, 10.20.0.2 에 DNS 서버가 위치한다. DNS 설정은 push dhcp-option DNS 를 사용한다.

push "dhcp-option DNS 10.20.0.2" 

맺음말

VPN을 구축하면서 자체 보안 뿐 아니라 다른 회사와의 협업 부분에서도 개선된 면이 있다. 앱 특성상 제도권 금융회사들과 협업하는 경우가 있다. 이들 회사는 높은 수준의 보안을 요구하고 이에 따라 협업시 고정 아이피 주소를 교환하는 작업이 자주 일어난다. 서버 측이야 문제될 것이 없지만 클라이언트는 사정이 좀 다르다. 개발자의 장소에 구애받을 뿐 아니라 휴대폰 망을 사용하는지, 와이파이를 사용하는지에 따라서도 제한을 받게 된다. 최근 클라이언트 개발에 있어서도 협업할 부분이 있었는데 아직 출시 전인 기능을 함께 테스트하기 위해 모바일 클라이언트가 금융회사 내부 자원에 접근해야 할일을 VPN을 통해 간단히 처리할 수 있었다.

들이는 품에 비해 만족도가 매우 높은 작업이었다. 사내보안 때문에 Security Group 수정이 잦거나, 관리가 안되는 징조가 보이는 상황이라면 도입을 시도해 보는 것을 추천한다.

참고

sami-parser 와 개발자의 매너

한국에서는 자막으로 주로 SMI 파일을 사용한다. 이 포맷은 MS 가 만들었고 한국에서는 자주 쓰이지만 전세계적으로 봤을 때는 많이 쓰이지 않는다. 대신 SRT 파일이 많이 사용된다. 그래서 외산 플레이어들이나 디바이스들은 잘 지원하지 않는다. 윈도우 계열에서 손을 뗀지가 벌써 10여년이라, 영상을 즐길 때 SMI 파일들은 항상 스트레스였다.

그래서 만든 프로젝트가 Sami-paser 였다. 일단, SMI 파일들을 제대로 파싱할 수 있다면, 그 다음의 변환 등은 쉽게 할 수 있기 때문에 후에 필요하면 스스로 변환기를 만들거나 누군가는 만들어낼 수 있기 때문이다. 사실 변환기를 제작하다 호구지책이 앞서고 언제나 새로운 것에 먼저 눈을 돌리는 MBTI 발명가형이다보니 진득하게 큰 그림을 완성하지 못했다. 이후 미드 볼 시간이 없기도 했고.

오랜만에 또 그 오래된 스트레스를 받았다. SMI 파일은 가지고 있는데 SRT 파일로의 변환이 필요한 상황. 새로 등장한 프로젝트를 살펴보다 평범한 주말 저녁의 기분이 망가졌다.

sami.js 라는 프로젝트의 개발자가 내 프로젝트의 코드가 “쓸데 없는 것이 많다”며 “한시간만에 잘 뽑”힌 프로젝트를 제작했다. [원글]

내 기억에 sami-parser 는 꽤 공을 들여 만들었다. 처음으로 NPM 에 공개한 프로젝트 이기도 하고, 인터넷에 도는 SMI 파일들의 문법들이 비정상인 경우가 너무 많다. 한마디로 개판이다. 이 문제를 해결하려고 모 자료실에서 100개 넘는 파일을 다운받아 테스트케이스로 만들어 돌리고 코드와 테스트 케이스에 반영했다. 물론 수집하고 돌려보는데도 1시간 이상이 든다. 그런데 한시간만에 만들어 냈다니.

그래서 코드를 보니 베껴졌다는 인상이 강하다.

Sami-parser 의 정규식Screen Shot 2016-06-05 at 5.16.48 AMsami.js 의 정규식Screen Shot 2016-06-05 at 5.17.22 AM Sami-parser 의 Sync 태그별 분류Screen Shot 2016-06-05 at 5.18.04 AMsami.js 의 Sync 태그별 분류Screen Shot 2016-06-05 at 5.18.29 AM

그리고 한시간 만에 만들 실력자라기엔 기본적인 코드리뷰에 잡힐 것이 많이 보인다. while 내에 var 라던지.

사실 한가지 언어로 제작된 정상적인 자막만 입력받을 것 이라면, 에러처리와 다중언어 지원은 부차적인 일일 수 있다. 하지만 말 그대로 파서는, Syntax Tree 를 만들고, 정상적으로 파싱되지 않을 때 그 이유를 정확히 알려줘야 하기 때문에 자막 제작기가 자주 실수하는 에러에 대한 에러코드나, SAMI 포맷이 지원하는 다국어를 지원하고자 노력했다. 하지만 이 부분이 “쓸 데 없는 코드”로 폄하되었다.

처음 만든 프로젝트라 과욕이 있었고, 그래서 2년이나 지금 다시 본 프로젝트는 Debug Mode 정도가 있으면 코드가 훨씬 더 간결했을 것이라는 생각이 든다. 그래서 쓸데 없는 코드라는 말은 받아들일 수 있다.

그러나 프로젝트에 대한 피드백은 프로젝트 홈에서 해야한다. 코드 베껴 놓고 나는 한시간 만에 만들었다(만들었다?)고 자랑하는 것 외에 다른 인상을 나는 받지 못했다. 정확한 내 감정은 비웃음 당했다 생각한다.

가끔 왜 그렇게 만들었는지 이해 없이 “복잡하게 만들어서” “기능이 없어서” “그 코드는 안돼서” 새로 만들어 제끼는 사람이 있다. 심지어 유명 오픈 소스 프로젝트에다 대고도 “복잡한 그걸 왜 도입하느냐” 는 식이다.

그런 사람들은 기존 만들어진 프로젝트를 다시만들 때는 정치를, 유명 프로젝트 도입에 대고는 난 공부안합니다라는 자랑을 서슴지 않는다.

이 글은 원 글에 트랙백이 걸릴 것이다.

슬쩍 떠보는 npm 과 package.json

GruntJS 와 같이 Node.js 로 만들어진 유틸리티들은 npm 을 통해 설치하고 사용하는 것이 쉽고 편리하다. 하지만 Node.js 를 깊이 공부해보려는 목적이 아니라면 굳이 npm 에 대해 깊이 알 필요는 없다. 그런 사람들과 입문자들을 위해 npm 을 통한 패키지의 설치/제거방법과 package.json 에 대해 간단히 알아보려고 한다.

npm 는 Node Package Manager 의 약자이다. 보통 npm 은 두가지 의미로 사용된다. 첫번째는 오픈소스로 작성된 Node.js 모듈들이 등록된 저장소인 http://npmjs.com 를 의미한다. 두번째는 패키지를 인스톨하고 의존성을 관리하는 자바스크립트로 작성된 커맨드라인 유틸리티이다. 커맨드라인 유틸리티는 npmjs.com 의 저장소로 부터 패키지를 찾고 설치하는 등의 기능을 사용할 수 있다. 이 글에서 npm 은 주로 커맨드라인 유틸리티의 의미로 사용하고, 첫번째 의미의 npm 은 npm 저장소라고 부를 것이다.

패키지 관리가 필요한 이유

일반적으로 Node.js 의 프로젝트는 의존하는 다른 패키지의 소스코드를 포함하지 않는다. 대신 의존하는 패키지들을 package.json 에 명시하고 개발자들은 npm 을 사용해 각자 설치해 사용한다. 특히 패키지들 중에는 C 코드를 컴파일해야 하는 것들도 있다. 이 때 컴파일된 결과물은 OS 나 시스템에 의존적이기 때문에 패키지에 포함되지 않는다. 따라서 다른 패키지의 소스코드를 포함하지 않는 것이 원칙이고 패키지 설치와 제거를 위해 npm 기본사용법을 알아야 한다.

패키지 설치와 제거

패키지 설치

npm install <패키지이름|패키지외부URL>

패키지 설치를 위해서는 install 명령을 사용한다. npm 저장소에 위치한 패키지들은 패키지이름을 적으면 설치된다. npm 패키지 외에 git 저장소나 외부 URL 에 위치한 패키지들도 설치도 가능하다. 외부 패키지 설치와 관련한 내용은 공식문서의 Install Package공식문서의 Specifics of npm’s package.json handling에 정리되어 있다.

지역패키지, 전역패키지 지정 옵션

npm 패키지는 설치되는 위치에 따라 지역패키지와 전역패키지로 나눌 수 있다.

전역(global)패키지는 시스템 전체에서 사용할 수 있도록 설치되는 패키지이다. 특히 명령어를 사용해야하는 경우에 많이 사용한다. 예를들어 grunt-cli 패키지는 grunt 명령을 포함하는데, 이 명령은 시스템 어디에서든 실행될 수 있어야 하므로 전역 패키지로 분류할 수 있다. 전역패키지로 설치하기 위해서는 전역을 의미하는 --global(또는 -g) 옵션을 사용한다.

npm install <패키지이름|패키지외부URL> --global

지역(local)패키지는 현재 프로젝트에만 한정해 사용하는 패키지를 말한다. 이 패키지들은 프로젝트 루트 디렉토리(package.json 이 있는 디렉토리)의 바로 아래에 node_modules 디렉토리에 설치된다. package.json 을 찾을 수 없으면 현재 디렉토리에 바로 아래에 node_modules 디렉토리를 만들고 여기에 패키지를 설치한다. --global 옵션을 명시하지 않은 경우 지역패키지로 설치된다.

의존성 명시 옵션

package.json 에는 프로젝트가 의존하고 있는 다른 프로젝트를 명시할 수 있다. 특히 유닛테스트용 패키지나 grunt 태스크 플러그인처럼 프로젝트를 개발하거나 테스트할 때만 필요한 패키지들만 따로 명시해 설치할 수도 있다.

--save : 패키지를 설치하고 package.jsondependencies 항목에 설치한 패키지의 이름과 버전을 명시한다.

--save-dev : 패키지를 설치하고 package.jsondevDependencies 항목에 설치한 패키지의 이름과 버전을 명시한다.

npm install <패키지이름|패키지외부URL> [--save-dev|--save]

의존성 전체 설치

npm install [--production]

package.jsondependenciesdevDependencies 에 명시된 의존성 패키지들은 다른 옵션없이 npm install 명령으로 설치할 수 있다.

프로젝트를 개발/테스트하려는 것이 아니라 활용만 하려는 목적이라면 개발의존성을 설치하는 것이 불필요하므로 devDependencies 의 패키지를 제외하고 설치할 수도 있다. 이 때는 --production 옵션을 사용한다.

패키지 제거

npm uninstall <패키지이름> [--save-dev|--save|--global]

패키지를 제거하는 명령은 npm uninstall 이다. npm install 과 마찬가지로 --global --save-dev --save 옵션을 사용할 수 있다.

주의할 점은 --save--save-dev 옵션을 사용해 의존성을 명시한 패키지들은 제거할 때도 --save--save-dev 를 사용해야 package.json 의 의존성 항목을 제거한다.

마찬가지로 전역패키지에서 찾아 제거하려면 --global 를 명시해야한다.

짧은 이름 사용하기

npm 은 명령어 중엔 별명을 사용할 수 있는 명령들이 있다. 예를 들어 npm installnpm i 로 줄여 쓸 수 있다. 그리고 npm uninstallnpm unpm rm, npm r 으로 줄여 사용할 수 있다.

package.json 생성

npm init [--yes]

package.json 은 정해진 규칙이 있는 JSON 형식의 파일이다. 하지만 세부 내용들을 모두 외워 생성하는 것은 어렵다. 이 때 npm init 명령을 통해 package.json 을 쉽게 생성할 수 있다.

npm init 은 대화형 인터페이스로 package.json 을 생성하도록 도와준다. 이 때 모든 값을 기본값으로 채우고 싶다면 -yes(또는 -y) 옵션을 사용할 수 있다. pacakge.json 의 일반적인 항목을 자동으로 채워 생성한다.

package.json 의 주요항목

package.json 은 npm 이 사용하는 설정 파일이다. 패키지의 이름 및 의존성 등이 이 파일에 명시된다. 이 파일의 주요항목을 살펴보자.

name 프로젝트의 이름이다. 기본값은 프로젝트의 디렉토리 이름이다.

version 프로젝트의 버전이다. Node.js 패키지의 버전은 유의적 버전(Semver: Semantic Versioning) 의 체계를 사용한다. 이 체계는 버전번호를 주버전(主, Major), 부버전(部, Minor), 수버전(修, Patch) 로 구분해 3개의 점(dot) 으로 표현한다. 즉, 2.1.3 버전이 있다고 한다면, 주버전은 2, 부버전은 1, 수버전은 3이다. nameversion 항목은 package.json 에서 가장 중요한 정보이다. 이 두가지 정보를 결합해 패키지의 식별자로 사용한다. 따라서 패키지의 내용이 변경되면 꼭 version 항목을 변경해야한다. 참고로 npm version [major|minor|patch] 명령을 사용하면 자동으로 package.json 의 version 항목을 변경하고 Git 저장소에 버전이름(v2.1.3 형식)으로 태그를 달 수 있다.

(참고: 유의적 버전에 대해서는 http://semver.org/lang/ko/ 를 참고하자.)

description 프로젝트의 구체적인 설명이다.

main 이 패키지의 엔트리포인트가 되는 자바스크립트 파일경로를 명시한다. 만약 패키지의 이름이 foo 라면 다른 패키지에서는 require('foo') 문으로 이 패키지를 로드한다. 이 때 main 에 지정된 파일을 로드하게 된다.

scripts 패키지에서 반복적으로 사용할 주요명령들을 지정해 사용할 수 있다. 기본값으로 생성된 test 를 실행하기 위해서는 npm test 으로 실행할 수 있다.

keywords 이 패키지를 설명하는 키워드들이다. 이렇게 지정된 키워드들은 npm search 명령으로 패키지를 검색할 때 검색어로 사용된다.

license 패키지의 라이선스 정책을 명시한다. 기본값은 ISC 이다. 참고로 ISC 는 INTERNET SYSTEMS CONSORTIUM 의 약자로 이 단체에서 제정한 공개 소프트웨어 라이선스이다.

author, contributors 객체형식 또는 문자열 형식으로 개발자의 이름과 이메일을 명시한다. author 는 원 저작자이기 때문에 문자열형식이나 객체형식으로 한명만 지정하고, contributors 는 여러 사람이 될 수 있으므로 배열 형식으로 지정한다. 사람을 표현할 때는 아래와 같이 이름, 이메일, URL을 명시할 수 있고, 이메일과 URL은 선택사항이다.

객체 형식으로 지정한 예

{ "name" : "Constantine Kim"
, "email" : "elegantcoder+nospam@gmail.com"
, "url" : "http://elegantcoder.com/"
}

문자열로 표현한 예

"Constantine Kim <elegeantcoder+nospam@gmail.com> (http://elegantcoder.com/)"

dependencies, devDependencies 이 패키지가 다른 패키지에 의존할 경우 의존성에 대한 항목이다. foo 라는 프로젝트의 2.x 버전에 의존적이라면 아래와 같이 명시한다.

{
  "dependencies" :
    "foo" : "2.x"
  }
}

이렇게 이름과 버전을 명시한 패키지들은 npm 저장소로부터 설치된다. 앞서 패키지 설치 장에서 봤듯 npm 저장소 외에도 git 저장소나 외부 URL 의 패키지도 명시할 수 있다.

dependencies 는 이 패키지에 의존하는 다른 프로젝트에서 구동시키기 위한 의존성이다. 즉, 이 패키지를 활용할 때 필요한 의존성을 명시한다. npm install --save 명령을 통해 패키지를 설치하면 이 항목에 프로젝트 정보가 저장된다.

devDependencies 에는 이 패키지를 테스트하거나 개발할 때 필요한 패키지들을 명시한다. npm install --save-dev 명령을 통해 패키지를 설치하면 이 항목에 프로젝트 정보가 저장된다.