Montag, 22. Februar 2010
So einfach vergeht einem die Lust am Schreiben 12:06
Sonntag, 7. Februar 2010
Rails-Applikationen mit nginx und Thin 22:31
Seit ich angefangen habe, mich mit Rails zu beschäftigen, lese ich einige Blogs von Firmen, die sich "hauptberuflich" mit Rails auf die eine oder andere Art und Weise beschäftigen. Dazu gehören unter anderem amerikanische Unternehmen wie Engine Yard [1], Rackspace[2] und GitHub[3]. In Deutschland ist Rails leider noch immer nicht so recht angekommen, die Anzahl wirklich interessanter, innovativer Unternehmen in diesem Bereich hält sich also stark in Grenzen. Die soeben genannten Unternehmen betreiben entweder für sich selbst oder im Kundenauftrag große Rails-Installationen und können sich solche Probleme, wie die im vorherigen Absatz geschilderten, absolut nicht erlauben. Insbesondere Engine Yard und GitHub betreiben viel Social Networking und haben sehr aktive gepflegte Blogs. Und in diesen bin ich auf so einige interessante Informationen gestossen, unter anderem auch mein Problem betreffend.
Wenn man eine Applikation in Rails entwickelt, verwendet man während der Entwicklungsphase der Einfachheit halber einen sehr rudimentären kleinen Webserver namens WEBrick. Er tut das, was er tun soll, startet schnell, eignet sich für den Produktbetrieb aufgrund fehlender Sicherheitsfeatures und ziemlich mauer Performance nur bedingt. Alternativ kann man Mongrel nutzen. Auch dieser ist fest mit Rails verbunden, bietet aber deutlich mehr Performance als WEBrick. Mongrel existiert auch in einer speziellen Cluster-Version. Mit Clustering ist hiermit gar nicht mal das verteilte Rechnen auf verschiedenen Systemen gemeint, sondern nur die Tatsache, dass mehrere Instanzen gestartet werden können. Dies ist ein im Rails-Bereich meinen Informationen nach ein übliches Setup. Es ist einfach aufzusetzen und Mongrel genügt für die meisten Zwecke. Aber Mongrel ist nun mal kein Apache und steht diesem in seinen Konfigurationsmöglichkeiten massiv nach. Einen reinen Mongrel-Cluster zu betreiben scheint also auch kein probates Mittel zu sein.
Nach dem Studium einiger Blog-Artikel entschied ich mich dann für den Toolstack, um den es hier gehen soll: nginx und Thin. nginx[4] als voll-funktionalen Webserver mit wenig Ressourcenhunger und Thin[5] als Application Server. Thin beschreibt sich selbst als die optimale Kombination aus dem Mongrel parser, Event Machine (einer Netzwerk-I/O-Bibliothek) und Rack (Minimal-Interface zwischen Webserver und Ruby-Applikation). Dieser Toolstack begeistert mich noch immer, ob er das auch unter wirklicher Last tun würde, kann ich (noch) nicht sagen, ich werde dann berichten.
Nun zur Installation.
Der erste Schritt sollte die Installation des entsprechenden Gems (und eines zugehörigen) sein. Mittels
sudo gem install thin; sudo gem install eventmachine --source http://code.macournoyer.com
installieren wir Thin. Um zu testen, ob alles in Ordnung ist, nehmen wir einen Verzeichniswechsel in zu unserer Rails-Applikation vor und tippen
thin start
ein. Es sollten ein paar Statusmeldungen ausgegeben werden, danach könnt ihr über http://domain.tld:3000 eure Rails-Applikation aufrufen. Sollte Thin nicht starten, was bei mir der Fall war, müsst ihr Thin noch zu eurer PATH-Variable hinzufügen. Thin liegt auf meinem Server (Ubuntu 9.04 Server) im Verzeichnis
/var/lib/gems/1.8/bin
Stellt sicher, dass dieser Eintrag als allererster in der PATH-Variable steht. Ich habe zu diesem Zweck meiner ~/.bashrc einfach am Ende folgende Zeile hinzugefügt:
export PATH=/var/lib/gems/1.8/bin:$PATH
Da das aber nicht das ist, was wir wollen, installieren wir nun nginx. Ich habe mich dafür entschieden, die aktuelle Stable aus dem Source Code zu kompilieren. Ein Blick auf http://nginx.org/en/download.html zeigt uns alle verfügbaren Versionen. Ich arbeite aktuell mit Version 0.7.65. Nach dem Download mittels
wget http://nginx.org/download/nginx-0.7.65.tar.gz
entpacken wir das Archiv mit
tar xvfz nginx-0.7.65.tar.gz
in das aktuelle Verzeichnis. In dieses Verzeichnis wird nun gewechselt. Ich habe meinen nginx mit den folgenden Optionen kompiliert:
| | |
Der abschließende Build und die Installation erledigen wir so:
make && make install
Nun geben wir noch
sudo thin install && sudo /usr/sbin/update-rc.d -f thin defaults
um Thin automatisch starten zu lassen.
Weiter geht es mit der Konfiguration.
Konfigurieren wir als erstes Thin für den Live-Betrieb:
sudo thin config -C /etc/thin/railsapp.yml -c /var/www/railsapp --servers 2 --socket /var/run/thin/railsapp.sock -e production
Dieser Einzeiler legt im Verzeichnis /etc/thin/ eine Konfigurationsdatei im YAML-Format mit dem Namen railsapp.yml an. In dieser Datei wird festgehalten, wie Thin arbeiten soll. In diesem konkreten Falle wird, was sehr empfehlenswert ist, eine Socket- anstelle einer TCP/IP-Verbindung verwendet. Es werden zwei Serverinstanzen gestartet, die parallel laufen. ACHTUNG! Wer hier die Zahl zu hoch wählt, macht es seinem Server ganz schnell ganz schwer. Also vorsichtig erhöhen und nur, wenn es unbedingt nötig ist. Bemerkt man einen Flaschenhals, kann man hier natürlich rumschrauben. Das Hauptverzeichnis der Rails-Anwendung ist in diesem Falle /var/www/railsapp und die Sockets werden in /var/run/thin/ angelegt. Der letzte Schalter legt noch die Rails-Environment fest, hier wird also das Production Environment genutzt.
Die Konfiguration von nginx ist recht simpel. Meine /etc/nginx/nginx.conf sieht wie folgt aus:
| | |
Als Systembenutzer setzt dieses Setup einen Benutzer mit dem Namen www-data voraus. Außerdem werden zwei Worker-Prozesse gestartet. Wer in seiner Rails-Anwendung eine Benutzerverwaltung einsetze, sollte natürlich auf https anstelle von http setzen. Wie man einen https-Container mit nginx einrichtet, werde ich gesondert an dieser Stelle beschreiben.
Im Verzeichnis /etc/nginx/sites-available legen wir nun einen vHost-Container für unsere Rails-Anwendung an. Dieser sollte einen sprechenden Namen als Dateinamen erhalten, also bspw. railsapp.domain.tld. Bei mir sieht der Inhalt wie folgt aus:
| | |
Mittels
ln -s /etc/nginx/sites-available/railsapp.domain.tld /etc/nginx/sites-enabled/railsapp.domain.tld
legen wir einen Symlink in das Verzeichnis sites-enabled an. In diesem befinden sich alle vHost-Container, die nginx bedienen soll.
Nun starten wir noch nginx und Thin neu
sudo /etc/init.d/nginx restart; sudo /etc/init.d/thin restart
Gebt Thin ein paar Sekunden, um wirklich antworten zu können. Danach sollte eure Rails-Anwendung über Port 80 ausgeliefert werden.
Sollte ich beim Erstellen dieser Anleitung einen Fehler gemacht haben, lasst es mich bitte wissen, möchte ja keine falschen Informationen im Netz publizieren.
[1] http://www.engineyard.com/
[2] http://www.rackspace.com/
[3] https://github.com/
[4] http://wiki.nginx.org/Main
[5] http://code.macournoyer.com/thin/
Mittwoch, 3. Februar 2010
Git und der Mac 09:39
Nun möchte ich aber ein paar Worte der Client-Seite widmen, in meinem Falle also der Verwendung von Git unter Mac OS X. Wirkliche Probleme gibt es dabei nicht, nur einige "nice-to-knows", die ich an dieser Stelle kurz zusammenfassen möchte. Sollte einem meiner Leser noch etwas fehlen, so möge er es über die Kommentare hinzufügen ;-). Danke schon mal.
1. Installation
Den Installer habe ich bei Google code gefunden: http://code.google.com/p/git-osx-installer/. Damit ist die Installation ein Klacks. Auf meinem System mit Mac OS 10.6 Snow Leopard musste ich aber noch einen kleinen Hack anwenden, damit auch tatsächlich die aktuelle Version aus diesem Installer verwendet wird. Das liegt daran, dass Mac OS, wie jedes andere UNIX auch, die PATH-Variable linear durchsucht und den ersten Treffer verwendet. Auf meinem System war es nun leider so, dass ich eine alte Version von Git unter /usr/local/bin liegen hatte, die neue Version aber unter /usr/local/git/bin liegt. Verwendet hat Mac OS immer die alte Version, da die PATH-Variable den Pfad zur neueren Git-Version als erstes auflistete.
Um das Problem zu beheben, habe ich die Datei
/etc/profiles
editiert (sudo nano /etc/profiles), die die globale PATH-Variable beinhaltet. Bei mir sieht die entsprechende Zeile wie folgt aus:
export PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/git/bin:/usr/local/bin:/usr/texbin:/usr/X11/bin
Somit sucht Mac OS nun zuerst nach der aktuellen Version. Andere Mac-OS-Installer von Git mögen die Binarys von Git woanders ablegen, der korrespondierende Pfad müsste dann entsprechend angepasst werden.
2. Konfiguration
Eine weitergehende Konfiguration von Git ist eigentlich nicht erforderlich, als sinnvoll haben sich aber einige Variablen herausgestellt. Folgende Kommandos habe ich für meine Git-Konfiguration verwendet:
2.1 Benutzerkonfiguration
git config --global user.name "Vorname Nachname"
git config --global user.email "user@domain.tld"
Diese Kommandos setzen die entsprechenden Git-Einstellungen global für den Systembenutzer. Diese sind somit für alle Repositorys eures Systembenutzers gültig. Abgelegt werden die Einstellungen in der Datei ~/.gitconfig. Um die Einstellungen spezifisch für ein Repository zu überschreiben, könnt ihr folgende Befehle verwenden:
git config user.name "Vorname Nachname"
git config user.email "user@domain.tld"
Diese Einstellungen werden in der Datei .git/config in eurem Repository-Verzeichnis abgelegt und sind somit auch nur für das jeweilige Repository gültig.
Es ist durchaus sinnvoll, diese Variablen zu setzen, da nur so gewährleistet ist, dass eure Commits eindeutig euch zugeordnet werden können. Diese Einstellungen können im Übrigen unabhängig von eventuellen Benutzern auf eurem Git-Server gesetzt werden.
2.2 Konfiguration der Ausgabe
Um die Ausgaben von Git farbig zu gestalten, müsst ihr folgendes eintippen:
git config --global color.ui "auto"
Auch hier gilt wieder, dass der Schalter --global die Einstellungen global setzt.
2.3 Weitere Einstellungen
Um Git für die Verwendung von Multi-Core-CPUs zu konfigurieren, folgenden Befehl eingeben:
git config --global pack.threads "0"
Um Apples opendiff für die Anzeige von diffs zu verwenden:
git config --global merge.tool opendiff
git config --global merge.summary true
.DS_Store-Dateien vom Repository ausschliessen:
git config --global core.excludesfile ~/.gitignore
echo ".DS_Store" >>~/.gitignore
Textmate als Standard-Editor setzen:
git config --global core.editor "mate -w"
2.4 Github-spezifische Einstellungen
Damit die geniale Social-Coding-Plattform GitHub (https://github.com) euren Benutzer korrekt erkennt, müssen zwei weitere Einstellungen gesetzt werden:
git config --global github.user
git config --global github.token
Eure entsprechenden Daten findet ihr unter https://github.com/account.
2.5 Textmate-Bundle
Für die Textmate-User unter euch gibt es im Übrigen ein Git-Bundle, welches wie folgt installiert werden kann:
mkdir -p ~/Library/Application\ Support/TextMate/Bundles
cd !$
git clone git://github.com/jcf/git-tmbundle Git.tmbundle
osascript -e 'tell app "TextMate" to reload bundles'
In Textmate müsst ihr nun noch die Shell-Variable TM_GIT erstellen. Diese muss (in meinem Falle) auf /usr/local/git/bin zeigen.
Wie gesagt, sollte irgendwo noch etwas wichtiges fehlen, lasst es mich bitte über die Kommentare wissen.
