Deploying a Simple Rails App with Ansible
Ruby on Rails is quickly becoming my framework of choice for my personal websites and projects. It's a pleasure to work with and has been easy to learn. But no framework is without its challenges. One of those challenges is of course deploying the app to a server. There are a lot of options for hosting and deploying a Rails app. But, I like to run my own servers which means I have to also take care of deploying to those servers. I'd prefer to be deploying images to AWS ECS but I don't need that kind of infrastructure for my personal website. It's just a blog it can suffer seconds of downtime when I deploy updates. So my approach these days is to use Ansible to handle the deploy steps.
---
- name: Deploy Rails
hosts: app.roylindauer.com
vars:
branch: "main"
homedir: "/myapp"
handlers:
- name: restart workers
become: true
become_user: root
service:
name: rails-workers
state: restarted
- name: restart web
become: true
become_user: root
service:
name: rails-web
state: restarted
- name: restart nginx
become: true
become_user: root
service:
name: nginx
state: restarted
tasks:
- name: Get Latest Source
git:
repo: git@github.com:roylindauer/roylindauer.com.git
dest: /myapp
update: yes
version: "{{ branch }}"
force: yes
notify:
- restart workers
- name: Bundle Install
shell:
chdir: "{{ homedir }}"
cmd: "bin/bundle install --without development --path vendor/bundle"
- name: Update Yarn
shell:
chdir: "{{ homedir }}"
cmd: "bin/yarn install"
- name: Check for Pending Migrations
shell:
chdir: "{{ homedir }}"
cmd: "bin/rails db:migrate:status | grep -e '^ down' | wc -l"
register: pending_migrations
- debug:
msg: "Pending Migrations: {{ pending_migrations['stdout'] }}"
- name: Stop Workers
become: true
become_user: root
service:
name: rails-workers
state: stopped
when: pending_migrations['stdout'] != '0'
- name: DB Migrations & Restart Services
shell:
chdir: "{{ homedir }}"
cmd: "bin/rake db:migrate"
when: pending_migrations['stdout'] != '0'
notify:
- restart workers
- name: Webpack
shell:
chdir: "{{ homedir }}"
cmd: "bin/webpack"
notify:
- restart web
- restart nginx
- name: Precompile Assets
shell:
chdir: "{{ homedir }}"
cmd: "bin/rails assets:precompile"
notify:
- restart web
- restart nginx
Basically, do a git pull, update gems, then check for pending migrations. If there are migrations, stop workers, run migrations. After that compile assets, then finally restart services.
For hosting a simple rails app on a single server this sort of deploy works very well.