Июн
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).

Leave Your Comment