見出し画像

[Puppeteer] PuppeteerのDockerコンテナ化(その1)

明けましておめでとうございます

新年明けましておめでとうございます。
今年もよろしくお願いいたします。

久しぶりのPuppeteer関連の投稿です。
年末年始のビットコインは爆上がり状態ですね。
3万ドルを超えてます。

放ったらかしにしていたwarlock君のアカウントの一つがロスカット食らって死んでいました。(ほとんど資金は抜いていたので、痛い出費にはなりませんでしたが)
今の所は怖くて手を出していないです。

そんなわけで今回は勉強することにして、Docker上にPuppeteerを実装していきます。

Dockerとは

Dockerは仮想化環境の一つです。
詳しいことは他の資料に譲るとして、これまでのハイパーバイザ型の仮想化環境とは違って、コンテナ型の仮想環境です。
AWSのような環境は自宅では簡単に構築できませんが、Dockerならかなり軽いので自宅で構築して運用に利用したり、開発の試行錯誤段階での環境構築にもうってつけかと思います。

アプリケーションの可搬性を高める手段としてソフトウェア開発・運用界隈では人気の環境です。
いちいちOS層から構築しなくても、必要なアプリケーション・機能がサクッと用意できることが魅力です。

最近は私もDockerにハマって(良い意味でお気に入りということ)いて、必要な環境やデータベースなどはこのDockerで用意しています。

PuppeteerをDockerに載せてみる

今回、BitMEX版PuppeteerのサンプルプログラムをDocker上に構築して、コンテナイメージを作ってみたいと思います。

必要な要件としては、

・Python 3.6.8環境
・PythonのWebsocketやTa-Lib(統計計算を行うためのライブラリ)などのモジュールの組み込み
・pythonの実行

があります。
それらの要件を順番にDockerファイルに定義していってみましょう。

Dockerコンテナイメージを作成するために、まず「Dockerfile」というテキストファイルを用意します。
ファイル名は何でも良いのですが、慣例的に「Dockerfile」というファイル名が採用されることが多いです。

以下にDockderfileの例を示します。

FROM python:3.6.8

# 作業ディレクトリを /puppeteer に設定
WORKDIR /puppeteer

# puppeteerフォルダの内容をコピー
COPY . .

# requirements.txt で指定された必要なパッケージを全てインストール
RUN pip3 install -r requirements.txt

# TA-Libのインストール
RUN wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz \
   && tar -zxvf ta-lib-0.4.0-src.tar.gz \
   && cd ta-lib \
   && ./configure --prefix=/usr \
   && make \
   && make install \
   && bash -c "echo "/usr/local/lib64" >> /etc/ld.so.conf" \
   && /sbin/ldconfig \
   && pip3 install ta-lib

# コンテナ起動時に puppeteer.py を実行
CMD ["python", "puppeteer.py", "puppets/sample/sample.py", "puppets/sample/sample.json"]

DockerfileはPuppeteerフォルダのルートに置くものとして話を進めます。
いま、Puppeteerのルートフォルダに上記のDockerfileを置きました。

Dockerfileの説明

ファイルの中身の説明です。

FROM python:3.6.8

で、ベースを構築しています。
Pythonのバージョン3.6.8を呼び出しています。
この命令でDockerレジストリ(インターネット上に公開されていてる)からPythonバージョン3.6.8がロードされてきます。

# 作業ディレクトリを /puppeteer に設定
WORKDIR /puppeteer

これから作業を行う作業フォルダを「/puppeteer」として指定します。

# puppeteerフォルダの内容をコピー
COPY . .

COPY命令で、現在ホストコンピュータで作業しているディレクトリ(Puppeteerのルート)から、コンテナ内の作業フォルダ(コンテナ内の/puppeteer)に全ファイルをコピーしています。
今回は話を簡単にするために、本来は適宜書き換えが必要なPuppeteerの定義ファイル(json)や、外部に出力するログのフォルダ(/logs)まで、全部をコンテナ内に同梱しています。

# requirements.txt で指定された必要なパッケージを全てインストール
RUN pip3 install -r requirements.txt

コンテナ内(/puppeteer)でPythonの必要モジュール(Ta-Lib以外)をインストールします。
もちろん、コンテナ内の話なので、自身が作業しているホストコンピュータ上には何の影響もありません。

# TA-Libのインストール
RUN wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz \
   && tar -zxvf ta-lib-0.4.0-src.tar.gz \
   && cd ta-lib \
   && ./configure --prefix=/usr \
   && make \
   && make install \
   && bash -c "echo "/usr/local/lib64" >> /etc/ld.so.conf" \
   && /sbin/ldconfig \
   && pip3 install ta-lib

次に、Ta-Libをインストールします。
必要なモジュールファイル(ta-lib-0.4.0-src.tar.gz)は外部からwgetで取得します。
上記では、コマンドを繋げて一回のRUNコマンドの中で処理を完結させています。
こうすることで、実はta-lib-0.4.0-src.tar.gzファイルはこのRUNコマンドの終了後にはクリーンナップされてコンテナ内には残りません。
ADD命令やCOPY命令でta-lib-0.4.0-src.tar.gzファイルをコンテナ内にロードしても良いのですが、後々ta-lib-0.4.0-src.tar.gzを削除する作業等が発生するので、キャッシュ内だけで完結する処理にまとめて見通しを良くしました。

# コンテナ起動時に puppeteer.py を実行
CMD ["python", "puppeteer.py", "puppets/sample/sample.py", "puppets/sample/sample.json"]

コンテナ起動時のコマンドを記述しています。
CMD命令はコマンドラインに複数のコマンドを列挙するのに役立ちます。
上記の記述は、コンテナ起動時に

python puppeteer.py puppets/sample/sample.py puppets/sample/sample.json

を実行しているのと同じ意味です。
今回は説明の簡略化のために、サンプルプログラムを直書きしていますが、環境変数等で実行するコマンドや処理を変更することも可能だと思います。
(環境変数をコンテナ外部から渡す処理については、今後取り上げていきます)

コンテナイメージ作成

上記のDockerfileからコンテナイメージを作ってみましょう。
dockerコマンドでビルドを実行します。

docker build -t puppeteer:latest .

上記のコマンドをPuppeteerのルートフォルダ上で実行します。
コマンド列の最後の「.」は、ソースフォルダをPuppeteerのルートフォルダに指定するためです。

ビルド結果は

画像1

IMAGESの中に「puppeteer:latest」として生成されました。

実行

docker runコマンドでコンテナを実行させてみましょう。

docker run -d -P --name puppeteer puppeteer:latest

実行状態を見てみると、ちゃんと動作しているようです。

画像2

今後

今回は、Puppeteerの本体、定義ファイルも全部コンテナ内にまとめてしまいましたが、定義情報やログの外部出しなども可能なように作り込んでいきたいと思います。
また、今回は一回のビルドで全部を作成していますが、PipでのモジュールインストールやTa-Libのビルドなど、時間のかかる処理が多いので、毎回最初から作成すると利便性が悪いです。
ここらへんを部分ビルドを用いてコンポーネント化できたらな、と思っています。

楽しいBotライフを!

ソフトウェア・エンジニアを40年以上やってます。 「Botを作りたいけど敷居が高い」と思われている方にも「わかる」「できる」を感じてもらえるように頑張ります。 よろしくお願い致します。