Zum Hauptinhalt springen

Ruby Applikationen betreiben

Dieser Artikel erklärt, wie man Ruby-Anwendungen auf Nines Managed Servern betreibt.

Container-Deployment

Wenn Sie Ihre Anwendung in einem Container ausführen möchten, finden Sie in unserem Artikel zu Podman die wichtigsten Informationen.

Container ermöglichen Ihnen, Ihre Anwendung in unterschiedlichen Umgebungen betreiben zu können, ohne dabei wesentliche Anpassungen an der Applikation selbst vornehmen zu müssen. Container erleichtern zudem die Verwaltung von Abhängigkeiten und helfen Ihnen, Ihre Anwendung zu skalieren, indem sie sie von anderen Prozessen im System isolieren.

Anforderungen

Für das folgende Beispiel nehmen wir an, dass Ihre Anwendung einen Ruby Webserver wie puma, thin, etc. unterstützt. Rails wird standardmässig mit puma ausgeliefert, weshalb wir diesen in unserem Beispiel verwenden.

1. Installieren Sie den Ruby Version-Manager

Um verschiedene Ruby-Versionen unabhängig des eingesetzten Betriebssystems zu verwenden, empfehlen wir die Nutzung eines Versionsmanagers wie rbenv.

So installieren Sie rbenv:

curl -fsSL https://github.com/rbenv/rbenv-installer/raw/HEAD/bin/rbenv-installer | bash
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
source ~/.bashrc

2. Ruby-Version installieren

Die gewünschte Ruby-Version kann nun installiert werden:

rbenv install --list # installierbare Versionen auflisten
rbenv install 3.2.0

Aktualisieren Sie anschliessend "Bundler" auf die neueste Version:

rbenv exec bundle update --bundler

3. Anwendung deployen

Das Deployment Ihrer Anwendung ist für jedes Projekt unterschiedlich. Mit Rails müssen Sie Assets kompilieren, sie und den Code auf den Server hochladen und Ruby-Abhängigkeiten installieren:

Führen Sie diese Befehle auf Ihrem lokalen Rechner aus

Assets kompilieren:

RAILS_ENV=production bundle exec rake assets:precompile

Dateien auf den Server kopieren:

rsync -a -v --delete --exclude='node_modules/*' --exclude='tmp/*' --exclude='vendor/*' --exclude='.git/*' ./ www-data@server.nine.ch:app/current

Sicherstellen, dass die Abhängigkeiten aktuell sind:

ssh www-data@server.nine.ch 'cd ~/app/current && BUNDLER_WITHOUT="development test" rbenv exec bundle install'

4. systemd-Service einrichten

Um sicherzustellen, dass ein Dienst weiterläuft, z.B. neu gestartet wird wenn er ausfällt oder nach einem Neustart des Servers wieder startet, empfehlen wir die Verwendung eines Systemd-Benutzerdienstes.

Dieses Beispiel lädt Umgebungsvariablen von ~/app/env und führt dann rails server -b localhost --log-to-stdout im Verzeichnis ~/app/current aus.

Die Konfiguration für eine solchen Systemd-Service hängt von Ihrer Anwendung ab. Das obige Beispiel geht davon aus, dass Sie eine Rails-Anwendung ausführen.

Erstellen Sie die Servicedatei in ~/.config/systemd/user/rails-app.service.

[Unit]
Description=Anwendung

[Service]
Type=simple
WorkingDirectory=%h/app/current

Environment=RAILS_ENV=production
Environment=PORT=3000

EnvironmentFile=%h/app/env

ExecStart=%h/.rbenv/bin/rbenv exec bundle exec rails server -b localhost --log-to-stdout

TimeoutSec=15
Restart=on-failure

PrivateTmp=yes
ProtectSystem=full

[Install]
WantedBy=default.target

Im nächsten Schritt wird der Dienst aktiviert und gestartet:

touch ~/app/env # sicherstellen, dass die Umgebungsdatei existiert
systemctl --user daemon-reload
systemctl --user enable rails-app.service
systemctl --user start rails-app.service

Ihre Anwendung sollte nun als Dienst registriert und bereits gestartet sein:

$ systemctl --user status rails-app.service
● rails-app.service - Anwendung
Loaded: loaded (/home/www-data/.config/systemd/user/rails-app.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2021-07-16 10:13:36 CEST; 5s ago
Main PID: 3615317 (ruby)
CGroup: /user.slice/user-33.slice/user@33.service/rails-app.service
└─3615317 puma 5.3.2 (tcp://localhost:3000) [current]

Jul 16 10:13:37 server rbenv[3615317]: => Run `bin/rails server --help` for more startup options
Jul 16 10:13:37 server rbenv[3615317]: Puma starting in single mode...
Jul 16 10:13:37 server rbenv[3615317]: * Puma version: 5.3.2 (ruby 3.0.2-p107) ("Sweetnighter")
Jul 16 10:13:37 server rbenv[3615317]: * Min threads: 5
Jul 16 10:13:37 server rbenv[3615317]: * Max threads: 5
Jul 16 10:13:37 server rbenv[3615317]: * Environment: production
Jul 16 10:13:37 server rbenv[3615317]: * PID: 3615317
Jul 16 10:13:37 server rbenv[3615317]: * Listening on http://127.0.0.1:3000
Jul 16 10:13:37 server rbenv[3615317]: * Listening on http://[::1]:3000
Jul 16 10:13:38 server rbenv[3615317]: Use Ctrl-C to stop

Fehlerbehebung

  1. Stellen Sie sicher, dass die .bashrc korrekt geladen wird
  2. Überprüfen Sie, ob der Dienst korrekt gestartet wurde: systemctl --user status app.service
  3. Überprüfen Sie die Log-Ausgabe: journalctl --user -f

Weitere Informationen zur Verwendung von Systemd finden Sie im folgendem Support-Artikel.

5. Webserver konfigurieren

https

Dadurch sollte Ihre Anwendung über http zugänglich sein. Um https-Unterstützung hinzuzufügen, verwenden Sie bitte proxy_letsencrypt_https, wie in nine-manage-vhosts mit Let's Encrypt dokumentiert.

Die Anwendung läuft jetzt auf einem lokalen Port. Um die Anwendung über http und https zu erreichen, muss der Webserver diese Anfragen an den lokalen Port weiterleiten.

Auf Ihrem Managed Server sind bereits zwei nine-manage-vhost Vorlagen für diesen Anwendungsfall vorinstalliert: proxy und proxy_letsencrypt.

Erstellen Sie einen neuen vHost und geben den lokalen Port der Anwendung über die Variable PROXYPORT an:

$ sudo nine-manage-vhosts virtual-host create example.com --template proxy --template-variable PROXYPORT=3000 --webroot ~/exampleapp/static

Virtual Host created: example.com
example.com
===========
DOMAIN: example.com
USER: www-data
WEBROOT: /home/www-data/exampleapp/static
TEMPLATE: proxy
TEMPLATE VARIABLES: PROXYPORT
3000
ALIASES: www.example.com
example.com.server.nine.ch

Bei Aufruf der URL http://example.com.server.nine.ch wird nun Ihre Applikation angesprochen.

Automatisierung des Deployments

Um das Deployment Ihrer Ruby-Anwendung zu automatisieren, können Sie Capistrano verwenden, ein Automatisierungstool für Remote-Server. Nachfolgend sind die Schritte zur Einrichtung und Verwendung von Capistrano aufgeführt:

Capistrano installieren

Fügen Sie Capistrano zu Ihrem Gemfile hinzu:

group :deployment do
gem 'capistrano', require: false
gem 'capistrano-rbenv', require: false
gem 'capistrano-rbenv-install', require: false
gem 'capistrano-rails', require: false
gem 'capistrano-systemd-multiservice', require: false
end

Führen Sie anschliessend die folgenden Befehle aus:

bundle install
cap install

Dies erstellt mehrere Standardkonfigurationsdateien für Capistrano in Ihrem Projekt.

Capistrano konfigurieren

Bearbeiten Sie die Datei Capfile, um die erforderlichen Capistrano-Plugins einzuschliessen:

require 'capistrano/setup'
require 'capistrano/deploy'

require 'capistrano/scm/git'
install_plugin Capistrano::SCM::Git

require 'capistrano/rbenv'
require 'capistrano/rbenv_install'
require 'capistrano/bundler'
require 'capistrano/rails'

require "capistrano/systemd/multiservice"
install_plugin Capistrano::Systemd::MultiService.new_service("app", service_type: "user")

# Laden Sie benutzerdefinierte Aufgaben aus `lib/capistrano/tasks`, falls vorhanden
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }

Bearbeiten Sie die Datei config/deploy.rb, um die Deployment-Einstellungen zu definieren:

lock "~> 3.16"

set :application, "your_app_name"
set :repo_url, "git@example.com:me/my_repo.git"

set :branch, ENV.fetch("CI_COMMIT_REF_NAME", "main")
set :deploy_to, "/home/#{fetch :user}/#{fetch :application}"
set :keep_releases, 5

set :rbenv_type, :user
set :rbenv_ruby, File.read(".ruby-version").strip
set :rbenv_path, "/home/#{fetch :user}/.rbenv"

append :linked_files, "env"
append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "vendor/bundle", "public/system"

before "systemd:app:validate", "systemd:app:setup"
after "deploy:publishing", "systemd:app:restart"

Hinterlegen Sie die Serverdetails in der Datei config/deploy/production.rb:

server 'server.nine.ch', user: 'www-data', roles: %w{app db web}

Definieren Sie die Ruby-Version in einer .ruby-version Datei:

3.2.0

Erstellen Sie anschliessend ein Template für den Systemd-Service in config/systemd/app.service.erb:

[Unit]
Description=<%= fetch :application %> Rails-Anwendung

[Service]
Type=simple

WorkingDirectory=<%= current_path %>
Environment=RAILS_SERVE_STATIC_FILES=true
EnvironmentFile=<%= shared_path %>/env

ExecStart=%h/.rbenv/bin/rbenv exec bundle exec rails server -b localhost --log-to-stdout

TimeoutSec=15
Restart=on-failure

PrivateTmp=yes
ProtectSystem=full

[Install]
WantedBy=default.target

Deployment mit Capistrano

Nun können Sie Ihre Anwendung mit Capistrano mit dem folgenden Befehl deployen:

bundle exec cap production deploy

Capistrano kümmert sich um die Details des Deployments, einschliesslich der Verwaltung der Ruby-Version, Abhängigkeiten, Asset-Kompilierung, Dateiübertragung und Verwaltung des systemd-Dienstes.

Dieses Vorgehen stellt sicher, dass Ihr Deployment optimiert und weniger fehleranfällig ist, wodurch effizientere und zuverlässigere Veröffentlichungen ermöglicht werden.