ECSでSeleniumを実行する際の注意点

2022/10/05に公開

通常、SeleniumをAWS上で実行する際はLambdaがよく利用される。しかし15分を超過するとLambdaが使用できなくなり、ECS on Fargateが代替手段となるので簡単に解説したい。

SeleniumをLambdaで実行する場合

まずSeleniumをLambdaで実行する際の参考となるサイトは以下があり、方法は次の通り。
https://zenn.dev/eito_blog/articles/72f7b459e2d591

  • Pythonのパッケージと、Seleniumで必要となるchromedriver、headless-chromiumをCloud9上でインストールしてローカルにZipでダウンロード。
  • ZipファイルをLambda関数のレイヤーに設置し、Python3.7でSeleniumを実行する。

しかし、この方法だと次の2点で問題がある。

  1. Lambdaのスペックを超過する重い処理ができない(15分超過やメモリ/ストレージの容量超過)。
  2. Lambdaレイヤーに設定できるZipファイルの容量に限界があり、必要なパッケージをインストールできない場合がある。

よって上記の問題からLambdaが使えない場合、同じサーバレスで実行する場合はECS on Fargateの手段を検討する必要がある。

SeleniumをECSで実行するためのDockerHub

次にECSでSeleniumを実行するにあたり、最も手軽な方法はDockerHubにある以下のベースイメージを利用することである。他の参考サイトもこちらを利用している。
https://hub.docker.com/r/joyzoursky/python-chromedriver/
当初、このイメージを利用する方法でトライしたが、M1 MacでDocker BuildするとエラーでBuildできない問題に直面したため、上記のSelenium Lambdaの方法をDockerで実行する方法を検討した。

SeleniumをDockerで実行するためのDockerFile

結論として、DockerFileを以下のように記述してBuildした。

DockerFile
FROM python:3.7 as build
# chromedriver & headless-choronium for selenium
RUN apt-get install -y unzip && \
    curl -SL https://chromedriver.storage.googleapis.com/2.37/chromedriver_linux64.zip > chromedriver.zip && \
    curl -SL https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-37/stable-headless-chromium-amazonlinux-2017-03.zip > headless-chromium.zip && \
    unzip chromedriver.zip -d /opt/ && \
    unzip headless-chromium.zip -d /opt/

FROM python:3.7
COPY --from=build /opt/headless-chromium /opt/
COPY --from=build /opt/chromedriver /opt/
# set display port to avoid crash
ENV DISPLAY=:99
ENV AWS_REGION=ap-northeast-1

WORKDIR /tmp
COPY requirements.txt /tmp/
RUN \
    apt update && \
    apt upgrade -y && \
    pip install --upgrade pip && \
    pip install --no-cache-dir -r requirements.txt
# chromedriver動作時のエラー(Status code was: 127)回避
RUN apt-get install -y libglib2.0-0 libgconf-2-4 libfontconfig1 libnss3

COPY main.py /tmp/
CMD python3.7 main.py

注意点は以下の通りである。

  • pythonのバージョンは3.7としている。これはダウンロードするchromedriver、headless-chromiumが3.7でないと起動しないためである。
  • RUN apt-get install -y libglib2.0-0 libgconf-2-4 libfontconfig1 libnss3 の記述が必要。これはchromedriver動作時のエラー(Status code was: 127)を回避するためである。
  • requirement.txtに追加でインストールしたいPythonパッケージを記述する。
requirement.txt
boto3
pandas
selenium==4.1.0
  • Docker Buildする際はdocker build --platform linux/amd64 -t <ECR> .とX86_64でbuildする必要がある。ARM64で起動するとエラーになる。

Seleniumのコード

上記のDockerFileとセットとなるmain.pyのサンプルコードである。

main.py
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC

def selenium_execute():
    options = webdriver.ChromeOptions()
    options.add_argument("--headless")
    options.add_argument("--disable-gpu")
    options.add_argument("--hide-scrollbars")
    options.add_argument("--single-process")
    options.add_argument("--ignore-certificate-errors")
    options.add_argument("--window-size=880x996")
    options.add_argument("--no-sandbox")
    options.add_argument("--homedir=/tmp")
    options.add_experimental_option("w3c", True)
    options.binary_location = "/opt/headless-chromium"
    prefs = {"browser.downloads.dir": "//tmp//", "download.default_directory": "//tmp//", "directory_upgrade": True}
    options.add_experimental_option("prefs", prefs)
    options.add_experimental_option('excludeSwitches', ['enable-logging'])
    #ブラウザの定義
    driver = webdriver.Chrome(
        "/opt/chromedriver",
        options=options
    )
    # ダウンロード実行可能に変更
    driver.command_executor._commands["send_command"] = ("POST", '/session/$sessionId/chromium/send_command')
    params = {
        "cmd": "Page.setDownloadBehavior",
        "params": {"behavior": "allow", "downloadPath": '//tmp//'},
    }
    driver.execute("send_command", params)
    driver.get("http://XXXXX")#サイトにアクセス


if __name__ == '__main__':
    selenium_execute()

注意点は以下の通りである。

  • chromedriver、headless-chromiumの配下をDockerFileで設置する場所に合わせる
  • Seleniumでダウンロードする際は、ECSにあるディレクトリをする。今回は以下のように/tmp/にダウンロードするよう指定している。
prefs = {"browser.downloads.dir": "//tmp//", "download.default_directory": "//tmp//", "directory_upgrade": True}

以上の注意点に気をつければエラーを回避してECSでSeleniumを実行できる。
ECS on Fargateの実行方法については、以下のサイトを参考にされたい。
https://dev.classmethod.jp/articles/s3event-trigger-ecstask-on-fargate-bia-lambda/#toc-5

Discussion