Skip to main content

Docker pour Ruby on Rails dans un environnement de développement local

Écrit par

Mikhail Tereschenko

blog feature ruby security

2 novembre 2022

0 minutes de lecture

Bonjour les développeurs Ruby ! Si vous cherchez une solution efficace pour configurer Docker pour Ruby on Rails dans votre environnement de développement local, cet article est fait pour vous. Il fait suite à notre précédent article sur l’installation de Ruby sur macOS pour le développement local.

Lorsqu’ils développent un projet Ruby on Rails, les développeurs Ruby doivent souvent prévoir une base de données, ainsi que d’autres prérequis pour l’environnement de développement. Cependant, installer tous ces éléments sur le système d’exploitation de votre machine hôte et utiliser exactement les versions requises peut parfois s’avérer difficile.

Chaque fois que j’essayais de créer un nouveau projet, je me disais qu’il me faudrait un bouton pour créer un environnement propre. J’ai donc décidé de créer une configuration basée sur Docker, que l’on peut facilement démarrer et arrêter à l’aide de docker-compose.yml de Docker.

Qu’est-ce que Docker Compose ?

Docker Compose est un outil d’infrastructure as code (IaC) qui vous permet de configurer et de connecter des applications et des services, tels que des proxys, des bases de données et des montages de volumes, afin de les mettre à disposition de manière réutilisable. Il est installé avec le pack logiciel Docker et sa configuration est définie en YAML.

Cette configuration Docker Compose pour un environnement de développement local peut être utilisée pour différents types de projets ; elle ne se limite pas à Ruby on Rails. Elle peut aussi servir pour des projets personnels ou des projets front-end côté client. Voici les principales raisons pour lesquelles je préfère utiliser des environnements Docker plutôt que de modifier le système d’exploitation de ma machine hôte :

  • facile à configurer

  • facile de séparer la logique de l’environnement

  • facile d’utiliser le même environnement pour différents projets

  • facile de partager l’environnement avec toute personne qui a besoin d’aide, sans exposer de code sensible

  • la machine hôte reste propre

Une configuration Docker pour Ruby on Rails

Pour configurer un environnement Docker pour Ruby on Rails destiné au développement local, vous aurez besoin des éléments suivants :

  • Un système d’exploitation de type Unix (j’utilise macOS, mais vous pouvez utiliser Ubuntu ou toute autre distribution Linux. Windows devrait également fonctionner)

  • Git

  • make (version 3.81 ou ultérieure)

  • Docker (version 19.03.12 ou ultérieure)

  • docker-compose (version 1.26.0 ou ultérieure)

  • Votre éditeur de texte préféré (Visual Studio Code dans mon cas)

Une fois que vous avez tout cela, vous pouvez commencer. Si vous préférez passer directement à la pratique, voici le dépôt open source qui contient toutes les instructions nécessaires et le code source complet des extraits que nous allons examiner. Mais puisque vous êtes déjà ici, suivez cet article pour découvrir le processus étape par étape.

Pour commencer, je vais créer un projet Ruby on Rails nommé foo_bar_project, par souci de simplicité.

1) Récupérez la configuration de l’environnement Docker Compose et supprimez le dépôt Git. Si vous souhaitez suivre l’ensemble des modifications dans un dépôt de code source Git, vous pourrez créer le vôtre par la suite.

git clone git@github.com:mtereschenko/simple_ror_environment.git && cd simple_ror_environment && rm -rf .git

Les étapes suivantes doivent être exécutées dans le répertoire ./environment. Vérifiez donc que vous exécutez les commandes depuis ce répertoire :

cd ./environment

2) Attribuez ensuite un nom de projet à cette configuration d’environnement. Par défaut, il s’agit de test_project. Dans notre exemple, nous devons le remplacer par foo_bar_project, comme indiqué précédemment. Pour cela, modifiez le fichier ./environment/.env.example afin de définir la variable PROJECT_NAME. Il est important d’utiliser le snake_case (mots séparés par des tirets bas) en minuscules pour les valeurs des variables :

PROJECT_NAME=foo_bar_project

3) Vous pouvez maintenant créer votre projet en exécutant la commande suivante :

make init

Comme vous pouvez le constater, un nouveau dossier nommé application contient maintenant le code Ruby on Rails.

4) Vous devez maintenant créer votre environnement de développement local avec Docker Compose. Cette étape est obligatoire après toute modification du Dockerfile ou du Gemfile de votre application.

make build

5) Vous pouvez maintenant démarrer l’environnement de développement Ruby local comme suit :

make start

Notez que cette commande ne démarre pas encore une application Ruby on Rails. Pour cela, nous devons ouvrir un shell dans l’environnement Docker et lui demander de démarrer le processus rails. Voici comment procéder :

make shell
rails s -p 3000 –binding=0.0.0.0

Environnement Docker pour Ruby on Rails destiné au développement localEnfin, ouvrez votre navigateur et rendez-vous à cette URL : http://foo_bar_project.localhost/. Vous devriez voir le projet Ruby on Rails que nous venons de créer.

Alors, qu’avons-nous à notre disposition ?

  • Notre projet contient un répertoire d’environnement qui regroupe tout le nécessaire à son exécution, ainsi qu’un répertoire d’application contenant le code de celle-ci. Ce répertoire est associé au conteneur Docker : vous y avez donc un accès complet depuis l’image Docker Ruby.

  • Nous avons rapidement accès au shell Ruby. Il n’est donc pas nécessaire d’installer localement un environnement Ruby, comme Rails, Rake, Bundler ou tout autre outil de l’écosystème Ruby.

  • Les commandes peuvent être exécutées après la commande make shell.

  • Cette configuration Docker Compose du projet comprend deux environnements préconfigurés. Si vous devez déployer votre application Ruby quelque part, vous pouvez créer votre propre environnement. Rien de plus simple !

Si vous souhaitez comprendre le fonctionnement de l’environnement Docker pour Ruby on Rails présenté ci-dessus, nous allons détailler l’image Docker Ruby, le Makefile et la configuration Docker Compose qui les fait fonctionner ensemble.

Une image Docker Ruby

Tout d’abord, l’image Docker Ruby est un élément essentiel. Il est également important de la créer correctement afin de réutiliser efficacement le cache des couches d’image Docker et de prendre en compte d’autres aspects liés à un environnement de développement local.

Voici le Dockerfile de l’image Docker Ruby :

FROM ruby:2.7.6-alpine3.16 as base_image
RUN apk add --no-cache git \
    build-base \
    libpq-dev \
    tzdata

FROM base_image as development
COPY ./artifacts/rails/Gemfile /tmp/Gemfile
COPY ./artifacts/rails/Gemfile.lock /tmp/Gemfile.lock
COPY ./containers/ruby/runners/runner.development.sh /rdebug_ide/runner.sh
RUN cd /tmp && \
  gem install ruby-debug-ide && \
  gem install debase && \
  bundle install && \
  chmod +x /rdebug_ide/runner.sh && \
  apk add --no-cache git \
  nodejs \
  yarn
WORKDIR /app

ENTRYPOINT ["tail", "-f", "/dev/null"]

FROM base_image as init
COPY ./containers/ruby/initializers/runner.init.sh /tmp/runner.sh
COPY ./containers/ruby/initializers/database.yml /tmp/database.yml
COPY ./containers/ruby/initializers/.gitignore /tmp/.gitignore
COPY ./containers/ruby/initializers/development.rb /tmp/development.rb
RUN chmod +x /tmp/runner.sh

WORKDIR /app

ENTRYPOINT ["/tmp/runner.sh"]

Comme vous pouvez le voir, cette configuration part du principe que certains paramètres périphériques sont définis pour disposer d’un environnement Ruby on Rails fonctionnel, notamment :

  • le fichier database.yml, prérempli avec les détails de connexion à la base de données Ruby on Rails

  • le fichier development.rb, qui contient la configuration de l’environnement d’exécution Ruby on Rails pour le développement

Ces paramètres sont définis à l’aide du script runners.sh, dans le répertoire ./environment/containers/ruby/initializers :

#!/bin/ash

cd /app

gem install rails

rails new . -d=postgresql --skip-git

yes | cp -rf /tmp/database.yml /app/config/database.yml
yes | cp -rf /tmp/development.rb /app/config/environments/development.rb
cp /tmp/.gitignore /app/.gitignore

Ce Dockerfile utilise également les builds Docker multiétapes. Vous pouvez ainsi réutiliser efficacement certaines parties dans différents environnements, si vous souhaitez utiliser la même configuration pour plusieurs workflows (tests, préproduction, etc.).

Docker Compose pour Rails

Le fichier Docker Compose situé dans `./environment/docker-compose.development.yml` rassemble tous les services nécessaires au fonctionnement d’une application Ruby on Rails dans Docker :

  • un serveur HTTP nginx

  • une application Ruby

  • un serveur de base de données PostgreSQL

Voici le fichier Docker Compose pour Rails utilisé dans cette configuration :

version: '3.7'
services:
  nginx:
    image: "${PROJECT_NAME}/nginx:development"
    container_name: ${PROJECT_NAME}-nginx
    build: 
      context: ./
      dockerfile: ./containers/nginx/Dockerfile
    depends_on:
      - ruby
    tty: true
    ports:
      - 80:80
    volumes:
      - ./`artifacts`/nginx/:/`var`/log/nginx:cached
   ruby:
    image: "${PROJECT_NAME}/ruby:development"
    container_name: ${PROJECT_NAME}-ruby
    depends_on:
      - postgres
    build:
      context: ./
      dockerfile: ./containers/ruby/Dockerfile
      target: development
    ports:
      - 13030:13030
    volumes:
      - ${APP_PATH}:/app:cached
    environment:
      DB_NAME: ${DB_NAME}
      PROJECT_NAME: ${PROJECT_NAME}
      DB_USER: ${DB_USER}
      DB_PASSWORD: ${DB_PASSWORD}
      DB_PORT: ${DB_PORT}
      PUMA_WORKERS: 0
      RAILS_MAX_THREADS: 1
     postgres:
    image: "${PROJECT_NAME}/postgres:development"
    container_name: ${PROJECT_NAME}-postgres
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    build:
      context: ./
      dockerfile: ./containers/postgres/Dockerfile
    ports:
      - ${DB_PORT}:5432
    volumes:
      - postgres_volume:/var/lib/postgresql/data

volumes:
  postgres_volume:

Makefile pour Docker

Enfin, pour fournir aux développeurs une interface simple leur permettant d’interagir facilement avec cet environnement de développement local Ruby, nous utilisons un Makefile :

.PHONY: help
# Make stuff

-include .env

export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1

.DEFAULT_GOAL := help

ARTIFACTS_DIRECTORY := "./artifacts"

CURRENT_PATH :=${abspath .}

SHELL_CONTAINER_NAME := $(if $(c),$(c),ruby)
BUILD_TARGET := $(if $(t),$(t),development)

help: ## Help.
@grep -E '^[a-zA-Z-]+:.*?## .*$$' Makefile | awk 'BEGIN {FS = ":.*?## "}; {printf "[32m%-27s[0m %s\n", $$1, $$2}'

init: ## Project installation.
@rm -f ./.env
@cp .env.example .env
@make init_app_directory
@make create_postgress_volume
@docker-compose -f docker-compose.init.yml build
@docker-compose -f docker-compose.init.yml up

build: ## Build images.
@make create_project_artifacts
@cp ${APP_PATH}/Gemfile "${ARTIFACTS_DIRECTORY}/rails/Gemfile"
@cp ${APP_PATH}/Gemfile.lock "${ARTIFACTS_DIRECTORY}/rails/Gemfile.lock"
@docker-compose -f docker-compose.$(BUILD_TARGET).yml build

shell: ## Internal image bash command line.
@if [[ -z `docker ps | grep ${SHELL_CONTAINER_NAME}` ]]; then \
echo "${SHELL_CONTAINER_NAME} is NOT running (make start)."; \
else \
docker-compose -f docker-compose.$(BUILD_TARGET).yml exec $(SHELL_CONTAINER_NAME) /bin/ash; \
fi

start: ## Start previously builded application images.
@make create_project_artifacts
@make start_postgres
@make start_ruby
@make start_nginx

run: ## Run ruby debugger session.
@docker-compose -f docker-compose.$(BUILD_TARGET).yml exec ruby /bin/ash /rdebug_ide/runner.sh

start_ruby: ## Start ruby image.
@if [[ -z `docker ps | grep ruby` ]]; then \
docker-compose -f docker-compose.$(BUILD_TARGET).yml up -d ruby; \
else \
echo "Ruby is running."; \
fi

start_postgres: ## Start postgres image.
@if [[ -z `docker ps | grep postgres` ]]; then \
docker-compose -f docker-compose.$(BUILD_TARGET).yml up -d postgres; \
else \
echo "Postgres is running."; \
fi

start_nginx: ## Start nginx image.
@if [[ -z `docker ps | grep nginx` ]]; then \
docker-compose -f docker-compose.$(BUILD_TARGET).yml up -d nginx; \
else \
echo "Nginx is running."; \
fi

stop: ## Stop all images.
@docker-compose -f docker-compose.$(BUILD_TARGET).yml stop

create_project_artifacts:
mkdir -p ./artifacts/rails
mkdir -p ./artifacts/db

init_app_directory:
@mkdir -p ${APP_PATH}

create_postgress_volume:
@sed -i '' -r  "s/postgres_volume:/${PROJECT_NAME}_db_volume:/g" docker-compose.development.yml

Exécuter efficacement des applications Ruby

J’espère que vous avez désormais acquis une nouvelle compétence : exécuter des applications Ruby, comme Ruby on Rails, dans votre environnement local à l’aide d’une configuration de conteneurs Docker. Une autre façon d’exécuter des applications Ruby en local consiste à utiliser des environnements virtuels Ruby, que nous avons présentés dans notre précédent article sur l’installation de Ruby sur macOS.

Maintenant que votre environnement de développement Ruby est prêt, vous voudrez peut-être aussi apprendre à sécuriser vos applications Ruby. Consultez les articles suivants pour en savoir plus sur la sécurité de Ruby :

La sécurité des conteneurs, pensée pour les développeurs

Snyk détecte et corrige automatiquement les vulnérabilités dans les images de conteneurs et les workloads Kubernetes.

Lire la suite

feature customer snowflake
Article

Sécuriser dès la conception : découvrez l’intégration de Snyk Studio à Snowflake Cortex Code

Snyk Studio s’intègre à Snowflake Cortex Code pour analyser le code généré par l’IA, les dépendances et les conteneurs à la recherche de vulnérabilités, dès le développement.

blog feature pypi spoof
Article

La Snyk AI Security Platform complète, gratuite pour les responsables de projets open source

Les responsables de projets open source croulent sous les signalements de vulnérabilités avérées et ont besoin d’aide pour les prioriser, les corriger et déployer les correctifs plus rapidement. Le Secure Developer Program de Snyk donne aux projets admissibles un accès gratuit à la Snyk AI Security Platform.

feature insights announcement
Blog

Compromission de la chaîne d’approvisionnement Node-gyp : un ver npm à propagation autonome dissimulé dans binding.gyp

Un nouveau ver npm détourne binding.gyp pour déclencher node-gyp lors de l’installation et permettre à des packages malveillants d’exécuter du code sans scripts de cycle de vie. Il vole des identifiants, s’installe durablement sur GitHub et se propage de mainteneur en mainteneur.