Запуск ruby on rails на uwsgi на примере redmine
Table of Contents
Для лично-рабочих нужд я активно использую task-tracking system под названием Redmine. Redmine практически всем хорош из открытых трекеров, но очень любит память. Традиционно он запускается через rails server (WEBRick) или rails-specific сервер thin. Во второй конфигурации у меня он жрал 300Мб оперативной памяти, а среднее время генерации страницы было близко к секунде, что совершенно неприемлимо. По этой причине я решил использовать uwsgi - совершенно прекрасный appserver, который я активно использую для своего творчества на python. Uwsgi работает очень быстро (действительно - очень!), достаточно экономно относится к памяти, обладает широчайшими возможностями конфигурирования - просто-таки мечта, а не сервер. До недавнего времени он умел работать только с python (под который интерфейс uWSGI, строго говоря, и создавался), но теперь умеет обрабатывать ruby и даже PHP. Минусом uwsgid является, во-первых, тот факт, что он находится на переднем крае разработок, а значит - может работать ой как своеобразно. Не менее своеобразно он настраивается, и документации по нему очень мало.
#
Идея
Запускать будем redmine, но это типовое rails приложение, все остальные запускаются так же. В качестве веб-сервера - nginx, апп-сервер - uwsgid, база данных - postgresql (но будет уточнение для mysql), для управления uwsgid будем использовать supervisord
#
Зависимости
Ставим системные компоненты:
apt-get update
apt-get install gcc cpp make nginx
#postgresql
apt-get install postgresql libpq-dev
#или mysql
apt-get install mysql libmysqlclient-dev
Лирическое отступление: я рекомендую использовать rvm вместо штатного руби. RVM живет вне пакетов, и обновлять его надо вручную, однако он позволяет получить самую свежую версию ruby, кроме того - он позволяет использовать несколько разных версий языка, а так же - несколько разных наборов библиотек (gem), не пересекая их друг с другом. Если у вас несколько приложений на ruby делят один сервер - это крайне удобный функционал.
Ставим ruby:
#системная версия
apt-get install ruby1.8 ruby1.8-dev rubygems
#ИЛИ rvm
curl -L https://get.rvm.io | bash -s stable
rvm install 1.9.3-p429
Теперь доустанавливаем gem bundle. Он отвечает за установку необходимых для работы веб-приложения библиотек
gem install bundle
#
Установка Redmine
Создадим базу данных и пользователя для работы с ней:
#вариант для postgresql
sudo -u postgres psql
psql# create user redmineuser nocreatedb nocreateuser;
psql# alter role redmineuser with password 'MySecretP@ssw0rd';
psql# create database redminedb owner redmineuser;
#вариант для mysql
mysql -p
mysql> create database redminedb;
mysql> grant all on redminedb.* to redmineuser@localhost identified by 'MySecretP@ssw0rd';
mysql> flush privileges;
Теперь скачиваем и ставим сам redmine. Последнюю версию берем [http://rubyforge.org/frs/?group_id=1850] тут.
wget http://rubyforge.org/frs/download.php/76933/redmine-2.3.1.tar.gz
tar -xf redmine-2.3.1.tar.gz
mv redmine-2.3.1 redmine
Для корректной работы надо исправить файл config/database.yml в корне приложения. Вот пример для postgresql:
production:
adapter: postgresql
database: redminedb
host: localhost
username: redmineuser
password: MySecretP@ssw0rd
encoding: utf8
schema_search_path: public
А вот пример для mysql:
production:
adapter: mysql
database: redminedb
host: localhost
username: redmineuser
password: MySecretP@ssw0rd
encoding: utf8
Теперь самое сложное - установка GEM-ов. Gem - это библиотека в терминологии ruby. Их количество без преувеличения огромно, и делают они буквально все - appservers, драйвера к библиотекам, рисование графиков… Любое нормальное руби-приложение использует множество гемов для работы. Для упрощения установки используется (сюрприз!) gem под названием bundle. Заходим в папку redmine и выполняем:
#вариант для postgresql
bundle install --without development test sqlite mysql rmagick
#ИЛИ для mysql
bundle install --without development test sqlite pg rmagick
Запуск приложения (любого!) от root не рекомендуется, так как взлом этого приложения скомпрометирует систему полностью. Сделаем непривелигированного юзера:
useradd --system -m -d /var/www/redmine -s /bin/bash redmine
Послеустановочные действия:
rake generate_secret_token
RAILS_ENV=production rake db:migrate
RAILS_ENV=production rake redmine:load_default_data
mkdir -p tmp tmp/pdf public/plugin_assets
chown -R redmine:redmine files log tmp public/plugin_assets
chmod -R 755 files log tmp public/plugin_assets
#
Установка и подключение uwsgid
Ставим uwsgid. Его придется ставить из gem, потому, что тот, что идет в комплекте с системой, слишком старый - и не умеет работать с rails
gem install uwsgi
Конфигурация uwsgi расскажет ему о том, как запустить rails. Пишем в файл uwsgi.ini
[uwsgi]
socket = /tmp/redmine.sock
chmod-socket = 770
master = true
lazy = true
processes = 2 #по количеству ядер в системе. У меня atom 525, два ядра
post-buffering = 4096
#следующие три строки - только для тех, кто использует RVM
rvm-path = /usr/local/rvm
#имя ruby, указывать обязательно, даже, если он указан по умолчанию
rvm = ruby-1.9.3-p429
#название gemset в формате язык@гемсет
gemset = ruby-1.9.3-p429@redmine
uid = redmine
gid = www-data
env = RAILS_ENV=production
chdir = /var/www/redmine
rack = /var/www/redmine/config.ru
http-modifier1 = 7
Сам по себе supervisor умеет порождать процессы-обработчики (это так называемый режим императора), но это совсем молодая фишка и работает она… Ну, как любая совсем новая фишка. Лично я рекомендую использовать для управления supervisord. Его задача - запускать и останавливать другие процессы (в данном контексте - uwsgi). Он обладает очень простым (если не сказать - примитивным) конфигурационным файлом и очень прост в работе. Устанавливаем:
apt-get install supervisord
/etc/init.d/supervisor start
Теперь нам надо создать конфиг для нашего приложения. В папке /etc/supervisor/conf.d
создаем файл с произвольным именем и окончанием .conf. Содержимое:
[program:redmine]
directory=/var/www/redmine
command=uwsgi --ini /var/www/redmine/uwsgi.ini
autostart=true
Теперь его надо подключить. У supervisord есть собственная консоль, она называется supervisorctl. Заходим:
supervisorctl
#поиск новых конфигов
supervisor> reread
#нашелся
redmine: available
#добавляем
supervisor> add redmine
redmine: added process group
#проверим, работает?
supervisor> status
redmine BACKOFF can't find command 'uwsgi'
Не находится он потому, что supervisorctl не может найти rvm-версию uwsgi. Ок, укажем вручную:
find / -name uwsgi
[...]
/usr/local/rvm/gems/ruby-1.9.3-p429/bin/uwsgi
[...]
Вносим изменения в наш конфиг /etc/supervisor/conf.d/redmine.conf
. Теперь он выглядит так:
[program:redmine]
directory=/var/www/redmine
command=/usr/local/rvm/gems/ruby-1.9.3-p429/bin/uwsgi --ini /var/www/redmine/uwsgi.ini
autostart=true
Обновим конфиг без перезагрузки supervisord:
supervisorctl update redmine
supervisorctl status
[...]
redmine RUNNING pid 25365, uptime 0:00:18
[...]
Отлично, uwsgi работает, подключаем nginx. Debian-way предполагает, что конфигурации сайтов находятся в отдельных файлах каталога /etc/nginx/sites-enabled. Содержимое /etc/nginx/sites-enabled/redmine
server {
listen 80;
server_name redmine.office;
location @redmine {
uwsgi_modifier1 7;
include uwsgi_params;
uwsgi_pass unix:///tmp/redmine.sock;
}
location / {
root /var/www/redmine/public;
try_files $uri $uri/index.html $uri.html @redmine;
}
}
Кроме того, потребуется описание типовых параметров uwsgi, файл /etc/nginx/uwsgi_params
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param UWSGI_SCHEME $scheme;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
Теперь достаточно перезапустить nginx - и редмайн готов к использованию!