Ruby on Rails Background Job 처리용 서버 만들기

시작하기에 앞서

글에서 다루고 있는 프로젝트는 Ruby on Rails, Puma, Capistrano, Sidekiq, aws EC2, aws RDS를 사용 중이며, production 환경을 기준으로 작성되었다.

Sidekiq 이미지 업로드 큐의 워커만 처리하는 worker-image, 이외 큐의 워커를 처리하는 worker-general, 두 개의 서버를 새로 만드는 것이 목적이었다.

(원글이 작성된 시점은 2021년 2월 23일로, 포스팅에서 설명한 대로 진행한 다음 조금의 에러가 있어서 설정을 조금 더 건드려 주었던 것으로 기억하는데 어떤 부분이었는지 기억이 나질 않아 덧붙일 수가 없다😭 개인적인 기록 용도로 적어 놓는 공간이지만, 혹시 이 포스트를 읽게 되는 분이 계시다면 그 부분을 감안해 주시면 좋겠다.)

aws-cli로 존재하는 인스턴스의 이미지(AMI) 만들기

config 파일 설정하기

aws-cli가 설치되어 있지 않은 경우 설치 가이드에 따라 aws-cli (Version 2.x)를 설치한다.

설치 후 생성된 .aws 폴더에 아래와 같이 config 라는 이름의 파일을 설정해 준다.

> vi .aws/config

[default]
region=ap-northeast-2
output=json

이 때, region의 경우 AMI를 만들고 싶은 해당 인스턴스가 존재하는 곳 이어야 한다.

AMI 만들기

터미널에 아래와 같이 입력 후 실행하면 json 형식으로 새로 만들어진 AMI의 ID가 반환된다.

> aws ec2 create-image \
  --instance-id i-EXAMPLE_INSTACE_ID \
  --name "for-worker-server" \
  --no-reboot

만들어진 AMI는 pending 상태가 된다. available 상태가 되어야지 다음 단계로 돌입할 수 있는데, 상태가 변하기 까지는 시간이 조금 걸릴 수 있다.

Terraform으로 aws EC2 인스턴스 만들기

Terraform 파일 작성하기

provider "aws" {
  access_key = "EXAMPLE_ACCESS_KEY"
  secret_key = "EXAMPLE_SECRET_KEY"
  region = "ap-northeast-2" # AMI가 존재하는 region과 같아야 한다
}

resource "aws_instance" "web" {  
  count = 2 # 지정한 숫자 만큼의 instance가 생성되며 count가 없을 경우는 자동으로 1로 설정된다
  ami = "ami-EXAMPLE_AMI"
  instance_type = "t2.medium"
  key_name = "EXAMPLE_KEY_NAME"
  vpc_security_group_ids = [
    "sg-EXAMPLE_SG"
  ]
  connection {
    user = "ubuntu"
    type = "ssh"
    host = self.public_ip
    private_key = file("~/.ssh/id_rsa")
    timeout     = "2m"
  }
}

위와 같은 .tf 파일을 작성한 후 아래 명령들로 실행 시킨다. (단, terraform init의 경우 이전에 실행했던 적이 있다면 패스한다.)

> terraform init
> terraform plan
> terraform apply

이 때, 동일한 세팅으로 인스턴스를 생성한 적이 있을 경우 앞서 생성했던 인스턴스가 삭제 될 수 있으므로 terraform plan 이후 생성되는 메시지를 잘 살펴 보아야 한다.

위의 이미지와 같이 N to add, 0 to destroy 임을 확실하게 확인해 주면 좋다.

RDS와 EC2 인스턴스 연결

RDS 콘솔에서 사용중인 RDS 인스턴스를 선택하고, 아래 이미지와 같이 Connectivity & security 탭에서 VPC security group을 확인한다.

EC2 콘솔에서 Security Groups 페이지로 들어간 후, RDS 콘솔에서 확인했던 것과 같은 Security Group을 선택한다.

Edit inbound rules를 클릭해 아까 Terraform을 통해 생성했던 EC2 인스턴스의 security group이 포함되도록 설정해 준다.

Capistrano 설정

config/deploy.rb에 아래와 같이 추가한다.

set :sidekiq_roles, %w{EXAMPLE_ROLE_1 EXAMPLE_ROLE_2}

config/deploy/production.rb에 아래와 같이 추가한다.

server 'PUBLIC_IP', user: 'EXAMPLE_USER', roles: 'EXAMPLE_ROLE_1'
server 'PUBLIC_IP', user: 'EXAMPLE_USER', roles: 'EXAMPLE_ROLE_2'

Sidekiq 설정

서버마다 sidekiq.yml, sidekiq.conf 파일을 별개로 만들어 줄 것이다. 서버에 접속해 아래와 같이 sidekiq.yml 파일을 만들거나 수정해 준다.

> vi EXAPLE_PROJECT/shared/config/sidekiq.yml

...
:roles: :EXAMPLE_ROLE
...
:queues:
...
  - EXAMPLE_QUEUE

sidekiq.yml(config.yml) 파일의 형태는 링크에서 확인해 볼 수 있다.

경로를 이동해 sidekiq.conf 파일 또한 생성 후 아래와 같이 수정한다.

> vi /etc/init/sidekiq.conf

...
  exec bundle exec sidekiq -C shared/config/sidekiq.yml -e production
EOT

Nginx 에러가 나타날 경우 해결 방법

접속 시 Nginx Default 페이지가 보일 경우

위의 이미지는 Nginx Default 페이지 화면이다.

생성된 EC2 인스턴스의 퍼블릭 IP 주소에 접속했을 때, 의도치 않았음에도 위와 같이 Nginx의 default 화면이 나타날 경우 default configuration 파일을 삭제하고 커스텀 파일만 남겨주면 해결 된다.

생성한 EC2 인스턴스가 두 개라, 일일이 ssh로 접속해서 지워주기는 번거로워서 Ansible을 Playbook을 만들어 실행시켰다.


---

- hosts: all 
  become: true
  become_method: sudo
  become_user: root

  tasks:
    - name: check whether default in nginx is exist
      stat:
        path: /etc/nginx/sites-available/default
      register: default

    - name: remove default nginx
      command: zsh -lc "rm default"
      args: 
        chdir: /etc/nginx/sites-available
      when: default.stat.exists
    
    - name: unlink default nginx
      command: zsh -lc "unlink default"
      args: 
        chdir: /etc/nginx/sites-enabled
      when: default.stat.exists

    - name: restart nginx
      service: 
        name: nginx
        state: restarted
> ansible-playbook -i INVENTORY_FILE EXAMPLE_PLAYBOOK.yaml

Ansible을 이용하지 않고 직접 삭제할 경우, 먼저 ssh로 해당 서버에 접속한다.

그 후 nginx sites-available에 존재하는 default 파일을 지운다.

> cd /etc/nginx/sites-available
> rm default

Symbolic link도 삭제한다.

> cd /etc/nginx/sites-enabled
> unlink default

마지막으로, Nginx를 재시작 한다.

> sudo service nginx restart

Nginx 502 Bad Gateway 에러가 나타날 경우

Puma가 안 켜졌을 가능성이 높다. 로컬에서 아래 명령을 실행 시킨다.

> bundle exec cap production puma:restart

서버에 접속해 Nginx를 재시작 한다.

> sudo service nginx restart

좋은 웹페이지 즐겨찾기