レアケースなのであまり参考にならないかもしれませんが、将来の私に何か役に立つことがあるかもしれないので、念の為残しておく備忘録です。
背景
関係のない2つのMySQLコンテナが存在している。
片方は非RailsのMySQLデータベース、片方はRailsのマイグレーションで作られたMySQLデータベース。
いずれも別々のdocker-compose環境で動作している。
今回は非RailsのデータをRailsのデータベースに流し込む需要があって、
割とサクッと実現できたので、環境の設定や手法を以下に記します。
docker-compose.yml
行頭に +
がついている行が、今回の作業のために追加した設定です。
別々のdocker-compose環境を同一networkで繋ぐために設定を追加します。
非Rails環境
version: '2'
services:
mysql:
container_name: mysql
image: mysql:5.7.21
ports:
- 3307:3306
volumes:
- ./sql:/docker-entrypoint-initdb.d
- ./mysql:/var/lib/mysql
environment:
MYSQL_DATABASE: not_rails
MYSQL_ROOT_PASSWORD: not_rails
command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci --max_connections=10000
+ networks:
+ - database-link
+networks:
+ database-link:
+ external: true
Rails環境
version: '3'
services:
server:
build: ./
ports:
- 3000:3000
depends_on:
- db
volumes:
- ./:/app:cached
environment:
MYSQL_DATABASE: hoge_development
MYSQL_USER: root
MYSQL_PASSWORD: password
MYSQL_HOST: db
MYSQL_PORT: 3306
+ networks:
+ - database-link
db:
image: mysql:5.7
container_name: db
ports:
- 3306:3306
volumes:
- ./sql:/docker-entrypoint-initdb.d
- ./tmp/mysql/data:/var/lib/mysql
environment:
MYSQL_DATABASE: hoge_development
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max_connections=10000
+ networks:
+ - database-link
+networks:
+ database-link:
+ external: true
dockerのnetworkを作る
networkの設定を追記後、いつもどおりにdocker-composeで起動しようとすると、以下のようなエラーが出ると思います。
❯ docker-compose up -d mysql
ERROR: Network database-link declared as external, but could not be found. Please create the network manually using `docker network create database-link` and try again.
エラー出力にも書いてあるとおり、コマンドを実行します。
❯ docker network create database-link
029b69a807695fe7d1fa3d0354bbd93a61779659fdb552415728e075e4150b31
これでdocker-composeが database-link
ネットワーク上で起動することができます。
上記は非Rails環境のdocker-compose環境だったので、Rails環境のdocker-composeも起動しておきます。
こちらはすでに database-link
ネットワークが作成されているので、いつもどおりに起動するはずです。
❯ docker-compose up -d server
Rubyスクリプト
データの流し込み用のスクリプトファイルをRails側のどこかに置きます。
今回は lib/test.rb に配置しました。
require 'mysql2'
# 非Railsのデータベースに接続する
client = Mysql2::Client.new(
socket: '/var/lib/mysql/mysql.sock',
username: 'root',
password: 'not_rails',
encoding: 'utf8',
database: 'not_rails',
host: 'mysql'
)
# 流し込みたいデータを全部持ってくる
sources = client.query('select * from source')
# 全データをeachでぐるぐる回す
sources.each do |r|
puts r # {"hoge"=>"aaaaaa", "fuga"=>"bbbbb", "name"=>"test", "value"=>"text"}
# RailsのModelのcreateメソッドで登録する
Destination.create(foo: r["hoge"], bar: r["fuga"], name: r["name"], value: r["value"])
end
これだけです。
ハマりそうなポイントとしては host
に設定する値を非Rails環境の docker-compose.yml に記述している services
の key の mysql
を指定するあたりでしょうか。
そこらへんをクリアできれば特に難しいことはしていないと思います。
スクリプトを実行する
以下のようにrubyコマンドで実行すると、エラーになります。
❯ docker-compose exec server ruby lib/test.rb
{"hoge"=>"aaaaaa", "fuga"=>"bbbbb", "name"=>"test", "value"=>"text"}
Traceback (most recent call last):
2: from lib/test.rb:20:in `<main>'
1: from lib/test.rb:20:in `each'
lib/test.rb:22:in `block in <main>': uninitialized constant Destination (NameError)
rubyコマンドでスクリプトを実行したときに、Destinationとか言う定数(クラス)なんて知らねぇよというエラーです。そりゃそうだ。でも知っててくれないと困る。
RailsのModelを認識させたい場合は、以下のように rails runner
(rails r
でも可) で実行すると幸せになれます。
❯ docker-compose exec server bundle exec rails runner lib/test.rb
{"hoge"=>"aaaaaa", "fuga"=>"bbbbb", "name"=>"test", "value"=>"text"}
...
以上です。