Správa linuxového serveru: Zprovoznění Ruby aplikací s RVM, Thin a Nginx

Ruby on Rails je jeden z mnoha frameworků jazyka Ruby určený pro tvorbu webových aplikací. Ačkoliv webových aplikací pro ně není tolik jako pro PHP, mnohé z nich určitě stojí za zvážení. Na rozdíl od PHP však jejich zprovoznění z pohledu správců serverů nemusí být úplně přímočaré. Tento článek osvětlí univerzální způsob nasazení Ruby (a zejména Rails) aplikací za pomoci RVM, Thin a Nginx.

Úvod

Na úvod musím předeslat, že nejsem Rails vývojář, tudíž se na tuto problematiku dívám primárně očima správce.

Ruby on Rails není jediný framework postavený na jazyce Ruby, těch je více (viz např. tento článek nebo příslušné heslo Wikipedie) a řada z nich je velmi zajímavá. Jejich nasazení je však obvykle pro správce zvyklého na LAMP poněkud problematické, zejména v prostředí linuxových distribucí, kde se naráží na několik problémů.

Jedním kamenem úrazu je fakt, že jazyk Ruby má svůj vlastní balíčkovací systém s názvem RubyGems, který, zcela přirozeně, koliduje s balíčkovacím systémem distribucí. Je sice možné instalovat pouze balíčky z distribuce, ale pokud vaše aplikace používá konkrétní verzi, která (pochopitelně) v repozitářích není, nastává problém. Použití balíčkovacího systému Ruby pak může přinášet jiné problémy (konflikty souborů, soubory nepatřící žádnému balíčku).

Druhým kamenem úrazu je skutečnost, že jazyk Ruby zaznamenal podstatné změny (přechod z řady 1.8 na řadu 1.9) a nové verze Ruby interpretů zatím ještě nejsou podporovány řadou na Ruby postavených komponent a aplikací. V Debianu je sice možné vedle sebe nainstalovat dvě různé verze Ruby interpretu, ale např. modul Passenger pro Apache, který mu umožňuje pracovat s Ruby aplikacemi, zatím není schopen použít více než jednu verzi interpretu najednou. Není tedy možné prostřednictvím něj zprovoznit dvě aplikace, kde jedna vyžaduje starší verzi interpretu a jedna novější.

RVM, Thin a Nginx

Výše uvedené problémy pomáhá řešit kombinace RVM a serverů Thin a Nginx. Nejprve představím jednotlivé komponenty.

RVM je zkratka pro Ruby Version Manager, tedy systém pro správu verzí Ruby. RVM můžete snadno využít k vytvoření optimálního prostředí pro běh Ruby aplikace. RVM nepotřebuje práva roota, poběží pod jakýmkoliv uživatelem a umožní vám nainstalovat jak konkrétní verzi Ruby interpretu, tak sadu „gemů“ (balíčků). Dokonce je možné nainstalovat více verzí interpretu a více „gemsetů“ (sad balíčků), přičemž pak se můžete mezi nimi přepínat. Má poměrně bohaté možnosti a také velmi dobrou dokumentaci.

Thin je webový server napsaný v Ruby, který by měl být rychlý, stabilní a bezpečný. Je dostupný jako Ruby „gem“ (balíček).

Nginx je webový server, který velmi pravděpodobně naleznete v repozitářích vámi používané distribuce. Tento webový server má malé nároky na paměť a vysoký výkon. Umí také fungovat jako reverzní proxy, což je přesně to, co od něj v tomto řešení potřebujete. Dá se snadno propojit se serverem Thin, dokonce dvěma způsoby (přes síť a přes socket). Více informací o Nginx naleznete v jednom z předchozích dílů tohoto seriálu.

Postup řešení je následující – nejprve si vytvoříte uživatele, pod kterým bude aplikace běžet (nebo použijete nějakého existujícího). Následně zprovozníte RVM a nainstalujete potřebné verze Ruby interpretu a příslušných „gemů“, které vaše aplikace vyžaduje. Poté nainstalujete gem „thin“. Thin spustíte a dostanete buď sockety, nebo síťové porty, kde Thin běží. Ty pak vložíte do konfigurace Nginx a propojíte s ním konkrétní virtuální server (virtual host).

V tomto dílu popíšu obecný postup, v příštím dílu na něj navážu a prakticky jej demonstruji na zprovoznění vynikajícího FOSS systému pro správu projektů Redmine, který určitě doporučuji vaší pozornosti.

Na závěr zmíním jediný možný problém – budete-li takto nasazovat více aplikací, každou s různým Ruby interpretem a gemy, patrně budete potřebovat zajistit dostatek RAM.

RVM

Předpokladem pro instalaci RVM je nainstalovaný Git, pokud jej nemáte, nainstalujte jej (v Debianu a podobných distribucích) příkazem:

aptitude install git

Instalace RVM je velmi jednoduchá. Nejprve však doporučuji vytvořit příslušného uživatele, pod kterým aplikace poběží.

adduser uzivatel
su uzivatel -
cd

Nyní, s právy daného uživatele, je možné provést samotnou instalaci RVM. Konkrétní podobu příkazu raději získejte z oficiální dokumentace a níže uvedený příkaz berte spíše jako ukázku (pro případ, že by se od vydání článku něco změnilo):

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

Po instalaci by se měl automaticky upravit váš .bashrc (pokud existuje), abyste mohli RVM po přihlášení spouštět. Tím je instalace RVM jako takového hotová.

Jelikož se Ruby interpreti kompilují, bude před jejich instalací ještě třeba nainstalovat potřebné balíčky, tj. kompilátory a hlavičkové soubory. Seznam (včetně konkrétního příkazu pro instalaci) získáte zadáním:

rvm requirements

Po instalaci příslušných balíčků je možné začít s instalací konkrétní verze Ruby interpretu – zde je třeba se obrátit na dokumentaci k vámi nasazované aplikaci a zjistit, jakou verzi potřebuje. Potřebuje-li verzi 1.8.7, nainstalujete ji takto:

rvm install 1.8.7

Tuto verzi interpretu můžete pro momentální shellové sezení „aktivovat“ následujícím způsobem:

rvm use 1.8.7

Pokud byste instalovali pouze jedinou aplikaci, nemusíte si dělat starosti s gemsety, tedy s možností používat různé sady Ruby balíčků s různými verzemi interpretu pro různé aplikace. Pro zjednodušení budu předpokládat právě tuto variantu. Chcete-li používat více aplikací, podívejte se do dokumentace k RVM, je velmi pěkně udělaná a vše je tam pěkně demonstrováno na příkladech.

Chcete-li učinit nějakou verzi Ruby interpretu výchozí, použijte tento příkaz:

rvm use 1.8.7 --default

Ruby aplikace si mohou s sebou tahat řadu závislostí – na vás tedy pak zbude doinstalování toho, co není distribuováno spolu s aplikací (zde je opět třeba se obrátit na dokumentaci k aplikaci). Kupříkladu, vyžaduje-li aplikace Rails framework ve verzi 2.3.11, nainstalovali byste jej takto:

gem install rails -v=2.3.11

Instalace Thinu

Thin nainstalujete úplně stejně jako jakýkoliv gem, tj. v rámci RVM prostředí použijete příkaz:

gem install thin

Testovací aplikace

Pro účely testování může posloužit „hello world“ aplikace napsaná ve frameworku (resp. DSL) Sinatra. Vytvořte si nějaký adresář v domovském adresáři (např. testapp) a v něm soubor app.rb s následujícím obsahem:

require 'sinatra'

get '/' do
  "LinuxEXPRES"
end

Následně vytvořte soubor config.ru s následujícím obsahem:

require './app'
run Sinatra::Application

Nyní můžete server v tomto adresáři spustit, a to příkazem:

thin -s 1 -R config.ru -a 127.0.0.1 -p 3100 start

Většinu parametrů je možné dekódovat užitím selského rozumu, -a udává IP, na které bude server naslouchat, -p pak konkrétní port, -R config.ru bere vámi vytvořený konfigurační soubor, který pouští Sinatra aplikaci, parametr start udává, že se má nastartovat příslušný server (funguje samozřejmě také stop či restart). Jediný parametr, který asi není jednoduché dekódovat, je -s, který udává počet běžících serverů. V tomto případě je zvolen jeden jediný, kdyby jich bylo více, první by poslouchal na portu 3100, další na 3101 atd.

Zda se zprovoznění aplikace povedlo, můžete otestovat textovým prohlížečem Lynx:

lynx 127.0.0.1:3100

Měli byste vidět text LinuxEXPRES.

Propojení s Nginx

Šablona pro nastavení Nginx může vypadat takto:

upstream  nas_thin {
   server 127.0.0.1:3100;
   server 127.0.0.1:3101;
   server 127.0.0.1:3102;
}

server {
        listen  1.2.3.4:80;
        server_name  example.cz;

        access_log  /var/log/nginx/example.cz.access.log;
        root /home/uzivatel/testapp/public;

        location / {
                proxy_set_header  X-Real-IP  $remote_addr;
                proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_redirect off;
                if (-f $request_filename/index.html) {
                        rewrite (.*) $1/index.html break;
                }
                if (-f $request_filename.html) {
                        rewrite (.*) $1.html break;
                }
                if (!-f $request_filename) {
                        proxy_pass http://nas_thin;
                        break;
                }
        }

}

Povšimněte si direktivy upstream – to je jednoduchý load balancer, tedy systém pro rozložení zátěže. Využívají se tedy střídavě všechny servery. Je možné specifikovat váhy jednotlivých serverů, ale to už je mimo rozsah tohoto článku (více vám napoví dokumentace k Nginx).

Většině parametrů je asi více méně rozumět (direktiva listenserver_name, nastavení proxy, rewrite pravidla pro statický obsah). Osvětlím dvě důležité věci:

root /home/uzivatel/testapp/public

V příkladu výše nepadlo o adresáři public ani slovo. Webové aplikace postavené na Ruby (a nejenom ty) obvykle obsahují řadu adresářů, v nichž je zdrojový kód, konfigurace apod., a pak nějaký adresář, který se má použít jako kořen pro webovou prezentaci. Je tomu tak proto, aby se zamezil přístup k těm ostatním souborům, kde je např. konfigurace databáze apod. Budete-li nasazovat Ruby aplikace, budete nejspíše používat adresář public v adresářovém stromu dané aplikace.

if (!-f $request_filename) {
     proxy_pass http://nas_thin;
     break;
}

Toto je poslední rewrite pravidlo, které nasměruje všechny ostatní požadavky na příslušný upstream zdroj, nas_thin zde odpovídá stejnojmennému zdroji specifikovanému v rámci direktivy upstream.

Tím bych tento díl ukončil. V příštím díle osvětlím celý tento proces na instalaci systému Redmine.