1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Docker コンテナ間で MySQL データベースのスキーマを比較する方法

1
Posted at

はじめに

別々の Docker コンテナで動いている MySQL データベース同士のスキーマを比較したい場面があります。

本記事では mysqldumpdiff を使ったシンプルな方法を紹介します。

検証環境の構築

ディレクトリ構成

mysqldiff-demo/
├── docker-compose.yml
└── init/
    ├── db1/
    │   └── 01_schema.sql
    └── db2/
        └── 01_schema.sql

docker-compose.yml

version: '3.8'

services:
  db1:
    image: mysql:8.0
    container_name: mysqldiff-db1
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: testdb
    ports:
      - '3306:3306'
    volumes:
      - ./init/db1:/docker-entrypoint-initdb.d
    networks:
      - db-network
    healthcheck:
      test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
      interval: 10s
      timeout: 5s
      retries: 5

  db2:
    image: mysql:8.0
    container_name: mysqldiff-db2
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: testdb
    ports:
      - '3307:3306'
    volumes:
      - ./init/db2:/docker-entrypoint-initdb.d
    networks:
      - db-network
    healthcheck:
      test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
      interval: 10s
      timeout: 5s
      retries: 5

networks:
  db-network:
    driver: bridge

初期化 SQL

意図的に差分を作るため、2 つの DB で異なるスキーマを定義します。

init/db1/01_schema.sql

USE testdb;

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(255) NOT NULL UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(200) NOT NULL,
    price DECIMAL(10, 2) NOT NULL,
    stock INT DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE orders (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT NOT NULL,
    total_price DECIMAL(10, 2) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (product_id) REFERENCES products(id)
);

init/db2/01_schema.sql

USE testdb;

-- users: phone カラムを追加
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(255) NOT NULL UNIQUE,
    phone VARCHAR(20),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- products: description を追加、stock を削除
CREATE TABLE products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(200) NOT NULL,
    description TEXT,
    price DECIMAL(10, 2) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE orders (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT NOT NULL,
    total_price DECIMAL(10, 2) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (product_id) REFERENCES products(id)
);

-- DB2 にのみ存在するテーブル
CREATE TABLE reviews (
    id INT AUTO_INCREMENT PRIMARY KEY,
    product_id INT NOT NULL,
    user_id INT NOT NULL,
    rating INT NOT NULL,
    comment TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (product_id) REFERENCES products(id),
    FOREIGN KEY (user_id) REFERENCES users(id)
);

起動

cd mysqldiff-demo
docker-compose up -d

テーブルが作成されたかを確認します。

docker exec mysqldiff-db1 mysql -u root -prootpass -e "SHOW TABLES FROM testdb;"
docker exec mysqldiff-db2 mysql -u root -prootpass -e "SHOW TABLES FROM testdb;"

スキーマ比較の実行

mysqldump でスキーマをダンプ

docker exec mysqldiff-db1 mysqldump -u root -prootpass --no-data testdb > db1_schema.sql
docker exec mysqldiff-db2 mysqldump -u root -prootpass --no-data testdb > db2_schema.sql

--no-data オプションでスキーマのみ(データなし)をダンプします。

diff で比較

diff -u db1_schema.sql db2_schema.sql

実行結果

--- db1_schema.sql
+++ db2_schema.sql
@@ -47,14 +47,36 @@
 CREATE TABLE `products` (
   `id` int NOT NULL AUTO_INCREMENT,
   `name` varchar(200) NOT NULL,
+  `description` text,
   `price` decimal(10,2) NOT NULL,
-  `stock` int DEFAULT '0',
   `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

+CREATE TABLE `reviews` (
+  `id` int NOT NULL AUTO_INCREMENT,
+  `product_id` int NOT NULL,
+  `user_id` int NOT NULL,
+  `rating` int NOT NULL,
+  `comment` text,
+  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`),
+  ...
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

 CREATE TABLE `users` (
   `id` int NOT NULL AUTO_INCREMENT,
   `name` varchar(100) NOT NULL,
   `email` varchar(255) NOT NULL,
+  `phone` varchar(20) DEFAULT NULL,
   `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,

検出された差分

テーブル 差分内容
users DB2 に phone カラム追加
products DB2 に description 追加、stock 削除
reviews DB2 にのみ存在

まとめ

今回はサクッとシンプルにやりたかったのでmysqldumpdiff を使った方法を取りましたが、大規模環境や自動化が必要な場合は他のツールが有効になってくるかと思います。
お試しや小さい環境で軽く比較をしたいときに参考にしてみてください。

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?