EmbulkでMySQLからPostgreSQLへデータ転送

## はじめに

異なるRDBMS間で、データを転送する業務が発生しました。
調べている中で、今更ながらEmbulkを知ったのでその使い方のメモです。
今回は、MySQL -> PostgreSQLのデータロードを行います。

## Embulkとは

[公式のGitHub](https://github.com/embulk/embulk)より

>Embulk is a parallel bulk data loader that helps data transfer between various storages, databases, NoSQL and cloud services.
Embulk supports plugins to add functions. You can share the plugins to keep your custom scripts readable, maintainable, and reusable.


ザックリ説明すると

- Embulkとは大量のデータを並列でロードを行うツール
- ロードの入出力先はストレージ、データベース、NoSQLやクラウドサービスが対応
- プラグインを使用することで、機能を追加することが可能

## 環境構築

Dockerを利用して、環境構築を行います。

### 前提

- Docker, Docker Composeをインストール済み

### ディレクトリ構成

```bash
embulk
├── Dockerfile
├── docker-compose.yml
├── mysql
│   └── init
│       ├── 01_database.sql
│       └── 02_mock_data.sql
└── postgres
    └── init
        └── 01_database.sql
```

### データベース

Docker Composeを利用してMySQLとPostgreSQlを構築します。

```yaml:docker-compose.yml
version: "3"
services:
  mysql:
    image: mysql:5.7
    ports:
      - "3306:3306"
    volumes:
      - ./mysql/init:/docker-entrypoint-initdb.d
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: root

  postgres:
    image: postgres:12
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: root
      POSTGRES_PASSWORD: root
    volumes:
      - ./postgres/init:/docker-entrypoint-initdb.d/

  adminer:
    image: adminer
    ports:
      - 8080:8080
```

#### データベースの初期化

##### MySQL

[ここ](https://www.mockaroo.com/)からサンプルデータのsqlをダウンロードします。

```sql:mysql/init/01_database.sql
create database embulk_in;
```

```sql:mysql/init/02_mock_data.sql
se embulk_in;

create table MOCK_DATA (
	id INT,
	first_name VARCHAR(50),
	last_name VARCHAR(50),
	email VARCHAR(50),
	gender VARCHAR(50),
	ip_address VARCHAR(20)
);
insert into MOCK_DATA (id, first_name, last_name, email, gender, ip_address) values (1, 'August', 'Stribling', 'astribling0@meetup.com', 'Male', '11.65.224.59');
insert into MOCK_DATA (id, first_name, last_name, email, gender, ip_address) values (2, 'Ian', 'Danovich', 'idanovich1@i2i.jp', 'Male', '135.187.239.143');
...
```

#### PostgreSQL

```sql:postgres/init/01_database.sql
create database embulk_out;
```

### embulk

Embulk用のDockerfileを作成します。

[こちら](https://qiita.com/hoto17296/items/a7d69172050fa9aab045)を参考にDockerfileを作成します。

```Dockerfile:Dockerfile
FROM openjdk:8-jre-alpine

# install Embulk
RUN wget -q https://dl.embulk.org/embulk-latest.jar -O /bin/embulk \
    && chmod +x /bin/embulk

# add plugin
RUN apk add --no-cache libc6-compat \
    && embulk gem install embulk-input-mysql \
    && embulk gem install embulk-output-postgresql 

WORKDIR /embulk

ENTRYPOINT ["java", "-jar", "/bin/embulk"]
```

#### プラグイン
-  [embulk-input-mysql](https://github.com/embulk/embulk-input-jdbc/tree/master/embulk-input-mysql)
   -  MySQL input用
-  [embulk-output-postgresql](https://github.com/embulk/embulk-output-jdbc/tree/master/embulk-output-postgresql)
   - PostgreSQL output用

### 起動
embulkのイメージ作成し、コンテナを起動します。

```bash
# embulkのイメージを作成
docker build -y embulk .
# MySQLとPostgreSQLのコンテナを起動
docker-compose up -d
```

### 確認

AdminerからMySQLのデータを確認します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639315/7a76422b-da69-6a63-9f43-94620781004a.png" width="400">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639315/6b9fabb4-2cc8-82d1-02ac-5b4b9b7ceabe.png" width="400">

## ロード

### コンフィグファイルの作成

MySQLからPostgreSQLへデータをロードするためのコンフィグファイルを作成します。

```yaml:embulk/seed.yml
in:
  type: mysql
  host: {localhostのプライベートアドレス}
  user: root
  password: "root"
  database: embulk_in
  table: MOCK_DATA
out:
  type: postgresql
  host: {localhostのプライベートアドレス}
  user: root
  password: "root"
  database: embulk_out
  table: MOCK_DATA
  mode: insert
  column_options:
    id: { type: "INT" }
    first_name: { type: " VARCHAR(50)" }
    last_name: { type: " VARCHAR(50)" }
    email: { type: " VARCHAR(50)" }
    gender: { type: " VARCHAR(50)" }
    ip_address: { type: " VARCHAR(20)" }
```

### 実行
ロードを行います。

```bash
# seed.ymlから完全なコンフィグファイルを生成
docker run --rm -it -v $(pwd):/embulk embulk guess seed.yml -o config.yml
# dry run
docker run --rm -it -v $(pwd):/embulk embulk preview config.yml
# 実行
docker run --rm -it -v $(pwd):/embulk embulk run config.yml
```

### 確認

AdminerからPostgreSQLのデータを確認します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639315/c2f2f6dc-f4dd-1502-fe20-3f52f079bb23.png" width="400">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639315/8fff92b1-f1bc-776b-d2cd-ba73f95e0783.png" width="400">

### 終わりに

利用したいプラグインがない場合でも(Hiveとか)、JDBCが存在すれば[embulk-input-jdbc](https://github.com/embulk/embulk-input-jdbc)でロードでき、利用範囲が広いと感じました。