Приклад деплою App на Ruby On Rails
В даній замітці розглядається приклад деплою проетку під назвою tools на VPS-сервер Ubuntu 18.04 в каталог /home/deployer/apps/project/, код проекту знаходиться на git-сервері bitbucket.org у приватному репозиторію. Використовуємо Ruby 2.4.0 та Ruby On Rails 5
Підготовка VPS-серверу
Під root’ом, в цілях деплою нашого app створюємо користувача deployer :
1 |
adduser deployer |
Додаємо його в sudo (/etc/sudoers)
1 |
deployer ALL=(ALL:ALL) NOPASSWD:ALL |
Налаштовуємо часовий пояс
1 |
tzselect |
Задаємо UTF-8 локаль, відредагувавши /etc/default/locale до наступного вигляду:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
LANG=uk_UA.UTF-8 LANGUAGE="en_US.UTF-8", LC_CTYPE="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME=ru_UA.UTF-8 LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_PAPER="en_US.UTF-8" LC_NAME="en_US.UTF-8" LC_ADDRESS="en_US.UTF-8" LC_TELEPHONE="en_US.UTF-8" LC_MEASUREMENT="en_US.UTF-8" LC_IDENTIFICATION="en_US.UTF-8" LC_ALL="en_US.UTF-8" |
В /etc/environment добавляємо наступне
1 2 |
LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 |
Далі виконуємо наступні команди
1 2 3 |
sudo locale-gen en_US.UTF-8 sudo locale-gen uk_UA.UTF-8 sudo dpkg-reconfigure locales |
Оновлюємо встановлений софт та інсталюємо необхідне ПО
1 2 3 |
sudo apt-get update sudo apt-get upgrade sudo apt-get install curl libcurl3 libcurl3-dev nodejs postgresql postgresql-contrib libpq-dev git-core mc imagemagick libmagickwand-dev |
Інсталюємо RVM
1 2 3 4 5 6 |
command curl -sSL https://rvm.io/mpapis.asc | gpg --import - curl -L get.rvm.io | bash -s stable source ~/.rvm/scripts/rvm rvm install 2.4.1 rvm use 2.4.1 --default rvm rubygems current |
Створюємо базу даних та користувача
1 |
sudo -u postgres psql |
1 2 3 |
create user deployer with password 'password'; alter role deployer superuser createrole createdb replication; create database MYAPP_production owner deployer; |
Інсталюємо Bundler та Passenger
1 2 |
gem install bundler gem install passenger |
Знищуємо nginx, якщо він був встановлений
1 2 |
sudo apt-get purge nginx nginx-full nginx-light nginx-naxsi nginx-common sudo rm -rf /etc/nginx |
Інсталюємо Nginx та редагуємо конфігураційни файл default-хосту
1 |
rvmsudo passenger-install-nginx-module |
Вище наведена команда скачає, скомпілює та заінсталює ngnix (за змовчанням в /opt/nginx) з підтримкою passenger (в інтерактивному режимі вибераємо Ruby, потім варіант установки – 1)
Конфігураційний файл /opt/nginx/conf/nginx.conf
В моєму випадку було встановлено ruby 2.4.1 та passenger 5.1.11 (для інших версій правимо конфіг у відповідних місцях)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
user deployer; worker_processes 1; events { worker_connections 1024; } http { passenger_root /home/deployer/.rvm/gems/ruby-2.4.1/gems/passenger-5.1.11; passenger_ruby /home/deployer/.rvm/gems/ruby-2.4.1/wrappers/ruby; passenger_app_env production; client_max_body_size 100m; include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name localhost; root /home/deployer/apps/project/current/public; passenger_enabled on; error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } |
Автозапуска Nginx
Виконуємо команду
1 |
crontab -e |
Добавляэмо рядок
1 |
@reboot /opt/nginx/sbin/nginx |
Генерація ssh ключів
Оскільки користувачу deployer потрібний доступ до git-серверу а репозиторій проекту у нас приватний, ми генеруємо ssh-key
1 |
ssh-keygen -t rsa -C "<your@mail>" |
копіюємо його, подивившись командою
1 |
cat ~/.ssh/id_rsa.pub |
на git-сервер нашого проекту
Підготовка проекту на локальній машині для деплоя
Для деплоя проекту, нам потрібний ssh-доступ з докальної машини на VPS-сервер, для цього добавимо ssh-key на сервер deploy’я
1 |
ssh-copy-id deployer@<deploy-server.hostname> |
якщо у config/secrets.yml ми маємо
1 2 |
production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> |
тоді генеруємо токен
1 |
bundle exec rake secret |
та вставляємо його замість <%= ENV[“SECRET_KEY_BASE”] %>
Якщо проект в стадії розробки, варто буде в config/environments/production.rb задати
1 |
config.consider_all_requests_local = true |
щоб бачити реальні помилки замість сторінки із “we’re sorry”
Capistrano
В нашому локальному проекті добавимо наступні gem’и (в Gemfile)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
group :development do # Джем, який добавляє специфічні для Rails таски, такі як прогон міграцій і компіляція ассетів gem 'capistrano-rails' gem 'capistrano-rails-console' # Джем, який добавляє можливість bundle до capistrano gem 'capistrano-bundler' # Добалвення підтримки RVM (менеджера версій для Ruby) gem 'capistrano-rvm' # Інтеграція пасажира и капістрано gem 'capistrano-passenger' gem 'capistrano-linked-files' end |
Виконуємо інсталяцію нових gem’ів та capistrano
1 2 |
bundle install cap install |
В результаті у нас з’являться наступні два нові файли
config/deploy.rb
config/deploy/production.rb
Конфігурація config/deploy.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# Назва проекту set :application, 'tools' # Шляз до tools репозиторія set :repo_url, 'git@bitbucket.org:username/tools' # Вітка за змовчанням set :branch, 'master' # Директорія для деплоя set :deploy_to, '/home/deployer/apps/tools' set :default_stage, 'production' set :log_level, :info # Файли та директорії (між деплоями), об'єкти яких немає в проеті потрібно забрати set :linked_files, %w{config/database.yml} set :linked_dirs, %w{tmp/pids tmp/cache tmp/sockets vendor/bundle public/uploads} # А це рекомендують добавити для проектів, які використовують ActiveRecord set :puma_init_active_record, true namespace :deploy do desc 'Restart application' task :restart do on roles(:app), in: :sequence, wait: 5 do # Your restart mechanism here, for example: # execute :touch, release_path.join('tmp/restart.txt') end end after :restart, :clear_cache do on roles(:web), in: :groups, limit: 3, wait: 10 do # Here we can do anything such as: # within release_path do # execute :rake, 'cache:clear' # end end task :seed do on roles(:all) do within release_path do with rails_env: fetch(:rails_env) do execute :rake, "db:seed" end end end end task :precompile do on roles(:all) do within release_path do with rails_env: fetch(:rails_env) do execute :rake, "assets:precompile --trace" end end end end task :setup do before "deploy:migrate", :create_db invoke :deploy end task :create_db do on roles(:all) do within release_path do with rails_env: fetch(:rails_env) do execute :rake, "db:create" end end end end end after :finishing, 'deploy:cleanup' end |
Конфігурація config/deploy/production.rb, полягає лише у втсавці ip-адресу vps-серверу
1 |
server '<ip>', user: 'deployer', roles: %w{web app db} |
Якщо ви не захотіли по якійсь причині використовувати ключі для доступу до VPS-серверу, ми можете прописати ssh-параметри доступу в цьому файлі
1 2 3 4 5 6 7 |
set :ssh_options, { forward_agent: false, auth_methods: %w(password), password: '<your_password>', user: 'deployer', } |
Конфігурація Capfile
1 2 3 4 5 6 7 8 9 10 |
require "capistrano/setup" require "capistrano/deploy" require 'capistrano/rvm' require 'capistrano/bundler' require 'capistrano/passenger' require 'capistrano/rails/assets' require 'capistrano/rails/migrations' require 'capistrano/linked_files' Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r } |
Виконуємо deploy!
1 2 |
bundle exec cap production linked_files:upload_files cap production deploy |