Июн
07
2011

Настройка сервера с нуля до запуска ruby on rails приложения (debian, nginx, unicorn, runit, percona server, rvm, capistrano…)

Не так давно мне надо было настраивать новый сервак. В ходе настройки я решил помечать свои действия, чтобы в будущем мне было куда подглядывать и делать это быстро. Полагаю, что эти мои пометки будут полезны и другим. Вот и получилась эта статья. Прошу заметить что данная статья в стадии черновика. Некоторые действия я мог делать в другом порядке, а потом что-то туда-сюда менять. А что-то и вовсе мог забыть пометить. Планирую при следующей настройке сервера привести в порядок эту инструкцию. А пока вот делюсь ею в таком виде =)

Дано: свежеустановленный debian6.

Задача: настроить сервер для работы с ruby on rails. Настроить и задеплоить приложение (у меня оно называлось samohodom).
Средства:

  • debian – ОС
  • nginx – веб сервер
  • unicorn – сервер для запуска rack приложений
  • runit – супервайзер, для стопроцентного запуска процессов
  • percona server – форк mySQL со всякими патчиками
  • rvm – ruby version manager. Позволяет иметь на одном сервере сразу несколько разных версий ruby
  • capistrano и capistrano-deploy – для деплоя нашего приложения на сервер
  • git – при разработке приложения в качестве системы контроля версий мы используем git. И деплоить будем из репозитория.

Первым делом обновим системку на всякий случай и установим пару необходимых (для меня) пакетов.

apt-get update
apt-get upgrade
apt-get install vim mc git-core curl

Установка nginx

Upd 23.10.2012: у nginx появились свои репозитории пакетов и теперь проще ставить nginx оттуда, а не собирать из исходников. Инструкции найдёте на странице скачивания nginx: http://nginx.org/ru/download.html

Сборка nginx из исходников (не рекомендуется без явной необходимости)

С оффициального сайта скачиваем последнюю стабильную версию nginx http://nginx.org/ru/download.html

wget http://sysoev.ru/nginx/nginx-1.0.4.tar.gz

Распаковываем и заходим в директорию:

tar xzf nginx-1.0.4.tar.gz
cd nginx-1.0.4
./configure --prefix=/opt/nginx

Если получили ошибку «./configure: error: C compiler gcc is not found», то значит у вас нету компилятора. Для решения стоит поставить целиком метапакет build-essential. Он подтянет по зависимостям и компилятор и прочие нужные штуки для компиляции программ.

apt-get install build-essential

Снова пытаетесь выполнить ./configure для nginx. Если будет ошибка типа такой:

checking for PCRE library ... not found
checking for PCRE library in /usr/local/ ... not found
checking for PCRE library in /usr/include/pcre/ ... not found
checking for PCRE library in /usr/pkg/ ... not found
checking for PCRE library in /opt/local/ ... not found

./configure: error: the HTTP rewrite module requires the PCRE library.
You can either disable the module by using --without-http_rewrite_module
option, or install the PCRE library into the system, or build the PCRE library
statically from the source with nginx by using --with-pcre=
option.

То выполняем:

apt-get install libpcre3 libpcre3-dev libpcrecpp0 libssl-dev zlib1g-dev

Результатом успешной работы ./configure будет что-то типа такого:

Configuration summary
  + using system PCRE library
  + OpenSSL library is not used
  + md5: using system crypto library
  + sha1: using system crypto library
  + using system zlib library

  nginx path prefix: "/opt/nginx"
  nginx binary file: "/opt/nginx/sbin/nginx"
  nginx configuration prefix: "/opt/nginx/conf"
  nginx configuration file: "/opt/nginx/conf/nginx.conf"
  nginx pid file: "/opt/nginx/logs/nginx.pid"
  nginx error log file: "/opt/nginx/logs/error.log"
  nginx http access log file: "/opt/nginx/logs/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"

Если ./configure отработал хорошо, то компилим и устанавливаем

make
make install

Настраиваем nginx

Конфигурируем nginx следующим образом. Мы сделаем в папке с конфигами папку servers/ в которую будем класть отдельные файлы для каждого проекта на нашем сервере. В основном кофиге nginx мы укажем загрузку всех файлов *.conf из этой директории.

Вот какие у меня получились конфиги:

/opt/nginx/conf/nginx.conf

daemon off;

user  nobody nogroup;
worker_processes  2; # нету смысла ставить больше, чем ядер процессора в сервере

#error_log  /var/log/nginx/error.log  info;

events {
    worker_connections  4096; # количество соединений на каждый рабочий процесс
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;

    keepalive_timeout  65;

    include gzip.conf;

    server_names_hash_max_size 262144;
    server_names_hash_bucket_size 128;

    include servers/*.conf;
}

/opt/nginx/conf/gzip.conf

gzip  on;
gzip_http_version  1.0;
gzip_proxied  any;
gzip_types  text/plain text/xml text/css text/javascript application/x-javascript application/xml application/xml+rss;

/opt/nginx/conf/servers/samohodom.conf

server {
    listen  80;
    server_name  samohodom.com;
    root /home/samohodom/web-app/public;
    client_max_body_size 32m;
    location / {
        try_files  $uri @unicorn;
    }
    location @unicorn {
        proxy_set_header  Client-Ip $remote_addr;
        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header  Host $host;
        proxy_pass  http://unix:/home/samohodom/web-app/tmp/sockets/unicorn.sock;
    }
}

Теперь делаем запуск nginx через супервайзер runit.

apt-get install runit
mkdir /etc/sv/nginx

Создаём файлик /etc/sv/nginx/run с вот таким содержимым:

#!/bin/sh
exec 2>&1
exec /opt/nginx/sbin/nginx

Делаем его исполняемым:

chmod +x /etc/sv/nginx/run

Теперь для теста можно выполнить этот файл и проверить, что теперь ваше приложение отвечает на 80 порту.

/etc/sv/nginx/run

Затем для останова выполнения этого файла нажмите Ctrl+c.

Теперь делаем симлинку, чтобы runit его запускал:

ln -s /etc/sv/nginx/ /etc/service

Сразу после этого runit должен запустить nginx. Проверить можно вот так:

root@domU-12-31-39-0A-19-93:~# ps aux | grep nginx
root     18977  0.0  0.0    164     4 ?        Ss   15:04   0:00 runsv nginx
root     18978  0.0  0.3  27812  1968 ?        S    15:04   0:00 nginx: master process /opt/nginx/sbin/nginx
nobody   18979  0.0  0.4  29392  2464 ?        S    15:04   0:00 nginx: worker process
nobody   18980  0.0  0.4  29392  2464 ?        S    15:04   0:00 nginx: worker process
root     18988  0.0  0.1   7928  1068 pts/0    S+   15:05   0:00 grep --color=auto nginx

Вот пара полезных команд:

  • sv status nginx – проверка статуса
  • sv up nginx – запустить nginx
  • sv down nginx – остановить nginx

Создаём пользователя для приложения

adduser samohodom

В home директории этого пользователя в файл .bashrc добавляем

export RAILS_ENV=production

Это чтобы когда мы на серваке при необходимости будем самостоятельно писать rails console или rails db:reset, то чтобы окружение использовалось не development, а production.

Устанавливаем rvm под root

Нам понадобится curl. Если его в системе нет, то устанавливаем:

apt-get install curl

Инструкции по установке rvm смотрим в первую очередь на оффициальном сайте: https://rvm.beginrescueend.com/rvm/install/

В моём случае это выглядело вот так:

bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)

В конце установки rvm напишет какие пакеты вам надо установить для разных интерпретаторов ruby. Мы, конечно, используем обычный ruby, а не какой-нибудь там ironruby или jruby. В моём случае мне rvm подсказал вот такую строчку:

apt-get install build-essential bison openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev

Так же нам надо добавить пользователя, который будет работать с rvm в группу rvm:

gpasswd -a samohodom rvm

Теперь можно зайти под нашим новым пользователем и запустить установку ruby. Для моего проекта нужен 1.9.2:

rvm install ruby-1.9.2-p180

MySQL

В качестве mysql сервера мы решили использовать percona-server. Этот тот же mysql, но с кое-какими патчами и улучшениями. В работе он абсолютно такой же как mysql.
Инструкции по его установке смотрите на оффициальном сайте: http://www.percona.com/

В моём случае это выглядело вот так. Добавляем ключи и репозитории перконы как описано тут (http://www.percona.com/docs/wiki/repositories:apt)

gpg --keyserver  hkp://keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2A
gpg -a --export CD2EFD2A | apt-key add -

В /etc/apt/sources.list добавляем:

deb http://repo.percona.com/apt squeeze main
deb-src http://repo.percona.com/apt squeeze main
apt-get update

Устанавливаем сам сервер (http://www.percona.com/docs/wiki/percona-server:installation:from-repositories#installation_on_apt-based_systems):

apt-get install percona-server-server
apt-get install libmysqlclient-dev

Создаём mysql пользователя и базу данных. Для этого входим в mysql консоль:

mysql -uroot -p

После ввода пароля попадаем в mysql консоль, где пишем примерно следующее (звёздочки заменяем на пароль для пользователя):

CREATE USER 'samohodom'@'localhost' IDENTIFIED BY  '**********';
CREATE DATABASE IF NOT EXISTS  `samohodom` CHARACTER SET 'utf8';
GRANT ALL PRIVILEGES ON  `samohodom` . * TO  'samohodom'@'localhost';

Настройка деплоя приложения через capistrano

Мы для деплоя используем capistrano. Но только не совсем в оригинальном виде, а с гемом capistrano-deploy.
В корень проекта кладём файлик Capfile cо следующим содержимым:

$:.unshift(File.expand_path('./lib', ENV['rvm_path'])) # Add RVM's lib directory to the load path.
require "rvm/capistrano"                  # Load RVM's capistrano plugin.
set :rvm_ruby_string, '1.9.2@samohodom'        # Or whatever env you want it to run in.

require 'capistrano-deploy'
use_recipes :git, :rails, :bundle, :unicorn

server 'samohodom.com', :web, :app, :db, :primary => true
set :user, 'samohodom'
set :deploy_to, '/home/samohodom/web-app'
set :repository, 'git@********.net:samohodom.git'

after 'deploy:update',  'bundle:install'
after 'deploy:restart', 'unicorn:stop'

Первые три строки необходимы для интеграции с rvm и подсомотрены вот тут: https://rvm.beginrescueend.com/integration/capistrano/
Теперь настроим запуск нашего приложения через unicorn. А после этого можно будет задеплоить.

Настриваем unicorn

Во-первых в Gemfile приложения добавляем:

group :production do
  gem 'unicorn', '~> 3.6.2', :require => nil
end

group :development do
  gem 'capistrano-deploy', '~> 0.1.1', :require => nil
end

Затем я на серваке создал гемсет для проекта и папку для него, а так же установил bundler в глобальный гемсет (т.е. он будет виден во всем гемсетах внутри этой версии руби)

rvm use --create ruby-1.9.2-p180@samohodom
rvm 1.9.2@global gem install bundler

Выполняем

cap deploy:setup

Кстати если на серваке нужна java (например мне она нужна для гема jammit), то рекомендую ставить sun-java6-jdk. Она находится в contrib или non-free репозитори

Для этого в /etc/apt/sources.list строки

deb http://ftp.us.debian.org/debian squeeze main
deb http://security.debian.org squeeze/updates main

заменяем на:

deb http://ftp.us.debian.org/debian squeeze main contrib non-free
deb http://security.debian.org squeeze/updates main contrib non-free

Затем обновляем списки пакетов и устанавливаем java:

apt-get update
apt-get install sun-java6-jdk

Далее настраиваем запуск unicorn через runsv:

mkdir /etc/sv/samohodom_unicorn
touch /etc/sv/samohodom_unicorn/run
chmod +x /etc/sv/samohodom_unicorn/run

В файле /etc/sv/samohodom_unicorn/run следующее содержимое:

#!/bin/sh
exec 2>&1
export USER=samohodom
export HOME=/home/$USER
export RAILS_ENV=production
UNICORN="/usr/local/rvm/bin/rvm 1.9.2@samohodom exec bundle exec unicorn"
UNICORN_CONF=/etc/unicorn/samohodom.rb
cd $HOME/web-app
exec chpst -u $USER:$USER $UNICORN -c $UNICORN_CONF

Как видно мы тут указали конфиг для unicorn для нашего приложения /etc/unicorn/samohodom.rb
Создаём директорию (если нету) и кладём туда файлик с содержимым:

worker_processes 4 # это число процессов, которые будут запускаться для unicorn. Если памяти мало, то лучше ставьте поменьше. Можно для начала 1 установить.

working_directory "/home/samohodom/web-app"

listen "/home/samohodom/web-app/tmp/sockets/unicorn.sock", :backlog => 64

pid "/home/samohodom/web-app/tmp/pids/unicorn.pid"

stderr_path "/home/samohodom/web-app/log/unicorn.stderr.log"
stdout_path "/home/samohodom/web-app/log/unicorn.stdout.log"

Так же удостоверьтесь, что у вас на серваке в папке с проектом есть директории tmp/pids/ и tmp/sockets/

Вроде с конфигами unicorn всё. Тут не спешим делать симлинку для автоматического запуска через runsv, а сперва пробуем запустить вручную:

/etc/sv/samohodom_unicorn/run

Пробуем открыть в браузере. Надо будет немного подождать чтобы все воркеры стартанули. Время их старта зависит от количества оперативы и процессора. Если долго не стартует, то в файле /etc/unicorn/samohodom.rb установите «worker_processes 1″.

Если всё заработало, то делаем симлинку для runsv на запуск unicorn, чтобы runit его запускал.

ln -s /etc/sv/samohodom_unicorn /etc/service

Если по каким-то причинам что-то не работает с unicorn и вы хотите это найти, то можно:

1. остановить запуск unicorn через runsv (sv down samohodom_unicorn) и запустить напрямую /etc/sv/samohodom_unicorn/run и посмотреть что напишет. Если ничего не напишет, то можно попробовать второй способ.
2. Кладём файлик /etc/sv/samohodom_unicorn/log/run с таким содержимым:

#!/bin/sh
LOG_FOLDER=/var/log/samohodom_unicorn
mkdir -p $LOG_FOLDER
exec svlogd -tt $LOG_FOLDER

Далаем этот файл исполняемым.
Перезапустите unicorn и посмотрите загляните в папку с логами (/var/log/samohodom_unicorn).

23 Comments to "Настройка сервера с нуля до запуска ruby on rails приложения (debian, nginx, unicorn, runit, percona server, rvm, capistrano…)"

  1. Genadii wrote:

    у меня после make выдается вот такая канатель

    make[1]: Leaving directory `/root/nginx-1.0.4′
    не подскажите как исправить ?

  2. yas wrote:

    если мне не изменяет память, то так и должно быть. Тут же не пишет об ошибках. Пробуйте дальше выполнить «make install»

  3. Genadii wrote:

    продолжил, теперь после
    /opt/nginx/conf/nginx.conf
    выдает
    -bash: /opt/nginx/conf/nginx.conf: Permission denied

    после /opt/nginx/conf/gzip.conf
    выдает
    -bash: /opt/nginx/conf/gzip.conf: No such file or directory

    а после exec /opt/nginx/sbin/nginx
    вообще закрылся ssh клиент ( Putty)

  4. Genadii wrote:

    видимо не видать мне руби как своих ушеи (

  5. RubyMajor wrote:

    Похоже на то, что у вас нет прав. Запустите make install от привелигированного пользователя.
    Автору спасибо, в ближайшее время как раз займусь деплойментом, читаю все подходящие статьи.

  6. Bms wrote:

    sudo /etc/sv/nginx/run
    nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
    nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
    nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
    nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
    nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
    nginx: [emerg] still could not bind()

    Что не так((

  7. MenX wrote:

    Не подскажете, почему у меня не работает управление nginx через sv. При команде например sv status nginx выдает:

    fail: nginx: unable to change to service directory: file does not exist

    Настраивал все прямо по этой инструкции.
    Спасибо.

  8. dozen wrote:

    @Bms у тебя значит уже работает nginx на 80 порту, либо стоит апач и занят 80 порт

  9. Грач wrote:

    Сначала вы писали:
    Мы сделаем в папке с конфигами папку sites/

    а потом есть строчка:
    /opt/nginx/conf/servers/samohodom.conf

    неувязка маленькая (8

  10. yas wrote:

    спасибо, поправил

  11. Dan wrote:

    не рекомендую RVM использовать на продакшене

  12. yas wrote:

    2Dan: почему же? как раз-таки rvm и разрабатывался в первую очередь для использования на production. И с ним действительно довольно удобно на серваке. Особенно выручает в случаях когда на серваке несколько рельсовых проектов на разных версиях руби. Так что я как раз за то, чтобы использовать на продакшене именно RVM!

  13. yas wrote:

    ещё вот добавлю: мой хостер http://locum.ru где я покупаю обычный shared хостинг но для rails приложений раньше не использовали RVM, а потом перешли именно на RVM. А у них там куча проектов крутится от разных юзеров с разными версиями рельс, с разными версиями гемов и прочее, прочее…

  14. f1aky wrote:

    мне показалось, или вы упустили установку рельс…

  15. yas wrote:

    2f1aky: вроде нет, не упустил. при сетапе деплоя через капистрано (не помню точно при именно при сетапе или просто при деплое там вызывается установка гемов) поставятся как рельсы, так и остальные гемы из Gemfile проекта.

  16. Serge wrote:

    Автор статьи будь так любелен
    Объясни, зачем? зачем блеять использовать сборку и установку пакета из исходников? Когда есть менеджеры управления пакетами?

    (apt-get)aptitude, yum, итд.

  17. yas wrote:

    2Serge: Вы такой умный блеать! На момент написания статьи у nginx ещё не было своих репозиториев поэтому приходилось свежую версию собирать из исходников. Потому как в стандартном дебиановском репозитории очень старая версия. Например сейчас там 0.7.67 (http://packages.debian.org/squeeze/nginx), а текущая последняя стабильная версия nginx 1.2.3 (http://nginx.org/ru/download.html)
    А сейчас да, заходите на страницу скачивания nginx и там написано про их репозитории. Пост обновил.

  18. Nginx-ruby-unicorn | Блог компании Net-Simple - Блог компании Net-Simple wrote:

    [...] http://bestblog.name/2011/06/nastrojka-servera-s-nulya-do-zapuska-ruby-on-rails-prilozheniya-debian-... [...]

  19. KonstantiN wrote:

    Подскажите, пожалуйста, в чем может быть проблема, в какую сторону копать…при деплое приложения на сервере не видет rvm
    executing «cd /home/konstantin/projects/dev-edim-s-polsoy/releases/20130130213839 && rvm use 1.9.3 do bundle install –gemfile /home/konstantin/projects/dev-edim-s-polsoy/releases/20130130213839/Gemfile –path /home/konstantin/projects/dev-edim-s-polsoy/shared/gems –deployment –quiet –without development test»
    servers: ["88.198.200.103"]
    [88.198.200.103] executing command
    *** [err :: 88.198.200.103] sh:
    *** [err :: 88.198.200.103] rvm: not found

    Но через ssh под этим пользователем все работает, rvm видит!

  20. exAspArk wrote:

    Спасибо за статью.

    Почти все получилось, но при запуске таски ‘unicorn:reload’ (after ‘deploy:restart’) вылетает ошибка:
    ‘bash: line 0: kill: (17440) – No such process’

    Короче при попытке убить процесс:
    ‘kill -HUP `cat /home/smartpresents/web-app/tmp/pids/unicorn.pid`’ вылетает ошибка, что процесс не может быть найден.

    Можете подсказать, почему процесс с pid = 17440, который записан в файле unicorn.pid, не существует?

  21. exAspArk wrote:

    Спасибо за статью!

    Сделал почти все, как было описано. Но при запуске ‘cap deploy’ срабатывает ‘unicorn:reload’. При выполнении этой таски вылетает следующая ошибка:
    ‘bash: line 0: kill: (17440) – No such process’

    Это происходит при выполнии:
    ‘kill -HUP `cat /home/name/web-app/tmp/pids/unicorn.pid`’

    Подскажите, почему не процесса с pid = 17440, который записан в unicorn.pid?

  22. madGest wrote:

    chpst: fatal: unable to setgroups: permission denied

    Как с этим быть?

  23. Sage wrote:

    А как же даунтайм зеро? После рестарта юникорн умирает и рунит запускает его снова. Никаких USR2 итд.

Leave Your Comment