Prestoの開発環境をdockerでローカルに作った話

【2020/01/06 追記】
この記事を作成したタイミングではPrestoの公式Dockerイメージがなかったため、Dockerイメージを自作し、その手順を記事にまとめています。
PrestoのVersion312からは公式にDockerイメージがサポートされたようですので、今後環境を自作する際は[公式Dockerイメージ](https://hub.docker.com/r/prestosql/presto)を利用することをオススメします。（@ebyhrさん 情報ありがとうございました！）


# はじめに

本業ではビッグデータを扱うサービスの開発に携わっています。
自分の担当箇所ではPrestoというミドルウェアを利用しているのですが、Presto周りの機能をローカルで開発する環境が整っておらず、以下のような不満がありました。

- ローカル開発用のPrestoがなく、開発中に気軽に動作確認できない
    - 動作確認するためにはテスト環境に修正中のソースコードをデプロイする必要があり、デプロイする度に10〜20分の待ち時間が発生します。

そこでローカル環境での開発の不満を解消すべく、最近気になってるdockerを使って環境構築に取り組みました。
なんらかの開発環境つくりたいなと思ってる人の参考になれば幸いです。

出来上がったファイル一式はこちら。
https://github.com/canpok1/env_presto

# Prestoとは？

Facebookが作った分散SQLエンジンです。大規模なデータに対して、リアルタイムにデータ分析を行うために作られました。Catalogという単位でデータソースを追加でき、以下のものに対応しています。

- Hive
- MySQL
- PostgreSQL
- Redis
- Redshift
- その他いろいろ

# どんな開発環境にするか

まず最初にどのような構成にするかを検討しました。開発しているサービスでは、Prestoにクエリを投げてHadoop上のデータ集計を行っているのですが、プログラム的にはPrestoにしか接続しておらず、その先のHadoopは意識していませんでした。
Hadoopの環境を作るのは大変そうだったので、今回はHadoopの代わりにmysqlを使うことに。
全体としては、次の3つのコンテナを使う構成です。

- mysql
    - 公式のイメージを使用
    - バックグラウンドで起動
- presto
    - イメージを自作
    - バックグラウンドで起動
- controller(コマンド実行用)
    - イメージを自作
    - mysqlやprestoにクエリを投げるための環境

構成が決まったので、構築作業を進めていきます。

## 1. ローカル環境にdockerをインストールする

以下のコマンドでdockerをインストール。brew便利。

```
brew cask install docker
```

## 2. docker-compose.ymlを作る

複数コンテナを立てる構成なので、docker-composeを使いました。　`docker-compose` というのは複数コンテナの管理を楽にしてくれるコマンドで、その設定ファイルが `docker-compose.yml` です。

```
version: '2'

services:
  # mysql稼働用コンテナ
  mysql:
    image: mysql:5.7
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD=yes
  # presto稼働用コンテナ
  presto:
    build: ./presto
    ports:
      - "8080:8080"
  # コマンド実行用コンテナ(mysqlやpresto-cliなど)
  controller:
    build: ./controller
```

## 3. Dockerfileを作る

Prestoとコマンド実行用コンテナのイメージは自作するため、Dockerfileを作ります。

こちらの記事を参考にしました。
https://qiita.com/pottava/items/452bf80e334bc1fee69a

### ベースにするDockerイメージを決める

Prestoの公式ドキュメントによると、prestoを動かすにはjavaが必要とのこと。
なので、javaがすでに入ってるイメージを利用することにします。


### コンテナ内部で作業して手順を確立させる

ベースイメージを元にコンテナを立ち上げて、一旦手動でpresto環境とコマンド実行環境を作ります。

コンテナを立ち上げは、このコマンドで。

```
docker run -it openjdk:8u181-alpine sh
```

### presto環境の作成
prestoのインストール方法は公式ドキュメントを確認。どうやらバイナリを配置して、設定ファイルを配置し、起動コマンドを実行すればいいようです。
だいたい次のようなコマンドを入力して環境つくりました。この後、Dockerfile化するため忘れずにメモ。

```
# 作業に必要なツールをダウンロード
apk --update add curl
apk --update add python
apk --update add less

# バイナリを配置
curl -L https://repo1.maven.org/maven2/com/facebook/presto/presto-server/0.215/presto-server-0.215.tar.gz | tar zx -C /usr/local

# 設定ファイルを配置
mkdir /usr/local/presto-server-0.215/etc
vi /usr/local/presto-server-0.215/etc/config.properties
vi /usr/local/presto-server-0.215/etc/jvm.config
vi /usr/local/presto-server-0.215/etc/node.properties
mkdir /usr/local/presto-server-0.215/etc/catalog
vi /usr/local/presto-server-0.215/etc/catalog/mysql.properties
mkdir /var/presto

# 起動コマンドを実行
/usr/local/presto-server-0.215/bin/launcher run
```

### コマンド実行環境の作成

こちらもPresto環境と同じように作成。Presto用CLIはjarファイルを配置するだけだったので楽でした。

```
# コンテナの立ち上げ
docker run -it openjdk:8u181-alpine sh

# 作業に必要なツールをダウンロード
apk --update add curl
apk --update add less
apk --update add mysql-client

# バイナリを配置
curl -L https://repo1.maven.org/maven2/com/facebook/presto/presto-cli/0.215/presto-cli-0.215-executable.jar -o /usr/bin/presto
chmod 755 /usr/bin/presto
```

### 動作確認

Presto環境とコマンド実行環境を手動で作った状態で動きを確認してみます。mysqlにデータベースを新規作成して、presto経由で情報を取得するという方法で。これが確認できれば、Prestoとmysqlの通信がうまくいってるので大丈夫なはず。これで動けば、あとちょっと。

以下、コマンド実行環境で実行しました。

```
mysql -u root -h 172.17.0.1 -e 'create database presto_sample'
presto --server 172.17.0.1:8080 --catalog mysql --execute 'show schemas'
```

実行結果はこちら

```
"information_schema"
"performance_schema"
"presto_sample"
"sys"
```

作成したデータベース名が取れてるので、動作確認OK!!!
これで手順確立が完了です。

## 4. Dockerfileを作成する

確立した手順をDockerfileとして作成します。メモった内容をベースに、次のように書き換えました。

- ベースイメージをFROMに記載
- 設定ファイルはADDで追加
- 各種コマンドはRUNで追加。
    - 不要なレイヤーが作成されることを防ぐため、1つのRUNに記載。
        - 'squash' オプション使うでもいのかな？未検証です。
- サービス起動は、CMDでフォアグラウンドで起動させるようにする

最終的にこんな感じになりました。

### Presto環境のDockerfile

```
FROM openjdk:8u181-alpine

RUN set -x; \
    apk --update add curl; \
    apk --update add python; \
    apk --update add less; \
    curl -L https://repo1.maven.org/maven2/com/facebook/presto/presto-server/0.215/presto-server-0.215.tar.gz | tar zx -C /usr/local; \
    mkdir /usr/local/presto-server-0.215/etc; \
    mkdir /usr/local/presto-server-0.215/etc/catalog; \
    mkdir /var/presto;
ADD etc/ /usr/local/presto-server-0.215/etc/
ADD etc/catalog/ /usr/local/presto-server-0.215/etc/catalog/
CMD ["/usr/local/presto-server-0.215/bin/launcher", "run"]
```

### コマンド実行環境のDockerfile

```
FROM openjdk:8u181-alpine

RUN set -x; \
    apk --update add curl; \
    apk --update add less; \
    apk --update add mysql-client; \
    curl -L https://repo1.maven.org/maven2/com/facebook/presto/presto-cli/0.215/presto-cli-0.215-executable.jar -o /usr/bin/presto; \
    chmod 755 /usr/bin/presto;
```

## 5. 最終確認

`docker-compose` コマンドで立ち上げから実行までできるか試します。
まずは、mysqlとprestoをバックグラウンドで立ち上げ。

```
docker-compose down
docker-compose up -d --build mysql presto
```

次にコマンド実行用は個別で立ち上げて確認。

```
# 立ち上げ
docker-compose run controller sh

# 動作確認
mysql -u root -h 172.17.0.1 -e 'create database presto_sample'
presto --server 172.17.0.1:8080 --catalog mysql --execute 'show schemas'
```

実行結果はこちら

```
"information_schema"
"performance_schema"
"presto_sample"
"sys"
```

動きました！！！

# まとめ

思ったよりも簡単に環境が作れました。
もっと洗練された方法もあると思いますが、とりあえず当初の不満は解消できそう。
公式イメージが用意されてるミドルウェアであれば、 `docker-compose.yml` にイメージ名を記載するだけで環境つくれそうですね。