Привет! Меня зовут Денис Веренцов, я Android-инженер из команды Emcee. Это технопродукт Авито, универсальное решение для запуска iOS и Android-тестов, с его помощью можно быстрее выкатывать новые фичи пользователям и клиентам. В этой статье я расскажу, как можно развернуть облачную инфраструктуру для запуска нативных автотестов Android-приложений на основе разработанного нами решения.
Статья будет полезна тем, кто хочет организовать инфраструктуру для запуска тестов, но не обладает подходящим для этого «железом». Материал также будет интересен тем, у кого есть желание попробовать технологию Emcee в деле.
Что внутри статьи:
Emcee и его преимущества
Emcee — это инструмент для мобильных автотестов. С его помощью можно развернуть инфраструктуру для нативных автотестов Android/iOS и запускать тесты, эффективно утилизируя ресурсы и повышая time-to-market.
Основные преимущества Emcee:
эффективность: тесты запускаются сразу на всех доступных ресурсах, не нужно выделять отдельные пулы ресурсов под определенные запуски тестов;
автоматический менеджмент жизненного цикла эмуляторов;
гибкая конфигурация запуска тестов: разные стратегии деления тестов, повторы упавших тестов, настройка таймаутов и так далее.
Облачная инфраструктура
На мой взгляд, у облачной инфраструктуры есть свои плюсы и минусы.
Плюсы:
можно быстро получить «железо» в широком спектре конфигураций. Это бывает полезно при проведении быстрых экспериментов или тестировании новых технологий;
можно обратиться в техподдержку, если есть проблемы или вопросы;
некоторые провайдеры на первое время дают гранты или бонусные рубли — первые эксперименты можно проводить бесплатно.
Минусы:
пожалуй, самый главный минус — стоимость: аренда мощного сервера или виртуальной машины может быть очень дорогой. Это десятки или даже сотни тысяч рублей в месяц;
не у всех провайдеров есть возможность выделить машины с KVM. У каждого провайдера нужно уточнять этот момент через техподдержку или документацию, а также проверять доступность KVM вручную;
нужно отдельно решать вопросы безопасности, так как без дополнительной подготовки такая инфраструктура открыта для интернета;
если для тестов нужны дополнительные инструменты или данные из корпоративной сети, то нужно думать, как соединить облачную инфраструктуру и корпоративную сеть.
У Emcee есть ряд требований к железу, поэтому перед арендой облачных мощностей нужно убедиться, что железо соответствует требованиям.
Требования такие:
OS на базе Linux, Docker, KVM (Kernel-based Virtual Machine)*;
процессор с архитектурой x86-64;
достаточное количество ресурсов для запуска нескольких docker-контейнеров. Минимум 4 CPU и 8ГБ RAM.
*На данный момент наличие KVM является обязательным, так как эта технология позволяет значительно улучшить перформанс Android-эмулятора. Подробнее можно прочесть в официальной документации эмулятора.
Аренда облачных ресурсов
Для примера был выбран провайдер VK Cloud, на котором в качестве демонстрации я арендую подходящую виртуальную машину (далее ВМ).
Создадим новый инстанс ВМ. Я выбрал Ubuntu 22.04, 8 CPU и 16ГБ RAM, а также диск SSD на 100ГБ.
Обратите внимание, что изначально конфигурация NESTED-X-X не была доступна. Для её получения я написал в техподдержку и спросил, как можно получить работающий KVM или рабочую вложенную виртуализацию внутри моей ВМ.
Далее настраиваем сеть:
Для доступа к ВМ я указал свой SSH-ключ. Ключ можно создать или указать свой в меню выбора ключа.
Дополнительно я добавил настройку Firewall: добавил новую группу безопасности emcee, в которой указал, какой входящий трафик разрешен для моей ВМ.
В группе безопасности emcee я указал порты, необходимые для работы Emcee: 8081, 8082 и 41000.
Следующим шагом предлагается настроить резервное копирование. Я отключил эту опцию и далее выбрал «Создать инстанс».
Немного ждем, пока ВМ подготовится и запустится.
После этого можно подключаться к ВМ по SSH с помощью ключа, который мы указывали при создании ВМ. Дополнительно в общей информации о ВМ описан способ подключения.
Как подготовить инфраструктуру
Подключаемся к ВМ по SSH:
ssh -i vktest ubuntu@<VM ip address>
Проверяем доступность KVM
После успешного подключения нужно проверить, что KVM доступен на данной ВМ. Для этого нужно установить утилиты cpu-checker и libvirt-clients . Можно установить что-то одно, но для примера я установлю обе.
Устанавливаем cpu-checker:
sudo apt-get install cpu-checker
И после установки вызываем в консоли команду sudo kvm-ok
, которая должна показать наличие или отсутствие KVM. Вывод команды, если KVM доступен:
INFO: /dev/kvm exists
KVM acceleration can be used
Если KVM недоступен, то вывод будет такой:
INFO: Your CPU does not support KVM extensions
KVM acceleration can NOT be used
Устанавливаем libvirt-clients:
sudo apt-get update && sudo apt-get install libvirt-daemon-system libvirt-clients
После установки вызываем в консоли команду virt-host-validate qemu
. Вывод команды, если KVM доступен:
QEMU: Checking for hardware virtualization : PASS
QEMU: Checking if device /dev/kvm exists : PASS
QEMU: Checking if device /dev/kvm is accessible : FAIL (Check /dev/kvm is world writable or you are in a group that is allowed to access it)
QEMU: Checking if device /dev/vhost-net exists : PASS
QEMU: Checking if device /dev/net/tun exists : PASS
QEMU: Checking for cgroup 'cpu' controller support : PASS
QEMU: Checking for cgroup 'cpuacct' controller support : PASS
QEMU: Checking for cgroup 'cpuset' controller support : PASS
QEMU: Checking for cgroup 'memory' controller support : PASS
QEMU: Checking for cgroup 'devices' controller support : WARN (Enable 'devices' in kernel Kconfig file or mount/enable cgroup controller in your system)
QEMU: Checking for cgroup 'blkio' controller support : PASS
QEMU: Checking for device assignment IOMMU support : WARN (No ACPI DMAR table found, IOMMU either disabled in BIOS or not supported by this hardware platform)
QEMU: Checking for secure guest support : WARN (Unknown if this platform has Secure Guest support)
Если KVM недоступен, то вывод может быть примерно таким:
QEMU: Checking for hardware virtualization : FAIL (Host not compatible with KVM; HW virtualization CPU features not found. Only emulated CPUs are available; performance will be significantly limited)
QEMU: Checking if device /dev/vhost-net exists : PASS
QEMU: Checking if device /dev/net/tun exists : PASS
QEMU: Checking for cgroup 'cpu' controller support : PASS
QEMU: Checking for cgroup 'cpuacct' controller support : PASS
QEMU: Checking for cgroup 'cpuset' controller support : PASS
QEMU: Checking for cgroup 'memory' controller support : PASS
QEMU: Checking for cgroup 'devices' controller support : PASS
QEMU: Checking for cgroup 'blkio' controller support : PASS
QEMU: Checking for device assignment IOMMU support : WARN (Unknown if this platform has IOMMU support)
QEMU: Checking for secure guest support : WARN (Unknown if this platform has Secure Guest support)
В случае, если после проверок обнаружилось, что KVM недоступен, то нужно узнать у техподдержки, как его включить/получить. А если такой возможности нет, то следует сменить провайдера.
Запускаем инфраструктуру Emcee через Docker Compose
Система Emcee запускается на основе docker-контейнеров. Минимальный набор контейнеров включается в себя три контейнера с сущностями:
очередь Emcee распределяет тесты по воркерам в завиcимости от стратегии распределения и повтора тестов;
воркер Emcee запускает тесты и собирает их результаты, управляет жизненным циклом Android-эмуляторов, которые запускаются внутри контейнера;
Artifactory — готовая система для менеджмента артефактов. Нужна для передачи файлов между воркерами и клиентами Emcee.
Так как используются docker-контейнеры, Emcee можно развернуть разными способами: через Docker или Docker Compose, а также через Kubernetes. Для простоты я выберу способ с Docker Compose, который можно установить по официальной документации.
Нам потребуется всего 2 файла, создадим docker-compose.yaml
:
version: '3'
services:
emcee-queue-service:
image: avitotech/emcee-queue:21.5.0
container_name: emcee-queue-service
ports:
- 41000:41000
queue-worker:
image: avitotech/emcee-worker:21.5.0
env_file:
- emcee-worker.env
depends_on:
- emcee-queue-service
deploy:
replicas: 2
devices:
- "/dev/kvm:/dev/kvm"
emcee-artifactory:
image: docker.bintray.io/jfrog/artifactory-oss:7.63.11
container_name: emcee-artifactory
ports:
- 8081:8081
- 8082:8082
volumes:
- emcee_artifactory:/var/opt/jfrog/artifactory
volumes:
emcee_artifactory:
Создадим второй файл, где указываются переменные окружения для воркера emcee-worker.env
:
EMCEE_WORKER_QUEUE_URL=http://emcee-queue-service:41000
EMCEE_WORKER_LOG_LEVEL=info
Имя хоста emcee-queue-service резолвится в локальный адрес контейнера с таким же именем.
Далее поднимаем контейнеры командой:
docker compose up -d
И проверяем, что поднятие прошло успешно:
> docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b631f9f32fa2 avitotech/emcee-worker:21.1.0 "./entrypoint.sh" 45 seconds ago Up 45 seconds 41001/tcp ubuntu-queue-worker-2
600a8a769bff avitotech/emcee-worker:21.1.0 "./entrypoint.sh" 45 seconds ago Up 44 seconds 41001/tcp ubuntu-queue-worker-1
6f7f5aca1fc0 docker.bintray.io/jfrog/artifactory-oss:7.63.11 "/entrypoint-artifac…" 46 seconds ago Up 45 seconds 0.0.0.0:8081-8082->8081-8082/tcp, :::8081-8082->8081-8082/tcp emcee-artifactory
cd2c4c1cb7b3 avitotech/emcee-queue:21.1.0 "/usr/local/bin/entr…" 46 seconds ago Up 45 seconds 0.0.0.0:41000->41000/tcp, :::41000->41000/tcp emcee-queue-service
Дополнительно можно проверить логи контейнера с воркером и увидеть, что воркер готов к работе:
> docker logs --tail 2 b631f9f32fa2
[INFO] [HttpServer] 2024-08-23 08:00:33.610: REST server at 41001 port started
[INFO] [StartWorkerCommand] 2024-08-23 08:00:33.611: Worker is ready for work
Кроме запуска контейнеров нужно настроить Artifactory. Для этого нужно:
зайти по адресу <ваш ip>:8082 и пройти первоначальную настройку. Для первого входа использовать первичные данные admin и password;
создать новый репозиторий с типом Generic и именем на ваш выбор;
создать нового юзера, данные которого будут использоваться в клиентах Emcee и в воркерах, либо включить анонимный доступ. Здесь важно выдать новому юзеру, в том числе анонимному, права на чтение/запись/удаление. Если создан новый юзер, то в конфигурации воркера нужно задать его username/password в файле конфигурации emcee-worker.env . Подробнее про конфигурацию воркера описано здесь.
Подробнее про настройку Artifactory можно прочесть в документации Emcee.
Отмечу, что если у вас уже есть готовый и настроенный Artifactory, то можно использовать его. Главное, чтобы Artifactory был доступен и для клиентов, и для воркеров Emcee.
На этом запуск и настройка Emcee завершены, наша система готова принимать тесты.
Запускаем тесты через Emcee
Для запуска тестов в Emcee нам нужен клиент Emcee, который можно скачать на странице с релизами.
Android-клиенты бывают двух видов:
cli-утилита;
Gradle plugin.
Я выберу cli-утилиту, которую можно установить разными способами.
Для запуска тестов нам потребуется файл с конфигурацией, например, config.yaml
:
queue:
baseUrl: http://emcee-network-address:41000 # адрес очереди Emcee
tests:
configurations:
- platform: android
appApk: ./apks/regress-debug.apk
testApk: ./apks/regress-debug-androidTest.apk
testTimeout: 120
screenRecordConfiguration:
videoRecordStrategy: record_none
devices:
- sdkVersion: 31 # версия Android SDK, на которой будут запущены тесты на эмуляторе
deviceType: "default"
outputs:
- junit # включаю создание отчета JUnit
- allure # включаю загрузку файлов для Allure отчета
storage:
type: artifactory
baseUrl: http://emcee-network-address:8081/artifactory/ # адрес настроенной Artifactory
repository: emcee-transport
user: "emcee_user"
password: "emcee_password"
Здесь файлы apk с приложением и тестами я положил рядом с файлом конфига. Как показывает практика, разные команды по-разному создают apk в рамках своих конвейеров на CI. Поэтому можно указать свой путь до актуальных apk файлов.
Бинарный файл с cli-утилитой я скачал вручную и теперь мой запуск прогона тестов выглядит так:
./emcee run config.yaml --outdir=results
После прогона тестов я получаю финальный результат:
Emcee run finished.
Sent tests count: 12
Executed tests count: 12
Run status: Failed
Successful tests count: 10
Skipped tests count: 1
Skipped tests:
com.avito.emcee.regress.ExampleInstrumentedTest#assumptionFalse
Failed tests count: 1
Failed tests:
com.avito.emcee.regress.ExampleInstrumentedTest#failed
Tests results written to: /my/path/results/emcee_artifacts/c15f0e85-7f3a-4007-95cc-25101b3aa231
com.avito.emcee.client.internal.result.JobResultHasFailedTestsException: These tests have failed:
com.avito.emcee.regress.ExampleInstrumentedTest#failed
Таким образом, мы успешно запустили прогон тестов в Emcee.
Бонус: готовое облако
Для тех, кто не хочет заморачиваться с виртуальными машинами и провайдерами, можно попробовать сразу запустить тесты в нашем облаке Emcee Cloud. В Emcee Сloud не нужно платить за аренду мощностей, плата берется только за время выполнения тестов. А для всех новых клиентов мы даем бесплатную квоту в 300 минут на прогоны тестов.
Три главных факта про Emcee
В современном мире можно быстро арендовать мощности под любые задачи, в том числе под инфраструктуру для автотестов.
Инструмент Emcee позволяет быстро развернуть масштабируемую инфраструктуру для автотестов Android (как попробовать Emcee для iOS можно почитать здесь).
Для запуска Emcee нужен подходящий сервер с Docker Compose, на котором можно развернуть контейнеры с Emcee и Artifactory: Artifactory нужно настроить либо использовать готовый.
Для тех, у кого нет своего железа и кто не готов платить за его аренду, мы создали сервис Emcee Cloud, где можно запускать свои тесты в облаке.
Спасибо за уделенное время для статьи! Если у вас остались вопросы и уточнения, вы можете оставить их в комментариях — буду рад прояснить.
genericuser
Спасибо за статью! Интересен такой нюанс: как вы управляете правами доступа к /dev/kvm внутри контейнера с эмулятором?
Если правильно помню, прокинутый /dev/kvm залетает в докер-контейнер с id его владельца на хосте. При попытке запустить эмулятор от лица непривилегированного пользователя может не хватит прав на работу с KVM.
/dev/kvm доступен только при работе контейнера, при сборке самого докер-образа его еще нет, заранее права не выдать. А выдавать права во время работы контейнера в стиле `sudo chmod` тоже не хочется.
d_verentsov Автор
Спасибо за вопрос. Внутри контейнера и при сборке его образа отдельно правами не управляем.
Вместо этого используем при запуске контейнера пользователя, у которого есть права доступа к /dev/kvm.