brunch

You can make anything
by writing

C.S.Lewis

by Freddy Mar 02. 2018

Rails Deploy on AWS EC2 AMI

베포할 때 마다 꺼내보면 좋은.

SSH 설정

.pem 확장자의 키 파일을 다운받은 뒤

~$ chmod 400 <PEM_FILE_NAME>.pem


Git

git 설치

~$ sudo yum search git
>> git-all.noarch 복사

~$ sudo yum install git-all.noarch
>> yes 입력해 계속 진행


git clone project

~$ git clone <YOUR_GIT_REPO_URL>


Ruby 세팅 (RVM)

시작하기 전에, curl이 필요하다.

~$ curl
이 때, command not defined 등의 '못알아듣겠다'는 뜻의 짧은 메세지가 나온다면 다음을 따라 curl 을 설치하자.

~$ sudo yum search curl
그러면 설치 가능한 curl 목록이 출력된다. 이 중 libcurl-devel.x86_64 를 설치하자.

~$ sudo yum install libcurl-devel.x86_64
망설이지 말고 yes를 입력하며 빠르게 완료.


자, 시작. RVM부터 설치하자.

참고로, RVM은 Ruby Version Manager의 약자다.

http://rvm.io/ 접속 후 Cut Rubies with ease! 하단의 install RVM: 이하 두 줄을 다음과 같이 복사해 붙여넣는다. (rvm에서 자세한 해시는 변경할 수 있으니 반드시 접속해서 복붙하자)

~$ gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E37D2BAF1CF37B13E2069D6956105BD0E739499BDB

# 주의: 맨 앞의 '\' 는 빼고 붙여넣어야 함
~$ curl -sSL https://get.rvm.io | bash -s stable

완료되면 다음과 같은 안내 메시지가 보일 때가 있다.
* To start using RVM you need to run `source /home/ec2-user/.rvm/scripts/rvm`
안내 메시지가 나온다면 그대로 실행하자.
~$ source /home/ec2-user/.rvm/scripts/rvm

잘 설치가 되었는지는 터미널에 ~$ rvm 을 입력해 사용법 안내가 뜨는 것으로 확인할 수 있다.


Ruby 설치

정작 ruby 설치는 간단하다.

~$ rvm install ruby


프로젝트의 의존성 라이브러리 설치

# 편의상 <PRJ_DIR_NAME> 를 prj 라고 하자
~$ cd prj
~/prj $ bundle install

이렇게 하면 bundle 이 없다고 나올 것이다. bundler를 먼저 설치 후 다시 실행.

~/prj $ gem install bundler
~/prj $ bundle install

# 홈으로 나온다.
~/prj $ cd
> ~ $ 로 터미널 위치가 변경된 것을 확인할 수 있다.


Nginx

Pushion Passenger 설치

~$ gem install passenger


Root 계정으로 이동

~$ sudo passwd
> 비밀번호 설정

~$ su
> 비밀번호 입력 뒤 root 계정으로 접속

~$ cd /
> root 디렉토리로 이동


Nginx 설치

/ $ passenger-install-nginx-module
> Enter 를 눌러 계속 진행이라고 뜨면, Enter를 누른다.

## 그러면 다음과 같은 메세지가 뜰 것이다.
Use <space> to select.
If the menu doesn't display correctly, press '!'
‣ ⬢  Ruby
   ⬢  Python
   ⬡  Node.js
   ⬡  Meteor

## 방향키로 파이썬으로 내려가 Space를 눌러 지워준 뒤, 다음과 같은 상태로 만들어줌.
   ⬢  Ruby
‣ ⬡  Python
   ⬡  Node.js
   ⬡  Meteor

 Enter를 한 번만 눌러 다음 단계로 이동. (여기서 더 진행하지 말고 안내를 따르자)


바로 이런 메세지를 만나게 될 것이다.

Warning: some directories may be inaccessible by the web server!

The web server typically runs under a separate user account for security
reasons. That user must be able to access the Phusion Passenger files.
However, it appears that some directories have too strict permissions. This
may prevent the web server user from accessing Phusion Passenger files.

It is recommended that you relax permissions as follows:

  sudo chmod o+x "/home/ec2-user"

Press Ctrl-C to return to the shell. (Recommended)
After relaxing permissions, re-run this installer.
  -OR-
Press Enter to continue anyway.


여기서 안내 메시지 대로 Ctrl or Cmd + C 를 눌러 잠시 프로세스를 중단한다.

그리고 안내 메시지에서 안내된 대로 다음 명령을 입력한다.

/ $ sudo chmod o+x "/home/ec2-user"

# 그리고 다시 다음을 실행.
/ $ passenger-install-nginx-module


이후에도 똑같이 진행하면 이번엔 다음 단계에서 멈춘다.

[ Cannot find the `curl-config` command ] 라는 빨간 글씨를 만났을 것이다.

(위에서 설치했다면 안 만날 수도 있다)

그러면 다시 Ctrl or Cmd + C 를 눌러 프로세스를 중단한다.


Curl 설치

/ $ sudo yum search curl
>> libcurl-devel.x86_64 복사

/ $ sudo yum install libcurl-devel.x86_64
>> y 입력해 계속 진행후 완료


다시 Nginx

/ $ passenger-install-nginx-module


이후에도 똑같이 진행. 이번엔 또 다른 단계에서 멈춘다. 메모리 부족 문제다.

EC2 t2.micro 를 사용하고 있다면, 다음 메시지를 만나게 된다:

Your system does not have a lot of virtual memory
Compiling Phusion Passenger works best when you have at least 1024 MB of virtual
memory. However your system only has 993 MB of total virtual memory (993 MB
RAM, 0 MB swap). It is recommended that you temporarily add more swap space
before proceeding. You can do it as follows:

  sudo dd if=/dev/zero of=/swap bs=1M count=1024
  sudo mkswap /swap
  sudo swapon /swap

See also https://wiki.archlinux.org/index.php/Swap for more information about
the swap file on Linux.

If you cannot activate a swap file (e.g. because you're on OpenVZ, or if you
don't have root privileges) then you should install Phusion Passenger through
DEB/RPM packages. For more information, please refer to our installation
documentation:

  https://www.phusionpassenger.com/library/install/nginx/

Press Ctrl-C to abort this installer (recommended).
Press Enter if you want to continue with installation anyway.


또 Ctrl or Cmd + C 를 눌러 프로세스를 중단하고, 다음을 그대로 실행한다:

/ $  sudo dd if=/dev/zero of=/swap bs=1M count=1024
/ $  sudo mkswap /swap
/ $  sudo swapon /swap

# 그리고 또 실행
/ $ passenger-install-nginx-module
> 이번에 멈출 땐 1을 입력해 (recommended) 를 선택해 그대로 진행.
> 이제야 본격적인 Nginx 설치가 시작된다.

# 그러다가 다음 메시지에서는 그대로 Enter.
Please specify a prefix directory [/opt/nginx]:
> 이제 어마어마한 설치를 진행하고 마지막에 Enter 를 눌러주면 끝난다.

그리고 root 계정에서 나와주자.

/ $ exit
그러면 다시 HOMEPATH (~$) 로 이동해 있을 것이다.


Nginx Config 설정

config 파일을 연다.

~$ sudo vi /opt/nginx/conf/nginx.conf


config 파일의 http 블록 내부에 있는 [ #gzip  on; ] 바로 아래에,

server 블록을 다음과 같이 추가해준다.

...

http{

      ...

      #gzip  on;
      
      server {
           listen 80;
           server_name <YOUR_DOMAIN_NAME or SERVER_IP>;
           root /home/ec2-user/<PRJ_DIR_NAME>/public;
           passenger_enabled on;
      }
}


서버 실행

자, 이제 Nginx를 사용해 서버를 실행해보자.

명령어들은 다음과 같다.
~$ sudo /opt/nginx/sbin/nginx                      # 서버 start   (서버가 stop 상태일때 가능)
~$ sudo /opt/nginx/sbin/nginx -s stop        # 서버 stop    (서버가 start 상태일때 가능)
~$ sudo /opt/nginx/sbin/nginx -s restart    # 서버 재시작 (서버가 stop 상태가 아닐때 가능)

이 중, start 를 실행하면 서버가 실행된다.


그리고 드디어 서버의 ip를 브라우저 주소창에 입력해 서버가 잘 돌아가는지 확인해보자.

겁먹지 말자. 정확히는, 서버는 잘 돌아갔으나, 우리의 앱 실행에 문제가 있는 상태다.

저런, 뭔가를 빠뜨렸다. 고쳐보자.


Asset Pipeline Precompile

Prj 디렉토리로 이동

~$ cd prj


다음의 프리컴파일 명령을 실행하자.

~/prj $ RAILS_ENV=production bin/rails assets:precompile

# (참고) asset의 변경사항이 생길 때마다 자주 쓰일 것이기 때문에, alias 로 만들어두면 편하다.


명령을 실행하면 에러가 발생할 수도 있다.(아마 지금 단계에서는 무조건.)


SECRET 설정

여기서는 gem 'figaro' 를 사용했다.

먼저 Gemfile 에서 'therubyracer' 의 주석을 해제하고, 아래에 gem 'figaro' 를 추가해준다.

그리고 다음 명령을 실행한다.

~/prj $ bundle exec figaro install

그러면 다음과 같은 메세지가 출력될 것이다.

      create  config/application.yml        # 새로운 환경변수 관리 파일을 생성해준다.
      append  .gitignore              # 그리고 그 파일은 원격 리포지토리에 올라가지 않도록 막아준다.


절대로. 절대로.

환경변수나 secret 들은 다른 곳 말고 저 안(config/application.yml)에만 넣어두고

깃헙 같은 곳에 올라가지 않게 철저히 관리하자.

해킹으로 인해 수천만원에 달하는 요금청구를 경험하고 싶지 않다면!!

제발!!!


일단 미리 말해두자면, 임의의 해시를 생성하는 방법은 다음 명령으로 실행할 수 있다.

~/prj $ rake secret

# 그럼 다음과 같은 임의의 괴 문자열이 출력된다. 복사해서 사용하면 된다.
0df9b73f238c36fee82258b7ad974a1d16396245447e0a5239fa7326e261d220de8b45d099f9539d464d8a6126ce03fa1f201d4192691487de1e772f509fd5


그리고 다음 두 개의 파일을 아래 처럼 편집 해준다.

# 먼저, config/application.yml

...

SECRET_KEY_BASE: <SOME_YOUR_HASH>    # rake secret 으로 생성한 Hash
DEVISE_SECRET: <SOME_OTHER_YOUR_HASH>    # rake secret 으로 생성한 또 다른 Hash
# 다음으로, config/initializers/devise.rb

...
Devise.setup do |config|
  ...
  config.secret_key = ENV['DEVISE_SECRET']     # 여기서 원래 주석으로 존재하던 해시는 남겨놨다가 요금폭탄 맞지말고 제발 지우자.
  ...
end


참고로, application.yml 파일에서 지정한 SECRET_KEY_BASE 는 config/secret.yml 에서 사용되고 있다. 두 환경변수의 키가 동일하기만 하면 되니까, SECRET_KEY_BASE 말고 다른 PRJ_MY_LOL_KEY 처럼 해커들이 예측할 가능성이 낮은 키 이름으로 변경해주면 좋다. 어쨌든 secret.yml 와 application.yml 에서 동일하기만 하면 된다.


그리고 다음 명령을 살짝 실행해주자. 앱을 (서버가 아니라) 껐다 켜는 명령이다.

~/prj $ touch tmp/restart.txt

본래 앱을 껐다 켜라고 있는 명령은 아니지만 리눅스 timestamp 시스템을 이용한 명령으로, 아마추어 수준에서는 앱을 껐다 켜는 용도로 자주 쓰인다.


지금은 등록한 환경변수들을 시스템에 기록하고 로드하기 위해 앱을 재시동 했다.

secret 설정이 끝났으니, 다시 돌아와 Asset Precompile을 실행해주자.


~/prj $ RAILS_ENV=production bin/rails assets:precompile

이어 출력되는 문장들을 통해 css, javascript, font 등이 컴파일 되는 것을 확인할 수 있다.

컴파일된 asset 들은 public/assets 폴더 내에 위치한다. 이 폴더는 굳이 개발환경에서 읽어올 필요가 없고 괜히 무거워지기만 하므로 .gitignore 에 추가해 업로드를 방지해준다.


여기까지 무난하게 완료되었다면 서버를 재시작하고, 앱도 재시작 해주자.

~/prj $ sudo /opt/nginx/sbin/nginx -s restart
~/prj $ touch tmp/restart.txt

그리고 다시 브라우저를 확인하면, 완성된 root 페이지를 확인할 수 있다.


추가적으로,,

Production 환경

개념보다는 필요한 것만 딱딱 얘기해본다.

혹시 바로 위에서 root 페이지가 나타나지 않고 에러가 발생하면, db migrate 가 필요한 것일 확률이 높다.

베포된 서버의 환경은 production환경이라 불리는데, development와는 다르게 보안을 위해 실수로라도 쉽게 변경할 수 없도록 막아주는 여러 장치가 되어있다.

이 이야기를 하는 이유는 같은 db migrate 라도 rake db:migrate 가 아니라

rake db:migrate RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1

라는 길고 긴 명령을 사용해야 하기 때문이다. (물론 많은 분들이 alias 를 설정해 쉽게 사용하곤 하지만..)

다른 rake db 명령들도 모두 뒤에 저 꼬리들을 붙여야만 한다.


만약 저 꼬리들 없이 그대로 사용하면 서버컴퓨터의 로컬 개발환경에서 개발환경의 DB에 명령하는 것이므로, 베포된 서비스와 무관한 동작을 하게된다.


마찬가지로 레일즈 콘솔 또한 rails c 가 아니라 rails c production 명령으로 진입해야한다.


로그 확인하기

개발환경과는 다르게도, 크게 서버 로그와 앱 로그가 있다.

서버 로그는 다시, access 로그와 error 로그를 가지고 있다.


먼저, access 로그는 '서버가 전달받는 모든 접속 요청'을 기록한다. 참고로, 앱에서 puts 로 프린트 하는 것들이 여기에서 찍힌다. (왜 그런지 궁금해서 찾다보면 또 다른 공부의 세계가 열린다)

로그 파일의 위치: /opt/nginx/logs/access.log

로그 쉽게 출력하기: sudo tail -f /opt/nginx/logs/access.log


다음으로, error 로그는 '서버 입장에서 레일즈가 구동되기에 부적합한 상태라고 판단되는 모든 에러'를 감지해 출력한다. 이해하기 쉽게 표현하자면 앱을 빌드하다가 실패하면 에러를 뿜는다고 보면 된다. 주로 읽다보면 spawning error 라는 말이 자주 나오는데, 가장 많은 경우, 앱 코드에 오타가 있을 확률이 높다.(삽질을 시작하면 된다) 이 에러는 저 위에서 첨부한 에러 화면과는 또 다른 에러 화면을 보여준다.

로그 파일의 위치: /opt/nginx/logs/error.log

로그 쉽게 출력하기: sudo tail -f /opt/nginx/logs/error.log


한편, 서버로그는 production 로그가 있다. production 환경이기 때문에 그렇다. 개발 환경에서 rails server 명령으로 서버를 띄워 실행했을 때 출력되는 모든 쿼리, 랜더링 등의 로그들이 이 곳에 쌓인다고 보면 쉽다.

1) 원래는 환경-development, test-에 따른 로그와 job을 설정하면 또 그에 따른 백그라운드 로그가 있을 수 있지만, 이 레벨에서 다루지는 않는다.

2) 쓸데 없이 조금 더 정확히 이해해 보자면 개발환경에서 기록하던 로그들을 access, error, production 이 나눠 갖는 구조에 가깝다. 뭐, 나중에 알면 되고 쓸데 없는 부연이다

로그 파일의 위치: ~/<YOUR_PRJ_DIR>/log/production.log

로그 쉽게 출력하기: sudo tail -f ~/<YOUR_PRJ_DIR>/log/production.log


여기까지 AWS EC2 AMI 를 기준으로 linux CentOS 환경에서 Rails 앱을 베포하는 과정이었다.


종종 빈스토크가 동작하지 않는 환경이나, 클라우드 환경의 제약으로 디버깅이 불편한 경우가 있다.

그럴땐 그냥 하드하게 세팅을 해버리는 편인데, 가끔씩 있는 일이다보니 잊어버리는 명령이나 빼먹는 순서들이 자꾸 생겨서 이번 기회에 세팅을 직접 하며 기록을 해봤다.

미래의 나를 포함해 무사히 삽질하고 무사히 베포 마치시기를.




궁금하거나 제가 잘못 알고 있는 점, 혹은 토론해보고 싶은 주제에 대한 댓글을 환영합니다!

아직 많이 부족하고 배워야 하는 3년차 신입입니다..ㅎㅎ

작가의 이전글 블록체인 쉽게 이해하기
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari