Ansible과 pm2를 이용해 Node.js 앱 띄우기

Ansible을 이용하여 Node.js 앱의 배포 및 실행 환경을 구축해보았습니다.

2017. 10. 29.

퇴고 안한 글! 이 글은 아직 퇴고가 진행되지 않았습니다. 오탈자를 발견하시면 댓글로 알려주세요. 빠르게 수정하도록 하겠습니다.

최근 Node.js 앱을 서비스 환경으로 운영해야할 필요가 생겼습니다. 기존 배포 환경은 전부 tomcat + spring boot에 맞춰져있었는데요, 이번 기회에 node.js 앱 배포 환경을 구축해보기로 했습니다.

준비사항

Ansible 설정

인벤토리 설정

우선 node.js 환경을 배포할 서버 인벤토리와 각종 변수들을 파일로 저장합니다.

#
# inventories/hosts
#

[node_app]
server_01 ansible_ssh_host=127.0.0.1

[node_app:vars]
app_name=node_app

여러 앱들간에 공유되는 변수들은 아래와 같이 group_vars 디렉토리로 분리하여 관리하는 것이 편리합니다.

#
# inventories/hosts/group_vars/all.yml
#

user_name: remote_username

Node.js 및 pm2 셋팅 role, playbook 추가

pm2는 노드 애플리케이션의 프로세스를 관리해주는 툴입니다. 기본적으로 forever와 유사한 역할을 하지만, 앱이 죽었을 때 자동으로 재시작하거나 동시에 n개의 프로세스를 띄워 서버 내 로드밸런싱을 해주는 등 더 많은 기능을 담고 있습니다.

여기에서는 그런 복잡한 기능은 사용하지는 않고, 앱의 프로세스를 유지하는 정도의 기능만을 사용하고자 합니다.

#
# roles/my.webapp_nodejs/tasks/main.yml
#

## pm2 설치
- name: install pm2
  npm: name=pm2 global=true production=true

## 앱이 배포될 경로 생성
- name: create app path
  file:
    path: "/home/{{ user_name }}/apps/{{ app_name }}"
    owner: "{{ user_name }}"
    state: directory
    recurse: true

우선 서버에 pm2를 설치하는 role과, 이를 활용해 앱을 운영할 수 있는 환경을 구축하는 playbook을 작성합니다.

#
# setup_webapp_nodejs.yml
#
# 실행 전 아래 구문을 통해 role을 import 해주어야 함 =>
#   ansible-galaxy install geerlingguy.nodejs --roles-path ./roles
#

- name: setup webapp nodejs
  hosts: "{{ host }}"
  remote_user: "{{ user_name }}"
  vars:
    - nodejs_version: "8.x"
  roles:
    - geerlingguy.nodejs
    - my.webapp_nodejs
  become: yes

node.js role은 geerlingguy.nodejs를 import하여 사용했습니다. 주석에 작성되어있는 것처럼 ansible-galaxy를 통해 role를 우선 import 해주어야합니다.

실행 구문은 아래와 같습니다.

ansible-playbook -i inventories/hosts setup_webapp_nodejs.yml \r
  --extra-vars "host=node_app"

앱 배포 및 실행 playbook 추가

순서는 다음과 같습니다.

  1. rsync를 이용해 앱을 서버로 배포
  2. npm 의존성 모듈을 설치 (업데이트)
  3. 앱의 실행 상태를 확인하여, 만약 실행중이라면 기존의 앱을 종료
  4. 앱 실행

이러한 흐름를 바탕으로 playbook을 작성합니다.

#
# deploy_webapp_nodejs.yml
#

- name: deploy webapp nodejs
  hosts: "{{ host }}"
  remote_user: "{{ user_name }}"
  vars:
    remote_path: "/home/{{ user_name }}/apps/{{ app_name }}"
  tasks:      
    ## 앱을 서버로 배포 (rsync)
    - name: sync app
    synchronize:
      src: "{{ local_path }}/"
      dest: "{{ remote_path }}"
      recursive: true

    ## npm 의존성 모듈을 설치
    - name: install dependencies
      npm: path={{ remote_path }}

    ## 앱의 설치 상태를 확인
    - name: check for webapp
      shell: "pm2 show {{ app_name }}"
      register: webapp_result
      ignore_errors: true
      become: true

    ## 기존의 앱을 종료
    - name: stop webapp
      shell: "pm2 stop {{ app_name }}"
      when: "webapp_status.rc == 0"
      ignore_errors: true
      become: true

    ## 앱 실행
    - name: start webapp
      shell: "pm2 start {{ remote_path }}/index.js --name {{ app_name }}
      become: true

실행 구문은 아래와 같습니다. (local_path 값으로는 배포할 앱의 로컬 경로를 지정합니다.)

ansible-playbook deploy_webapp_nodejs.yml -i inventories/hosts \r
  --extra-vars="host=node_app local_path=(path_of_app)"

서비스 잘 떴는지 확인

배포한 서버에 직접 접속할 수 있는 환경이라면, 직접 들어가서 확인해보는게 무엇보다도 확실합니다.

서버에 접속하여 아래 명령어를 통해 서비스가 잘 떴는지 확인해봅시다.

pm2 status

또는

pm2 show (app_name)
크리에이티브 커먼즈 라이선스

이 저작물은 크리에이티브 커먼즈 저작자표시-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.

© 2011 - 2020 Do Hoerin, LYnLab