
Wie man Ruby on Rails dockerisiert und deployed
Lukas MauserDieses Dockerfile baut deine Rails App mit einem Multi-Stage Setup, das Gems installiert, Assets precompiled und dann nur das in ein schlankes finales Image kopiert, was Production braucht.
Falls du nur zum Kopieren und Einfügen hier bist, hier ist das fertige Dockerfile, das ein Image für deine Rails App erstellt:
FROM ruby:3.3-slim AS base
WORKDIR /rails
ENV RAILS_ENV=production \
BUNDLE_DEPLOYMENT=1 \
BUNDLE_PATH=/usr/local/bundle \
BUNDLE_WITHOUT=development:test
FROM base AS build
# Build-Tools und Postgres-Header, nur beim Kompilieren der Gems nötig
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libpq-dev
# Erst die Gems installieren, damit dieser Layer gecacht bleibt, wenn sich nur der Quellcode ändert
COPY Gemfile Gemfile.lock ./
RUN bundle install && rm -rf "${BUNDLE_PATH}"/ruby/*/cache
# Die App kopieren und Assets precompilen
COPY . .
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
FROM base AS runtime
# Hier wird nur die Postgres-Runtime-Library gebraucht, nicht die Header
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y libpq5 && \
rm -rf /var/lib/apt/lists/*
# Die installierten Gems und die gebaute App rüberholen
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build /rails /rails
EXPOSE 3000
CMD ["./bin/rails", "server", "-b", "0.0.0.0"]
Und hier ist die .dockerignore Datei:
.git
log/*
tmp/*
storage/*
node_modules
.env
Um das Image zu bauen und auszuführen, nutze diese Befehle:
docker build -t rails-app .
docker run -p 3000:3000 -e RAILS_MASTER_KEY=your_master_key rails-app
Nicht nur zum Kopieren und Einfügen hier? Dann lass uns durchgehen, was im Dockerfile passiert!
Das Setup
Für dieses Tutorial gehe ich davon aus, dass du eine Rails App hast, die mit Postgres spricht, was das häufigste Setup ist. Lokal führst du bin/rails server aus und alles läuft einfach. Für Production wollen wir ein kleines, self-contained Image, also splitten wir die Arbeit in eine Build-Stage, die alle Compiler hat, und eine Runtime-Stage, die keine davon hat.
Das Dockerfile
Die base Stage setzt gemeinsame Environment-Variablen. RAILS_ENV=production und BUNDLE_WITHOUT=development:test stellen sicher, dass wir keine Test- und Development-Gems ins Image ziehen.
Die build Stage macht die schwere Arbeit:
- Build-Dependencies:
- Installiert
build-essential,gitundlibpq-dev. Die braucht man, um native Gem-Extensions wiepgzu kompilieren, aber du willst sie nicht im finalen Image haben.
- Gem-Installation:
- Kopiert
GemfileundGemfile.lockeinzeln und führt dannbundle installaus. Das vor dem Kopieren des restlichen Codes zu machen heißt, dass Docker deine Gems cacht und sie nur neu installiert, wenn sich das Gemfile ändert.
- Asset-Precompilation:
- Führt
assets:precompilemitSECRET_KEY_BASE_DUMMY=1aus. Rails braucht beim Precompile irgendein Secret, um zu booten, und dieses Flag liefert ein Wegwerf-Secret, damit du deinen echten Key nicht in den Build leaken musst.
Die runtime Stage ist bewusst nackt:
- Runtime-Image:
- Installiert nur
libpq5, die Shared-Library, die daspgGem zur Laufzeit braucht. - Kopiert die installierten Gems und die fertige App aus der Build-Stage.
- Exponiert Port 3000 und startet Puma gebunden an
0.0.0.0, damit es Verbindungen von außerhalb des Containers annimmt.
Zur Laufzeit braucht Rails RAILS_MASTER_KEY (oder SECRET_KEY_BASE), um deine Credentials zu entschlüsseln, also gib es als Environment-Variable weiter, statt es zu committen.
Deployment
Du kannst diesen Docker Container bei jedem Cloud-Anbieter deployen, der Docker unterstützt. Du könntest zum Beispiel Plattformen wie Heroku, DigitalOcean oder AWS ECS nutzen. Da ich Mitgründer von Sliplane bin, zeig ich dir, wie du es dort deployst.
Nach der Anmeldung kannst du einen neuen Service erstellen, indem du dein GitHub Repository auswählst. Behalt dann die Standardeinstellungen bei, füg RAILS_MASTER_KEY und deine DATABASE_URL als Environment-Variablen hinzu und klick auf Deploy.

Nach dem Deployment ist deine Rails App unter einer Subdomain von sliplane.app verfügbar, normalerweise ist das einfach dein Service-Name.
Du kannst auch die Logs deiner App sehen, Metriken wie CPU- und Speichernutzung einsehen, persistenten Speicher hinzufügen und vieles mehr. Wann immer du in dein Repository pushst, deployed Sliplane deine App automatisch.
Wenn du Sliplane ausprobieren möchtest, sind die ersten 2 Tage kostenlos! Probier es aus und lass mich wissen, was du davon hältst :)
Nächste Schritte
Beim Deploy willst du normalerweise bin/rails db:migrate ausführen. Ein winziges Entrypoint-Script, das Migrations ausführt und dann Puma startet, erledigt das sauber. Brauchst du Hilfe beim Verdrahten davon oder beim Anbinden einer Managed-Postgres-Datenbank? Melde dich gerne!
Bis dann,
Lukas