Cette fois, je vais vous présenter la procédure pour créer un environnement Docker pour une application Web qui combine Rails 6 et MySQL 8.
À partir de Rails 6, webpacker est installé en standard, et à partir de MySQL 8, la méthode d'authentification de l'utilisateur a changé, il y avait donc diverses parties qui étaient bloquées dans la construction de l'environnement, donc j'espère que cela sera utile.
Afin de permettre un développement fluide par plusieurs personnes, l'objectif est de créer un environnement où ** si vous clonez à partir d'un référentiel distant, l'application démarrera simplement par docker-compose up **.
Les différentes versions sont les suivantes.
L'environnement d'exécution utilise Docker Desktop pour Mac (version 2.3.0.4).
Créez / déplacez un répertoire. Le nom de l'application Rails créée cette fois est «sample_app».
$ mkdir sample_app && cd $_
Créez un Gemfile dans votre environnement local en utilisant l'image ruby.
-v
est une option pour le montage de liaison (synchronisation des répertoires hôte et conteneur).
En synchronisant le répertoire courant de l'hôte avec le répertoire de travail du conteneur, les fichiers créés sur le conteneur sont placés sur l'hôte.
$ docker run --rm -v `pwd`:/sample_app -w /sample_app ruby:2.7.1 bundle init
Décommentez la partie gem" rails "
du Gemfile créé et spécifiez la version des rails.
Gemfile
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
- # gem "rails"
+ gem "rails", '~> 6.0.3.2'
Créez un Dockerfile pour créer un environnement Docker qui exécute rails new
.
Rails 6 exécute également rails webpacker: install
lorsque vous créez une application, alors n'oubliez pas d'installer ** yarn. ** **
Cette fois, utilisez npm
pour installer yarn
.
Dockerfile
FROM ruby:2.7.1
RUN apt-get update -qq && \
apt-get install -y nodejs \
npm && \
npm install -g yarn
#Directeur de travail/sample_Spécifié dans l'application
WORKDIR /sample_app
#Copier Gemfile local sur Dokcer
COPY Gemfile /sample_app/Gemfile
# /sample_installation du bundle sur le répertoire de l'application
RUN bundle install
Démarrez le conteneur en utilisant l'image créée en construisant le Dockerfile, et faites rails new
sur le conteneur.
$ docker build -t sample_app .
$ docker run --rm -v `pwd`:/sample_app sample_app rails new . –skip-bundle --database=mysql
Créez docker-compose.yml
.
Cette fois, par souci de brièveté, je me connecte à MySQL en tant qu'utilisateur root. Lors de la connexion en tant qu'utilisateur général, il est nécessaire de définir les variables d'environnement suivantes pour l'image MySQL.
Variable d'environnement | Contenu |
---|---|
MYSQL_USER | Nom d'utilisateur |
MYSQL_PASSWORD | Mot de passe de l'utilisateur |
Les informations de la base de données sont conservées en créant un volume nommé mysql_data
.
docker-compose.yml
version: '3'
services:
web: #Conteneur lancé par Ruby on Rails
build: .
ports:
- '3000:3000' #Rendez-le accessible sur le port 3000 de localhost
volumes:
- .:/sample_app #Synchronisation des fichiers d'application
depends_on:
- db
command: ["rails", "server", "-b", "0.0.0.0"]
db: #Conteneur que MySQL démarre
image: mysql:8.0.21
volumes:
- mysql_data:/var/lib/mysql #Persistance des données
command: --default-authentication-plugin=mysql_native_password #Définissez la méthode d'authentification sur 8 séries ou une version antérieure.
environment:
MYSQL_ROOT_PASSWORD: 'pass'
MYSQL_DATABASE: 'sample_app_development'
volumes:
mysql_data: #Enregistrement du volume de données
Je vais donner une explication supplémentaire du docker-compose.yml
ci-dessus.
L'image MySQL Docker crée une base de données avec le nom défini sur MYSQL_DATABASE
.
Puisque l'environnement de développement de Ruby on Rails utilise la base de données «[nom de l'application] _development», «sample_app_development» est enregistré dans «MYSQL_DATABASE».
Vous pouvez maintenant préparer la base de données pour l'environnement de développement sans exécuter rails db: create
.
À partir de MySQL 8, la méthode d'authentification est passée de mysql_native_password
à caching_sha2_password
.
Avec la méthode d'authentification standard MySQL 8 caching_sha2_password
, il n'est pas possible de se connecter à la base de données, et le message d'erreur suivant s'affiche au démarrage de l'application Rails.
Mysql2::Error::ConnectionError
Plugin caching_sha2_password could not be loaded: /usr/lib/x86_64-linux-gnu/mariadb19/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory
Par conséquent, --default-authentication-plugin = mysql_native_password
utilise la méthode d'authentification précédente de mysql_native_password
.
Ensuite, configurez la connexion à la base de données pour Ruby on Rails.
config/database.yml
default: &default
adapter: mysql2
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: pass # (Cette fois c'est la racine)MYSQL_ROOT_Match avec PASSWORD
host: db #Définir le nom du conteneur de base de données
Maintenant que nous avons un environnement Docker qui combine Ruby on Rails 6 et MySQL 8, commençons-le.
$ docker-compose up
C'est OK si vous accédez à localhost: 3000
et l'écran suivant s'affiche.
Vérifions également la persistance des données dans la base de données. Par exemple, créez une fonction liée à «événement» avec «échafaudage».
$ docker-compose exec web rails g scaffold event title:string
$ docker-compose exec web rails db:migrate
Accédez à localhost: 3000 / events / new
et enregistrez un enregistrement appelé" sample event "comme exemple.
C'est OK si les données restent même si le conteneur est supprimé et démarré.
$ docker-compose down
$ docker-compose up
$ docker-compose exec web rails c
> Event.last.title
=> "Exemple d'événement"
En créant une base de données dans l'environnement de développement à l'aide de «MYSQL_DATABASE», l'application Rails peut être démarrée sans exécuter «db: create».
Cependant, ** cela seul ne suffit pas comme environnement de développement ** car la base de données ([nom de l'application] _test
) de l'environnement de test utilisé dans le code de test n'a pas été créée.
Dans l'image MySQL Docker, si vous placez le script (.sql
, .sh
, .sql.gz
) dans / docker-entrypoint-initdb.d
, il sera exécuté au démarrage du conteneur. il y a. [^ docker-entrypoint-initdb]
Tirez parti de cette fonctionnalité pour créer une base de données pour l'environnement de test.
** Les scripts sont exécutés dans l'ordre alphabétique **, donc s'il y a des dépendances entre les scripts, soyez également conscient du nom du fichier.
$ mkdir docker-entrypoint-initdb.d && cd $_
$ vim 00_create.sql
00_create.sql
--Créer une base de données pour l'environnement de test
CREATE DATABASE sample_app_test;
De plus, le droit d'accès à la base de données des utilisateurs généraux est uniquement la base de données définie sur MYSQL_DATABASE
.
Par conséquent, ** Lors de la connexion à une base de données en tant qu'utilisateur général, il est nécessaire non seulement de créer la base de données, mais également d'accorder les droits d'accès suivants. ** **
01_grant.sql
--Lors de l'utilisation d'un utilisateur général nommé webapp
GRANT ALL ON `sample_app_test`.* TO webapp@'%';
Ajoutez un montage de liaison afin que le script créé puisse être lu sur le conteneur.
docker-compose.yml
version: '3'
services:
web:
build: .
ports:
- '3000:3000'
volumes:
- .:/sample_app
depends_on:
- db
command: ["rails", "server", "-b", "0.0.0.0"]
db:
image: mysql:8.0.21
volumes:
- mysql_data:/var/lib/mysql
+ - ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_ROOT_PASSWORD: 'pass'
MYSQL_DATABASE: 'sample_app_development'
volumes:
mysql_data:
Supprimez et démarrez le conteneur db et vérifiez si la base de données est créée automatiquement. Ce n'est pas grave si les bases de données «[nom de l'application] _development» et «[nom de l'application] _test» existent.
#Créer une base de données à partir de zéro en supprimant également les informations de persistance de la base de données
$ docker-compose down --volumes
$ docker-compose up
$ docker-compose exec db mysql -uroot -ppass -D sample_app_development
mysql> show databases;
+------------------------+
| Database |
+------------------------+
| information_schema |
| mysql |
| performance_schema |
| sample_app_development |
| sample_app_test |← La base de données pour le test a été créée
| sys |
+------------------------+
6 rows in set (0.00 sec)
Vous pouvez également vous connecter avec succès depuis une application Rails.
$ docker-compose exec web rails c
> ENV['RAILS_ENV']
=> "development
$ docker-compose exec web rails c -e test
> ENV['RAILS_ENV']
=> "test"
Les modèles suivants sont souvent considérés comme un moyen de créer un environnement de développement Rails avec Docker.
#Lancer le conteneur
$ docker-compose up
#Créer une base de données
$ docker-compose exec web rails db:create
#Migration de table
$ docker-compose exec web rails db:migrate
L'application Rails et la base de données sont liées par docker-compose, et la base de données utilisée par l'application est construite sur le conteneur.
Il n'y a pas de problème avec la méthode ci-dessus, mais dans ce cas ** Il faut du temps pour créer manuellement la base de données et la table sur le conteneur au premier démarrage. ** **
Considérant le cas du partage d'un environnement Docker avec plusieurs personnes, il est idéal que l'environnement puisse être démarré en faisant simplement docker-compose up
après le clonage du fichier d'application à partir du référentiel distant.
Si possible, je voudrais éviter la situation où je dois prendre la peine de dire aux membres partagés "Créer la base de données sur le conteneur au premier démarrage".
À partir de là, si vous clonez à partir d'un référentiel distant, faites simplement docker-compose up
pour configurer les paramètres afin que l'application Rails puisse être démarrée.
Dans l'environnement de développement, la synchronisation du code source à l'aide de bind mout (synchronisation des répertoires hôte et conteneur) est souvent utilisée.
Le fichier d'application cloné à partir du référentiel distant a un répertoire package.json
, mais pas de répertoire node_modules
.
Par conséquent, si vous faites docker-compose up
après le clonage, le répertoire sans node_modules
sera monté en liaison. En conséquence, une erreur vous invitant à exécuter yarn install
se produit et l'application ne peut pas être démarrée.
========================================
Your Yarn packages are out of date!
Please run `yarn install --check-files` to update.
========================================
To disable this check, please change `check_yarn_integrity`
to `false` in your webpacker config file (config/webpacker.yml).
yarn check v1.22.5
info Visit https://yarnpkg.com/en/docs/cli/check for documentation about this command.
Pour éviter cela, vous devez exécuter yarn install
au démarrage du conteneur.
Par exemple, vous pouvez exécuter yarn install
lors du démarrage du conteneur en procédant comme suit.
docker-compose.yml
version: '3'
services:
web:
build: .
+ command: ["./start.sh"]
- command: ["rails", "server", "-b", "0.0.0.0"]
ports:
- '3000:3000'
volumes:
- .:/sample_app
depends_on:
- db
db:
image: mysql:8.0.21
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_ROOT_PASSWORD: 'pass'
MYSQL_DATABASE: 'sample_app_development'
start.sh
#!/bin/bash -eu
yarn
rails server -b '0.0.0.0'
Modifiez les autorisations du shell.
$ chmod 755 start.sh
Le shell est appelé par la commande lors du démarrage du conteneur, et "yarn install" est exécuté dans le shell.
Après avoir exécuté yarn install
, l'application Rails démarrera sur rails server
, donc l'erreur précédente sera résolue.
Comme pour yarn install
, la migration de la table doit être exécutée par le script shell qui est appelé au démarrage du conteneur.
start.sh
#!/bin/bash -eu
yarn
+ rails db:migrate
rails server -b '0.0.0.0'
Cependant, bien que vous puissiez contrôler l'ordre de démarrage des conteneurs en utilisant depend_on
de docker-compose.yml
, vous ne pouvez pas attendre le début du conteneur [^ startup-order], alors préparez-vous à démarrer le conteneur db. Si db: migrate
est exécuté avant la fin de, la migration échouera.
[^ startup-order]: Docker Doc "Contrôle de l'ordre de démarrage dans Compose"
Pour automatiser la migration, vous devez attendre que le conteneur db démarre avant que db: migrate
ne soit exécuté.
Il existe plusieurs façons d'attendre que la base de données soit prête, mais cette fois wait-for-it Voici comment utiliser>.
Si vous placez wait-for-it.sh
dans le répertoire courant et créez docker-compose.yml
comme suit, le script sera exécuté après avoir attendu le démarrage de la base de données.
docker-compose.yml
version: '3'
services:
web:
build: .
- command: [""./start.sh"]
+ command: ["./wait-for-it.sh", "db:3306", "--", "./start.sh"]
ports:
- '3000:3000'
volumes:
- .:/sample_app
depends_on:
- db
db:
image: mysql:8.0.21
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_ROOT_PASSWORD: 'pass'
MYSQL_DATABASE: 'sample_app_development'
Ceci conclut l'introduction de la procédure de création d'un environnement Docker pour Rails 6 + MySQL 8.
En exécutant le shell au démarrage du conteneur, l'environnement de développement peut être construit en douceur même lorsque plusieurs personnes utilisent l'environnement Docker.
Cette fois, en appelant le shell au démarrage du conteneur, yarn install
et db: migration
sont sûrement exécutés, mais le contrôle de la commande lorsque le conteneur démarre est <a href =" https: // ". Vous pouvez également le faire avec un outil appelé github.com/progrium/entrykit "target =" _ blank "> Entrykit .
Je travaille sur Twitter ( @ nishina555 ). J'espère que vous me suivrez!