Kategorie

Die neue Generation der Rails Server und vereine.ch

Juni 2nd, 2015

Vor 3 Jahren haben wir unser Produkt Citrin Rails Server aufgeschaltet. Diese vorkonfigurierten virtuellen Server bieten eine einfache Möglichkeit schnell und flexibel eine Ruby on Rails Applikation zu veröffentlichen.

Nun ist es soweit die nächste Generation der Rails Server vorzustellen. Hier eine kurze Übersicht der Neuerungen:

  • Basierend auf dem aktuellen Ubuntu LTS (14.04)
  • Probleme beim Server Reboot behoben
  • CSF vorinstalliert um Brute-Force Attacken auf Firewallebene zu verhindern
  • citrin gem mit logrotate autoconfig
  • Privater gitlab-Account für alle Rails Server Kunden

Wir wollen unseren Kunden die Möglichkeit geben ihren Rails Server aktuell zu halten*. Deshalb stellen wir bestehenden Kunden auf Anfrage kostenlos einen Rails Server der neuen Generation zur Verfügung und betreiben diesen bis zu einem Monat parallel zum Alten um diesen Zeit für die Migration der Applikation(en) zu geben.

  • Ubuntu 12.04 erhält nur noch bis 2017 Updates

Ich werde hier nun die Migration eines solchen Rails Servers anhand der vereine.ch Applikation beschreiben. Die Vereine App wurde mit den Standard-Tools des ursprünglichen Citrin Rails Servers deployed: Apache+Passenger, MySQL und Subversion als VCS.

Schritt 1: Der neue Server

Zuerst brauche ich natürlich Zugang zu einem neuen Rails Server für die Migration. Dazu habe ich einen solchen bei Citrin bestellt. Die einzige aussergewöhnliche Anforderung war, dass ich statt der neusten Ruby Version 1.9.3 als default konfiguriert haben wollte damit Passenger unter der gleichen Version läuft wie auch mein ursprüngliches System. Dank RVM ist es problemlos möglich verschieden Versionen parallel zu installieren und diese auch nachträglich zu wechseln.

Citrin stellt mir nun also einen neuen Server i8rh01 zur Verfügung und hinterlegt dort meinen public key im .ssh/authorized_keys des rails-dev Users.

Schritt 2: Das Subversion Repository auf git migrieren

Wer nicht Subversion verwendet kann diesen Schritt getrost überspringen.

Der ursprüngliche Rails Server kam mit Helper-Scripts zum erstellen von Subversion repositories auf dem Server direkt. Für die neue Generation haben wir uns entschieden jedem Rails Server Kunden auf Anfrage einen Account auf unserem gitlab Server zur Verfügung zu stellen. Hier also eine kurze Anleitung wie man das Subversion Repository zu git migriert.

Der erste Schritt soll in einem ausgecheckten Repository Verzeichnis ausgeführt werden.

svn log -q | awk -F '|' '/^r/ {sub("^ ", ", $2); sub(" $", ", $2); print $2" = "$2" <"$2">"}' | sort -u > authors-transform.txt

Nun die Datei authors-transform.txt um die E-Mail Addressen in <> ergänzen.

Als nächstes das git-svn tool installieren. Hier am Beispiel von Ubuntu.

aptitude install git-svn

Nun kann das Subversion Repository einfach als git Repository geklont werden.

git svn clone file:///svn/vereine [^] --no-metadata -A authors-transform.txt --stdlayout ~/temp

Nun noch die Definition der ignorierten Files übernehmen.

cd ~/temp
git svn show-ignore > .gitignore
git add .gitignore
git commit -m 'Convert svn:ignore properties to .gitignore.'

Als nächstes kann man über das gitlab Webinterface ein Repo für vereine.ch anlegen. URL und Zugangsdaten gibt es individuell bei Citrin.

git remote add origin git@gitlab01.citrin.ch:citrin/vereine.git
git push -u origin master

Schritt 3: Deployment

Im einfachsten Fall checkt man das Repository einfach auf dem neuen Server aus:

cd /var/www/rails_apps/prod
git clone git@gitlab01.citrin.ch:citrin/vereine.git

Falls sich nichts am Setup der Versionsverwaltung geändert hat kann man auch einfach den alten Application Root kopieren.

cd /var/www/rails_apps/prod
rsync -av rhXY.citrin.ch:/var/www/rails_apps/prod/vereine/ vereine/

In allen fällen soll schlussendlich die Rails Applikation unter /var/www/rails_apps/prod/vereine/ ausgecheckt sein.

Dort noch bundle install ausführen

cd /var/www/rails_apps/prod/vereine
bundle install --path vendor/bundle

Capistrano
Für vereine.ch verwende ich Capistrano als deployment Tool. Hier sind die Anpassungen die für das Deployment auf den neuen Server nötig waren.

Editieren: config/deploy.rb und 2 Zeilen manuell anpassen.

set :repository, "git@gitlab01.citrin.ch:citrin/vereine.git"
set :scm, :git

Der Rest lässt sich mit String-Replace anpassen

:%s/rh05/i8rh01

Schritt 4: Apache Konfiguration kopieren

Die Konfiguration die vom citrin gem der ersten Generation erstellt wurde ist kompatibel also kann das VirtualHost file einfach kopiert werden.

scp root@rh05.citrin.ch:/etc/apache2/sites-available/prod.vereine.conf /etc/apache2/sites-available/prod.vereine.conf 
cd /etc/apache2/sites-enabled
ln -s ../sites-available/prod.vereine.conf

Da vereine.ch auch unter https verfügbar ist habe ich auch die dazugehörige Konfiguration kopiert.

scp rh05.citrin.ch:/etc/apache2/sites-enabled/prod.vereine.conf_443 /etc/apache2/sites-enabled/prod.vereine.conf_443
scp rh05.citrin.ch:/etc/ssl/certs/vereine.ch.crt /etc/ssl/certs/vereine.ch.crt
scp rh05.citrin.ch:/etc/ssl/certs/vereine.ch.ca /etc/ssl/certs/vereine.ch.ca
scp rh05.citrin.ch:/etc/ssl/private/vereine.ch.key /etc/ssl/private/vereine.ch.key

Zudem mussten noch ein paar Apache Mods aktiviert werden.

cd /etc/apache2/mods-enabled
ln -s ../mods-available/ssl.conf 
ln -s ../mods-available/ssl.load 
ln -s ../mods-available/socache_shmcb.load
ln -s ../mods-available/rewrite.load

Schritt 5: MySQL Datenbank kopieren

Auf dem alten Server die Daten dumpen.

mysqldump -u vereine_prod -p vereine_prod > vereine.sql
scp vereine.sql i8rh01.citrin.ch:/tmp/

Auf dem neuen Server eine Datenbank erstellen und die Daten einlesen.

citrin create_database vereine
vi config/database.yml 
mysql -u vereine_prod -p vereine_prod < /tmp/vereine.sql

Die vereine.ch Applikation hat noch persistente Daten ausserhalb der Datenbank im Filesystem die ich ebenfalls Synchronisiert habe.

rsync -av root@rh05.citrin.ch:/var/www/rails_apps/prod/vereine/shared/system/ /var/www/rails_apps/prod/vereine/shared/system/

Schritt 6: Logrotate einrichten

Zuletzt lasse ich noch logrotate einrichten um zu verhindern, dass die Application Logs den Server vollschreiben.

citrin setup_logrotate vereine

Die Standardkonfiguration würde also den production log in /var/www/rails_apps/prod/vereine/log/ konfigurieren. Da die Vereine Applikation aber mit capistrano deployed wird muss ich noch den Pfad anpassen.

Die Datei /etc/logrotate.d/rails-app-vereine-prod editieren und

/var/www/rails_apps/prod/vereine/log/production.log {

ersetzen mit

/var/www/rails_apps/prod/vereine/shared/log/production.log {

Verbesserte Ruby Performance

Dezember 12th, 2012

Für Ruby 1.9.3 sind diverse Performance Tweaks bekannt die jedoch in der standard RVM Version nicht vorhanden sind. Dieser Blogpost wird aufzeigen wie man diese auf einem Citrin Rails Server anwendet.

Die Optimierungen zusammengefasst

  • GCC Flags für Binary Optimization
  • Falcon patch
  • Ruby 1.9.3 Environment Variabeln

Die Auswirkungen und Performance Messungen findet man in den Quellen. Hier wird nur die Anwendung auf einem Rails Server gezeigt.

Als Beispiel nehmen wir das auf einem Rails Server Standard gehostete vereine.ch. Hier haben die Tweaks einen Performance Gewinn von 20%-30% über die 5 meist genutzten URLs gebracht.

Ruby ruby-1.9.3-p327 mit Optimierungen installieren

Zuerst kommt das Update auf die aktuelle RVM Version.

rvm get head --auto
rvm reload

Nun kann man Datei ~/.rvmrc erstellen mit dem Inhalt

rvm_configure_env=(CFLAGS="-march=native -O3")

Nun noch automake installieren und danach die neue Ruby Version mit dem Patch kompilieren.

aptitude install automake
rvm install 1.9.3-p327 --patch falcon

Um einen reibungslosen Übergang für die bestehenden Apps zu garantieren kann man das gemset der alten Ruby version in die neue kopieren.

rvm gemset copy ruby-1.9.2-p290 ruby-1.9.3-p327

Nun noch das Passenger Apache Modul unter der neuen Version kompilieren.

 rvm use ruby-1.9.3-p327
 passenger-install-apache2-module 

Danach noch den Passenger auf die richtige Ruby version konfigurieren:
In /etc/apache2/mods-enabled/passenger.load und /etc/apache2/mods-enabled/passenger.conf z.B.

   PassengerRoot /usr/local/rvm/gems/ruby-1.9.3-p327/gems/passenger-3.0.9
# PassengerRoot /usr/local/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.9

Nach dem Webserver Neustart verwenden alle Rails Applikationen das neue Ruby.

service apache2 restart

Ruby Umgebungsvariabeln

Mit einem besseren Memory Allocator kann nochmal mehr Performance rausgeholt werden.

apt-get install libtcmalloc-minimal0
export LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.0.1.0

Zudem kann man in Ruby 1.9.3 das Verhalten des GC und mehr über Umgebungsvariabeln optimieren

export RUBY_HEAP_MIN_SLOTS=800000
export RUBY_HEAP_FREE_MIN=100000
export RUBY_HEAP_SLOTS_INCREMENT=300000
export RUBY_GC_MALLOC_LIMIT=79000000
export RUBY_FREE_MIN=200000
export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1.8

Mit einem Wrapperscript kann man diese auch für die vom Passenger gestarteten Ruby Prozesse verfügbar machen.

vi /usr/local/my_ruby_wrapper_script

Das Script soll so aussehen.

#!/bin/sh
export RUBY_HEAP_MIN_SLOTS=800000
export RUBY_HEAP_FREE_MIN=100000
export RUBY_HEAP_SLOTS_INCREMENT=300000
export RUBY_GC_MALLOC_LIMIT=79000000
export RUBY_FREE_MIN=200000
export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1.8
export LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.0.1.0
exec "/usr/local/rvm/wrappers/ruby-1.9.3-p327/ruby" "$@"

Nun noch ausführbar machen…

chmod +x /usr/local/my_ruby_wrapper_script

und in der Passenger Konfiguration angeben indem man in /etc/apache2/mods-enabled/passenger.conf

   PassengerRoot /usr/local/rvm/gems/ruby-1.9.3-p327/gems/passenger-3.0.9

ersetzt mit

   PassengerRuby /usr/local/my_ruby_wrapper_script

SMS via aspsms versenden mit PHP via SOAP

September 6th, 2011

aspsms bietet die Möglichkeit SMS über verschiedene Schnittstellen zu versenden.

Eine Möglichkeit ist die Verwendung der SOAP-Web-Schnittstelle. Damit wird der Kern einer PHP-Applikation sehr trivial:

  $sms_sender = new SoapClient(
     'http://webservice.aspsms.com/aspsmsx.asmx?WSDL'
  );
  $params = array(
    'UserKey' => 'XXXXXXXXXXX',
    'Password' => 'xxxxxxxxxxxx',
    'Recipient' => $empfaenger,
    'Originator' => $sender,
    'MessageText' => $nachricht
  );
  $result = $sms_sender->SimpleTextSMS($params);

Einen benutzbaren PHP-Client inkl. Shell-Script für den Aufruf kann frei und auf eigenes Risiko verwendet werden. Einzig ein Userkey und Passwort des zu benutzenden aspsms-Accounts ist im Code noch einzutragen.

Voraussetzung: In PHP muss die SOAP-Extension geladen sein.
Unsere Kunden benötigen übrigens keinen eigenen aspsms-Account, sondern können über unseren Webservice direkt mit dem E-Mail Account SMS versenden.