Python + Selenium + ChromeDriver 環境を Docker Compose でまとめてみた

以前、Python + Selenium を使って Chrome ブラウザを操作する、スクレイピングのサンプルプロジェクトを紹介した。

今回はこの環境を Docker Compose で構築して、ホスト OS 環境を汚すことなく動かせるようにしてみる。

コード全量が置いてある GitHub リポジトリは以下。

Docker Compose とは?

Docker Compose とは、複数の Docker コンテナを組み合わせて使用する際に、うまいことまとめて実行してくれるツール。Docker 本体に同梱されているので、Docker をインストールしてあれば docker-compose コマンドが既に動作するはずだ。

例えば、

  1. Python を動かすコンテナ
  2. Chrome ブラウザがインストールしてあるコンテナ
  3. Python コンテナから Chrome コンテナを操作できるように仲介する Selenium Hub コンテナ

というように、起動する順序やポートの関係性が重要な時に、それをシェルスクリプト等で実現するのではなく、Docker Compose の定義体 (YAML ファイル) に起こしておくことで、あとはよしなにやってもらえる、という便利なコマンドだ。

今回自分が作った例では、複数のコンテナを扱うことはないのだが、Docker Compose を使うと

などという長ったらしいコマンドを打つ必要がなくなり、

と打つだけで実行可能になって楽なので、使ってみた。

Docker イメージ環境をイメージ (想像) する

さて、今回動かしたいプロジェクトは、

が OS 上にインストールされていないと、サンプルコードだけ持ち込んでも動作させられない。

愚直にやるとしたら、Dockerfile

という感じに実装すると思う。勿論それでも良いのだが、今回は既に Python + Chromium + Selenium が揃っているベースイメージを見つけたので、それを利用しようと思う。

Docker コンテナ上に Chrome・Chrome Driver・Selenium をインストールする

自分が使用したのは joyzoursky/python-chromedriver:3.7-selenium というイメージだ。

何をやっているか調べるため、Dockerfile を読んでみる。

中を読むと、python:3.7 という公式イメージをベースに、Chrome と Chrome Driver をインストール、さらに pip で Selenium をインストールしている。なるほど、このぐらいなら自分で実装しても良いレベルだが、今回はコレをそのまま利用することにしよう。

Docker Compose ファイルを書く

さて、自分のプロジェクトディレクトリで、docker-compose.yaml ファイルを書く。内容は以下のとおり。

my-python:
  # ディレクトリを指定するとその配下の Dockerfile を取得して実行する
  build: ./
  # `$ docker ps` 時に NAME として見える名前
  container_name: my-python
  # 勝手に終了しないよう設定しておく
  command: tail -f /dev/null
  # `$ docker exec -it my-python bash` でアタッチした際のカレントディレクトリとなる
  working_dir: /root/app/
  # ボリュームのマウント
  volumes:
    - ./:/root/app/
  # 環境変数
  environment:
    - TZ=Asia/Tokyo

あとは読めば分かるレベルかと。

さて、build プロパティではディレクトリを指定しているが、そのディレクトリの配下にある Dockerfile を探すようになっている。今回は単一の Docker イメージを使うので、プロジェクトルートディレクトリ直下にしたが、必要に応じて複数イメージ用のディレクトリを分けて置いておくと良い。

その Dockerfile の内容は次のとおり。

# ココで前述のベースイメージを指定している
FROM joyzoursky/python-chromedriver:3.7-selenium

# - Vi・Vim が入っていないのでインストールする
# - pip をアップデートして pipienv をインストールする
RUN set -x && \
  apt-get update && \
  apt-get install -y vim && \
  pip install --upgrade pip && \
  pip install pipenv

このプロジェクトがすぐに動かせるよう、pipenv をインストールしてある。また、コンテナ内でちょっとした編集ができるように vim も入れているというワケ。

Docker Compose で起動してみる

このような設定ファイルを用意したら、次のコマンドを実行する。

$ docker-compose up -d
Building my-python
# …中略…
Creating my-python ... done

-d--detach (デタッチ) の意味。対象のイメージが存在しなければその場で docker pull および docker build を行い、そのまま docker run してくれるのだが、すぐにアタッチする必要はないので、-d を付けている。

このコマンドで Dockerfile をベースにしたビルドまでが完了し、コンテナが起動していることが確認できるだろう。

$ docker ps
CONTAINER ID        IMAGE                                COMMAND               CREATED             STATUS              PORTS               NAMES
81526a50b822        practice-python-scraping_my-python   "tail -f /dev/null"   10 seconds ago      Up 9 seconds                            my-python

それではこのコンテナにアタッチしてみる。

$ docker exec -it my-python bash

docker-dompose.yamlworking_dir プロパティで指定したディレクトリにいる状態で、bash 接続できる。

ココからサンプルプロジェクトを動かしていくには、以下のように実行していく。

# 環境構築
$$ pipenv install --dev

# スクリプト実行
$$ pipenv run crawl
$$ pipenv run scrape

共有ディレクトリを設定しているので、結果はホスト OS からも確認できるだろう。

以上

docker コマンドにオプションをたくさん付けて何個もコンテナを起動したりしていたのが、全てを設定ファイルに書いておいてコマンド一発で起動できるようになった。

複数コンテナを扱わなくても楽になることが多いので、Docker Compose はぜひ覚えておきたい。

Chrome や Chrome Driver をどのようにコンテナ化するかという方法は他にも考えられ、今回の方法だけが唯一の正解というワケではないので、各自「ビルド時間が短く済法」だったり「イメージサイズが小さく済む構成」だったり「スケールしやすい構成」だったりを考えてみて欲しい。