メインコンテンツへスキップ
  1. Blogs/

Gitlab CI/CDでseleniumを利用する方法

·2155 文字·
Blog Gitlab Python
hiroki
著者
hiroki
クラウドを作るお仕事をしてます。
目次

はじめに
#

E2Eテストや、定期的なスクレイピングのために、seleniumによるブラウザ動作の検証を実行したいことがあります。 今回これをGitlab CI/CDで実行する方法を紹介します。

1. dockerでselenium
#

Gitlab CI/CDで実行する前に、まずdocker image内部でseleniumがうまく動くかチェックします。

ありがたいことにseleniumを実行できる各種browserのimageが用意されているのでこれを使います。docsもしっかりしているのでここでは基本的な使い方のみ紹介します。

1. selenium実行対処のブラウザーのコンテナを起動(edgeもfirefox等もあります)

$ docker run --rm -it -p 4444:4444 -p 5900:5900 -p 7900:7900 --shm-size 2g selenium/standalone-chromium:latest

2. :4444にアクセスする。

http://localhost:4444にアクセスすると、selenium Gridと呼ばれるブラウザの管理画面に移動することができます。

ここで任意のbrowserが起動しているか、browserのversionや現在のsession一覧を確認できます。

alt text

browserに接続できるのは1sessionのみで、既にbrowserに接続している場合新しく接続ができないので、selenium実行後にはdriverを閉じるようにしておきましょう。

atexit.register(driver.quit)

3. :7900にアクセスする。

:7900はVNCにアクセスすることができ、実際に稼働しているブラウザーの画面をみることできます。(passwordはsecret)

http://localhost:7900でアクセスするより、公式のREADMEに記載されているようなクエリ付きURLが、passwordの自動入力や画面の自動リサイズがあり便利です。

http://localhost:7900/?autoconnect=1&resize=scale&password=secret

これによってコンテナ内で動作しているブラウザをGUIで確認できるので、debugに非常に便利です。

alt text

4. seleniumでアクセスする。

seleniumの接続先はhttp://localhost:4444/wd/hubになるので、これに向けてコードを実行します。

import atexit
import os
import time

from selenium import webdriver

REMOTE_SERVER = os.environ.get("REMOTE_SERVER", "http://localhost:4444/wd/hub")


def init_driver() -> webdriver.Remote:
    options = webdriver.ChromeOptions()

    # 必要に応じてメモリ削減対策を有効にする
    # options.add_argument("--headless")
    options.add_argument("--disable-gpu")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-dev-shm-usage")

    driver = webdriver.Remote(
        command_executor=REMOTE_SERVER,
        options=options,
    )
    atexit.register(driver.quit)
    return driver


if __name__ == "__main__":
    driver = init_driver()
    driver.get("https://hirohirolab.com")
    print(driver.title)
    time.sleep(10)  # VNCでの挙動確認用

:7900でVNCにアクセスすれば、ブラウザの状態を確認できます。

alt text

このようにコンテナ内で、seleniumのコードが問題なく動くかチェックしておきましょう。

2. Gitlab CI/CDでseleniumを利用する
#

コンテナ内で動くことが確認できれば、CI/CDで同じことができるか確認しますが、割と簡単でGitlab公式でも既に解説が存在します。 https://docs.gitlab.com/ee/ci/examples/end_to_end_testing_webdriverio/

解説に従って以下のような.gitlab-ci.ymlを作ります。

selenium:
  image: python
  services:
    - name: selenium/standalone-chrome
      alias: chrome
      variables:
        HEALTHCHECK_TCP_PORT: "4444"
  variables:
    REMOTE_SERVER: "http://chrome:4444/wd/hub"
  before_script:
    - pip install selenium
  script:
    - python selenium_sample.py

services

serivcesはPipelineのジョブ実行中のコンテナに、追加で接続できるコンテナのことです。 今回ジョブのコンテナにはimage: pythonを指定して、seleniumを実行し、servicesにブラウザのコンテナとしてname: selenium/standalone-chromeを指定しています。

Gitlabではこの異なるコンテナ間の接続は、Legacy container linksと呼ばれる、dockerのlegacyな機能を使っている様です。 https://docs.gitlab.com/ee/ci/services/

Github Actionsでも同様のservicesという仕組みがあり、こちらはdocker NWのbridge機能(docker composeと同様)を使って接続を実施している様です。 https://docs.github.com/ja/actions/using-containerized-services/about-service-containers#running-jobs-in-a-container

alias

servicesのコンテナ内部のhostnameは通常、docker image名で/があれば、__ or -で置き換えるという形になります。

従って今回の場合、selenium__standalone-chrome or selenium-standalone-chromeでserviceの名前解決ができます。 https://docs.gitlab.com/ee/ci/services/#accessing-the-services

しかし分かりにくいので、alias: chromeでコンテナ内部の名前を変更しています。

HEALTHCHECK_TCP_PORT

serivceのコンテナが起動する前に、ジョブのscriptが実行されると失敗して困る可能性があります。 例えばDBをservicesとして設定時や、今回の場合ではbrowser起動前にseleniumが走ることなどがあると思います。

この場合にはvariablesとしてHEALTHCHECK_TCP_PORTを定義しておくと、script実行待ちをしてくれるの便利です。

https://docs.gitlab.com/runner/executors/docker.html#how-gitlab-runner-performs-the-services-health-check

3. 実際に実行してみる
#

5行目でselenium/standalone-chromeが起動していることがわかります。

Starting service selenium/standalone-chrome:latest ...

8行目でselenium/standalone-chromeが利用できるようになるまで待機します。(今回は一瞬で起動OKとなっていますが)

Waiting for services to be up and running (timeout 30 seconds)...

alt text

たまに以下のようにcrashすることがあります。

selenium.common.exceptions.WebDriverException: 
Message: unknown error: session deleted because of page crash
from unknown error: cannot determine loading status
from tab crashed

この場合はmemory不足が疑われるので、以下のようなoptionでmemory削減を検討しましょう。

    # options.add_argument("--headless")
    options.add_argument("--disable-gpu")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-dev-shm-usage")

おわりに
#

今回のコードやPipelineの実行結果は以下に載せています。参考にどうぞ。

blog / gitlab-ci-selenium-integration

0
0

Related

Gitlab CI/CDでrepositoryにpushする方法
·1257 文字
Memo Gitlab
ElasticSearchを使ったlog収集2 -Elastic Agentの追加-
·3798 文字
Blog ElasticSearch
ElasticSearchを使ったlog収集1 -Elastic Agentとは?-
·3778 文字
Blog ElasticSearch