Emcee можно
скачать с репозитория GitHub и развернуть на своих серверах. В этой статье я хочу рассказать, как мы запустили
Emcee Cloud на мощностях Авито для тестирования приложений других компаний. Запуск стороннего кода на наших серверах ставит много вопросов по безопасности. Очевидный способ решить эти проблемы — сендбоксинг с помощь виртуализации. Реализовать это на macOS оказалось нетривиально и нам пришлось поломать голову. Рассказываю, что мы сделали, чтобы обезопасить внутреннюю сеть и данные пользователей.
Попробовали самый простой инструментДля запуска виртуализации есть масса решений, в том числе и для macOS. Компания Apple предоставляет фреймворк Virtualization с высокоуровневым API для создания и конфигурации виртуальных машин. Чтобы его использовать, нужно разработать свой формат виртуальной машины, где нужно сохранять конфигурацию, диск виртуальной машины, nvram. Такие подготовленные виртуальные машины мы называем образами и используем для клонирования. Надо озаботиться хранением этих образов и доставкой их на машины тестовой фермы. Каждый подготовленный образ с установленным Xcode и Simulator рантаймами для наших целей занимает около 60 Гб. Для прототипа запуска Emcee в облаке мы стали рассматривать готовые решения.
В коммерческих продуктах Parallels, VMWare, UTM основной упор сделан на то, чтобы пользоваться виртуальными машинами из оконного интерфейса, как ОС внутри ОС. Например, чтобы виртуализировать Windows или Linux на macOS. Виртуальные машины там можно бекапить и откатывать состояния, приостанавливать и возобновлять работу, подключаться к ним по vnc. В задаче автоматизации тестирования мы этим не пользуемся, мы будем клонировать подготовленную виртуальную машину и запускать один раз на время выполнения одной задачи, а после этого её удалять. Зато нам важна возможность управлять виртуальными машинами через rest api или cli.
Популярные инструменты нам не подходили и по другим причинам:
- Сложно настроить автоматизированную установку приложения на macOS-хост (мы используем Puppet). Эти приложения дистрибутируются как dmg-образы или установщики, их нельзя установить с помощью homebrew или macports.
- Все они имеют пользовательский интерфейс и несут с собой много ресурсов для его отображения. Хоть в некоторых решениях есть возможность запускать виртуальную машину в безоконном режиме, всё равно само приложение занимает много места. Например, UTM занимает ~1 Гб.
- Нет удобного функционала для хранения и распространения образов. У нас несколько образов под разные окружения, которые мы регулярно обновляем. Каждое решение использует свой уникальный формат образа, и чтобы их применить в задаче автоматизации, надо дополнительно реализовать хранилище образов с версионированием.
Поэтому для быстрого старта мы стали искать другие варианты и остановились
на утилите Tart. По сути, это простая cli-обёртка для фреймворка виртуализации на macOS. Проект
с открытым исходным кодом, есть
заранее подготовленные образы, в том числе с предустановленным Xcode. Есть образы с бета-версиями macOS и Xcode. Например, можно проверить работу своего CI на новой версии macOS/iOS в виртуальной машине без изменения окружения хоста. Запустить виртуальную машину очень легко:
tart clone ghcr.io/cirruslabs/macos-ventura-base:latest ventura-basetart run ventura-baseОдин из значимых плюсов для нас — возможность конвертации образа виртуальной машины в oci-совместимый образ. Это позволяет использовать любой репозиторий docker-образов вроде docker hub или GitHub packages. Мы просто загружаем и скачиваем образы в наш внутренний репозиторий, который уже используется в Авито Linux-сообществом. Недостаток такого подхода в том, что образ виртуальной машины — это всегда один уникальный слой в oci-образе. Получается, что слои не шарятся между образами и каждый новый образ, даже с минимальными изменениями, будет загружаться целиком и занимать полный объём в хранилище.
Запустили виртуальную машину и провели тестыМы изолируем запуск тестов не только от внутренней инфраструктуры Авито, но и клиентов облака друг от друга. У фреймворка на macOS есть ограничение: одновременно можно запустить не более двух виртуальных машин. Конечно, хотелось бы больше, но лимит зашит внутри операционной системы. В пограничных случаях мы можем не до конца использовать ресурсы хоста из-за наличия такого ограничения.
Запуск проходит в четыре этапа:
1. Сначала клонируем образ с нужным окружением из нашего репозитория образов. В нём уже всё настроено: скопирован публичный ключ для доступа по SSH, установлен Xcode, необходимые рантаймы симулятора и сам Emcee binary.
tart clone registry.avito.ru/emcee/ios/emcee:latest emcee-test-runner2. Готовим временную директорию, где размещаем бандлы xctest, target, runner и другие ресурсы, которые нужны для тестирования. Затем запускаем виртуальную машину, в которую монтируем созданную директорию. Возможность монтировать директорию появилась только в macOS 13.0 Ventura.
tart clone registry.avito.ru/emcee/ios/emcee:latest emcee-test-runner3. Получаем IP-адрес запущенной виртуальной машины и проверяем её доступность. Иногда на это требуется несколько секунд, пока dhcp-демон выделит сетевой адрес.
tart clone registry.avito.ru/emcee/ios/emcee:latest emcee-test-runner4. Запускаем наш тест-раннер Emcee внутри виртуальной машины по SSH от пользователя _emcee. При запуске передаём идентификатор работы — так раннер сможет найти временную директорию, в которой мы уже разместили все ресурсы. После этого Emcee запускает тесты так, как будто работает на обычной машине.
ssh -i ~/.ssh/emcee _emcee@192.168.64.2 \ 'JOB_ID=834efdb6-6044-4b44-8fcb-560710936f37 bin/Emcee runTests ...'Изолировали трафик из виртуальной сетиТестовые бандлы — это упакованные binary с ресурсами, переданные клиентами в emcee cloud. Запускать приложения, которые передала третья сторона, небезопасно. Поэтому нам нужно изолировать ещё и трафик из сети виртуальных машин. В фреймворке Virtualization есть
три способа, как это сделать:- Подключить сетевое устройство виртуальной машины напрямую к физическому интерфейсу host OS, например, en0.
- Создать виртуальный коммутатор, который объединит все машины вместе с хостом в виртуальную сеть.
- Так называемая software network, когда весь трафик из виртуальной машины приходит на socket в host OS. Как будет обрабатываться трафик, решает разработчик, который встраивает фреймворк в своё приложение.
Для изоляции трафика первый способ не подходит, это наименее безопасный способ подключения виртуальной машины к сети. В третьем надо реализовать обработку низкоуровневых сетевых пакетов, это трудоёмко и не очень производительно. Самый подходящий вариант — создать виртуальный коммутатор. Так мы сможем контролировать трафик через настройки packet filter на macOS.