Remote ContainerでPython Seleniumする

##モチベーション
社内でSelenium研修担当しているのですが、受講者に環境作ってもらうのが面倒なので、簡単にできないかと思い、Remote Container使うとできそうなので、やってみた。

##環境(以下のものがInstallされている前提です)
Win10
VSCode
Docker for Windows

##Dockefile
まず、最終的に作成したDockerfileから

``` Dockefile
FROM python:3.7.3-slim

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
    apt-utils \
    gcc \
    build-essential \
    && apt-get install -y wget \
    && apt-get install -y unzip \
    && wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \
    && wget https://chromedriver.storage.googleapis.com/91.0.4472.101/chromedriver_linux64.zip \
    && unzip chromedriver_linux64.zip \
    && wget https://moji.or.jp/wp-content/ipafont/IPAexfont/IPAexfont00401.zip \
    && unzip IPAexfont00401.zip -d ~/.fonts/ \
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*
```

上から説明していきます。


``` 
FROM python:3.7.3-slim
``` 
python:3.7.3-slimを基本Imageとして使用する。


``` 
    && apt-get install -y --no-install-recommends \
    apt-utils \
    gcc \
    build-essential \
``` 
apt-utils、gcc、build-essentialをInstallする。
参考にしたサイトでInstallしていたので、そのまま使いましたが、不要かもしれません。

``` 
    && apt-get install -y wget \
    && apt-get install -y unzip \
``` 
Install Packageの取得・回答に必要なwget、unzipをInstallする。

``` 
    && wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \
    && apt install -y ./google-chrome-stable_current_amd64.deb \
    && rm ./google-chrome-stable_current_amd64.deb \
``` 
google-chrome-stable_current.debをダウンロード→install→deb削除

``` 
    && wget https://chromedriver.storage.googleapis.com/91.0.4472.101/chromedriver_linux64.zip \
    && unzip chromedriver_linux64.zip \
    && rm chromedriver_linux64.zip \
``` 
chromedriverをダウンロード→解凍→zip削除

``` 
    && wget https://moji.or.jp/wp-content/ipafont/IPAexfont/IPAexfont00401.zip \
    && unzip IPAexfont00401.zip -d ~/.fonts/ \
    && rm IPAexfont00401.zip \
``` 
日本語フォントをダウンロード→解凍して~/.fonts/に移動→zip削除

``` 
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*
``` 
お片付け。

##Dockerfile以外の準備
``` 
python
├ .devcontainer
│ ├ devcontainer.json：コンテナの設定
│ └ Dockerfile：Docker Imaage定義（前述の通り）
├ .vscode
│ └ extensions.json：VS Codeに推奨のPluginを定義
├ src
│  └ selenium
│     └ test_google.py：テスト用プログラム
└ requirements.txt：コンテナ起動後に自動的にPipでInstallするモジュールを記載

```  

上から説明していきます。

``` devcontainer.json
{
    "name": "Python Project",
    "dockerFile": "Dockerfile",
    "settings": {
        "terminal.integrated.shell.linux": "/bin/bash",
        "python.pythonPath": "/usr/local/bin/python"
    },
    "extensions": [
        "ms-python.python"
    ]
    "postCreateCommand": "pip install -r requirements.txt"
}
``` 
- name:Remote Containerの名前なので、なんでもいいです。意識することはありません。
- dockerFile：使用するDockerfileを指定。
- setting：コンテナ起動後に使用するTerminalの設定とPythonのPath設定
- extensions：VS CodeのPlugin指定
- postCreateCommand：コンテナ起動後に自動でpip モジュールをinstallする設定をしてます。

``` extensions.json
{
    "recommendations": [
        "ms-vscode-remote.remote-containers"
    ]
}
```
記載のPluginがInstallされていない場合は、おすすめされます。


```requirements.txt
pytest==5.2.2
selenium==3.141.0
```
pytestとseleniumを使ったテストプログラムを動かしたいので、この2つを自動でInstallする設定にしています。

``` test_google.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options

class TestGoogle():
    def setup_method(self):
        option = Options()
        option.add_argument('--headless')
        option.add_argument('--no-sandbox')
        self.driver = webdriver.Chrome("/chromedriver",options=option)
        driver = self.driver
        driver.get(
            "https://www.google.com/"
        )

    def test_google(self):
        driver = self.driver
        textbox = driver.find_element(By.NAME, "q")
        textbox.clear()
        textbox.send_keys("remote containerが良い")
        textbox.send_keys(Keys.RETURN)


    def teardown_method(self):
        self.driver.save_screenshot("screenshot.png")
        self.driver.quit()
```

ポイントだけ記載します。

- LinuxのChromeをHeadlessで起動するために'--headless'と'--no-sandbox'を指定する必要があります。
- chromedriverの場所は、Dockerfileの中でルート(/)上に展開されているので、"/chromedriver"という指定にしています。

## 環境構築の動作結果
VSCodeの左下部分を選択すると、Remote Containerに関連するコマンドが表示されるので、「Open Folder in Container」を選択する。
ここでpythonフォルダを選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29032/507e23f2-a29c-36b6-9a21-4b132f1a0ce5.png)


devcontainer.jsonm→Dockerfileの順番でファイルが読み込まれ、Dockerfileで定義されたImageのBuildが走ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29032/a3696737-4dff-6d30-cde7-1a8ae5085ec1.png)
Show log部分を選択すると、buildのlogを見ることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29032/e608dbcb-e45c-e2bf-c8b3-8fdc0d17aea1.png)
imageのbuildが成功すると、コンテナが起動され、
postCreateCommandに記載した通り、pipモジュールがinstallされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29032/01caf0be-c0ac-419a-92fd-a6cf33395cab.png)
pip installまで終わると、起動環境です。
(pipのバージョンが古いとwarning出てますが、無視します)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29032/4528ff4d-5019-2686-07ae-28b8bee47ad7.png)

bashを選択すると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29032/6c2d0f8d-ed30-2878-6fb8-68019d225e5f.png)
起動したコンテナにattachされ、コンテナの中に入れます。
which google-chromeとやると、chromeがinstallされていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29032/a57a65c8-9cef-f0c0-71c1-b4d2a9765a19.png)



## テストコードの動作結果
pytest test_google.pyでテストコードを実行。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29032/02f265e4-3e75-42dd-90ba-2bffe43fd85b.png)
Headlessなので、当然Chromeが動いていることは分かりません。。
スクリーンショットを撮る設定をしておいたので、screenshot.pngを見ると、ちゃんと動いていたことが分かります。

![screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29032/1580fc2b-b10c-7b8d-0cca-384587a7a95a.png)

## 最後にImageの容量確認。
例で載せたDockerfileだとImageの容量は815.2MB。

最後のお片付けとダウンロードしたdeb,zipを消さないと931.17MBになり、120MBも差が出ました。
お片付け重要ですね。もっと減らせると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29032/b790a022-9f44-0bdf-a594-d1df340c9de3.png)