![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
Das Dockerisieren Ihres Ruby on Rails mit einer React-Frontend-Anwendung kann Ihren Entwicklungs-Workflow und Ihren Bereitstellungsprozess erheblich verbessern. Indem Sie eine standardisierte Umgebung für Ihre App erstellen, stellen Sie ein konsistentes Verhalten in verschiedenen Entwicklungs-, Test- und Produktionsphasen und sogar zwischen verschiedenen Systemen sicher. Tatsächlich ist es darauf ausgelegt, Probleme im Zusammenhang mit Systemunterschieden zu minimieren. Diese Anleitung führt Sie durch die wesentlichen Schritte, damit Ihre Rails- und React-App in Docker-Containern reibungslos läuft.
Docker stellt sicher, dass die Anwendung unabhängig davon, wo sie bereitgestellt wird, auf dieselbe Weise ausgeführt wird, sei es auf der Maschine eines Entwicklers, in einer Testumgebung oder auf einem Produktionsserver. Diese Konsistenz wird durch die Containerisierung aller Abhängigkeiten und Konfigurationen erreicht.
Docker-Container enthalten alle notwendigen Abhängigkeiten, damit die Anwendung ausgeführt werden kann. Das bedeutet, dass Abweichungen in Systembibliotheken oder fehlende Abhängigkeiten auf verschiedenen Systemen die Funktionalität der Anwendung nicht beeinträchtigen.
Docker-Container werden isoliert voneinander und vom Hostsystem ausgeführt. Diese Isolierung verhindert Konflikte zwischen verschiedenen Anwendungen und ihren Abhängigkeiten auf demselben System.
NB: Kenntnisse der Docker-Syntax sind erforderlich
Bei der Dockerisierung geht es um zwei Schlüsselkonzepte: Images und Container. Images dienen als Blaupausen für Container und enthalten alle notwendigen Informationen zum Erstellen eines Containers, einschließlich Abhängigkeiten und Bereitstellungskonfigurationen. Ein Container ist eine Laufzeitinstanz eines Images und besteht aus dem Image selbst, einer Ausführungsumgebung und Laufzeitanweisungen. Docker legt im Allgemeinen einen Standard für die Auslieferung von Software fest.
Um Docker mit einer einfachen Analogie zu erklären: Stellen Sie sich Container als die Schiffscontainer auf einem Lagerplatz vor, Bilder als die in diesen Containern platzierten Objekte und das Schiff als das System, auf dem die Container laufen.
Wenn Sie Ihre Anwendung einrichten und erstellen, sind bestimmte Umgebungskonfigurationen erforderlich. Sie können beispielsweise keine Rails-Anwendung ausführen, ohne dass auf Ihrem System eine Ruby-Umgebung installiert ist. Ebenso können Sie keine React-Anwendung ohne Node.js
ausführen und Sie können keine React-Pakete ohne einen Node-Paketmanager wie npm
oder Yarn
usw. installieren.
Da der Container isoliert vom System des Benutzers läuft, stellen wir alle diese Pakete in unserem Container zur Verfügung, so wie wir es getan hätten, wenn wir ihn direkt auf unserem System erstellt hätten. Der Container fungiert also als eigenständiges System, wie eine virtuelle Maschine. Es gibt Unterschiede zwischen Docker und virtuellen Maschinen, aber dieses Beispiel dient nur der weiteren Erläuterung.
Lassen Sie uns nun die Rails-Anwendung dockerisieren. Dazu benötigen wir drei Dateien in unserer Rails-Anwendung: eine Dockerfile
, eine docker-compose.yml
und eine bin/docker-entrypoint
. Lassen Sie uns jede dieser Dateien im Detail untersuchen.
NB: Kenntnisse der Docker-Syntax sind erforderlich
Das Dockerfile
ist eine Blaupause zum Erstellen eines Docker-Containers. Es enthält eine Reihe von Anweisungen, die Docker zum Erstellen eines Images verwendet, das dann zum Ausführen von Containern verwendet werden kann. Lassen Sie uns ein Dockerfile
für eine Ruby on Rails- und React-Anwendung aufschlüsseln:
ARG RUBY_VERSION=3.1.4 FROM ruby:$RUBY_VERSION
ARG RUBY_VERSION=3.1.4
: Definiert ein Build-Argument namens RUBY_VERSION
mit einem Standardwert von 3.1.4
. Dies kann zur Build-Zeit überschrieben werden.
FROM ruby:$RUBY_VERSION
: Verwendet das ruby
Basisimage mit der durch RUBY_VERSION
angegebenen Version. Dadurch wird der Container mit der Ruby-Laufzeitumgebung eingerichtet. Wie bereits erwähnt, muss Ruby installiert sein, um eine Rails-Anwendung ausführen zu können. RUN apt-get update -qq && \ apt-get install -y build-essential libvips bash bash-completion libffi-dev tzdata postgresql curl && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man
apt-get update -qq
: Aktualisiert die Paketliste aus den Repositories, mit -qq
für stille Ausgabe.
apt-get install -y
... : Installiert verschiedene Pakete: build-essential
: Wichtige Pakete zum Erstellen von Software (wie GCC).
libvips
: Bibliothek zur Bildverarbeitung.
bash
, bash-completion
: Bash-Shell und ihre automatische Vervollständigung.
libffi-dev
: Bibliothek für Fremdfunktionsschnittstellen.
tzdata
: Zeitzonendaten.
postgresql
: PostgreSQL-Datenbankclient.
curl
: Tool zum Übertragen von Daten von URLs.
apt-get clean
: Bereinigt das lokale Repository der abgerufenen Paketdateien.
rm -rf /var/lib/apt/lists/ /usr/share/doc /usr/share/man
: Entfernt Paketlisten und Dokumentation, um die Bildgröße zu reduzieren. RUN curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \ apt-get install -y nodejs && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update && \ apt-get install -y yarn
curl -fsSL https://deb.nodesource.com/setup_current.x | bash -
: Lädt das NodeSource-Setup-Skript herunter und führt es aus, um Node.js zu installieren.
apt-get install -y nodejs
: Installiert Node.js.
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
: Fügt den Yarn-GPG-Schlüssel hinzu, um seine Pakete zu überprüfen.
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
: Fügt das Yarn-Repository zur Quellenliste hinzu.
apt-get update && apt-get install -y yarn
: Aktualisiert die Paketliste und installiert Yarn. ENV NODE_OPTIONS=--openssl-legacy-provider
ENV NODE_OPTIONS=--openssl-legacy-provider
: Legt eine Umgebungsvariable fest, um die Legacy-OpenSSL-Unterstützung für Node.js zu aktivieren. WORKDIR /rails
WORKDIR /rails
: Legt das Arbeitsverzeichnis für nachfolgende Anweisungen auf /rails
fest. ARG RAILS_ENV ENV RAILS_ENV=$RAILS_ENV
ARG RAILS_ENV
: Definiert ein Build-Argument namens RAILS_ENV
zum Angeben der Rails-Umgebung (wie development
, test
, production
).
ENV RAILS_ENV=$RAILS_ENV
: Setzt die Umgebungsvariable RAILS_ENV
auf den Wert des Build-Arguments. COPY Gemfile Gemfile.lock ./ RUN bundle install
COPY Gemfile Gemfile.lock ./
: Kopiert die Gemfile
und Gemfile.lock
in das Arbeitsverzeichnis.
RUN bundle install
: Installiert die im Gemfile
angegebenen Ruby-Gems. COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile
COPY package.json yarn.lock ./
: Kopiert package.json
und yarn.lock
in das Arbeitsverzeichnis.
RUN yarn install --frozen-lockfile
: Installiert Front-End-Abhängigkeiten mit Yarn und stellt sicher, dass die genauen Versionen in yarn.lock
verwendet werden. COPY . .
COPY . .
: Kopiert den gesamten Anwendungscode in das Arbeitsverzeichnis. RUN bundle exec bootsnap precompile --gemfile app/ lib/
RUN bundle exec bootsnap precompile --gemfile app/ lib/
: Kompiliert den Bootsnap-Cache vorab, um schnellere Startzeiten von Rails-Anwendungen zu ermöglichen. Bootsnap ist ein Gem, das die Startzeiten von Ruby und Rails beschleunigt, indem aufwändige Berechnungen zwischengespeichert werden. RUN if [ "$RAILS_ENV" = "production" ]; then \ SECRET_KEY_BASE=1 bin/rails assets:precompile; \ fi
RUN if [ "$RAILS_ENV" = "production" ]; then
... : Führt die Asset-Vorkompilierung nur bedingt aus, wenn RAILS_ENV
auf production
eingestellt ist. Dieser Schritt ist entscheidend für die Vorbereitung von Assets für eine Produktionsumgebung. COPY bin/docker-entrypoint /rails/bin/ RUN chmod +x /rails/bin/docker-entrypoint
COPY bin/docker-entrypoint /rails/bin/
: Kopiert ein benutzerdefiniertes Entrypoint-Skript in den Container.
RUN chmod +x /rails/bin/docker-entrypoint
: Macht das Entrypoint-Skript ausführbar. ENTRYPOINT ["/rails/bin/docker-entrypoint"] EXPOSE 5000 // you can use any port of your choice CMD ["./bin/rails", "server"]
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
: Legt das Entrypoint-Skript fest, das beim Starten des Containers ausgeführt wird. Dieses Skript richtet normalerweise die Umgebung ein, bereitet die Datenbank vor und startet die Anwendung.
EXPOSE 5000
: Zeigt an, dass der Container auf Port 5000 lauscht. Dies ist eine Dokumentationsfunktion und veröffentlicht den Port nicht.
CMD ["./bin/rails", "server"]
: Gibt den Standardbefehl an, der beim Starten des Containers ausgeführt werden soll, nämlich den Rails-Server zu starten. Die Datei docker-compose.yml
wird zum Definieren und Ausführen von Docker-Anwendungen mit mehreren Containern verwendet. Sie ermöglicht Ihnen, die Dienste, Netzwerke und Volumes Ihrer Anwendung in einer einzigen Datei zu konfigurieren. In diesem Fall werden wir zwei Dienste verwenden. Hier ist die Datei docker-compose.yml
für die Rails-Anwendung:
db
) codedb: image: postgres:14.2-alpine container_name: demo-postgres-14.2 volumes: - postgres_data:/var/lib/postgresql/data command: "postgres -c 'max_connections=500'" environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} ports: - "5432:5432"
image: postgres:14.2-alpine
: Gibt das für diesen Dienst zu verwendende Docker-Image an. In diesem Fall ist es das PostgreSQL 14.2-Image, das auf der Alpine Linux-Distribution basiert. Alpine-Images sind für ihre geringe Größe bekannt, die dazu beitragen kann, die Gesamtgröße des Images gering zu halten.
container_name: demo-postgres-14.2
: Benennt den Container demo-postgres-14.2
. Dieser Name wird verwendet, um in Befehlen und Protokollen auf den Container zu verweisen.
volumes
: postgres_data:/var/lib/postgresql/data:
Mountet ein benanntes Volume postgres_data
in /var/lib/postgresql/data
innerhalb des Containers. In diesem Verzeichnis speichert PostgreSQL seine Daten und stellt sicher, dass die Datenbankdaten zwischen Containerneustarts erhalten bleiben.
command: "postgres -c 'max_connections=500'"
: Überschreibt den Standardbefehl des PostgreSQL-Images. Es startet PostgreSQL mit einer Konfigurationsoption, um die maximale Anzahl von Verbindungen auf 500 zu erhöhen.
environment
: POSTGRES_DB: ${POSTGRES_DB}
: Legt den Namen der zu erstellenden Standarddatenbank unter Verwendung der Umgebungsvariable POSTGRES_DB
fest.
POSTGRES_USER: ${POSTGRES_USER}
: Legt unter Verwendung der Umgebungsvariable POSTGRES_USER
den Standardbenutzernamen für den Zugriff auf die PostgreSQL-Datenbank fest.
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
: Legt unter Verwendung der Umgebungsvariable POSTGRES_PASSWORD
das Kennwort für den Standardbenutzer fest.
ports
:"5432:5432"
: Ordnet Port 5432 auf dem Host Port 5432 im Container zu. Dies ermöglicht den Zugriff auf PostgreSQL auf dem Hostcomputer über Port 5432.demo-web
) codedemo-web: build: context: . args: - RAILS_ENV=${RAILS_ENV} command: "./bin/rails server -b 0.0.0.0" environment: - RAILS_ENV=${RAILS_ENV} - POSTGRES_HOST=${POSTGRES_HOST} - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - RAILS_MASTER_KEY=${RAILS_MASTER_KEY} volumes: - .:/rails - app-storage:/rails/storage depends_on: - db ports: - "3000:3000"
build:
context: .
: Gibt den Build-Kontext für das Docker-Image an. In diesem Fall bezieht sich .
auf das aktuelle Verzeichnis. Dies bedeutet, dass Docker die Docker-Datei im aktuellen Verzeichnis verwendet, um das Image zu erstellen.args
: RAILS_ENV=${RAILS_ENV}
: Übergibt das Build-Argument RAILS_ENV
an den Docker-Build-Prozess und ermöglicht Ihnen, die Rails-Umgebung anzugeben (wie etwa development
, test
oder production
).
command: "./bin/rails server -b 0.0.0.0"
: Überschreibt den Standardbefehl des Docker-Images. Startet den Rails-Server und bindet ihn an alle Netzwerkschnittstellen ( 0.0.0.0
), was notwendig ist, damit der Dienst von außerhalb des Containers erreichbar ist.
environment:
RAILS_ENV=${RAILS_ENV}
: Legt die Rails-Umgebung innerhalb des Containers mithilfe der Umgebungsvariable RAILS_ENV
fest.
POSTGRES_HOST=${POSTGRES_HOST}
: Legt die PostgreSQL-Hostadresse fest.
POSTGRES_DB=${POSTGRES_DB}
: Legt den Datenbanknamen fest.
POSTGRES_USER=${POSTGRES_USER}
: Legt den PostgreSQL-Benutzer fest.
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
: Legt das PostgreSQL-Benutzerkennwort fest.
RAILS_MASTER_KEY=${RAILS_MASTER_KEY}
: Legt den Rails-Hauptschlüssel fest, der zum Verschlüsseln von Anmeldeinformationen und anderen Geheimnissen verwendet wird.
volumes
:
.:/rails
: Mountet das aktuelle Verzeichnis (in dem sich die Datei docker-compose.yml
befindet) in /rails
innerhalb des Containers. So können Sie Dateien auf Ihrem Host bearbeiten und diese Änderungen im Container widerspiegeln lassen.
app-storage:/rails/storage
: Mountet ein benanntes Volume app-storage
in /rails/storage
innerhalb des Containers. Dies wird normalerweise zum Speichern Rails-spezifischer Dateien wie Protokolle, Uploads und zwischengespeicherte Dateien verwendet.
depends_on
:
db
: Stellt sicher, dass der demo-web
wartet, bis der db
Dienst bereit ist, bevor er gestartet wird. Docker Compose handhabt die Reihenfolge der gestarteten Dienste basierend auf dieser Einstellung. ports:
"3000:3000"
: Ordnet Port 3000 auf dem Host Port 3000 im Container zu. Dadurch können Sie über Port 3000 auf die Rails-Anwendung auf dem Hostcomputer zugreifen. codevolumes: postgres_data: app-storage:
postgres_data
: Definiert ein benanntes Volume postgres_data
das vom db
zum Speichern von PostgreSQL-Daten verwendet wird.app-storage
: Definiert einen benannten Volume- app-storage
der vom demo-web
zum Speichern anwendungsspezifischer Daten wie Uploads und Protokolle verwendet wird. Das Skript bin/docker-entrypoint
ist ein wichtiger Teil der Docker-Einrichtung. Es wird beim Start des Containers ausgeführt und übernimmt normalerweise die Einrichtung der Umgebung, die Vorbereitung der Datenbank und andere Initialisierungsaufgaben, die vor dem Start der Hauptanwendung erforderlich sind. Hier ist ein Beispiel für ein Skript bin/docker-entrypoint
und eine detaillierte Erklärung jedes Teils:
bashCopy code#!/bin/bash set -e
#!/bin/bash
: Diese Zeile gibt an, dass das Skript mit der Bash-Shell ausgeführt werden soll.
set -e
: Dies weist das Skript an, sofort beendet zu werden, wenn ein Befehl einen Exit-Code ungleich Null zurückgibt. Dadurch wird sichergestellt, dass das Skript die Ausführung stoppt, wenn ein Schritt fehlschlägt. Dadurch kann verhindert werden, dass nachfolgende Schritte in einem ungültigen Zustand ausgeführt werden.
Bedingte Datenbankerstellung oder -migration
# If running the rails server then create or migrate existing database if [ "${*}" == "./bin/rails server" ]; then ./bin/rails db:create ./bin/rails db:prepare fi
"${*}"
) ./bin/rails server
ist. Das *
ist ein spezieller Parameter, der alle an das Skript übergebenen Positionsparameter enthält.
./bin/rails db
: Wenn die Bedingung erfüllt ist, versucht dieser Befehl, die Datenbank zu erstellen. Dies entspricht dem Ausführen von rails db:create
, wodurch die Datenbank gemäß der Definition in der Datenbankkonfigurationsdatei ( config/database.yml
) eingerichtet wird.
./bin/rails db
: Dieser Befehl führt rails db:prepare
aus, wodurch sichergestellt wird, dass die Datenbank eingerichtet und migriert wird. Er erstellt die Datenbank, wenn sie noch nicht existiert, und führt Migrationen aus, wenn die Datenbank bereits erstellt wurde. Dies ist eine Kombination aus rails db:create
und rails db:migrate
.
bashCopy codeexec "${@}"
exec "${@}"
: Dies ersetzt den aktuellen Shell-Prozess durch den Befehl, der als Argumente an das Skript übergeben wurde. Das @
-Symbol enthält alle Positionsparameter, die an das Skript übergeben werden. Wenn das Skript beispielsweise mit ./bin/rails server
aufgerufen wird, führt diese Zeile ./bin/rails server
effektiv als Hauptprozess des Containers aus. Ein gut gestaltetes Dockerfile
ist unerlässlich, um eine zuverlässige und konsistente Umgebung für Ihre Ruby on Rails- und React-Anwendung zu erstellen. Indem Sie das Basisimage definieren, Umgebungsvariablen festlegen und Abhängigkeiten installieren, stellen Sie sicher, dass Ihre Anwendung in verschiedenen Umgebungen reibungslos läuft.
Docker rationalisiert nicht nur Ihren Entwicklungsprozess, sondern verbessert auch die Zuverlässigkeit Ihrer Anwendung in der Produktion. Es gibt Optimierungsbereiche, aber dies ist nur ein allgemeiner Überblick darüber, wie die Rails-Anwendung dockerisiert wird.
Dockerfile
, docker-compose.yml
und bin/docker-entrypoint
ARG RUBY_VERSION=3.1.4 FROM ruby:$RUBY_VERSION # Install dependencies RUN apt-get update -qq && \ apt-get install -y build-essential libvips bash bash-completion libffi-dev tzdata postgresql curl && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man # Install Node.js and Yarn RUN curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \ apt-get install -y nodejs && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update && \ apt-get install -y yarn # Set environment variable to enable legacy OpenSSL support ENV NODE_OPTIONS=--openssl-legacy-provider # Rails app lives here WORKDIR /rails # Set environment variable for the build ARG RAILS_ENV ENV RAILS_ENV=$RAILS_ENV # Install application gems COPY Gemfile Gemfile.lock ./ RUN bundle install # Install frontend dependencies COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile # Copy application code COPY . . # Precompile bootsnap code for faster boot times RUN bundle exec bootsnap precompile --gemfile app/ lib/ # Precompiling assets for production without requiring secret RAILS_MASTER_KEY RUN if [ "$RAILS_ENV" = "production" ]; then \ SECRET_KEY_BASE=1 bin/rails assets:precompile; \ fi # Entrypoint prepares the database. COPY bin/docker-entrypoint /rails/bin/ RUN chmod +x /rails/bin/docker-entrypoint # Use an absolute path for the entry point script ENTRYPOINT ["/rails/bin/docker-entrypoint"] # Start the server by default, this can be overwritten at runtime EXPOSE 5000 CMD ["./bin/rails", "server"]
services: db: image: postgres:14.2-alpine container_name: demo-postgres-14.2 volumes: - postgres_data:/var/lib/postgresql/data command: "postgres -c 'max_connections=500'" environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} ports: - "5432:5432" demo-web: build: context: . args: - RAILS_ENV=${RAILS_ENV} command: "./bin/rails server -b 0.0.0.0" environment: - RAILS_ENV=${RAILS_ENV} - POSTGRES_HOST=${POSTGRES_HOST} - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - RAILS_MASTER_KEY=${RAILS_MASTER_KEY} volumes: - .:/rails - app-storage:/rails/storage depends_on: - db ports: - "3000:3000" volumes: postgres_data: app-storage:
#!/bin/bash set -e # If running the rails server then create or migrate existing database if [ "${*}" == "./bin/rails server" ]; then ./bin/rails db:create ./bin/rails db:prepare fi exec "${@}"