Gem in a Box: Private Gems unternehmensintern veröffentlichen

Die Ruby-Welt verwendet als Paketsystem RubyGems. Es ist die erste Wahl beim Modularisieren und anschließenden Verteilen von Code aller Art (Bibliotheken, Anwendungsteile, …). Dabei hat sich zur Abhängigkeitsverwaltung Bundler etabliert, es kann die Gems aus verschiedenen Quellen installieren und verwenden. Soll die Quelle allerdings privat und geschützt sein, dann scheiden viele Optionen aus. Gem in a Box kann bei dieser Aufgabenstellung die Lösung sein.

Bundler: Gem-Quellen

Bundler bietet grundsätzlich drei verschiedene Gem-Quellen an:

  • Ein RubyGems-Repository, üblicherweise rubygems.org; das ist der normale Fall, die angegebenen Gems werden alle aus dieser Quelle installiert:
# Gemfile
source :rubygems
gem 'rails'
  • Die Angabe eines Git-Repositories direkt bei der Gem-Definition:
# Gemfile
gem "nokogiri", :git => "git://github.com/rails/rails.git", :branch => "3-1-stable"
# Alternative Schreibweise für ein GitHub-Repository
gem "rails", :github => "rails/rails"
  • Ein lokaler Pfad zu dem entpackten Gem:
# Gemfile
gem "nokogiri", :path => "~/gems/nokogiri"

Probleme

Will man in Projekten allerdings private Gems verwenden, scheiden die obigen Lösungen aber leider aus:

  • Ein Gem im öffentlichen RubyGems-Repository ist eben öffentlich.
  • Der Zugriff auf das Git-Repository des Gems ist normalerweise geschützt und von den Produktivserver aus nicht unbedingt problemlos möglich.
  • Ein Pfad zum entpacktem Gem ist auf Produktivservern in der Praxis schwierig, man müsste einen zentralen Dateiserver per NFS, SMB etc. anbinden, auf dem alle Gems platziert werden.

Wir bei Nix-wie-weg® haben das Problem mit einem eigenem RubyGems-Repository gelöst, das wir mit Gem in a Box aufgesetzt haben.

Quellserver aufsetzen

Die Einrichtung geht leicht von der Hand, die Homepage bietet die wenigen Informationen, die man benötigt. Wir betreiben die Anwendung mit Apache2 und Passenger, die Rack-Konfigurationdatei ist leicht modifiziert, um HTTP-Basic-Authentifizierung zu realisieren:

# config.ru
require 'rubygems'
require 'geminabox'

Geminabox.data = '/var/www/gems.nwwo.de/data'

use Rack::Auth::Basic, 'GemInABox' do |username, password|
  username == 'nix-wie-weg' && password == ';-)'
end

run Geminabox

Den eigenen Server benutzen

In den Gemfiles kann dann die zweite Gem-Quelle inklusive Zugangsdaten sowie die schützenswerten Gems ganz bequem angegeben werden:

# Gemfile
source :rubygems
source 'https://nix-wie-weg:;-)@hostname.domain.tld/'

[...]

gem 'vip_gem'

Gems hochladen

Nett ist übrigens auch die Integration ins gem-Kommando: gem inabox pkg/vip_gem-0.1.17.gem lädt das Gem automatisch in das Repository, damit ist es sofort verfügbar!

Entwickelt man die Gems mit den rake tasks von Bundler, dann ist “Running a Private GemServer inside the Firewall” von Alex Rothenberg interessant. Er beschreibt unter anderem, wie sich Bundler patchen lässt, um rake release weiter zu verwenden. Die erstellten Gems werden dann per gem inabox verteilt, statt zu rubygems.org hochgeladen zu werden.

Alternativen

… gibt es bestimmt einige, bekannt ist mir zum Beispiel Gemfury, das quasi ein fremdgehostetes Gem in a Box ist. Wer da keine Sicherheitsbedenken hat und die Kosten nicht scheut, bekommt natürlich eine noch einfachere Lösung an die Hand.