Dockeriser votre Ruby on Rails avec une application frontale React peut considérablement améliorer votre flux de travail de développement et votre processus de déploiement. En créant un environnement standardisé pour votre application, vous garantissez un comportement cohérent à travers les différentes étapes de développement, de test, de production et même sur différents systèmes. En fait, il est conçu pour minimiser les problèmes liés aux différences entre les systèmes. Ce guide vous guidera à travers les étapes essentielles pour que votre application Rails et React fonctionne correctement dans les conteneurs Docker.
Pourquoi Dockeriser une application ?
- Cohérence entre les environnements :
Docker garantit que l'application s'exécute de la même manière quel que soit l'endroit où elle est déployée, que ce soit sur la machine d'un développeur, dans un environnement de test ou sur un serveur de production. Cette cohérence est obtenue en conteneurisant toutes les dépendances et configurations.
- Gestion des dépendances :
Les conteneurs Docker incluent toutes les dépendances nécessaires à l'exécution de l'application. Cela signifie que les variations dans les bibliothèques système ou les dépendances manquantes sur différents systèmes n'affectent pas la fonctionnalité de l'application.
- Isolement :
Les conteneurs Docker s'exécutent indépendamment les uns des autres et du système hôte. Cette isolation évite les conflits entre différentes applications et leurs dépendances sur le même système.
- Portabilité :
- Les conteneurs Docker peuvent être facilement déplacés et exécutés sur n'importe quel système prenant en charge Docker, qu'il s'agisse d'une machine locale, d'un service cloud ou d'un serveur dédié. Cela rend l'application hautement portable et flexible en termes de déploiement.
NB : Une connaissance de la syntaxe Docker est requise
La dockerisation implique deux concepts clés : les images et les conteneurs. Les images servent de modèles pour les conteneurs, contenant toutes les informations nécessaires pour créer un conteneur, y compris les dépendances et les configurations de déploiement. Un conteneur est une instance d'exécution d'une image, comprenant l'image elle-même, un environnement d'exécution et des instructions d'exécution. Docker en général établit une norme pour les logiciels d'expédition.
Pour expliquer Docker avec une analogie simple : considérez les conteneurs comme les conteneurs d'expédition dans un chantier, les images comme les articles placés à l'intérieur de ces conteneurs et le navire d'expédition comme le système sur lequel les conteneurs fonctionnent.
Chaque fois que vous configurez et créez votre application, certaines configurations d'environnement sont nécessaires. Par exemple, vous ne pouvez pas exécuter une application Rails sans qu'un environnement Ruby soit installé sur votre système. De même, vous ne pouvez pas exécuter une application React sans Node.js
, et vous ne pouvez pas installer de packages React sans un gestionnaire de packages Node comme npm
ou Yarn
, etc.
Puisque le conteneur fonctionne indépendamment du système de l'utilisateur, nous allons rendre tous ces packages disponibles dans notre conteneur comme nous l'aurions fait si nous l'avions construit directement sur notre système, ainsi, le conteneur agira comme un système sur celui-ci. propre, comme une machine virtuelle. Il existe des différences entre Docker et la machine virtuelle, mais cet exemple sert simplement à expliquer davantage.
Maintenant, allons de l'avant et dockerisons l'application Rails. Pour ce faire, nous aurons besoin de trois fichiers dans notre application Rails : un Dockerfile
, un docker-compose.yml
et un bin/docker-entrypoint
. Examinons chacun de ces fichiers en détail.
NB : Une connaissance de la syntaxe Docker est requise
Fichier Docker
Le Dockerfile
est un modèle pour créer un conteneur Docker. Il contient une série d'instructions que Docker utilise pour créer une image, qui peut ensuite être utilisée pour exécuter des conteneurs. Décomposons un Dockerfile
pour une application Ruby on Rails et React :
. Image de base
ARG RUBY_VERSION=3.1.4 FROM ruby:$RUBY_VERSION
-
ARG RUBY_VERSION=3.1.4
: Définit un argument de build nomméRUBY_VERSION
avec une valeur par défaut de3.1.4
. Cela peut être remplacé au moment de la construction.
-
FROM ruby:$RUBY_VERSION
: utilise l'image de baseruby
avec la version spécifiée parRUBY_VERSION
. Cela configure le conteneur avec le runtime Ruby. Tout comme je l'ai mentionné plus tôt, pour exécuter une application Rails, vous devez avoir installé Ruby.
2. Installer les dépendances
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
: Met à jour la liste des packages à partir des référentiels, avec-qq
pour une sortie silencieuse.
-
apt-get install -y
... : Installe divers packages :build-essential
: packages essentiels pour la création de logiciels (comme GCC).libvips
: Bibliothèque de traitement d'images.bash
,bash-completion
: Shell Bash et son auto-complétion.libffi-dev
: bibliothèque d'interface de fonctions étrangères.tzdata
: Données de fuseau horaire.postgresql
: client de base de données PostgreSQL.curl
: Outil pour transférer des données depuis des URL.
-
apt-get clean
: nettoie le référentiel local des fichiers de package récupérés.
-
rm -rf /var/lib/apt/lists/ /usr/share/doc /usr/share/man
: Supprime les listes de packages et la documentation pour réduire la taille de l'image.
3. Installez Node.js et 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
-
curl -fsSL https://deb.nodesource.com/setup_current.x | bash -
: télécharge et exécute le script d'installation de NodeSource pour installer Node.js.
-
apt-get install -y nodejs
: Installe Node.js.
-
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
: Ajoute la clé Yarn GPG pour vérifier ses packages.
-
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
: Ajoute le référentiel de Yarn à la liste des sources.
-
apt-get update && apt-get install -y yarn
: met à jour la liste des packages et installe Yarn.
4. Variables d'environnement
ENV NODE_OPTIONS=--openssl-legacy-provider
-
ENV NODE_OPTIONS=--openssl-legacy-provider
: définit une variable d'environnement pour activer la prise en charge OpenSSL héritée pour Node.js.
5. Définir le répertoire de travail
WORKDIR /rails
-
WORKDIR /rails
: Définit le répertoire de travail pour les instructions ultérieures sur/rails
.
6. Construire des arguments et des variables d'environnement
ARG RAILS_ENV ENV RAILS_ENV=$RAILS_ENV
-
ARG RAILS_ENV
: définit un argument de construction nomméRAILS_ENV
pour spécifier l'environnement Rails (commedevelopment
,test
,production
).
-
ENV RAILS_ENV=$RAILS_ENV
: Définit la variable d'environnementRAILS_ENV
à la valeur de l'argument de construction.
7. Installer les gemmes d'application
COPY Gemfile Gemfile.lock ./ RUN bundle install
-
COPY Gemfile Gemfile.lock ./
: Copie leGemfile
etGemfile.lock
dans le répertoire de travail.
-
RUN bundle install
: installe les gemmes Ruby spécifiées dans leGemfile
.
8. Installer les dépendances frontales
COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile
-
COPY package.json yarn.lock ./
: Copie lepackage.json
etyarn.lock
dans le répertoire de travail.
-
RUN yarn install --frozen-lockfile
: installe les dépendances frontales à l'aide de Yarn, en s'assurant qu'il utilise les versions exactes dansyarn.lock
.
9. Copier le code de candidature
COPY . .
-
COPY . .
: Copie tout le code de l'application dans le répertoire de travail.
10. Précompiler le code Bootsnap
RUN bundle exec bootsnap precompile --gemfile app/ lib/
-
RUN bundle exec bootsnap precompile --gemfile app/ lib/
: précompile le cache Bootsnap pour des temps de démarrage plus rapides de l'application Rails. Bootsnap est un joyau qui accélère les temps de démarrage de Ruby et Rails en mettant en cache des calculs coûteux.
11. Précompiler les actifs pour la production
RUN if [ "$RAILS_ENV" = "production" ]; then \ SECRET_KEY_BASE=1 bin/rails assets:precompile; \ fi
-
RUN if [ "$RAILS_ENV" = "production" ]; then
... : exécute sous condition la pré-compilation des actifs uniquement siRAILS_ENV
est défini surproduction
. Cette étape est cruciale pour préparer les actifs à un environnement de production.
12. Script de point d'entrée
COPY bin/docker-entrypoint /rails/bin/ RUN chmod +x /rails/bin/docker-entrypoint
-
COPY bin/docker-entrypoint /rails/bin/
: copie un script de point d'entrée personnalisé dans le conteneur.
-
RUN chmod +x /rails/bin/docker-entrypoint
: Rend le script du point d'entrée exécutable.
13. Définir le point d'entrée et la commande
ENTRYPOINT ["/rails/bin/docker-entrypoint"] EXPOSE 5000 // you can use any port of your choice CMD ["./bin/rails", "server"]
-
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
: Définit le script de point d'entrée qui s'exécutera au démarrage du conteneur. Ce script configure généralement l'environnement, prépare la base de données et démarre l'application.
-
EXPOSE 5000
: Indique que le conteneur écoute sur le port 5000. Il s'agit d'une fonctionnalité de documentation et ne publie pas le port.
-
CMD ["./bin/rails", "server"]
: Spécifie la commande par défaut à exécuter au démarrage du conteneur, qui consiste à démarrer le serveur Rails.
docker-compose.yml
Le fichier docker-compose.yml
est utilisé pour définir et exécuter des applications Docker multi-conteneurs. Il vous permet de configurer les services, réseaux et volumes de votre application dans un seul fichier. Dans ce cas, nous allons utiliser deux services. Voici le fichier docker-compose.yml
pour l'application Rails :
1. Service de base de données ( 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
: Spécifie l'image Docker à utiliser pour ce service. Dans ce cas, il s'agit de l'image PostgreSQL 14.2 basée sur la distribution Alpine Linux. Les images alpines sont connues pour leur petite taille, ce qui peut contribuer à réduire la taille globale de l’image.
-
container_name: demo-postgres-14.2
: Nomme le conteneurdemo-postgres-14.2
. Ce nom est utilisé pour référencer le conteneur dans les commandes et les journaux.
-
volumes
:postgres_data:/var/lib/postgresql/data:
monte un volume nommépostgres_data
sur/var/lib/postgresql/data
à l'intérieur du conteneur. Ce répertoire est l'endroit où PostgreSQL stocke ses données, garantissant que les données de la base de données persistent entre les redémarrages du conteneur.
-
command: "postgres -c 'max_connections=500'"
: Remplace la commande par défaut de l'image PostgreSQL. Il démarre PostgreSQL avec une option de configuration permettant d'augmenter le nombre maximum de connexions à 500.
-
environment
:POSTGRES_DB: ${POSTGRES_DB}
: Définit le nom de la base de données par défaut à créer, à l'aide d'une variable d'environnementPOSTGRES_DB
.POSTGRES_USER: ${POSTGRES_USER}
: définit le nom d'utilisateur par défaut pour accéder à la base de données PostgreSQL, à l'aide de la variable d'environnementPOSTGRES_USER
.POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
: Définit le mot de passe de l'utilisateur par défaut, en utilisant la variable d'environnementPOSTGRES_PASSWORD
.
-
ports
:-
"5432:5432"
: mappe le port 5432 sur l'hôte au port 5432 dans le conteneur. Cela permet d'accéder à PostgreSQL sur la machine hôte via le port 5432.
-
2. Service d'application Web ( 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: .
: Spécifie le contexte de construction de l'image Docker. Dans ce cas,.
fait référence au répertoire courant. Cela signifie que Docker utilisera le Dockerfile dans le répertoire actuel pour créer l'image. -
args
:RAILS_ENV=${RAILS_ENV}
: transmet l'argument de constructionRAILS_ENV
au processus de construction Docker, vous permettant de spécifier l'environnement Rails (commedevelopment
,test
ouproduction
).
-
command: "./bin/rails server -b 0.0.0.0"
: remplace la commande par défaut de l'image Docker. Démarre le serveur Rails et le lie à toutes les interfaces réseau (0.0.0.0
), ce qui est nécessaire pour que le service soit accessible depuis l'extérieur du conteneur.
environment:
RAILS_ENV=${RAILS_ENV}
: Définit l'environnement Rails à l'intérieur du conteneur à l'aide de la variable d'environnementRAILS_ENV
.POSTGRES_HOST=${POSTGRES_HOST}
: Définit l'adresse de l'hôte PostgreSQL.POSTGRES_DB=${POSTGRES_DB}
: Définit le nom de la base de données.POSTGRES_USER=${POSTGRES_USER}
: Définit l'utilisateur PostgreSQL.POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
: Définit le mot de passe de l'utilisateur PostgreSQL.RAILS_MASTER_KEY=${RAILS_MASTER_KEY}
: Définit la clé principale Rails, qui est utilisée pour crypter les informations d'identification et autres secrets.
volumes
:.:/rails
: monte le répertoire actuel (où se trouve le fichierdocker-compose.yml
) sur/rails
à l'intérieur du conteneur. Cela vous permet de modifier des fichiers sur votre hôte et de refléter ces modifications dans le conteneur.app-storage:/rails/storage
: monte un volume nomméapp-storage
sur/rails/storage
à l'intérieur du conteneur. Ceci est généralement utilisé pour stocker des fichiers spécifiques à Rails tels que les journaux, les téléchargements et les fichiers mis en cache.
depends_on
:-
db
: garantit que le servicedemo-web
attend que le servicedb
soit prêt avant de démarrer. Docker Compose gère l'ordre de démarrage des services en fonction de ce paramètre.
-
ports:
-
"3000:3000"
: Mappe le port 3000 sur l'hôte au port 3000 dans le conteneur. Cela vous permet d'accéder à l'application Rails sur la machine hôte via le port 3000.
Volumes
codevolumes: postgres_data: app-storage:
-
postgres_data
: définit un volume nommépostgres_data
utilisé par le servicedb
pour conserver les données PostgreSQL. -
app-storage
: définit un volume nomméapp-storage
utilisé par le servicedemo-web
pour conserver les données spécifiques à l'application, telles que les téléchargements et les journaux.
-
bin/docker-point d'entrée
Le script bin/docker-entrypoint
est une partie cruciale de la configuration de Docker. Il est exécuté au démarrage du conteneur et gère généralement la configuration de l'environnement, la préparation de la base de données et d'autres tâches d'initialisation nécessaires avant de démarrer l'application principale. Voici un exemple de script bin/docker-entrypoint
et une explication détaillée de chaque partie :
Shebang et sortie en cas d'erreur
bashCopy code#!/bin/bash set -e
-
#!/bin/bash
: Cette ligne spécifie que le script doit être exécuté à l'aide du shell Bash.
-
set -e
: Cela demande au script de se terminer immédiatement si une commande renvoie un code de sortie différent de zéro. Cela permet de garantir qu'en cas d'échec d'une étape, le script arrête l'exécution, ce qui peut empêcher les étapes suivantes de s'exécuter dans un état non valide.
Création ou migration conditionnelle de bases de données
# 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
- if [ "${*}" == "serveur ./bin/rails" ]; then ... fi : Cette instruction conditionnelle vérifie si la commande passée au script (
"${*}"
) est./bin/rails server
. Le*
est un paramètre spécial qui contient tous les paramètres de position transmis au script.
./bin/rails base de données
: Si la condition est remplie, cette commande tentera de créer la base de données. Cela équivaut à exécuter
rails db:create
qui configure la base de données comme défini dans le fichier de configuration de la base de données (config/database.yml
).
./bin/rails base de données
: Cette commande exécutera
rails db:prepare
, ce qui garantit que la base de données est configurée et migrée. Il créera la base de données si elle n'existe pas et exécutera des migrations si la base de données est déjà créée. Il s'agit d'une combinaison derails db:create
etrails db:migrate
.Exécution du processus principal
bashCopy codeexec "${@}"
-
exec "${@}"
: Ceci remplace le processus shell actuel par la commande passée en arguments au script. Le symbole@
contient tous les paramètres de position transmis au script. Par exemple, si le script est appelé avec./bin/rails server
, cette ligne exécute effectivement./bin/rails server
en tant que processus principal du conteneur.
-
Conclusion
Un Dockerfile
bien conçu est essentiel pour créer un environnement fiable et cohérent pour votre application Ruby on Rails et React. En définissant l'image de base, en définissant les variables d'environnement et en installant les dépendances, vous vous assurez que votre application fonctionne correctement dans différents environnements.
Docker rationalise non seulement votre processus de développement, mais améliore également la fiabilité de votre application en production. Il existe des domaines d'optimisation, mais ceci n'est qu'un aperçu général de la façon de dockeriser l'application Rails.
Script complet pour le Dockerfile
résultant, docker-compose.yml
et 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 "${@}"