【IaCで作るselenium環境】05_Androidコンテナを構築する(Ansibleプロビジョニング編)
――――――――――――――――――――――――――――――――――
【2021-01-20 更新】
VideoRecorderはSelenoidが勝手に起動してセッション張るので、docker-composeに書かなくていいですよ、とご指摘を頂きました。
ありがとうございました。
これによりplaybookに追記を行いました。
――――――――――――――――――――――――――――――――――
直近の関連エントリ
――――――――――――――――――――――――――――――――――
こんにちは。SHIFTのスクラムマスター・テスト自動化エンジニアの石丸です。
前回Azureの登録を行いました。
1ヶ月の無償期間が切れる前にこのシリーズが終わるように、ここからスピードアップしていきます。
今回は実際にたてたVMにAndroidコンテナの準備を施していきます。
■今回のテーマ
今回のテーマは「AnsibleでAzureVMへプロビジョニング」です。
前回構築したAzureの仮想マシン環境にAnsibleでAndroid環境を整えます。
必要なソフトウェアのインストールや設定を自動で行うツールとして、今回は弊社エントリでもちょくちょくテーマに上がっているAnsibleを使用します。
■前提
・DockerDesktop Version 3.0.0(現時点での最新)
・windows環境での構築
・【重要】第4回でDNS名設定、SSH疎通ができていること
■前回のおさらい
前回の最後はこんな感じでした。
第3回までに準備した環境の外側に、ポツンと空っぽのVMが立っている状態です。
これからVMに対してAnsibleで設定を加えていきます。
■Ansibleって?
通常新しくPCを用意した場合、必要なソフトウェアのインストールやセットアップ、あとPC自体の環境設定等々かなりいろいろな準備をしないとなりません。
これがPC1台ならまだよいのですが、数台、数十台に同様の設定を施すとしたらいかがでしょうか?
また何度も設定しなおす場合はどうでしょう?
私のようなものぐさは想像するだけで恐ろしくなります。
そこで登場するのが構成管理ツールです。
設定ファイルを用意することにより、たとえ何台であっても一気に、何度でも、しかも自動でセットアップすることが可能です(構成管理の自動化)。
Ansibleは構成管理ツールとしてはかなりメジャーなプロダクトです。
無料OSS版のダウンロード方法は以下をご覧ください。
■Ansible導入のポイント
さて、実はAnsibleはwindowsにはインストールできません。
(windowsはコントロールノードにできない)
※macは可、brewコマンドであっさりインストールできる
ゆえにちょっと工夫が必要になります。
恐らくWSL2だとあっさり入ると思いますが(未検証)、IaCがテーマなのでWindows上でAnsibleコンテナを準備しようと思います。
==================================================
※注意
Docker Hubに公式版Ansibleイメージがありますが、2020年12月時点で約3年間ホスティングされていない模様です。使うのは避けましょう。
==================================================
■フォルダ構成
今回はちょっとファイルの構成がややこしいです。ファイルの構成を整理します。
・ローカルPC1
C:
|ーUsers
| |ー<ユーザフォルダ>
| |ー.ssh
| |ーselenoidvm_key.pem(第4回でDLしたキーペア)
|
|ーtmp
|ーansible(場所は任意)
|ーDockerfile
|ーhosts
|ーplaybook_node.yml
|ーansible.cfg
|
|ーselenoid(第1回で作成したフォルダのコピー)
|ーdocker-compose.yml
|ーconfig
|ーbrowsers.json
今回新規に準備したansibleフォルダ配下に第1回で作成したselenoidフォルダをコピーしておきます。
■Ansibleコンテナの準備
では実際に準備を進めていきましょう。
手順が大きく7つあります。
手順1:hostsファイルの準備
hostsファイルは配布先マシンの情報です。
今回はAzureVMの情報を記述します。
[selenoid]
myselenoidvm.eastus.cloudapp.azure.com
[selenoid:vars]
ansible_port=22
ansible_user=azureuser
手順2:playbookの準備
Ansibleの本体ともいうべきファイルで、マシンに施す設定の中身が書かれています。
ubuntuへのdocker-ceインストール手順は公式ページがあるので、こちらをもとにplaybookを組んでゆきます。
---
# targetセクション
- name: selenoid_VM
hosts: all
become: yes
become_method: sudo
# varsセクション
# 引数として設定値があれば定義しておく
# vars:
#
# tasksオプション
# 構成管理の本体
tasks:
- name: Upgrade # apt-get updateはこれ
apt:
name: "*"
state: latest
- name: 基本インストール # apt-get installはこれ
apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg-agent
- software-properties-common
state: latest
force: yes
- name: タイムゾーンを日本時間に変更 # timedatectlはこれ
timezone:
name: Asia/Tokyo
- name: docker取得 # apt-key addは
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: リポジトリの追加 # add-apt-repository debはこんな感じ
apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/{{ansible_distribution|lower}} {{ansible_distribution_release}} stable
- name: dockerインストール # apt-get install 再び
apt:
name:
- docker-ce=5:20.10.0~3-0~ubuntu-bionic
- docker-ce-cli=5:20.10.0~3-0~ubuntu-bionic
- containerd.io
- name: pipインストール # apt-get install再び
apt:
name:
- python3-pip
force: yes
state: latest
- name: dockerのインストール Ansible用
pip:
state: latest
name:
- docker
- docker-compose
- name: selenoidのコピー
copy:
src: ./selenoid
dest: /usr/local/
mode: '0644'
- name: chromeブラウザのpull_84
docker_image:
name: selenoid/vnc_chrome:84.0
source: pull
- name: モバイルchromeブラウザのpull_75
docker_image:
name: selenoid/chrome-mobile:75.0
source: pull
state: absent
- name: androidのpull_8.1
docker_image:
name: selenoid/android:8.1
source: pull
- name: videorecorderのpull
docker_image:
name: selenoid/video-recorder:latest-release
source: pull
- name: docker-compose down
docker_compose:
project_src: /usr/local/selenoid/
state: absent
- name: docker-compose up
docker_compose:
project_src: /usr/local/selenoid/
build: yes
task内のnameを見て頂ければ、何をやっているのかだいたい把握できるかなと思います。
今回VMをubuntuで建てているので、使用するコマンドは主にaptです。
AnsibleではLinuxコマンドがAnsible用に定義されていて、その書式に合わせて記述をしていきます。
書式に関しては以下をご確認ください。
またこのあたりの概念に関して、株式会社リアルグローブ・オートメーティッド(RGA)の水谷さんのエントリがlatestバージョンの2.10に沿って書かれており大変参考にさせて頂きました。感謝。
(2021-01-20修正)
Selenoidではブラウザコンテナと同様にVideoRecorderのイメージも事前にpullしておく必要があります。
手順3:ansible.cfgの準備
Ansible自体の設定ファイルです。
GitHubにてexampleが公開されています。
こちらを参考にしつつ、今回は以下の部分を記述しておきます。
https://github.com/ansible/ansible/blob/devel/examples/ansible.cfg
[defaults]
# ホスト情報を集める際のタイムアウト設定
gather_timeout = 20
# pythonのバージョン指定(超重要!)
interpreter_python=/usr/bin/python3
# SSH接続タイムアウト設定
timeout = 120
[ssh_connection]
# StrictHostKeyChecking無効
ssh_args = -o StrictHostKeyChecking=no
手順4:selenoidフォルダのコピー
AnsibleがVMに配置するselenoidを構築します。
ローカルのselenoidフォルダをansibleフォルダにコピーしたうえで、以下のファイルを修正してください。
手順5:browsers.jsonの変更
Androidコンテナ(Android、chrome-mobile)の記述を追加しておきます。
{
"chrome": {
"default": "83.0",
"versions": {
"84.0": {
"image": "selenoid/vnc_chrome:84.0",
"port": "4444",
"tmpfs": {"/tmp": "size=512m", "/var": "size=128m"},
"path": "/"
},
"83.0": {
"image": "selenoid/vnc_chrome:83.0",
"port": "4444",
"tmpfs": {"/tmp": "size=512m", "/var": "size=128m"},
"path": "/"
},
"mobile-75.0": {
"image": "selenoid/chrome-mobile:75.0",
"port": "4444",
"tmpfs": {"/tmp": "size=512m", "/var": "size=128m"},
"path": "/wd/hub"
}
}
},
"android": {
"default": "8.1",
"versions": {
"8.1": {
"image": "selenoid/android:8.1",
"port": "4444",
"tmpfs": {"/tmp": "size=512m", "/var": "size=128m"},
"path": "/wd/hub"
}
}
}
}
手順6:docker-compose.ymlの変更
Videoのパスとcommandの追記を行います。
特にcommandがキモです。
Androidコンテナは、内部でAVDとAppiumの展開を行っています。
なので今までのdocker-compose.ymlの設定だと構築完了前にタイムアウトしてしまいます。
(略)
…
environment:
- OVERRIDE_VIDEO_OUTPUT_DIR=/home/azureuser/docker/selenoid/video
command: >
-conf /etc/selenoid/browsers.json
-video-output-dir /opt/selenoid/video
-log-output-dir /opt/selenoid/logs
-session-attempt-timeout 6m
-service-startup-timeout 6m
-mem 6g
-cpu 2.0
…
(略)
これでセッション維持時間とサービスが立ち上がるまでの時間のタイムアウトを延長します。
また割り当てるメモリとcpuも、VMの上限めいっぱい設定します。
手順7:Dockerfileの準備
最後にAnsibleコンテナを構築するためのDockerfileです。
# syntax = docker/dockerfile:1.1-experimental
FROM alpine:3.12.1
RUN set -x \
&& apk add --no-cache \
sudo \
bash \
wget \
python3 \
py3-pip \
openssh-client
RUN apk add --no-cache ansible
RUN set -x \
&& mkdir -p /etc/ansible/selenoid \
&& mkdir -p -m 0700 /root/.ssh/ \
&& ssh-keyscan myselenoidvm.eastus.cloudapp.azure.com >> ~/.ssh/known_hosts
COPY hosts /etc/ansible
COPY playbook_node.yml /etc/ansible
COPY ansible.cfg /etc/ansible
COPY ./selenoid /etc/ansible/selenoid
WORKDIR /etc/ansible
RUN ssh-keygen -q -N '' -t ed25519 -f ~/.ssh/id_ed25519
RUN --mount=type=secret,id=ssh,target=/root/.ssh/selenoidvm_key.pem \
cat ~/.ssh/id_ed25519.pub | ssh -i /root/.ssh/selenoidvm_key.pem azureuser@myselenoidvm.eastus.cloudapp.azure.com 'cat >> .ssh/authorized_keys'
RUN ansible -i hosts myselenoidvm.eastus.cloudapp.azure.com -m ping
CMD ["ansible-playbook", "-i", "hosts", "playbook_node.yml" ]
ポイントはbuildkitの記述です。
AnsibleからVMにsshする公開鍵としてed25519で発行し、それをVMに転送する際にselenoidvm_key.pemを使用する必要があります。
selenoidvm_key.pemをCOPYコマンドで配布するとDockerの履歴に残ってしまうのでCOPYコマンドは使用できません。
そこで--mount=type=secretを使用して鍵情報をマウントし、直接コンテナに格納しなくてもsshできるようにします。
==================================================
※注意
このDockerfileの記述方法ですとhostnameを直接記述しているため、Ansibleの複数ドメインに対応できません。
ですので、あくまで今回の例に限った記述とご理解頂ければ幸いです。
==================================================
■Ansibleコンテナの実行
Dockerイメージの作成
Dockerfileからイメージをビルドします。
PowerShellを管理者権限で起動、Dockerfileの場所までcdしてbuildコマンドを実行します。
PS C:> cd c:\tmp\ansible
PS C:\tmp\ansible> docker image build -t test01/ansible:0.0.1 --secret --no-cache id=ssh,src=$HOME/.ssh/selenoidVM_key.pem .
正常に実行されると以下のように出力されます。
PS C:\tmp\ansible> docker image build -t test01/ansible:0.0.1 --secret id=ssh,src=$HOME/.ssh/selenoidvm_key.pem .
[+] Building 19.9s (20/20) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 1.69kB 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> resolve image config for docker.io/docker/dockerfile:1.1-experimental 2.1s
=> CACHED docker-image://docker.io/docker/dockerfile:1.1-experimental@sha256:de85b2f3a3e8a2f7fe48e8e84a65f6fdd5cd5183afa6412fff9caa6871649c44 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 1.69kB 0.0s
=> [internal] load metadata for docker.io/library/alpine:3.12.1 1.5s
=> [ 1/12] FROM docker.io/library/alpine:3.12.1@sha256:c0e9560cda118f9ec63ddefb4a173a2b2a0347082d7dff7dc14272e7841a5b5a 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 405B 0.0s
=> CACHED [ 2/12] RUN set -x && apk add --no-cache sudo bash wget python3 py3-pip openssh-client 0.0s
=> CACHED [ 3/12] RUN apk add --no-cache ansible 0.0s
=> [ 4/12] RUN set -x && mkdir -p /etc/ansible/selenoid && mkdir -p -m 0700 /root/.ssh/ && ssh-keyscan myselenoidvm.eastus.cloudapp.azure.com >> ~/.ssh 2.3s
=> [ 5/12] COPY hosts /etc/ansible 0.1s
=> [ 6/12] COPY playbook_node.yml /etc/ansible 0.1s
=> [ 7/12] COPY ansible.cfg /etc/ansible 0.1s
=> [ 8/12] COPY ./selenoid /etc/ansible/selenoid 0.1s
=> [ 9/12] WORKDIR /etc/ansible 0.1s
=> [10/12] RUN ssh-keygen -q -N '' -t ed25519 -f ~/.ssh/id_ed25519 0.4s
=> [11/12] RUN --mount=type=secret,id=ssh,target=/root/.ssh/selenoidvm_key.pem cat ~/.ssh/id_ed25519.pub | ssh -i /root/.ssh/selenoidvm_key.pem azureuser@mysel 2.7s
=> [12/12] RUN ansible -i hosts myselenoidvm.eastus.cloudapp.azure.com -m ping 9.6s
=> exporting to image 0.3s
=> => exporting layers 0.3s
=> => writing image sha256:156dabec583c14f32005337b902e6691e91c52caabeba8f0f9cf126b8c8de927 0.0s
=> => naming to docker.io/test01/ansible:0.0.1
test01/ansible:0.0.1 というイメージが出来ています。
PS C:\tmp\ansible> docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
test01/ansible 0.0.1 156dabec583c 3 minutes ago 217MB
コンテナの実行
出来上がったイメージをもとにコンテナを実行します。
PS C:\tmp\ansible> docker container run -itd --name ansible test01/ansible:0.0.1
87fb010cd9e4fa6ab3e35fcbaec139ab58448bc8cad327364453eb8491ddb220
これでVMに対するプロビジョニングが走り出します。
「ansible」というコンテナが出来ましたのでログを確認します。
PS C:\tmp\ansible> docker container logs -f ansible
PLAY [selenoid_VM] *************************************************************
TASK [Gathering Facts] *********************************************************
ok: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [Upgrade] *****************************************************************
ok: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [基本インストール] ****************************************************************
ok: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [タイムゾーンを日本時間に変更] **********************************************************
changed: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [docker取得] ****************************************************************
changed: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [リポジトリの追加] ****************************************************************
changed: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [dockerインストール] ************************************************************
changed: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [pipインストール] ***************************************************************
changed: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [dockerのインストール Ansible用] **************************************************
changed: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [selenoidのコピー] ************************************************************
changed: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [chromeブラウザのpull_84] ******************************************************
changed: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [モバイルchromeブラウザのpull_75] **************************************************
ok: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [androidのpull_8.1] ********************************************************
changed: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [docker-compose down] *****************************************************
ok: [myselenoidvm.eastus.cloudapp.azure.com]
TASK [docker-compose up] *******************************************************
changed: [myselenoidvm.eastus.cloudapp.azure.com]
PLAY RECAP *********************************************************************
myselenoidvm.eastus.cloudapp.azure.com : ok=15 changed=10 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
PS C:\tmp\ansible>
AnsibleによってVMの環境が整いました。
今回作成された構成
■まとめ
実際の構築手順
1. hostsファイルの準備
2. playbookの準備
3. ansible.cfgの準備
4. selenoidフォルダのコピー
5. browsers.jsonの変更
6. docker-compose.ymlの変更
7. Dockerfileの準備
8. Ansibleコンテナの実行
==================================================
VMの構成管理の自動化、いかがだったでしょうか。
これでVMの設定がいくらか楽になりました。
次回は、やっと本題。
苦労してAzureに準備したAndroidコンテナを動かしてみようと思います。
ではでは。
――――――――――――――――――――――――――――――――――
【ご案内】
テスト自動化のご相談は以下までお気軽にご連絡ください。
https://forms.office.com/Pages/ResponsePage.aspx?id=IkyjGtUOzUeqMMEbzjGdlSf__O4V1URMn-5BpGP8xd9UNE9ESkRPUEs1Wk9FM0REU1BXODFBSkI0MC4u
お問合せはお気軽に
https://service.shiftinc.jp/contact/
SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/
SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/
SHIFTの導入事例
https://service.shiftinc.jp/case/
お役立ち資料はこちら
https://service.shiftinc.jp/resources/
SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/