Kubernetes Meetup Tokyo #5の登壇資料です。
アジェンダ
- Why Selenium Grid?
- Why Selenium Grid on Kubernetes?
- How-tos
- Gotachas
Why Selenium Grid?
- 複数ブラウザを使ったE2Eテストを並列化するため
Selenium
ブラウザのオートメーションツール。WebアプリケーションのE2Eテストなどに使う
Selenium Grid
複数のマシンやコンテナにSeleniumのテストを分散並列実行させるためのプロキシ。FirefoxやChromeなど複数ブラウザを使ったE2Eテストを並列化するなどの目的で使う
Why Selenium Grid on Kubernetes?
Dev/Prod Parity & Self-hosting
Selenium Grid: Pain Points
- Selenium GridのURLがローカルと非ローカル環境で異なる(Dev/Prod Parity)
- 経費的な問題でBrowserStack、SauceLabsなどの有償サービスを使いたくない→Self-hosting
- Selenium Gridの構築がめんどくさい
Selenium Grid on Kubernetes: Good Points
- Selenium GridのURLがローカルと非ローカル環境で一緒(Dev/Prod Parity)
- Self-hosting
- Selenium Gridの構築がコマンド一発
How-tos
- Kubernetes(K8S)クラスタ作成: ローカル & AWS
- K8SにSelenium Gridをインストール
- Chromeノードにリモートデスクトップ接続して観察・デバッグ
- Pythonのreplでテストコードを書く
- pytestでテスト実行
- K8SにConcourseをインストール
- テスト実行の様子を観察
- プロセス並列で実行
K8Sクラスタ作成: ローカルマシン上に
kubernetes/minikubeという便利なツールが
minikube start --cpus 4 --memory 4096
- CPUは4コア(Concourse Web/Workerでそれぞれ1コア+その他で2コア)
- minikubeVMのデフォルトメモリサイズは1024M
- MySQL, Redis, Selenium Grid Hub, Selenium Node
Firefox/Chromeを起動するとだいたい4GBくらい
K8Sクラスタ作成: AWS上に
kubernetes-incubator/kube-awsという便利なツールが
$ mkdir my-cluster
$ cd my-cluster
$ kube-aws init --cluster-name=mycluster \
--external-dns-name=mycluster.example.com \
--region=ap-northeast-1 \
--availability-zone=ap-northeast-1a \
--key-name=mykeypair \
--kms-key-arn="arn:aws:kms:ap-northeast-1:xxxxxxxxxx:key/xxxxxxxxxxxxxxxxxxx" \
--hosted-zone-id=myhostedzoneid
$ kube-aws render credentials --generate-ca
$ kube-aws render stack
$ kube-aws up --s3-uri s3://<your-bucket>/<optional-prefix>
※メンテナです。宣伝乙ごめんね
Selenium Gridインストール
- Kubernetesにアプリをインストールする場合は基本的にhelmというツール使用
- VNCクライアントでWebDriver Podにリモートデスクトップ接続して、ブラウザが動く様子をみたい
(chrome|firefox)Debug.enabled=true
helm install stable/selenium \
--set chromeDebug.enabled=true \
--set firefoxDebug.enabled=true
--name selenium-grid
Seleniumテストを書く環境作成: kubectl exec
ブラウザ=SeleniumのRemoteWebDriver
kubectl run selenium-python --image=google/python-hello
export PODNAME=`kubectl get pods --selector="run=selenium-python" --output=template --template="{{with index .items 0}}{{.metadata.name}}{{end}}"`
# 初回はdocker pullに時間がかかるので数分待ってから・・・
kubectl exec --stdin=true --tty=true $PODNAME bash
pip install selenium
python
Seleniumテストを書く環境作成: telepresence
telepresence という、ローカルマシンからK8Sネットワークに透過的にアクセスできるようにするツール
$ telepresence --new-deployment telepresence \
--method inject-tcp \
--namespace default \
--run-shell
Starting proxy...
@minikube|bash-3.2$
macOS内のbashとそこから起動したプロセスすべてが「K8Sクラスタのネットワーク」に繋がった状態になる
pip install selenium
python
Pythonのreplでテストコードを書く
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
driver = webdriver.Remote(
command_executor='http://selenium-grid-selenium-hub:4444/wd/hub',
desired_capabilities=getattr(DesiredCapabilities, "CHROME")
)
driver.get("http://google.com")
assert "google" in driver.page_source
driver.close()
pytestでテスト実行
pip install -U pytest
import time
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities im
port DesiredCapabilities
def test_chrome():
driver = webdriver.Remote(
command_executor='http://selenium-grid-selen
ium-hub:4444/wd/hub',
desired_capabilities=getattr(DesiredCapabili
ties, "CHROME")
)
driver.get("http://google.com")
time.sleep(5)
assert "google" in driver.page_source
driver.close()
pytest
しばらく待つとテストが通る。
だいたいおわり
Gotachas
- Debugging
- Distributed Testing
ChromeノードにVNCで接続
- VNC: いわゆるリモートデスクトップ
- kubectl port-forwardコマンドを使うと、Kubernetesクラスタ内のpodのポートをローカルマシン側にバインドできる(!)
kubectl port-forward --namespace default \
$(kubectl get pods --namespace default \
-l app=selenium-grid-selenium-chrome-debug \
-o jsonpath='{ .items[0].metadata.name }') 5900
macOS標準装備のVNCクライアントで接続
open vnc://127.0.0.1:5900
テスト実行の様子を観察
driver.get("http://google.com")
実際、VNCクライアントで見てみるとChromeが動いていることがわかる。
複数プロセスでテストを分散並列実行
pytest-xdistを使う。
pip install --upgrade setuptools
pip install pytest-xdist
...
pytest -n <プロセス数>
※ setuptoolsをアップグレードしないと-nオプションが認識されない。pythonあるあるなの?
複数マシンでテストを分散並列実行
Why?
- 素朴にpytest -nすると、1コンテナに割り当てたCPU・メモリでさばけるプロセス数までしかスケールしない
How?
- テスト配布元マシン 1 --同期--> N テスト実行マシン
- submitter --> ファイルストレージ --> master --> worker
Example
- submitter(macOS) --> Minio on K8S --> master on K8S Pod --> worker on K8S Job
- kubernetes-incubator/client-python + Minio/AWS S3 + pytest-xdistで実装できる
- submitterの実装例
参考リンク
まとめ
- Dev-Prod Parity
- ローカルマシンでも本番サーバでも全く同じテストスクリプトでSelenium Gridを使ったテストが可能
- 環境構築の容易さ
- K8SさえあればSelenium Gridはhelm install一発
- デバッグ
- VNCでブラウザの動く様を観察する
- 分散テスト
- プロセス並列、マシン並列
- 登場したツール
- Kubernetes, Selenium Grid, minikube, kube-aws, helm, VNC,
kubectl port-forward
,open vpn://...
, telepresence, pytest-xdist
- Kubernetes, Selenium Grid, minikube, kube-aws, helm, VNC,
自己紹介 & おわり
twitter/github/slack.k8s.io: @mumoshu (むもしゅ)
Primary maintainer of kubernetes-incubator/kube-aws
Fin