AWS Fargate使ってサーバーレスでSelenium+Headless Chromeを実行する

この記事に行き着いた方でしたら、日々自動化を進めている中にも、ブラウザでのクリック、クリック、入力、クリック、みたいな作業が残っている人が多いと思います。

REST等でAPIが公開されていれば良いのですが、そういうAPIが提供されていないサービスもたくさんあります。

ブラウザの自動化でいつもお世話になっているSeleniumですが、一日数回の実行のためにサーバーを立てておくのももったいない。ということで、常時起動のサーバーを立てない方法としてFargateを使ってみることにしました。

やりたいこと

Seleniumを動かしたいです。Seleniumの動かし方等はこの記事では扱いません。

シナリオ

シナリオも、このブログのタイトルのテキストを取るだけです。

f:id:yomon8:20190804221349p:plain

f:id:yomon8:20190804221308p:plain

Dockerイメージ準備

プログラム

やりたいことシンプルなので、プログラムもシンプル。 yomon8_title.py という名前で保存。

from selenium import webdriver

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument("--disable-setuid-sandbox")
chrome_options.add_argument('--window-size=1420,1080')
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
driver = webdriver.Chrome(chrome_options=chrome_options)

url = 'https://yomon.hatenablog.com/'
driver.get(url)
elm_title = driver.find_element_by_id('title')
print(elm_title.text)

ベースのイメージ

Seleniumの環境のベースは、こちらのイメージを使わせていただいています。

joyzoursky/python-chromedriver:3.7-alpine3.8-selenium

https://hub.docker.com/r/joyzoursky/python-chromedriver/

Dockerイメージをビルド

以下のDockerfileで、Dockerイメージをビルドします。

FROM joyzoursky/python-chromedriver:3.7-alpine3.8-selenium
WORKDIR /usr/work
COPY ./yomon8_title.py  /usr/work
CMD ["python", "yomon8_title.py"]

ビルド実行。

$ docker build -t yomon8title .

テストしてみます。タイトルが取得できています。

$ docker run -it --rm yomon8title
YOMON8.NET

ECRへのデプロイ

Fargateで使うためにECRに入れてから使うことにします。

ECRログイン

以下のURLを参考にログインします。

https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/Registries.html#registry_auth

Bashなら以下のコマンドで一発です。

$(aws ecr get-login --region ap-northeast-1 --no-include-email)

# --省略

Login Succeeded

ECRにリポジトリ作成

以下のコマンドで作成しておきます。

$ aws ecr create-repository  --repository-name yomon8title

ECRにイメージをデプロイ

ECRにデプロイ用にタグを付け直して、Pushします。

$ docker build -t 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/yomon8title .
$ docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/yomon8title

ECS(Fargate)へのタスク設定

CloudWatch Logsのグループ作成

コンテナ実行時のログ出力用にロググループを作成します。

$ aws logs create-log-group --log-group-name yomon8title

クラスタ作成

Fargate実行に使うクラスタも作っておきます。

$ aws ecs create-cluster --cluster-name yomon8-cluster

タスク定義

$ cat <<EOF > input.json
{
    "family": "get-yomon8-title", 
    "networkMode": "awsvpc", 
    "containerDefinitions": [
        {
            "name": "yomno8title", 
            "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/yomon8title",
            "logConfiguration": {
              "logDriver": "awslogs",
              "options": {
                "awslogs-region": "ap-northeast-1",
                "awslogs-group": "yomon8title",
                "awslogs-stream-prefix": "fargate"
              }
            }
        }
    ], 
    "requiresCompatibilities": [
        "FARGATE"
    ], 
    "cpu": "256", 
    "memory": "512",
    "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole"
}
EOF

上記の設定を利用してタスク定義をデプロイします。

$ aws ecs register-task-definition --cli-input-json file://input.json

Fargateタスクのスケジューリング実行

毎日1回処理する設定にしてみようと思います。

ここまではCLIでやりましたが、ここはGUIで設定してみたいと思います。

CLIの手順はこのあたりを参考にできます。 docs.aws.amazon.com

ターゲットにDockerイメージを指定して、スケジュール実行できます。以下は5分毎というスケジュールにしていますが、Cron式を利用した柔軟なスケジュールも可能です。

正常にスケジュール生成完了。CloudWatch Rulesなんかが設定されます。

5分に一回タイトルのテキスト取れているようです。

まとめ

まず、役に立たない例ですみません。ただ、この記事をここまで読んでいただいたような方ならSeleniumの使い方は別の良い記事探していただけると思っています。

こういった、帯に短し襷に長し的な、LambdaとEC2の間のような要件にはFargateの出番が出てくると感じています。

参考

チュートリアル: AWS CLI を使用して Fargate タスクのクラスターを作成する - Amazon Elastic Container Service