30歳からのプログラミング

30歳無職から独学でプログラミングを開始した人間の記録。

Embulk に入門して Amazon RDS にあるデータを BigQuery に転送する

この記事では、Embulk を使ってデータ転送を行う方法について述べていく。
今回は題材として Amazon RDS から Google Cloud の BigQuery にデータを転送する。Embulk の実行はローカルマシンで行う。

使っている Embulk のバージョンは0.9.25
0.100.11だと異なる手順や設定が必要になると思われるので注意。

事前準備

まずは Amazon RDS のインスタンスを作成する。今回はデータベースの種類は MySQL にした。バージョンは8.0.35
ローカルマシンから Embulk を実行する都合上、パブリックアクセスを「あり」にしておく必要がある。そして、セキュリティグループを適切に設定し、ローカルマシンの IP アドレスからのアクセスを許可しておく必要もある。
作成後は$ docker run -it --rm mysql mysql -u admin -p -h <RDSインスタンスのエンドポイント>でインスタンスにログインし、以下のクエリを実行する。

CREATE DATABASE source_db;
USE source_db;
CREATE TABLE user (
  id INT NOT NULL AUTO_INCREMENT,
  name VARCHAR(191) NOT NULL,
  PRIMARY KEY (id)
);
INSERT INTO user (name) VALUES ('Alice'), ('Bob');

source_dbというデータベースを作り、そのなかにuserテーブルを作成、以下のデータを投入した。

mysql> SELECT * FROM user;
+----+-------+
| id | name  |
+----+-------+
|  1 | Alice |
|  2 | Bob   |
+----+-------+
2 rows in set (0.01 sec)

このデータを BigQuery に転送するのが今回の目的。

次に BigQuery 側の準備を行う。
任意の GCP プロジェクトの BigQuery にdestination_datasetというデータセットを用意しておく。テーブルは作らなくてよい。
RDS だけでなく BigQuery にアクセスする権限も必要なので、サービスアカウントキーを JSON 形式で発行しておく。

ローカルマシンで Embulk を実行できるようにする

今回は Docker を使って Embulk の実行環境を用意する。
Dockerfileinit_embulk_commands.sh、2 つのファイルを用意する。

まずはDockerfile

FROM openjdk:8-jdk

# embulk.jarをダウンロード
RUN mkdir -p /root/.embulk/bin && \
    curl -o /root/.embulk/bin/embulk.jar -L "https://dl.embulk.org/embulk-0.9.25.jar"

# 必要なgemをインストールするためのスクリプトを追加
COPY init_embulk_commands.sh /root/init_embulk_commands.sh
RUN chmod +x /root/init_embulk_commands.sh && /root/init_embulk_commands.sh

WORKDIR /workspace

# embulk実行のためのシェルコマンドを設定
RUN echo '#!/bin/bash\njava -classpath "/root/.embulk/bin/embulk.jar:/root/.embulk/lib/postgresql.jar" org.embulk.cli.Main "$@"' > /usr/local/bin/embulk && \
    chmod +x /usr/local/bin/embulk

CMD [ "embulk", "--version" ]

このなかでinit_embulk_commands.shをコピーしそれを実行している。
Dockerfileのコメントに書いたようにこれは、必要な gem をインストールするためのシェルスクリプト。
まずは以下の内容にする。

#!/bin/bash

# embulk.jarへのパス
EMBULK_JAR="/root/.embulk/bin/embulk.jar"

# 必要なgemをインストール
java -jar $EMBULK_JAR gem install embulk -v 0.9.25

この状態で$ docker build -t embulk-image .を実行して Docker image を作成する。

そしてその image から Docker container を作成・実行して Embulk のバージョンが表示されれば、Embulk の実行は成功。

$ docker run --rm  embulk-image
embulk 0.9.25

転送設定を記述し実行する

Embulk を動かすことに成功したので次は、転送元と転送先を設定し、実際に転送を行うようにする。

Embulk は多種多様なデータソースを対象としており、今回対象とした MySQL と BigQuery 以外にも、 Redshift や Snowflake なども対象にすることができる。
これを可能にしているのがプラグインシステムであり、対応するプラグインさえあれば、転送元や転送先を自由に設定できる。

今回の例では MySQL を転送元、BigQuery を転送先にするので、embulk-input-mysqlembulk-output-bigqueryというプラグインが必要になる。

init_embulk_commands.shを以下のように書き換えて、Docker image の作成時に必要なプラグインがインストールされるようにする。

#!/bin/bash

# embulk.jarへのパス
EMBULK_JAR="/root/.embulk/bin/embulk.jar"

# 必要なgemをインストール
java -jar $EMBULK_JAR gem install embulk -v 0.9.25
java -jar $EMBULK_JAR gem install embulk-input-mysql
java -jar $EMBULK_JAR gem install jwt -v 2.3.0
java -jar $EMBULK_JAR gem install multipart-post -v 2.1.1
java -jar $EMBULK_JAR gem install public_suffix -v 4.0.7
java -jar $EMBULK_JAR gem install mini_mime -v 1.0.2
java -jar $EMBULK_JAR gem install representable -v 3.0.4
java -jar $EMBULK_JAR gem install embulk-output-bigquery -v 0.6.4

使いたいプラグイン以外にも様々な gem をインストールしているが、それらは、embulk-output-bigqueryの依存関係を解決するために必要な gem。
必要な gem とそのバージョンは以下の記事を参考にした。
embulk-input-bigqueryのインストールでエラー - kikukawa's diary

そしてDockerfileCMD [ "embulk", "--version" ]CMD ["embulk", "run", "config.yml"]に書き換える。

config.ymlは Embulk の転送設定を記述するファイルであり、どのデータをどこに転送するのか記述していく。

今回は以下の内容のembulk/config.ymlを用意する。

in:
  type: mysql
  host: RDSインスタンスのエンドポイント
  port: 3306
  user: admin
  password: "rds password"
  database: source_db
  table: user
  select: "*"

out:
  type: bigquery
  mode: replace
  auth_method: json_key
  json_keyfile: "key.json"
  project_id: BigQueryのプロジェクト名
  dataset: destination_dataset
  table: user
  auto_create_table: true

inが転送元でoutが転送先。

out.json_keyfileにはサービスアカウントキーのパスを記述する。今回はkey.jsonにしたので、config.ymlと同じディレクトリ、つまりembulkディレクトリにkey.jsonとして置いておく。

つまり以下の構成になる。

.
├── Dockerfile
├── embulk
│   ├── config.yml
│   └── key.json
└── init_embulk_commands.sh

この状態で再び image を作り、そこから container を作成し実行する。container がconfig.ymlkey.jsonを利用できるように、-vオプションで Volume を作っている。

$ docker build -t embulk-image .
$ docker run --rm -v "$(pwd)/embulk:/workspace" embulk-image

そうするとdestination_datasetuserテーブルが作られ、RDS に入れておいたのと同じデータが入っている。