정적 이미지 사용하기

React Native는 웹뷰를 통해 인터페이스를 구축하는 하이브리드 방식(예를 들면 Ionic)과는 달리 자바스크립트로 작성한 코드가 Native UI 컴포넌트로 만들어집니다. React Native에서 이미지를 사용하는 코드는 iOS와 Android 모두 통합되어 있지만, 정적인 이미지 파일을 추가하는 부분은 Naming에 있어 차이가 있습니다. 이번에는 React Native에서 정적 이미지를 사용하는 방법과, 정적 이미지 추가 시 반복되는 작업을 좀 더 효율적으로 할 수 있도록 Node를 사용하여 스크립트를 작성하는 부분을 다뤄보도록 하겠습니다. 글 작성 기준 React Native의 최신버전은 0.4입니다.

React Native 정적 이미지 사용하기

React Native에서 정적 이미지를 추가하는 방법은 공식홈페이지에서도 잘 설명되어 있지만 한번 더 살펴보겠습니다.

다음과 같이 react-native 의 기본적인 Image 컴포넌트를 통해 정적인 이미지 파일을 사용할 수 있습니다. 아래의 코드는 작성된 컴포넌트의 파일과 같은 경로에 있는 gold.png라는 파일을 사용합니다.

1
<Image source={require('./gold.png')} />

하나의 파일을 두개의 플랫폼(iOS와 Android)에서 같이 사용할 수 있지만 만약 플랫폼에 따라 다른 이미지를 사용하고 싶다면 gold.png라는 파일을 gold.android.pnggold.ios.png로 각각 저장하여 사용할 수 있습니다. 이와 같은 경우는 주로 Android와 iOS에서 같은 목적으로 사용되는 이미지가 다를 경우 유용합니다. (React Native에서 iOS와 Android의 Entry file이 index.ios.js와 index.android.js 인것과 같은 개념입니다.)

또한 React Native의 packager플랫폼 뿐만 아니라 디바이스 스크린의 해상도에 따라서도 다른 이미지를 제공할 수 있습니다. 따라서 다음과 같이 이미지 파일의 이름을 해상도에 따라 달리하여 사용할 수 있습니다.

1
2
3
4
├─ Test.js
└── img/
├── gold@2x.png
└── gold@3x.png
1
2
{/* Test.js 코드의 render 부분 */}
<Image source={require('./img/gold.png')} />

파일 구조와 Test.js의 코드가 위와 같을 때 iPhone 6와 iPhone 6 Plus는 각각 gold@2x.pnggold@3x.png 파일을 사용합니다. 만약 디바이스 스크린의 해상도에 해당하는 파일이 없다면 가장 밀접한 해상도를 가진 파일을 사용합니다.

정리하면 디바이스의 플랫폼과 해상도에 따라 파일을 사용하고 싶을 경우 다음과 같이 사용할 수 있습니다.

1
2
3
4
5
6
├─ Test.js
└── img/
├── gold@2x.android.png
├── gold@2x.ios.png
├── gold@3x.android.png
└── gold@3x.ios.png

React Native에서 정적인 이미지를 사용할 경우 주의해야할 점은 공식홈페이지를 참고하시면 좋을것 같습니다.

Native 측면에서 바라보기

React Native는 기존 Android와 iOS에서 이미지를 추가하여 사용하는 방법을 그대로 사용할 수도 있습니다. 이미 위의 방법으로 해결이 가능하며 이 방법이 좀 더 복잡하기에 사용을 권장드리지 않지만 이런방법으로도 가능하다는걸 알고계시면 좋을것 같습니다. Native에서 Android와 iOS의 이미지 파일은 다음과 같은 경로에 저장하여 사용합니다.

  • Android Test-app/android/app/src/main/res/
  • iOS Test-app/ios/Test-app/images.xcassets/
### Android Android에서 해상도별로 이미지를 추가하는 방법을 알아보겠습니다.

1.처음 프로젝트 생성시에는 drawable관련 폴더가 없으므로 android/app/src/main/res/ 에 해당 폴더들을 생성합니다.

  • drawable-mdpi
  • drawable-hdpi
  • drawable-xhdpi
  • drawable-xxhdpi
  • drawable-xxxhdpi

2.해상도 별로 각 drawable 폴더에 파일을 저장합니다. (각 폴더별 저장되는 이미지는 파일명이 모두 같아야합니다.) 파일명이 gold.png 라면 각 폴더에는 다음과 같이 존재하게 됩니다.

  • drawable-mdpi/gold.png
  • drawable-hdpi/gold.png
  • drawable-xhdpi/gold.png
  • drawable-xxhdpi/gold.png
  • drawable-xxxhdpi/gold.png

iOS

iOS에서 이미지를 추가하는 방법은 Android에 비해 좀 더 번거롭습니다. 글로 설명하는것보다 사진을 참고하는 것이 이해하기 쉽기 때문에 사진을 첨부합니다.

1.먼저 xcode에서 프로젝트의 root폴더에서 ios폴더를 로드한 후 images.xcassets 폴더를 클릭 후 AppIcon 아래의 빈공간을 우클릭하면 New Image set라는 메뉴가 있습니다. 클릭 후 1x, 2x, 3x에 이미지를 넣으신 후 이미지의 이름을 설정합니다.
xcode에서 이미지 추가1

2.위와 같이 이미지를 넣고나면 해당 경로에 다음과 같은 형식으로 파일이 생성됩니다. Contents.json은 이미지 파일에 대한 정보를 갖고 있습니다.
xcode에서 이미지 추가2

이미지 사용하기

Android와 iOS에 이미지 추가가 모두 끝났습니다. 추가한 이미지를 React Native 에서 사용해보겠습니다.

1
2
{/* Test.js 코드의 render 부분 */}
<Image source={require('image!gold')} />

위의 코드에 **image!**라는 부분의 추가와 이미지 파일의 확장자가 사라졌다는게 전과 다릅니다. 이미지의 위치를 알리는 경로 또한 명시할 필요가 사라졌습니다.

코드로 한번 더 복습하기

이제 React Native에서 정적인 이미지를 추가하는 방법을 모두 알아보았습니다. 마지막으로 코드상에서 정적인 이미지를 사용하는 방법을 정리해보겠습니다.

– Native 에서 이미지를 추가하는 방법을 사용하였을 경우

1
2
{/* Test.js 코드의 render 부분 */}
<Image source={require('image!gold')} />

– 프로젝트 폴더내에 추가 후 상대경로를 사용하는 경우

1
2
{/* Test.js 코드의 render 부분 */}
<Image source={require('./image/gold.png')} />

– 첫번째와 두번째 방법을 모두 사용하는 경우 (Native에서 사용되는 폴더에서 이미지를 찾은 후 존재하지 않을 경우 상대경로를 사용하여 이미지를 사용)

1
2
{/* Test.js 코드의 render 부분 */}
<Image source={ {uri: 'gold', isStatic: true} } />

눈으로 확인하는 결과

iPhone6와 iPhone6 Plus 에서 Gold 이미지가 기기의 해상도에 맞게 다른 파일로 사용된것을 확인할 수 있습니다.

![iPhone6 에서의 Gold 이미지](/images/post/2017-01-22/iPhone6.png)
![iPhone6Plus 에서의 Gold 이미지](/images/post/2017-01-22/iPhone6Plus.png)

다음 포스팅에서는 정적인 이미지 파일을 쉽게 추가하여 사용할 수 있도록 자동화하는 스크립트 작성에 대해서 작성하겠습니다.

.bashrc 와 .bash_profile 의 차이

bash 쉘(Shell) 이란?

쉘(Shell)은 운영체제에서 **사용자가 입력하는 명령을 읽고 해석하여 대신 실행해주는 프로그램**입니다. 운영체제 상에서 다양한 운영체제 기능과 서비스를 구현하는 인터페이스를 제공하며, 사용자와 운영체제의 내부(커널)` 사이의 인터페이스를 감싸는 층이기 때문에 셸이라는 이름이 붙었습니다. 쉘은 운영체제에서 필수적으로 존재합니다.

운영체제는 로그인한 사용자가 없다면 하나의 쉘도 실행되지 않은 상태이며, 사용자가 로그인을 시도하면 운영체제는 ID와 패스워드를 받아들이는 로기은 프로그램을 실행하고, 사용자가 입력한 ID와 패스워드를 검증한 후 인증된 사용자라면 쉘을 실행하여 사용자 세션을 쉘에게 전달합니다.

쉘의 역할은 사용자가 입력한 명령을 해석하여 대신 실행해주는 것입니다. 쉘의 내부 명령어라면 스스로 실행한 뒤 화면에 표시해주고 내부 명령어가 아니라면 PATH 환경변수에 지정된 경로에서 입력받은 명령과 같은 파일을 찾아 exec() 시스템콜을 호출하여 실행한 뒤 키보드와 마우스 등의 입력장치와 모니터에 해당하는 표준 출력장치의 제어권을 해당 프로그램에 넘겨준 뒤 프로그램이 끝날 때 까지 대기하는 역할을 합니다.

bash 쉘은 유닉스에서 사용하는 커맨드 쉘의 일종으로 GNU 프로젝트를 위해 만들어졌습니다. 초기의 유닉스 쉘인 본 쉘(Bourne Shell)과 새로 태어났다는 뜻의 영어 ‘born again’을 합쳐 **본 어게인 쉘(Bourne-again Shell)**이라고 불렸으나, 일반적으로 bash로 줄여 부릅니다.

Login Shell 과 Non-Login Shell

Login Shell

Login은 ID와 패스워드를 입력해서 Shell을 실행하는 것을 말합니다. 따라서 ssh로 접속하거나 로컬에서 GUI를 통해 Shell을 실행하는 것은 Login Shell 입니다.
.profile, .bash_profile 이 두 파일은 Login할 때 로드되는 파일입니다. .profile은 꼭 bash가 아니더라도 로그인하면 로드되며, .bash_profile은 꼭 bash로 로그인 할 때만 실행됩니다.

Non-Login Shell

Non-Login Shell은 로그인 없이 실행하는 Shell을 말합니다. ssh로 접속하고 나서 다시 bash를 실행하는 경우나, GUI 세션에서 터미널을 띄우는 것도 여기 해당합니다. ‘sudo bash’나 ‘su’같은 것도 해당합니다.

.bashrc 와 .bash_profile 의 차이

.bashrc

이미 로그인 한 상태에서 새 터미널 창을 열 때마다 로드됩니다. (Non-Login Shell에서 실행됩니다.)

.bash_profile

시스템에 로그인할 때마다 로드됩니다. (Login Shell에서 실행됩니다.) 대부분 개별 사용자에 대한 설정에 대한 코드들이 들어갑니다. 예를 들면 nvm(Node Version Manager)은 기본적으로 nvm을 사용하지 않고 Node를 설치할 때와는 다르게 각 사용자의 경로에 설치되게 되는데, 이럴때 nvm의 PATH를 .bash_profile 파일에 기재합니다.

.profile

로그인할 때 로드됩니다. 개별 사용자에 대한 설정 코드들 중 bash와는 관계없는 부분을 기재합니다.

  • 만약 Mac에서 새 터미널 창을 열 때마다 .bashrc를 로드하고 싶다면 .bash_profile에서 .bashrc를 로드하면 됩니다.
    1
    2
    3
    4
    # Source bashrc
    if [ -f ~/.bashrc ]; then
    . ~/.bashrc
    fi

ls 명령어 결과 색상 변경하기

미리보는 결과 화면

이번 글에서는 다음과 같이 ls 명령어를 사용했을 때 보이는 결과를 색상을 이용하여 쉽게 구분할 수 있도록 만들어 보겠습니다.

ls 명령어 결과

색상 표시 여부 설정 & 색상 설정

~/.bashrc 또는 ~/.bash_profile 파일에 다음 코드를 추가합니다.

1
2
3
# ls 명령어 색상 표시 여부 & 색상 설정
export CLICOLOR=1
export LSCOLORS=DxFxBxDxCxegedabagacad

색상 변경하기

CLICOLOR색상표시 여부를 활성화하는 것이며 0일때 비활성, 1일때 활성입니다.
LSCOLORS는 CLICOLOR로 색상이 활성화 되었을 때 각 종류별로 어떤 색으로 표시할 지를 지정하는 것 입니다. 두 글자씩 쌍으로 이루어져 있으며 앞 글자는 전경색(foreground), 뒤의 글자는 배경색(background)를 의미합니다. 각 알파벳이 의미하는 색상은 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
a : 검은색
b : 빨강색
c : 녹색
d : 갈색
e : 파란색
f : 마젠타색(magenta)
g : 시안(cyan)
h : 밝은 회색
A : 두꺼운 검은색(보통 어두운 회색으로 보인다.)
B : 두꺼운 빨간색
C : 두꺼운 녹색
D : 두꺼운 갈색(보통 노란색으로 보인다)
E : 두꺼운 파란색
F : 두꺼운 마젠타색
G : 두꺼운 시안
H : 두꺼운 밝은 회색(밝은 흰색처럼 보인다)
x : 전경생과 배경색의 기본색상

fb의 쌍 순서는 다음과 같은 순서로 색을 지정합니다.

1
2
3
4
5
6
7
8
9
10
11
1. 디렉토리
2. 심볼릭 링크
3. 소켓
4. 파이프
5. 실행가능 파일
6. 특수 블락
7. 특수문자
8. setuid 비트가 설정된 실행파일
9. setgid 비트가 설정된 실행파일
10. sticky비트가 있으면서 다름사람이 쓸 수 있는 디렉토리
11. sticky비트가 없으면서 다름사람이 쓸 수 있는 디렉토리

Qvic 서비스 아키텍처 설계

회사에서 새로운 서비스를 준비하며 이번 9-b 스프린트동안 구축한 Qvic의 AWS 구조는 다음과 같습니다. 각각의 서비스에 대한 자세한 내용은 AWS 사이트와, 책을 참조 하였고, 이번 글에서는 이와 같은 환경을 구축하며 생겼던 문제들과 앞으로는 조금 더 쉽게 구축 할 수 있도록 일련의 과정에 대해 설명하고자 합니다.

Qvic AWS Architecture


1. IAM 생성

IAM은 Identity and Access Management(식별 및 접근 관리)의 약어로 사용자와 그룹을 생성하고 AWS의 각 리소스에 대해 접근제어와 권한관리를 제공한다. 이러한 IAM 을 EC2 Instance를 생성하며 설정할 수가 있는데 이미 만들어진 EC2 Instance에는 IAM 역할을 설정할 수가 없다. (처음에 모르고 하다가 나중에 지우고 다시 EC2를 생성하며 IAM을 설정하는 일이 생길 수 있다.) 물론 IAM 을 설정하지 않아도 EC2 Instance에서 API로 액세스 키와 시크릿 키를 설정해서 AWS 리소스에는 접근할 수 있지만 나중에 Auto Scaling 기능으로 자동으로 생성되는 EC2 인스턴스에 액세스키와 시크릿키를 일일이 설정해주는 것은 상당히 귀찮은 일이다. 이를 위해 먼저 IAM 을 생성한 후 EC2를 생성하는 것이 좋다.
* IAM 생성 후 생성 된 IAM에 권한을 부여하는 것은 나중에도 가능하므로 자세한 내용을 알지 못한다면 일단 생성 후 EC2에 적용만 해놓아도 된다.


2. EC2 생성 -> 개발환경 구축 -> AMI 생성

사용중인 AWS 계정이 Free Tier 라면 t2.micro (1달 750시간 무료) Instance로 생성하여 AMI(Amazon Machine Image)를 생성하는 것도 효율적인 방법이다. 추후에 AMI를 사용하여 EC2를 새로 생성할 수도 있고, 이미 생성된 EC2 Type을 변경할 수도 있다.

EC2의 Instance는 다음과 같이 생성하였다. (모두 Ubuntu Image를 사용하였다. EC2를 생성할때 만들어지는 .pem 파일의 백업은 중요하다!)
Express를 사용하여 프로젝트를 진행하였기 때문에 3000번 포트가 필요하여 Security Group 설정에서 Add Rule을 통해 3000번 포트를 추가해 주었다.

  • Blue-Green Deployment 를 위해 Auto Scaling (자동으로 EC2 인스턴스를 생성하여 서비스를 확장하는 기능) 을 적용한 Prod 용 Instance 2개
  • Dev 용 Instance 1개

먼저 Dev 용으로 Instance를 생성 하였고, 다음과 같은 개발환경을 구축하였다.

  • 기본 ubuntu 계정을 제외하고 팀원들의 각각 사용자 계정 추가 (비밀번호 설정, root 권한을 사용할 수 있도록 설정)
  • 각 사용자마다 .pem 키를 사용하여 로그인 하는 것이 보안상 안전하지만 편의상 비밀번호로 로그인 할 수 있도록 설정 (ssh 의 공개키와 비공개키 개념 필요)
  • node v6.6.0 설치 (사용자가 여러명이고 진행중인 프로젝트마다 node의 버전이 다르다면 nvm 을 설치하는것 추천)
  • git 다운로드 및 ssh 설정
  • bash 및 vim 설정 (만들어진 script 파일을 받아 실행)

다음은 Prod 용 Instance 개발환경 구축이다. Prod 용은 Dev Instance 와는 다르게 Auto Scaling을 적용할 것이기 때문에 Dev Instance 와는 조금 다른 설정이 필요하다. Auto Scaling은 트래픽이 증가하면 자동으로 EC2 Instance를 생성하여 서비스를 확장하기 때문에 자동으로 생성된 EC2 Instance가 자동으로 서비스를 시작 할 수 있도록 구축해야 한다. 따라서 다음과 같은 설정이 필요하다.

  • node v6.6.0 설치
  • git 다운로드 및 ssh 설정
  • bash script 파일

Auto Scaling 그룹을 생성기 전에 설정하는 EC2 생성 옵션 설정에서 'User data' 라는 칸에 자동으로 EC2가 생성된 후 root 권한으로 실행할 스크립트를 작성한다. 이때 git에서 프로젝트를 clone 한 후 자동으로 서비스를 시작하도록 하는 코드가 작성되어야 한다. 이 부분이 어려운 부분은 아니지만 경로 등… 여러가지 설정을 한 후 Auto Scaling이 잘 적용되는지 확인하기 위해서는 생성한 Auto Scaling에 인위적으로 부하를 걸어 Instance가 생성되도록 하고 ‘User data’에 작성한 스크립트가 잘 실행되는지 까지 확인해야 한다. 생각보다 시간이 걸리고 인스턴스를 반복적으로 생성하고 삭제 (과금…) 하는 부분이 부담스러워서 직접 EC2 에 bash script 파일을 작성한 후 ‘User data’ 에서는 이 script를 실행하도록만 작성하였다. 작성한 script는 먼저 만들어 두었던 Dev Instance 에서 테스트 한 후 잘 작동하는 것을 확인한 후 Prod Instance로 옮겼다.
이렇게 생성한 Dev와 Prod 용 Instance를 사용하여 AMI를 생성한다.


3. ELB (Elastic Load Balancing) 사용

Auto Scaling 그룹을 생성 하면서 ELB 를 선택하는 부분이 있기 때문에 ELB를 먼저 생성해야 한다. AWS에서 제공하는 ELB는 2가지가 있다.

AWS - ELB

1. Application load balancer
**Layer 7 로드밸런싱**을 통해 패킷을 조사하고, HTTP 및 HTTPS 헤더에 접근해서 좀 더 지능적인 부하 분산 작업이 가능하다. 예를들어, URL에 /api 라는 경로를 포함하고 있는 경우, 다른 서버 그룹으로 요청을 보낼 수 있으며 /mobile은 또 다른 서버 그룹으로 보낼 수 있다. 각 애플리케이션 로드밸런서는 10개의 URL 규칙을 만들 수 있으며 이를 통해 여러 개의 마이크로서비스를 독립적으로 실행하고 확장할 수 있다.

2. Classic load balancer
**Layer 4 로드밸런싱**을 사용하여 네트워크 프로토콜 레벨에서 제공 되며, 실제 패킷을 살펴 보지는 못하기 때문에 HTTP나 HTTPS 같은 특정 프로토콜을 인지하지 않고 부하를 분산한다.

ELB 생성시 주의할 점은 다음과 같다.

  • Express를 사용하기 때문에 3000번 포트를 추가해 준다. (Security Group 설정에서도 추가)
  • 헬스 체크(Health Check) 기능 설정시 3000번 포트로 변경해준다.
  • 헬스 체크 주기(Health Check Interval)와 Threshold는 적절히 설정해준다.
  • 로드밸런싱할 Instance를 추가할 때 생성해 두었던 Prod 한개를 설정한다. (Blue-Green Deployment 를 하기 위해서는 각각의 Instance에 서로 다른 load balancer를 설정해야 한다.)

혹시 Elastic IP가 적용되어 있었다면 제거한다. 앞으로 서비스에 접속할 때는 EC2 Instance에 바로 접속하지 않고 ELB 의 URL로 접속한다. (후에 Route 53에서 자신의 도메인으로 설정할 수 있다.)


4. Auto Scaling 적용

EC2 Instace 생성 옵션을 설정하고, Auto Scaling 그룹을 생성한다. EC2 Instance 생성 옵션을 설정하면서 주의할 점이 몇가지 있다.

  • IAM role 은 자동으로 생성되는 EC2 Instance에서 사용할 IAM 역할이다. IAM 역할을 사용하면 액세스 키와 시크릿 키 없이 AWS API를 사용할 수 있으므로 당장은 AWS API 를 사용하지 않더라도 설정해 두는것이 좋다.
  • Advanced Details를 누르면 나오는 User data는 EC2 Instance가 생성된 후 root 권한으로 자동으로 실행할 script를 입력하는 곳이다. AMI를 생성하며 작성했던 script가 실행되도록 작성한다.
  • #!/bin/bash
    /home/ubuntu/auto_start.sh
  • Express를 사용하기 때문에 Security Group 설정에서 Add Rule을 통해 3000번 포트를 추가해 준다.
  • 미리 생성해 두었던 ELB를 적용한다.

여러가지 설정들이 있는데 이는 나중에 수정이 가능하므로 처음 생성시에 너무 고민하지 않아도 된다. 필요할 때 수정해주고 모르는것은 좀 더 조사해보면서 수정하면 된다.

<종료정책 설정>
처음 Auto Scaling을 만들고 테스트를 하면서 당황했던 것이있다. 처음에 유지되고 있던 1개의 Instance에 인위적으로 부하를 걸면 내가 설정해놓은 정책에 따라 Instance가 자동으로 생성되고, 삭제되게 되는데 마지막에 생성된 Instance가 그대로 남고 원래 존재하던 Instance가 제거 되는 것이다. Auto Scaling이 적용된 Instance에는 자동 생성되는 Instance의 AMI 와는 조금 다르게 환경 구축이 되어있는데 사라져서 당황했었다. 이는 Auto Scaling의 종료정책 때문인데 종료정책의 종류는 다음과 같다.

  • OldestInstance : Auto Scaling은 그룹에서 가장 오래된 Instance를 종료한다.
  • NewestInstance : Auto Scaling은 그룹에서 가장 새로운 Instance를 종료한다.
  • OldestLaunchConfiguration : Auto Scaling은 가장 오래된 시작 구성을 가진 Instance를 종료한다.
  • ClosestToNextInstanceHour : Auto Scaling은 다음 번 결제 시간에 가장 근접한 인스턴스를 종료한다.
  • Default : Auto Scaling은 해당 기본 종료 정책을 사용한다. (기본 종료 정책은 네트워크 아키텍처 전반에서 가용 영역이 균일하게 적용 되도록 설계되어있다.)

위와 같은 종료정책은 Auto Scaling 설정시 설정하는 부분이 아니고 생성한 후 변경해 주어야 하는 부분이라 놓칠 수 있다. 기본 종료 정책이 아닌 다른 정책이 필요하다면 변경해 주어야한다.


5. Route 53

Route 53은 EC2, ELB, S3, CloudFront와 연동 가능한 DNS 서비스이다. Free Tier에서도 무료로 사용이 불가능하다. Route 53을 사용하기 위해서는 도메인이 필요한데 아직 구매하지 않았다면 Route 53 에서 구매하는 것을 추천한다. 외부에서 구매한 도메인은 네임서버를 따로 설정해 주어야한다.
A 레코드를 통해 미리 생성했던 ELB를 쉽게 설정해 줄 수 있다. (후에 Blue-Green Deployment시 2개의 ELB를 서로 교체해주면 된다.)


6. 그외 여러 주의사항

  • Free Tier 에서 한달에 EC2 Instance는 750시간 무료이고 EBS는 30GB가 무료이다. 보통 EC2 Instance만 신경써서 4~5개를 한번에 만들고 후에 제거하고 하는데 EC2 Instance 생성시 따로 EBS 크기를 정해주지 않으면 기본이 8GB이기 때문에 4개만 생성해도 EBS로 인해 과금이 된다. (정지해도 과금이 된다.)
  • Elastic IP는 EC2 Instance 1개에 대해 할당하고 있을때만 무료이다. 만약 EC2 Instance를 중지하거나 제거한다면 Elastic IP도 제거해 주어야 한다.
  • Free Tier 사용시 CloudWatch 의 주기는 5분일때 무료이다. 주기를 줄이면 과금된다.
  • EC2의 개발환경 세팅시 AMI를 자주 만들어주자… AIM 설정이라던가 Auto Scaling의 종료정책을 몰라서 많이 날려먹었다.
  • 예상하지 못한 과금은 무서우니 알림을 설정해놓자.

NVM (Node Version Manager) 사용하기

오늘은 NVM에 대해서 알아보겠습니다. 저는 회사에서 Ionic 을 통해서 하이브리드 앱을 개발하고 있습니다. Ionic의 개발환경은 기본적으로 Node.js를 필요로 합니다. 당시 처음 입사하였을때는 회사에서 사용중인 Node v4.4.0을 설치하여 사용하고 있었습니다. 그러나 후에 여러개의 프로젝트를 하며 ES6 문법을 사용하기 위해 상위 버전의 Node를 사용해야하 하는 일이 생겼습니다. 이런 경우 보통 Node를 제거한 후 상위 버전을 사용하게 된다면 후에 다시 Ionic 프로젝트를 할때 문제가 됩니다. 이럴때 NVM을 사용한다면 여러개의 Node 를 버전별로 쉽게 관리하고 사용할 수 있습니다. 지금부터 NVM을 사용했을때의 이점과 설치 및 사용방법에 대해 알아보겠습니다.

NVM (Node Version Manager)

NVM은 말 그대로 Node의 버전을 관리해주는 매니저입니다. Ruby에는 RVM이 있듯이 Node에서는 NVM을 사용합니다. 한 사용자 계정에 여러개의 Node 버전을 설치하여 선택하여 사용할 수 있습니다.

NVM 사용시 이점

  • 여러 버전의 Node를 쉽게 사용할 수 있습니다. (기존의 버전을 삭제할 필요가 없습니다.)
  • NVM을 사용하지 않고 설치한 Node는 /usr/local/bin/ 경로에 설치되지만 NVM을 사용하여 설치했을 경우에는 /User/kimjongmin/.nvm/versions/node/ 경로에 설치됩니다. NVM을 사용했을 경우 사용자의 종속되어 설치되기 때문에 npm을 통하여 모듈을 설치할 때도 기존과는 달리 -g 옵션을 주지 않아도 설치 가능합니다. (npm또한 Node와 같이 설치되기 때문에 Node 버전마다 다르게 설치됩니다.)
  • Node 버전에 따라 npm도 다르게 설치되기 때문에 모듈의 버전들도 각기 다르게 관리할 수 있습니다. 예를들어, Node v4.4.0 에서는 cordova v5.7.1을 Node v6.6.0 에서는 cordova v6.1.1을 설치하여 사용할 수 있습니다.

NVM 설치

NVM 설치전 기존에 설치되어 있던 Node를 제거하는것을 권장하지만 NVM 설치 후 제거하여도 괜찮습니다.

1
2
curl을 이용하여 설치
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.4/install.sh | bash

설치 후 PATH 정보는 .bashrc에 저장되므로 재로그인 없이 사용하려면 변경된 .bashrc를 다시 적용시켜주어야 합니다.

1
$ source ~/.bashrc

NVM 명령어

1
2
3
// 현재 최신 버전의 Node 설치 (별도의 버전을 지정하지 않고 현재 최신 버전으로 설치합니다.)
$ nvm install node
$ node -v (버전확인)
1
2
3
4
5
6
// 설치된 Node 특정 버전 삭제하기
$ nvm uninstall v4.4.0

```bash
// 설치된 Node는 ~/.nvm/versions/ 경로에서 확인 가능합니다.
$ which node
1
2
// NVM에서 지원하는 Node의 버전을 확인할 수 있습니다.
$ nvm ls-remote
1
2
// 특정 Node 버전 설치는 다음과 같이 가능합니다.
$ nvm install v4.4.0
1
2
// 설치되어 사용가능한 Node 버전 확인
$ nvm ls
1
2
// 특정 Node 버전 사용
$ nvm use v6.6.0
1
2
// 터미널 시작시 노드 기본버전 설정
$ nvm alias default v6.6.0

Tip) 자주쓰는 명령어 alias 등록하기
저는 NVM을 통해 Node v4.4.0과 v6.6.0을 설치하여 사용하고 있습니다. 프로젝트마다 Node 버전이 달라 프로젝트 변경시 Node의 버전도 변경해 주어야 하는 번거로움이 있어 ~.bash_custom에 alias 로 등록하여 사용하고 있습니다. (~.bashrc, ~.bash_profile ) 저는 다음과 같이 사용합니다. (파일에 추가 후 source 명령어로 변경된 파일을 적용하거나 새로운 쉘을 열어야 적용됩니다.)

1
2
3
alias nv='node -v'
alias n4='nvm use v4.4.0'
alias n6='nvm use v6.6.0'

모듈 설치

NVM use 명령어를 통해 원하는 Node 버전을 선택 후 npm install 을 통해 필요한 모듈을 설치할 수 있습니다. 기존 사용법과 동일하나 NVM 은 /User에 설치되기 때문에 더이상 sudo 명령어를 사용하지 않아도 됩니다. 또한 하나의 Node 버전에서 필요한 모듈을 설치 후 새로운 Node 버전을 생성할 때 특정 버전 npm 패키지를 마이그레이션 할 수 있습니다.

1
$ nvm install v6.6.0 --reinstall-packages-from=4.4.0

기존에 설치되어 있던 Node 제거

1
$ sudo rm -rf /usr/local/lib/node /usr/local/lib/node_modules /var/db/receipts/org.nodejs.*

Linux & Ubuntu 계정 추가 & 설정

AWS의 EC2를 사용하면서 ubuntu에 사용자를 추가해주는 경우가 빈번히 생겨 그 과정을 정리해보려 합니다. 각각의 유저가 자신의 사용자 계정을 사용한다면 자신만의 파일과 작업 공간을 가질 수 있고, 잘못사용해서 시스템에 피해가 생기는 일도 어느정도 예방할 수 있습니다.

EC2 인스턴스에 사용자를 추가하는 작업에는 (1) 사용자를 시스템에 추가하고 (2) 해당 사용자에게 원격으로 로그인하는 방법을 제공하는 두 가지 작업이 포함됩니다.

올바른 방법은 하나의 EC2에서 생성한 각각의 사용자 계정마다 key pair를 생성해 주고, 각 계정에 맞게 설정된 key pair를 통해서만 접속 할 수 있도록 설정을 해야합니다.

그러나 최초 EC2 인스턴스를 생성하며 만들었던 key pair를 모든 사용자가 공유한다던가, password 기반의 로그인을 활성화 하여 ssh key를 사용하지 않고 password 기반으로 로그인을 할 수도 있습니다.

이번 포스팅에서는 (1) 사용자를 시스템에 추가한 후 (2-1) EC2 인스턴스를 생성하며 사용했던 key pair(기본 사용자 로그인시 사용하는 key pair)를 사용하거나, (2-2) password 기반의 로그인을 활성화하여 ssh key를 사용하지않고 로그인할 수 있도록하는 방법에 대해 정리합니다.

root password 설정

1
[ubuntu ~] $ sudo passwd root

password 기반의 로그인을 활성화하기

1
[ubuntu ~] $ sudo vi /etc/ssh/sshd_config

다음을 수정합니다. no를 yes로 변경합니다.
# Change to no to disable tunnelled clear text passwords
PasswordAuthentication no

root 계정으로 로그인

1
[ubuntu ~] $ su - root

다른 사용자 계정 추가

1
[root ~] $ adduser newuser

새로 생성한 사용자 계정의 비밀번호 변경

1
[root ~] $ sudo passwd newuser

새로 생성한 사용자 계정에 root 권한을 사용할 수 있도록 설정

1
[root ~] $ sudo visudo

다음을 수정합니다.
root ALL=(ALL) ALL 아래에
newuser ALL=(ALL) ALL을 추가합니다.

같은 key pair로 로그인 할 수 있도록 새로 생성한 사용자 계정으로 ubuntu 의 것을 복사

* 이부분에 대한 자세한 내용은 SSH KEY 에 대하여 알아야합니다.
* ubuntu 계정의 .ssh 폴더를 복사해 newuser 계정에 복사합니다.

1
[root ~] $ ssudo cp /home/ubuntu/.ssh /home/newuser/.ssh

복사한 key pair의 소유자를 jmkim으로 변경 (-R : 하위 폴더까지 모두 소유권을 바꿔줌)

1
[root ~] $ sudo chown -R newuser:newuser /home/newuser/.ssh

sshd 서비스 재시작

-Ubuntu

1
[root ~] $ sudo service ssh restart

-Linux

1
[root ~] $ sudo service sshd restart

이제 EC2 instance를 생성할때 만들었던 .pem 파일과 설정한 비밀번호를 통해 새로 생성한 계정으로 서버에 접속할 수 있습니다.

참고 : AWS 공식 사이트 - Managing User Accounts on Your Linux Instance

module.exports와 exports 차이 이해하기

모듈이란?

모듈이란 관련된 코드들을 하나의 코드 단위로 캡슐화 하는 것을 말합니다. Node.js 에서 예시를 살펴보겠습니다.
다음과 같은 greeting.js 라는 파일이 있습니다. 이 파일은 두개의 함수를 포함하고 있습니다.

1
2
3
4
5
6
7
8
// greetings.js
sayHelloInEnglish = function() {
return "Hello";
};

sayHelloInSpanish = function() {
return "Hola";
};

모듈 추출하기(exporting)

gretting.js 의 코드가 다른 파일에서 사용될 때 그 효용성이 증가할 것입니다. 이러한 일을 하기 위해서는 다음과 같은 3가지의 단계를 거쳐야 합니다.

1.greeting.js 파일의 코드 첫 부분에 다음과 같은 코드가 존재해야 합니다.

1
2
// greetings.js
var exports = module.exports = {};

2.다른 파일에서 exports 객체를 사용하기를 원한다면 greeting.js 파일에서 다음과 같이 작성해야 합니다.

1
2
3
4
5
6
7
8
9
// greetings.js
// var exports = module.exports = {};

exports.sayHelloInEnglish = function() {
return "HELLO";
};
exports.sayHelloInSpanish = function() {
return "Hola";
};

위의 코드에서 exports 를 module.exports 로 대체할 수 있으며 같은 결과를 얻을 수 있습니다. 이 부분이 잘 이해가 가지 않는다면 exports 와 module.exports 가 같은 객체를 참조한다고 기억하기 바랍니다.

3.module.exports 의 현재 값은 다음과 같습니다.

1
2
3
4
5
6
7
8
9
module.exports = {
sayHelloInEnglish: function() {
return "HELLO";
},

sayHelloInSpanish: function() {
return "Hola";
}
};

모듈 사용하기(importing)

main.js 라는 새로운 파일에서 greeting.js 의 메소드를 사용 할 수 있도록 import 하는 과정은 다음과 같습니다.

1.먼저 require이라는 키워드는 Node.js 에서 module(모듈)을 import(추가) 하기 위해 사용합니다. require는 다음과 같이 정의되어 있습니다.

1
2
3
4
5
6
var require = function(path) {

// ...

return module.exports;
};

2.main.js에서 greetings.js를 require 합니다.

1
2
// main.js
var greetings = require("./greetings.js");

위의 코드는 아래와 동일한 코드 입니다.

1
2
3
4
5
6
7
8
9
10
// main.js
var greetings = {
sayHelloInEnglish: function() {
return "HELLO";
},

sayHelloInSpanish: function() {
return "Hola";
}
};

3.main.js 에서 greeting.js 의 값과 메소드에 접근할 수 있습니다.

1
2
3
4
5
6
7
8
// main.js
var greetings = require("./greetings.js");

// "Hello"
greetings.sayHelloInEnglish();

// "Hola"
greetings.sayHelloInSpanish();

중요 포인트

require 키워드는 object 를 반환합니다. 그리고 module.exports 와 exports 는 call by reference 로 동일한 객체를 바라보고 있고, 리턴되는 값은 항상 module.exports 입니다.

모듈은 기본적으로 객체이고, 이 객체를 module.exports, exports 모두 바라보고 있는데, 최종적으로 return 되는 것은 무조건 module.exports 라는 것입니다.

1
2
3
4
5
6
7
8
9
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res) {
res.render('index', { title: 'Express' });
});

module.exports = router;

위의 소스는 다음과 같이 해석할 수 있습니다.
express.Router() 가 리턴한 “객체”에 일부 프로퍼티를 수정한 뒤, 이 객체 자체를 모듈로 리턴한 것입니다.