Данная документация относится к версии: latest

Документация по Moon версии 1.x на английском языке опубликована здесь.

Moon - это решение для браузерного тестирования совместимое с Selenium, Cypress, Playwright and Puppeteer, использующее кластер Kubernetes or Openshift для запуска браузеров.

1. Начало работы

1.1. Начало работы

Данный раздел описывает установку Moon с ограничением в четыре параллельных браузерных сессии. Подробная информация о том как установить лицензионный ключ, позволяющий снять это ограничение описан в разделе установка лиценионного ключа.

1.1.1. Установка в Kubernetes

Системные требования
  1. Работающий кластер Kubernetes

  2. Установленная утилита kubectl с настроенным доступом к кластеру

  3. Если вы запускаете кластер Kubernetes на виртуальных машинах мы рекомендуем создавать виртуальные машины с насколько возможно большим количеством процессоров. Это позволит избежать проблем с фрагментацией памяти и нехваткой ресурсов. К примеру, если у вас имеется 24 процессора мы рекомендуем создать 3 виртуальные машины с 8 процессорами, а не 12 виртуальных машин по 2 процессора.

  4. Если вы запускаете Moon в кластере, развернутом на рабочей станции при помощи инструмента minikube - ознакомьтесь с разделом Вариант 3: у вас Minikube.

Вариант 1: Установка с помощью Helm
Установка с помощью Helm является рекомендуемым способом установки Moon. Мы предполагаем, что используется версия Helm 3. Более старые версии не поддерживаются.

Мы предоставляем готовые Helm чарты, поэтому установка Moon с помощью Helm делается очень просто:

  1. Добавьте репозиторий Aerokube, содержащий Helm чарты:

    $ helm repo add aerokube https://charts.aerokube.ru/
    $ helm repo update
  2. Для уточнения доступных версий используйте команду:

    $ helm search repo aerokube --versions
  3. Создайте неймспейс:

    $ kubectl create namespace moon
  4. Установите или обновите Moon командой:

    $ helm upgrade --install -n moon moon aerokube/moon2
  5. Helm чарт для Moon содержит различные параметры конфигурации, которые можно посмотреть командой:

    $ helm show values aerokube/moon2

    Для изменения каких-либо параметров используйте аргумент --set:

    $ helm upgrade --install --set=moon.enabled.resources=false -n moon moon aerokube/moon2
  6. По умолчанию, развернутому объекту Ingress присваивается имя хоста moon.aerokube.local. Вы можете его изменить командой:

    $ helm upgrade --install -n moon moon aerokube/moon2 --set ingress.host=moon.example.com

    Откройте ссылку http://moon.example.com/ в браузере и вы увидите интерфейс пользователя. В коде Selenium тестов используйте ссылку http://moon.example.com/wd/hub.

  7. По умолчанию Moon запускается в режиме HTTP-only. Для включения TLS шифрования, то есть HTTPS, вам необходимо предоставить TLS сертификат и приватный ключ:

    $ helm upgrade --install -n moon moon aerokube/moon2 --set ingress.host=moon.example.com --set-file ingress.tlsCert=server.crt --set-file ingress.tlsKey=server.key

    Обычно сертификат и приватный ключ предоставляются либо сторонними поставщиками (центрами сертификации) либо отделом безопасности в вашей организации. Для создания тестовой пары сертификат+приватный ключ используйте следующие команды:

    # Создание CA ключа и сертификата
    $ openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 356 -nodes -subj '/CN=My Cert Authority'
    # Создание серверного ключа, создание сертификата и подписание сертификата
    $ openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj '/CN=moon.aerokube.local'
    $ openssl x509 -req -sha256 -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

    При использовании таких тестовых сертификатов вам понадобится явно, вручную разрешить браузеру открывать Moon интерфейс.

  8. Если Moon устанавливается на машину с архитектурой процессора ARM64 (например, Mac M1 и подобные CPU или облачные ноды Kubernetes с архитектурой ARM64), то выбор доступных браузеров ограничен. Selenium будет работать с Chromium, Firefox или Safari (другие браузеры не имеют версий, совместимых с Linux ARM64). Playwright, Cypress и Puppeteer не будут работать вообще. Для того, чтобы использовать браузеры, совместимые с ARM64, вам необходимо настроить файл values.yaml следующим образом:

    Использование образов с браузерами, совместимых с ARM64
    browsers:
      default:
        playwright: {}
        cypress: {}
        devtools: {}
        selenium:
          MicrosoftEdge: null
          opera: null
          chrome:
            default: 124.0.6367.60-1
            repository: quay.io/browser/chromium
          firefox:
            default: 125.0.3-1
            repository: quay.io/browser/firefox
          safari:
            default: 613.1.6.1
            repository: quay.io/browser/webkit
Вариант 2: Установка с помощью Minikube

Каждый браузер по умолчанию требует 1 процессор и 2 гигабайта памяти. В вашем кластере Minikube мы рекомендуем как минимум 4 процессора и 8 гигабайт памяти. При меньшем количестве процессоров поды могут не стартовать из-за нехватки вычислительных ресурсов. Мы не рекомендуем использовать Docker драйвер для Minikube.

  1. Запуск Minikube на Linux

$ minikube start --cpus=4 --memory=8G --disk-size=20G --driver kvm2
Запуск Minikube на MacOS и процессором архитектуры x86
$ minikube start --cpus=4 --memory=8G --disk-size=20G --driver=hyperkit
Запуск Minikube на MacOS и процессором архитектуры ARM64 (M1 и подобные процессоры)
$ brew install qemu
$ brew install socket_vmnet
$ brew tap homebrew/services
$ HOMEBREW=$(which brew) && sudo ${HOMEBREW} services start socket_vmnet
$ minikube start --cpus=4 --memory=8G --disk-size=20G --driver qemu --network socket_vmnet
Запуск Minikube на Windows
$ DISM /Online /Enable-Feature /All /FeatureName:Microsoft-Hyper-V # Enable Hyper-V
$ minikube start --cpus=4 --memory=8G --disk-size=20G --driver=hyperv
  1. Включите поддержку Ingress в Minikube:

    $ minikube addons enable ingress

    Данная команда может не работать на некоторых версиях Minikube для Mac M1 и подобных процессоров.

  2. Сам процесс установки выполняется с помощью Helm и был описан выше.

  3. Настройка доступа в Moon по сети:

    1. Вариант 1. Используйте команду minikube ip для обновления настроек Moon.

      1. Обновление с помощью вывода команды minikube ip:

        $ kubectl patch svc moon -n moon --patch "{\"spec\":{\"externalIPs\":[\"$(minikube ip)\"]}}"

        На Windows вывод команды minikube ip необходимо подставить вручную, поскольку выражение $() может не сработать.

      2. Добавьте moon.aerokube.local в файл /etc/hosts:

        $ sudo echo "$(minikube ip) moon.aerokube.local" >> /etc/hosts

        На Windows вам может понадобиться обновить файл вручную.

    2. Вариант 2. Используйте туннель minikube. Этот вариант возможен только при использовании minikube с драйвером Docker.

      1. Добавьте moon.aerokube.local в /etc/hosts:

        $ sudo echo '127.0.0.1 moon.aerokube.local' >> /etc/hosts
      2. Запустите туннель Minikube в отдельном терминале, введите пароль, когда потребуется:

        $ minikube tunnel
  4. Откройте ссылку http://moon.example.com/ в браузере, вы увидите интерфейс пользователя. В коде Selenium тестов используйте ссылку http://moon.example.com/wd/hub.

1.1.2. Установка в Openshift

  1. Системные требования:

    • Работающий кластер Openshift версии 4.x

    • Установленный oc клиент с настроенным доступом к кластеру. Установка была протестирована на пользователе с правами администратора кластера Openshift.

  2. Создайте проект для Moon (аналог неймспейса в Kubernetes):

    $ oc new-project moon

    В следующих шагах мы предполагаем, что созданный проект называется moon.

  3. Добавьте репозиторий с Helm чартами:

    $ helm repo add aerokube https://charts.aerokube.ru/
    $ helm repo update
  4. Установите или обновите Moon командой:

    $ helm upgrade --install --set ingress.openshift=true -n moon moon aerokube/moon2

    Флаг -n moon указывает на проект, созданный на предыдущем этапе.

  5. Отредактируйте идентификаторы пользователя и группы конфигурация объекта для совпадения со значениями, разрешенными политиками Openshift (например, установите идентификатор 1000650000, конкретное значение зависит от конфигурации Openshift):

    $ oc edit config.moon.aerokube.com default -n moon

Для тестирования на локальной машине вы можете использовать Openshift Local. В этом случае вам необходимо дополнительно передать имя хоста для Ingress следующим образом:

$ helm upgrade --install --set ingress.openshift=true --set ingress.host=moon.apps-crc.testing -n moon moon aerokube/moon2

После запуска подов Moon добавьте moon.apps-crc.testing в /etc/hosts:

$ sudo echo '127.0.0.1 moon.apps-crc.testing' >> /etc/hosts

1.1.3. Рекомендации по Работе с Helm

Values-файлы Helm

Как было сказано выше, использование Helm чарта является рекомендуемым способом установки Moon в Kubernetes и Openshift. Наш Helm чарт поставляется с рекомендуемыми значениями настроек по-умолчанию, которые будут работать "из коробки" в большинстве случаев. Тем не менее, бывают случаи, когда необходимо установить Moon с заранее включенными продвинутыми функциями и иметь возможность легко воспроизводить данную конфигурацию позднее. Например, по-умолчанию в Moon отключена видеозапись браузерных сессий, но она может требоваться в ваших сценариях тестирования. Аналогично, вы можете захотеть запускать браузеры в нескольких неймспейсах или использовать дополнительные доверенные TLS сертификаты.

Хотя все эти возможность могут быть включены ручным редактированием соответствующих объектов Moon (конфигурационного объекта, набора браузеров, набора устройств) с помощью команды kubectl edit, все эти изменения будут перезаписаны Helm при следующей выкладке Helm чарта. Helm предоставляет лучший способ для хранения воспроизводимой конфигурации выкладки - values-файлы. Это работает следующим образом:

  1. Каждый Helm чарт содержит файл values.yaml с рекомендуемыми значениями параметров по-умолчанию. Этот файл распространяется вместе с другими частями чарта. Например, актуальный файл values.yaml для Moon 2.x хранится здесь.

  2. Если требуется поменять некоторые значения по-умолчанию на пользовательские значения, вы создаете локальный файл values.yaml, содержащий только значения, которые вы хотите переопределить. Например, в Helm чарте Moon число реплик Moon может быть задано, используя поле deployment.replicas в values.yaml. При этом ваш файл values.yaml будет выглядеть так:

    deployment:
      replicas: 3

    Такой файл следует хранить под предпочитаемой вами системой контроля версий. Такой подход гарантирует, что вы никогда не потеряете пользовательские настройки для установки Moon.

  3. Для того, чтобы применить свой файл values.yaml при установке (переустановке) Moon - передайте полный путь до values.yaml в команде Helm:

    $ helm upgrade --install -f путь/до/values.yaml -n moon moon aerokube/moon2

    Переопределение параметров values.yaml аналогично, но более удобно, чем передача тех же самых ключей через флаг --set, например:

    $ helm upgrade --install --set deployment.replicas=3 -n moon moon aerokube/moon2
Настройка Пользовательских Ресурсов Moon

В Moon 2.x все настройка хранятся как встроенные объекты Kubernetes, называемые пользовательскими ресурсами:

Наш Helm чарт имеет отдельный ключ в values.yaml, соответствующий каждому из этих ресурсов:

Пользовательские ресурсы Moon могут быть также настроены через файл values.yaml
quota: # Хранит список квот
  quota1:
    # Параметры квоты Quota1
  quota2:
    # Параметры квоты Quota2

configs: # Хранит список конфигурационных объектов
  config1:
    # Параметры конфигурационного объекта Config1
  config2:
    # Параметры конфигурационного объекта Config2

browsers: # Хранит список наборов браузеров
  browsersset1:
    # Параметры набора браузера Browsersset1
  browsersset2:
    # Параметры набора браузера Browsersset2

license: # Хранит пользовательский лицензионный ключ для Moon (в данный момент Helm чарт поддерживает только один лицензионный ключ)

Как вы видите, для всех пользовательских ресурсов кроме лицензий вы можете определить несколько разных объектов: несколько конфигурационных объектов, несколько квот и несколько наборов браузеров. Все поля, которые вы выставляете в спецификации пользовательского ресурса преобразуются "как есть" в соответствующий ресурс Kubernetes. Например, пусть в values.yaml определен набор браузеров:

Пример определения набора браузеров в values.yaml
browsers:
  my-browserset:
    selenium:
      firefox:
        repository: quay.io/browser/firefox
      chrome:
        repository: quay.io/browser/chrome

Когда вы применяете Helm чарт с таким определением в файле values.yaml, будет автоматически создан такой ресурс Kubernetes типа BrowserSet (т.е. набор браузеров) Kubernetes:

Эквивалентные объект типа "набор браузеров" в Kubernetes
apiVersion: moon.aerokube.com/v1
kind: BrowserSet
metadata:
  name: my-browserset
  namespace: moon # Здесь будет имя неймспейса, куда установлен Moon
spec:
  selenium:
    firefox:
      repository: quay.io/browser/firefox
    chrome:
      repository: quay.io/browser/chrome

Если вы создаете несколько объектов в списке наборов браузеров в values.yaml, то будет создано соответствующее количество пользовательских ресурсов Kubernetes.

1.2. Архитектура

1.2.1. Компоненты Moon

Компоненты Moon

moon components

Кластер Moon состоит из нескольких компонентов:

  1. Одна или несколько реплик приложений Moon. Их основная задача заключается в старте/остановке контейнеров с браузерами. Реплики обычно доступны как сервисы Kubernetes на стандартном порту Selenium - 4444. Все тесты должны отправлять запросы в этот сервис Kubernetes. Это же приложение предоставляет API, используемый для получения информации о запущенных браузерах (в версии Moon 1.x это отдельное приложение под названием Moon API).

  2. Одна или несколько реплик приложений Moon Conf. Это приложение перезапускает поды Moon, когда вы обновляете лицензионный ключ.

  3. Одна или несколько реплик приложений Moon UI. Moon UI собирает информацию от Moon и визуализирует ее. Реплика обычно доступна на стандартном HTTP порту 8080.

  4. Запущенные поды с браузерами.

1.2.2. Режимы работы Moon

В Moon 2.x возможно два режима запуска и работы: используя один неймспейс и используя множество неймспейсов.

Режим одного неймспейса

single-namespace-mode

В режиме одного неймспейса сам Moon и все запущенные браузерные поды выполняются в одном неймспейсе Kubernetes. В версии Moon 1.x это был единственный возможный режим. Он может использоваться в ситуации когда с Moon работает только одна команда или в ситуации когда вам не нужно ограничивать количество используемых браузеров. По умолчанию Moon запускается именно в этом режиме.

Режим множества неймспейсов

multiple-namespaces-mode

В режиме множества неймспейсов Moon запускается в одном неймспейсе, а браузеры запускаются в другом, отдельном неймспейсе. Общее количество таких неймспейсов не ограничено. Этот режим нужен когда вам необходимо контролировать вычислительные ресурсы, браузеры и правила сетевого доступа (network policies) для каждой команды по-отдельности. Настройка Moon для работы в данном режиме описана здесь.

1.2.3. Содержимое браузерных подов

В дополнение к контейнеру с браузером каждый под созданный в Moon содержит один или более образов сервисных контейнеров.

Table 1. Служебные контейнеры
Название Назначение Условия, при которых запускается

ca-certs

Выпуск сертификатов для браузера

Всегда при инициализации пода

defender

Создание и ограничение в одну браузерную сессию в поде, обработка таймаутов

Всегда

proxy

Авторизация в прокси для Selenium

Когда используется прокси

video-recoder

Запись экранных видео работающих браузеров

Когда сконфигурирована запись видео

vnc-server

Предоставление VNC доступа к сессиям

Если отображается окно браузера

x-server

Предоставление X сервера для запуска браузеров в экранном режиме

Если отображается окно браузера

  • Используйте как можно большие размеры нод кластера. К примеру, имея всего 100 процессоров лучше запустить 5 нод с 20ю процессорами на каждой, чем 50 нод с двумя процессорами в каждом. Браузерные поды в некоторых случаях требуют более двух процессоров и в случае нехватки вычислительных ресурсов вы столкнетесь с постоянной фрагментацией кластера.

  • По возможности не создавайте кластерных нод с операционными системами RedHat \ CentOS. Из-за специфических настроек безопасности (фаервол, SeLinux) эти дистрибутивы сложны в конфигурировании и вы можете столкнуться с непонятными проблемами.

  • Рекомендуемый сетевой интерфейс контейнера - Calico. По возможности не используйте Flannel. У Calico производительность выше, чем у Flannel, особенно в больших кластерах.

  • Не стремитесь ограничиваться одной репликой Kubernetes API. Moon использует Kubernetes API для запуска и удаления подов с браузерами. Если вы планируете запускать сотни параллельных сессий браузера, наблюдайте за системными метриками Kubernetes API (Kubernetes master). Перегруженное Kubernetes API может перестать отвечать на запросы, что приведет к зависанию подов с браузерами.

1.4. Необходимые права доступа

Moon не требует сложных прав доступа и ему вполне достаточно настроек доступа Kubernetes по умолчанию. По умолчанию Moon запускает браузеры в том же неймспейсе moon, где он запущен (режим одного неймспейса). Версия Moon 2.0.0 и выше поддерживает множество неймспейсов Kubernetes. Это позволяет вам запускать Moon в неймспейсе moon, а браузеры в произвольном количестве неймспейсов для разных пользователей (режим множества неймспейсов). Это дает возможность легко задать максимальное количество браузеров, доступных каждой команде.

1.4.1. Режим одного неймспейса

Следующая таблица содержит права доступа, необходимые для запуска Moon в режиме одного неймспейса:

Table 2. Необходимые права доступа в режиме одного неймспейса

Право

Назначение

Операции get, watch, list, create, delete, update и patch для подов

Управление браузерными подами

Операции get, watch, list, create, delete, update и patch для config maps

Доступ пользователей и групп к подам

Операции get, watch, list, create, delete, update и patch для deployments и replica sets

Управление лицензией

Операции get, watch и list для ресурсов Moon в API группе moon.aerokube.com

Конфигурация Moon. Лицензия Moon (licenses.moon.aerokube.com) распространяется на весь кластер, таким образом ClusterRole является необходимым ресурсом.

1.4.2. Режим множества неймспейсов

В режиме множества неймспейсов необходимые права доступа отличаются:

Table 3. Необходимые права доступа в неймспейсе, где запущен Moon

Право

Назначение

Операции get, watch и list - сбор информации о неймспейсе

Контроль количества браузеров запущенных в одном неймспейсе

Операции get, watch и list для подов

Анализ подов в неймспейсе Moon

Операции get, watch, list, create, delete, update и patch для deployments и replica sets

Управление лицензией

Операции get, watch и list ресурсов Moon в API группе moon.aerokube.com

Конфигурация Moon. Лицензия Moon (licenses.moon.aerokube.com) распространяется на весь кластер, таким образом ClusterRole является необходимым ресурсом.

Для каждого пользовательского неймспейса Moon требует следующих прав:

Table 4. Необходимые права для пользовательского неймспейса

Право

Назначение

Операции get, watch, list, create, delete, update и patch для подов

Управление браузерными подами

Операции get, watch, list, create, delete, update и patch для config maps

Управление доступом пользователей к браузерным подам

1.5. Различие версий Moon 2.x и Moon 1.x

Версия Moon 2.x - новая версия Moon, включающая множество нововведений и улучшений. Данный раздел дает представление о наиболее значимых изменениях.

  • Множество неймспейсов Kubernetes. Moon версии 1.x позволяет запускать все браузеры в общем (одном) неймспейсе Kubernetes. Однако, общий кластер Moon часто используется разными командами в компании. Часто необходимо уметь ограничить количество используемых браузеров для каждой команды. Ограничение количества запускаемых браузеров фактически означает ограничение вычислительных ресурсов для каждой команды. В Kubernetes эта проблема уже решена с помощью так называемых неймспейсов. Неймспейсы можно рассматривать как проекты, которым администратор Kubernetes выделил некоторое количество вычислительных ресурсов. В Moon версии 2.x вы можете создать неограниченное количество различных неймспейсов, по одному на каждую команду? а затем сконфигурировать Moon, чтобы запускать браузеры в этих неймспейсах. Это дает администратору Kubernetes полный контроль над вычислительными ресурсами для каждой команды. Действие лицензионного ключа Moon распространяется на все эти неймспейсы. В Moon 1.х отдельный неймспейс для команд требовал отдельной копии Moon и отдельного лицензионного ключа. В некоторых случаях это ограничивало возможность запуска большего количества браузеров в период высокой нагрузки. Во Moon 2.x действие одного лицензионного ключа распространяется на множество неймспейсов и, таким образом, если емкость лицензионного ключа позволяет - каждая команда при необходимости может получить больше браузерных сессий чем обычно. Более подробно это описано в разделе ref:#architecture[Архитектура].

  • Улучшенная конфигурация. Версия Moon 1.x использует конфигурационные файлы в формате JSON. Например, файл с описанием браузеров в версии Moon 1.x хранится в Kubernetes и выглядит так:

    Стандартный файл с описанием браузеров версии Moon 1.x
    {
      "firefox": {
        "default": "95.0",
        "versions": {
          "95.0": {
            "image": "browsers/firefox:95.0",
            "port": "4444",
            "path": "/wd/hub"
          }
        }
      }
    }

    В версии Moon 2.x описание браузеров является встроенной функциональностью Kubernetes, которая называется browser set (объект конфигурации браузеров) и выглядит так:

    Описание конфигурации браузеров в Moon 2.x
    apiVersion: moon.aerokube.com/v1
    kind: BrowserSet
    metadata:
      name: default
      namespace: moon
    spec:
      selenium:
        firefox:
          repository: quay.io/browser/firefox
        chrome:
          repository: quay.io/browser/chrome

    Вы можете простым способом смотреть и изменять эти настройки с помощью любого клиента Kubernetes, например:

    $ kubectl get browsersets -n moon -o yaml # Show all available browser sets
    $ kubectl edit browserset default -n moon

    То же самое касается других настроек. Даже работа с лицензионным ключом Moon возможна с помощью стандартных инструментов:

    $ kubectl get license -n moon
    NAME      LICENSEE          SESSIONS   EXPIRES
    default   Acme Inc.         10         2022-10-11T18:38:42Z

    Каждое изменение в этих объектах автоматически проверяется Kubernetes перед сохранением, что предотвращает возможные ошибки.

  • Новые версии браузеров доступны автоматически. В Moon версии 1.x требовалось вручную добавлять образ для каждой версии браузера в файл со списком версий. Если версия браузера отсутствовала в списке, Moon 1.x не мог запустить браузер. Единственное, что требуется для Moon версии 2.x это указать образ репозитория для каждого типа браузера. После этого новые версии определяются автоматически.

  • Улучшенная производительность браузеров. Moon версии 2.x использует совершенно новую архитектуру старта браузеров, которая запускает только необходимые компоненты операционной для работы конкретного браузера. Например, компоненты, управляющие элементами окон браузера, используются при старте только если браузер запущен в экранном режиме. Это дает возможность сделать образы более легковесными, с более быстрой загрузкой и более быстрой отработкой команд.

  • Меньшее использование облачных вычислительных ресурсов. Переработанная архитектура старта браузеров позволяет как минимум на 20% уменьшить использование облачных ресурсов (процессоров, памяти, сетевого трафика).

  • Улучшенное сетевое взаимодействие. Moon версии 1.x для коммуникации с браузерными подами во многом полагается на реализацию DNS от Kubernetes (например e.g. CoreDNS). Известно что сервис DNS часто подвержен проблемам с кэшированием и специфичными для облака сетевыми ошибками, что иногда приводит к разрыву браузерной сессии. Moon версии 2.x полагается на IP адрес пода и не зависит от сервиса DNS вообще.

  • Отсутствие встроенных механизмов аутентификации. Moon версии 1.x поддерживает только базовую HTTP аутентификацию. Moon версии 2.x в свою очередь не предоставляет встроенного механизма аутентификации вообще. Вместо этого для реализации любого нужного вам механизма аутентификации (например mutual TLS authentication) вы можете использовать уже существующее программное обеспечение совместимое с Kubernetes, например Nginx Ingress Controller). Moon получает имя пользователя из HTTP заголовков Authorization или X-Moon-Quota. Более развернуто это описано в раздел Пользователи.

  • Поддержка OpenID Connect. Moon версии 2.x содержит готовый к использованию контейнер для использования механизма аутентификации OpenID Connect. Это позволяет легко использовать уже существующий публичную или корпоративную реализацию протокола OAuth. Например, вы можете легко загрузить существующих Github пользователей.

  • Улучшена поддержка самоподписанных корневых центров сертификации TLS. Компании часто используют самоподписанные TLS сертификаты для внутренних веб-сервисов. В Moon 2.x настройка работы с такими самоподписанными сертификатами делается один раз в конфигурации Moon для всех компонентов Moon и версий браузеров (нужно прописать сертификат внутреннего центра сертификации).

    Moon 2 самоподписанный корневой сертификат
    apiVersion: moon.aerokube.com/v1
      kind: Config
      metadata:
        annotations:
        name: default
        namespace: moon
      spec:
        additionalTrustedCAs: |
          -----BEGIN CERTIFICATE-----
          ...
  • Расширенные возможности Selenium. Moon полностью совместим с W3C Webdriver protocol. Это означает что все возможности Selenium 4.x будут доступны сразу после установки. В дополнение к стандартной функциональности Moon дает возможность расширения некоторых возможностей, таких как взаимодействие с буфером обмена или сохранение файлов из контейнера. Например, вы легко можете скопировать и вставить произвольные текстовые данные и изображения из ваших тестов в буфер обмена браузера. Также вы можете ходить через прокси-сервис с аутентификацией.

1.6. Moon и другие решения

Moon использует лучшие практики и возможности существующих решений по автоматизации браузерного тестирования и добавляет еще больше полезного:

  1. Универсальный инструмент для тестирования в браузерах. Moon поддерживает все самые популярные технологии тестирования в браузерах, такие как Selenium, Playwright, Cypress, Puppeteer без необходимости какой-либо дополнительной настройки. Новые образы с браузерами собираются и публикуются автоматически.

  2. Автоматическая неограниченная масштабируемость. В кластере у вас будет всегда достаточное количество браузеров любой желаемой версии. При поднятии кластера в облачных платформах типа Yandex Cloud или Cloud.ru вы можете настроить автоматическое масштабирование, которое будет применяться в зависимости от текущей загрузки. Это позволит совместить производительность и приемлемую цену вычислительных ресурсов.

  3. Не имеет внутреннего состояния (stateless). Selenoid и Selenium Grid 3.x хранят в памяти всю информацию о запущенных в данный момент браузерах. Selenium Grid 4.x с той же целью использует механизм хранения списка сессий в key-value хранилище (например Redis). Если по какой-то причине информация о запущенных сессиях браузера теряется - все сессии закрываются. Moon в свою очередь не хранит состояние сессии в себе (это делается в Kubernetes), может реплицироваться на несколько датацентров. При рестарте реплики или ее остановке сессии не обрываются.

  4. Полный контроль потребления вычислительных ресурсов. Moon позволяет легко настроить потребляемые вычислительные ресурсы для каждого компонента. Расход вычислительных ресурсов становится предсказуемым, стоимость кластера становится легко подсчитать.

  5. Высокая доступность. Любое изменение настроек кластера не прерывает работу браузерных сессий. Каждый компонент кластера завершает работу безопасно без разрыва сессий.

2. Основная функциональность

2.1. Веб интерфейс

  1. Данный веб-интерфейс доступен начиная с версии Moon 2.4.0.

  2. Данный веб-интерфейс включен по-умолчанию, начиная с версии Moon 2.6.2. Для более старых версий его поддержку нужно включить явно при установке Moon. Для включения - используйте следующий параметр в значениях Helm чарта:

    deployment:
      experimentalUI: true

    После включения новый веб интерфейс автоматически доступен по обычному адресу Moon c добавлением /ui/ в конец, например https://moon.example.com/ui/. Старый интерфейс по прежнему доступен по старому адресу (например https://moon.example.com/), в дальнейшем, планируется отказаться от старого интерфейса полностью.

В Moon реализован пользовательский интерфейс, который позволяет выводить список браузерных сессий, фильтровать их по какому-либо признаку, отображать экран браузера, запускать сессии для ручного тестирования и так далее.

Общий вид веб интерфейса Moon UI

moon ui general view

Главная страница веб интерфейса отображает список стартующих и уже запущенных браузерных сессий. Для каждой сессии вы можете увидеть имя браузера, версию, название теста, метку, статус, длительность работы и так далее. Для удаления текущей сессии вам необходимо дважды кликнуть на кнопку с иконкой мусорной корзины (два клика необходимы для предотвращения случайного нажатия и удаления сессии). Для того чтобы создать сессию для ручного тестирования, нажмите на кнопку с названием браузера вверху веб интерфейса.

Фильтрация в интерфейсе Moon UI

moon ui session filters

В одном кластере Moon параллельно могут запускаться десятки, сотни или даже тысячи браузерных сессий. Используйте фильтрацию, чтобы найти сессию, относящуюся к вашему проекту или определенному номеру сборки. Вы можете отфильтровать сессии по id, имени and меткам Kubernetes:

  • Идентификатор сессии это уникальное значение, которое Moon автоматически генерирует для каждой сессии. Изменить его нельзя. Полный идентификатор выглядит так (пример): chrome-73-0-ac15ffaa-e641-4c7f-a54c-f25b5be1f135. В веб интерфейсе отображается только несколько первых символов из этого длинного значения.

  • Название сессии - это задаваемое в произвольной форме значение для того, чтобы, при необходимости, описать цель создания сессии. Обычно название совпадает с названием проверяемого тест кейса. Для изменения названия сессии используйте капабилити name для Selenium либо URL параметр name для Playwright, Cypress или Developer tools, например:

    wss://moon.example.com/playwright/chromium?name=MyTestCaseName
  • Метки сессии это пары ключ-значение, задаваемые в произвольной форме, позволяющие вам добавить дополнительные метаданные к каждой сессии. Это может быть, к примеру, номер сборки, имя проекта, информация о номере релиза и так далее. Для добавления меток используйте функциональность labels capability в Selenium или задайте их в конфигурации браузеров. Каждая метка в Moon конвертируется в Kubernetes label и добавляется на соответствующий под. При задании меток используются точно такой же синтаксиси, как в Kubernetes label selectors. Например, если заданы метки project (название проекта) и buildNumber (номер сборки), то по ним можно фильтровать так:

    Фильтрация по меткам
    project=MyCoolProject # Полное совпадение одной из меток
    
    project=MyCoolProject,buildNumber=42 # Полное совпадение значений меток project и buildNumber
    
    project in (MyCoolProject, AnotherProject),buildNumber!=42 # Выбрать project из списка
    
    project notin (MyCoolProject, AnotherProject),!buildNumber # Выбрать project не из списка, buildNumber не задано
    
    project!=AnotherProject,buildNumber # Любое значение project кроме AnotherProject, buildNumber выставлено
Веб интерфейс Moon и экран браузера

moon ui browser screen

При нажатии на строчку в списке сессий будет автоматически отображен экран браузера, если это действие применимо к сессии. Например, для сессии, запущенной в режиме без экрана (headless) при нажатии на строчку не произойдет ничего. По умолчанию экран браузера отображается только в режиме для чтения, чтобы случайно не вмешаться в работу уже запущенных тестов. Для того чтобы начать взаимодействие с браузером - нажмите на значок замка (🔒) и экран разблокируется. Кликните на значок еще раз - экран браузера станет вновь "только для чтения". На экране браузера вы можете наблюдать выполнение автоматического теста и вмешиваться при необходимости. При запуске браузера для ручного тестирования вы можете использовать экран браузера для поэтапного прохождения вашего тестового сценария. Все возможности браузера (например, инструменты разработчика) доступны и работают в точности так же как и на физической машине. Используйте привычные сочетания клавиш Ctrl+C\Ctrl+V или Cmd+C\Cmd+V для копирования и вставки значений с вашего компьютера в экран браузера в Moon.

2.1.1. Консоль

Эта функциональность доступна начиная с версии Moon 2.6.1.

Консоль это интерфейс командной строки доступный в экране пользовательского интерфейса Moon, который дает больше возможностей для ручного тестирования. Имеются следующие возможности:

  • Вывод списка доступных браузеров и мобильных устройств эмуляции.

  • Запуск, вывод списка, удаление браузерных сессий с работающими браузерами и с включенной эмуляцией мобильных устройств.

  • Легкое предоставление произвольных дополнительных возможностей браузера.

  • Открытие сессии VNC для ручного тестирования

Консоль выглядит так:

Консоль Moon

moon ui console

Чтобы открыть консоль:

  • Вариант 1. Кликните на кнопку, показанную на картинке.

  • Вариант 2. Нажмите на значок ~ (тильда) на клавиатуре.

Консоль Moon работает подобно стандартному терминалу Unix. Для вывода списка доступных команд наберите:

Вывод списка доступных команд
moon$ -h
Usage:
  create
  delete
  list
  get
  vnc
  clear
  exit

Описание синтаксиса команд доступно при добавлении флага -h или -help:

Помощь по синтаксису команд
moon$ delete -h
Desc:
  delete - stop session

Usage:
  delete <session-id>

Предыдущие набранные команды доступны при нажатии стрелок вверх и вниз на клавиатуре. Очистить вывод предыдущих команд можно стандартным способом:

Очистка экрана консоли
moon$ clear

Для выхода из консоли просто закройте окно кнопкой либо наберите:

Выход из консоли
moon$ exit

Список доступных браузеров можно вывести так:

Вывод списка доступных браузеров
moon$ get browser
opera
safari
MicrosoftEdge
chrome
firefox

Для вывода списка только последних пяти версий браузера chrome наберите:

Вывод списка доступных браузеров
moon$ get browser -n chrome -l 5
120.0.6099.224-6 (default)
# Если в объекте browser set определено больше версий, они будут показаны здесь

Вывод списка доступных мобильных устройств:

Вывод списка доступных мобильных устройств
moon$ get device -e "iPhone X" # Частичное совпадение по имени
"Apple iPhone X"
"Apple iPhone XR"
"Apple iPhone Xs"
"Apple iPhone Xs Max"
moon$ get device -e "iPhone X$" # Совпадение по регулярному выражению
"Apple iPhone X"

Для запуска браузера Chrome наберите:

Запуск настольного браузера
moon$ create browser -n chrome # Версия Chrome по-умолчанию
chrome-120-0-124bcfdf-6f03-424c-80b4-6c2ee5b2f36f # Это ID запущенной сессии
moon$ create browser -n chrome -v 120.0 # Конкретная версия Chrome
moon$ create browser -n chrome -caps '{"goog:chromeOptions": {"args": ["start-maximized"]}}' # Дополнительные капабилити Selenium в формате JSON

Запуск мобильных устройств:

Запуск мобильной эмуляции
moon$ create device -n "Apple iPhone Xs" -url https://aerokube.com/
chrome-120-0-6099-224-6-46e1198c-f73d-401d-be6c-6e127ef53f24

Открытие VNC для браузерной сессии:

Просмотр браузерной сессии
moon$ vnc chrome-120-0-6099-224-6-46e1198c-f73d-401d-be6c-6e127ef53f24

Список запущенных сессий браузера:

Список сессий
moon$ list
chrome-120-0-124bcfdf-6f03-424c-80b4-6c2ee5b2f36f

Удаление работающей сессии:

Удаление браузерной сессии
moon$ delete chrome-120-0-124bcfdf-6f03-424c-80b4-6c2ee5b2f36f

2.2. Работа с Selenium

Мы создали несколько простых проектов с исходным кодом, демонстрирующих использование Moon с разными Selenium библиотеками:

Запуск тестов Selenium в Moon является довольно простой задачей. Используйте следующий Selenium URL в ваших тестах:

Selenium URL
https://moon.example.com/wd/hub

Moon полностью совместим с W3C WebDriver specification, все стандартные возможности Selenium будут доступны сразу после установки. Выбор браузера делается выставлением capability browserName в вашем коде, например:

Пример теста Selenium на Python
from selenium import webdriver

capabilities = {
    "browserName": "chrome"
}

driver = webdriver.Remote(
    command_executor='https://moon.example.com/wd/hub',
    desired_capabilities=capabilities
)

Версия браузера, которая будет использована для теста, зависит от конфигурации Moon, по умолчанию берется самая последняя доступная версия. Явно задать версию можно с помощью значения capability browserVersion:

Задание конкретной версии браузера
capabilities = {
    "browserName": "chrome",
    "browserVersion": "96.0"
}

С помощью расширений протокола WebDriver Moon предоставляет дополнительные возможности, описанные ниже.

2.2.1. Дополнительные Selenium capability, поддерживаемые Moon

Moon поддерживает набор расширенных Selenium capabilities. Значения, включающие определенную функциональность Moon, задаются в коде в ключе moon:options:

Задание Moon capabilities
capabilities = {
    "browserName": "chrome",
    "moon:options": { # Все капабилити, специфичные для Moon, находятся в ключе moon:options
        "enableVideo": True,
        "screenResolution": "1280x1024"
    }
}

В строго типизированных языках типа Java или C# для задания Moon capabilities нужно использовать Map (Dictionary), например:

Задание Moon capabilities в Java
capabilities.setCapability("moon:options", Map.of(
    "screenResolution", "1280x1024"
));
Разрешение экрана: screenResolution

Moon позволяет изменить разрешение экрана браузера:

Тип: строка, формат: <ширина>x<высота>
screenResolution: "1280x1024"

Можно изменить глубину цвета:

Тип: строка, формат: <ширина>x<высота>x<глубина-цвета>
screenResolution: "1280x1024x24"

Эта capability задает разрешение экрана рабочего стола, а не размер окна браузера. В большинстве браузеров размер открываемого окна задается по умолчанию, поэтому размер скриншота может быть меньше чем заданное разрешение экрана. Изменить размер окна можно вручную, либо используя функцию maximize в Selenium.

Имя теста: name

Во время отладки часто полезно задать конкретное название для каждого теста. Это можно сделать с помощью следующей capability:

Тип: строка
name: "myCoolTestName"

Основное применение этой capability - отладка тестов в графическом интерфейсе, она показывает название конкретного теста для каждой сессии.

Запись видео: enableVideo, videoName, videoScreenSize, videoFrameRate, videoCodec, pattern
Запись видео необходимо настроить заранее.

Для включения записи видео для сессии добавьте капабилити:

Тип: boolean
enableVideo: true
  • По умолчанию полученная видеозапись называется video.mp4. Задать другое имя можно так:

    Тип: строка
    videoName: "my-cool-video.mp4"
    В название файла обязательно добавляйте расширение файла - mp4.
  • По умолчанию записывается вся картинка в экране. Capability screenResolution позволяет изменить высоту и ширину записываемого видео. Также с помощью capability вы можете поменять экранный размер записываемого видео. В случае если заданная capability videoScreenSize меньше чем настоящий размер экрана - видео будет обрезано начиная с верхнего левого угла.

    Тип: строка
    videoScreenSize: "1024x768"
  • Частота кадров по умолчанию составляет 12 кадров в секунду. Сapability videoFrameRate позволяет изменить это значение:

    Тип: целое число
    videoFrameRate: 24
  • По умолчанию для вывода видео Moon использует кодек libx264. Если этот кодек использует слишком много процессорного времени вы можете изменить его с помощью capability videoCodec:

    Тип: строка
    videoCodec: "mpeg4"
  • Для организации своей иерархии хранения в S3 для загружаемых видео используйте capability pattern (или s3KeyPattern):

    Тип: строка
    pattern: "$quota/$browserName/$sessionId"
Сбор сетевой активности веб-страницы: enableHAR
  1. Данная функциональность доступна начиная с Moon версии 2.7.2.

  2. Использование данной капабилити требует предварительной настройки S3 хранилища.

В некоторых случаях вам может потребоваться собрать все HTTP-запросы, отправляемые браузером в течение Selenium сессии. Moon может автоматически сохранять весь сетевой трафик браузероа в так называемый HAR файл и загружать его в S3 хранилище. Для того чтобы включить сбор сетевой активности браузерной сессии, добавьте следующую капабилити:

Тип: boolean
enableHAR: true
Переменные окружения в сессии: env

Иногда вам может потребоваться задать переменные окружения для каждого тестового сценария (например для тестирования разных локалей). Используйте capability :

Тип: массив, формат: <ключ>=<значение>
env: ["LANG=ru_RU.UTF-8", "LANGUAGE=ru:en", "LC_ALL=ru_RU.UTF-8"]

Переменные окружения, заданные таким образом, добавляются к переменным, заданным в конфигурации Moon. Для использования этой capability в строго типизированных языках типа Java или C# используйте List:

Задание переменных env в Java
capabilities.setCapability("moon:options", Map.of(
    "env", Arrays.asList("LANG=ru_RU.UTF-8", "LANGUAGE=ru:en", "LC_ALL=ru_RU.UTF-8")
));
Дополнительные записи в /etc/hosts: hosts

Для каждого образа вы можете сконфигурировать отдельный список псевдонимов имени хоста в файле /etc/hosts в browsers set. Но иногда вам необходимо добавить еще несколько значений для конкретного тестового сценария. Это можно сделать следующим образом:

Тип: массив, формат: <имя-хоста>:<ip-адрес>
hosts: ["example.com:192.168.0.1", "test.com:192.168.0.2"]

Значения, заданные таким образом, переопределяют значения в /etc/hosts.

Используемые DNS сервера: nameservers

По умолчанию браузерные поды используют DNS сервера, заданные в Kubernetes. Иногда вам может потребоваться переопределить эти значения для конкретного тестового сценария. Это можно сделать следующим образом:

Тип: массив, формат: <ip-адрес-dns-сервера>
nameservers: ["192.168.0.1", "192.168.0.2"]
Переопределение таймаута сессии: sessionTimeout

Иногда вам может потребоваться изменить максимальное время простоя (idle timeout) для некоторых браузерных сессий. Это можно сделать при помощи следующей capability:

Тип: строка
sessionTimeout: "1m30s"

Таймаут всегда указывается в формате Golang - 30s or 2m or 1h2m30s и тому подобное.

Эмуляция мобильных устройств: mobileDevice

Следующая capability позволяет сконфигурировать эмуляцию мобильных устройств:

Type: object
"mobileDevice": {
    "deviceName": "Apple iPhone XR",
    "orientation": "landscape"
}

Выбрать устройство для эмуляции можно с помощью ключа deviceName:

Тип: строка
deviceName: "Apple iPhone XR"

Задать нужную ориентацию устройства (альбомную или портретную) можно с помощью ключа orientation:

Тип: строка
orientation: "landscape"

Возможные значения ключа orientation: portrait, vertical (то же что и portrait), landscape, horizontal (то же что и landscape). В строго типизированных языках типа Java или C# используйте Map:

Задание mobileDevice в Java
capabilities.setCapability("moon:options", Map.of(
    "mobileDevice", Map.of(
        "deviceName": "Apple iPhone XR",
        "orientation": "landscape"
    )
));
Метки подов: labels

В некоторых случаях возникает необходимость передать дополнительные метаданные к каждой браузерной сессии, например, окружение, информацию из системы контроля версий, номер сборки, название проекта и так далее. Эти метки могут быть использованы для сбора различной статистики по использованию браузеров.

Тип: ассоциативный массив, формат: "<ключ>": "<значение>"
labels: {"project": "MyCoolProject", "build-number": "14353"}

Метки, заданные этой capability переопределяют метки из описания конфигурации браузера. Больше информации о метках доступно по ссылке Using Custom Kubernetes Labels.

Уровень логирования браузерной сессии: logLevel
Эта функция доступна начиная с версии Moon 2.2.0 и выше.

По умолчанию логирование браузерных сессий в Moon очень ограничено с целью снизить нагрузку на кластер и системы логирования в целом. Вы можете поменять уровень логирования с помощью capability logLevel:

Тип: строка
logLevel: "INFO"

Список поддерживаемых браузеров: Google Chrome, Microsoft Edge, Opera и Firefox. Возможные значения для этой capability зависят от браузера:

Table 5. Поддерживаемые уровни логирования для Chrome, Microsoft Edge и Opera
Значение капабилити

ALL

DEBUG

INFO

WARNING

SEVERE

OFF

Table 6. Поддерживаемые уровни логирования для Firefox
Значение капабилити

fatal

error

warn

info

config

debug

trace

Подключение дополнительных шрифтов: additionalFonts
  1. Эта функциональность доступна начиная с Moon версии 2.2.1.

  2. При запуске сессии для ручного тестирования из Moon UI эта функциональность включается автоматически.

  3. При подключении этой функциональности шрифты копируются в браузерный контейнер для каждого нового пода, как результат - браузеры могут стартовать немного медленнее.

По умолчанию браузеры запускаемые в Moon не поддерживают китайский, японский, тайский и другие азиатские языки. Подключить шрифты, содержащие японские/китайские и т.д. символы можно с помощью еще одной capability:

Тип: boolean
additionalFonts: true
Дополнительные данные для браузера: context

Эта функциональность доступна начиная с версии Moon 2.3.0.

Эта capability позволяет загружать произвольные данные на браузерный под. Запакуйте все необходимые файлы в архив *.tar.gz, значение capability должно содержать полный URL до места хранения архива. Более подробную информацию вы можете найти здесь.

Тип: строка
context: "https://example.com/browser-data.tar.gz"
Отключить менеджер окон: windowManager

Эта функциональность доступна начиная с версии Moon 2.7.0.

Менеджер окон - системное приложение, которое контролирует расположение и внешний вид окон в оконном графическом пользовательском интерфейсе. По-умолчанию, все браузеры запускаются с включенным менеджером окон. Данная капабилити позволяет отключить запуск менеджера окон. Основное изменение, которое при этом произойдет - у окон пропадут заголовки и рамки. Вы не сможете вручную поменять размер или переместить окно браузера при ручном тестировании, но вы по-прежнему можете это делать при помощи кода.

Тип: boolean
windowManager: false # По-умолчанию true
Автоматически выбирать сертификат клиента для взаимной TLS аутентификации: autoSelectClientCerts
  1. Эта функциональность доступна начиная с версии Moon 2.7.2.

  2. Данная капабилити работает только с браузером Chrome.

Некоторые тестируемые приложения сегодня используют так называемую взаимную TLS аутентификацию. Чтобы автоматически выбирать первый доступный TLS сертификат клиента, используйте капабилити:

Тип: boolean
autoSelectClientCerts: true

2.2.2. Headless режим

По умолчанию все браузеры в Moon стартуют в экранном режиме (вы можете видеть окно браузера). Большинство браузеров в наши дни поддерживают так называемый "безэккранный" ("headless") режим, когда страницы открываются в фоновом режиме и пользователь не видит никаких окон. Обычно этот режим включается флагом --headless в команде запуска браузера в Selenium capabilities.

Запуск Chrome в headless режиме
capabilities = {
    "browserName": "chrome",
    "goog:chromeOptions": {
        "args": ["--headless"]
    }
}

Moon автоматически распознает когда браузер стартует в headless режиме. Браузеры, запущенные в таком режиме, не используют графические компоненты типа Х-сервера или оконного менеджера, соответственно Moon также не запускает эти компоненты. Благодаря наличию поддержки headless режима нет необходимости указывать капабилити enableVNC, чтобы отображать окно браузера в интерфейсе Moon.

2.2.3. Запись видео

Запись видео должна быть настроена при установке Moon.

Если видеозапись включена, то для того, чтобы записать видео, вам нужно добавить еще одну capability в ваш тест:

Включение видеозаписи в Selenium капабилити
capabilities = {
    "moon:options": {
        "enableVideo": True
    }
}

Чтобы поменять название видео, размер экрана, частоту кадров и так далее нужно добавить одну из соответствующих капабилити.

2.2.4. Эмуляция мобильных устройств

  1. Эта функциональность доступна начиная с версии Moon 1.8.0 и выше.

  2. Эмуляция работает только с Chrome.

  3. Тестирование мобильных приложений невозможно.

Автоматическое тестирование мобильных платформ весьма актуально в наши дни. Использование настоящих устройств, подключенных к серверу через USB, требует слишком много усилий по настройке и поддержке. Использование эмуляторов Android требует настоящих железных серверов либо виртуальных машин с включенной вложенной виртуализацией. Запуск симуляторов iOS требует использования настоящих устройств от Apple. Даже при правильном расчете вычислительных ресурсов такие тесты выполняются медленнее и потребляют гораздо более памяти и процессорного времени чем настольные браузеры на физических машинах.

При этом основной целью тестирования является выявление как можно большего количества багов, а не сложное и дорогостоящее развертывание инфраструктуры автоматизации тестирования. В то же время, большое количество багов мобильной версии веб-приложения можно воспроизвести послав нужный HTTP заголовок User-Agent в браузер и выставив такой же размере экрана, как и в реальном мобильном устройстве. Подобная функциональность уже доступна в Chromium-based браузерах и называется эмуляция мобильных устройств.

Вот пример capabilities для включения этой функциональности:

Мобильная эмуляция в Java
ChromeOptions options = new ChromeOptions();
options.setCapability("browserVersion", "96.0");
options.setCapability("moon:options", Map.of(
    "mobileDevice", Map.of(
        "deviceName", "Apple iPhone XR",
        "orientation", "landscape",
    )));
Мобильная эмуляция в Python
capabilities = {
    "browserName": "chrome",
    "browserVersion": "96.0",
    "moon:options": {
        "mobileDevice": {
            "deviceName": "Apple iPhone XR",
            "orientation": "landscape"
        }
    }
}

Moon поставляется с готовым списком поддерживаемых устройств, хранящийся в объекте конфигурации устройств. Полный список доступных устройств содержится в разделе Supported Mobile Devices. Отредактируйте список для добавления вашего устройства.

2.2.5. Доступ к буферу обмена

  1. Буфер обмена доступен только пока браузерная сессия запущена.

  2. При использовании изображений поддерживается только формат PNG.

  3. Если имеется установленный Lightning клиент доступ к буферу обмена работает сразу после установки.

Иногда вам может потребоваться взаимодействовать с буфером обмена, чтобы проверить работоспособность копирования/вставки текста. В Moon реализован специальный API для этой цели.

  1. Запустите новую сессию, например с идентификатором firefox-95-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840.

  2. Для получения доступа к буферу обмена необходимо послать следующий HTTP запрос:

    $ curl -H 'Accept: application/json' https://moon.example.com/wd/hub/session/firefox-95-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840/aerokube/clipboard
    
    {"value": "some-clipboard-value", "media": ""}

    Если буфер обмена содержит графическое изображение, ответ будет содержать байты закодированного в Base64 изображения:

{"value": "iVBORw0KGgoAAAAN....", "media": "image/png"}
  1. Следующим запросом вы можете вставить в буфер обмена текстовое значение:

    $ curl -X POST -H 'Content-Type: application/json' --data '{"value": "some-clipboard-value"}' https://moon.example.com/wd/hub/session/firefox-95-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840/aerokube/clipboard
  2. Для того чтобы вставить в буфер обмена изображение - пошлите закодированные в Base64 байты изображения:

    $ curl -X POST -H 'Content-Type: application/json' --data '{"value": "iVBORw0KGgoAAAAN....", "media": "image/png"}' https://moon.example.com/wd/hub/session/firefox-95-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840/aerokube/clipboard

2.2.6. Загрузка файлов в браузер

Загрузка файлов в браузер - это встроенная в Selenium функциональность, поддерживаемая большинством Selenium клиентов. Далее показано несколько примеров как делается загрузка в других клиентах:

  1. Загрузка в standard Java client

// Находим поле для загрузки файла
WebElement input = driver.findElement(By.cssSelector("input[type='file']"));

// Убеждаемся, что элемент отображается
((JavascriptExecutor) driver).executeScript("arguments[0].style.display = 'block';", input);

// Настраиваем Selenium клиента для загрузки локальных файлов на удаленный сервер
driver.setFileDetector(new LocalFileDetector());

// Specify you local file path here (not path inside browser container!)
input.sendKeys("/path/to/file/on/machine/which/runs/tests");
Загрузка в Lightning Java client
// Находим поле для загрузки файла
WebElement fileInput = driver.elements().findFirst(By.cssSelector("input[type='file']"));

// Загружаем файл
Path fileToUpload = Paths.get("/path/to/file/on/machine/which/runs/tests");
String fileRemotePath = driver.document().uploadFile(fileToUpload);

// Устанавливаем путь до файла как значение поля для загрузки файла
fileInput.sendKeys(fileRemotePath);
Загрузка в Python
from selenium.webdriver.remote.file_detector import LocalFileDetector

# ...

# Находим поле для загрузки файла
input = driver.find_element_by_css_selector("input[type='file']")

# Убеждаемся, что элемент отображается
driver.execute_script("arguments[0].style.display = 'block';", input)

# Загружаем файл
driver.file_detector = LocalFileDetector()
input.send_keys("/path/to/file/on/machine/which/runs/tests")
Загрузка в C#
// Создаем драйвер в Selenium
ChromeOptions options = new ChromeOptions();
IWebDriver driver = new RemoteWebDriver(new Uri("https://moon.example.com/wd/hub"), options);

// Открываем страницу
driver.Navigate().GoToUrl("https://example.com/");

// Загружаем файл
IAllowsFileDetection allowsDetection = (IAllowsFileDetection)driver;
allowsDetection.FileDetector = new LocalFileDetector();
driver.FindElement(By.Id("uploadfile_0")).SendKeys("/tmp/file.txt");
Загрузка в Webdriver.io
var filePath = path.join('/path/to/file/on/machine/which/runs/tests');
var remoteFilePath = browser.uploadFile(filePath);
$("input[type='file']").setValue(remoteFilePath);

2.2.7. Дополнительные данные для браузера

  1. Эта функциональность доступна начиная с версии Moon 2.3.0.

  2. Поддерживаются только архивы упакованные в *.tar.gz. Поддержки *.zip архивов нет по причине более низкой производительности.

Часто при работе с браузером вам нужны дополнительные данные: расширения браузера, тестовые файлы, файлы настроек браузера (профиль) и так далее. В обычном Selenium такая информация передается во фрагментах кода. Важно знать что все эти данные передаются в теле HTTP запроса. Каждый раз, пересылая файл или изображение, Selenium сначала считывает данные в память, что резко повышает потребление памяти. Другой, более эффективный путь передачи этих данных - упаковка их в архив (например на стороне CI сервера). URL со ссылкой на такой архив посылается как Selenium capability, что позволяет каждой браузерной сессии загрузить данные, а только после этого запускать браузер. Такой архив мы называем контекст браузера, соответствующая capability называется просто context:

Тип: строка
context: https://example.com/browser-data.tar.gz

При использовании капабилити context Moon загрузит и распакует архив в директорию /home/<user>, где <user> это имя пользователя, созданного на этапе configuration object. Имя пользователя по умолчанию - user, соответственно директория по умолчанию - /home/user/.

Как распаковывается архив
browser-data.tar.gz    ===>     /home/user
|                               |
---- some-file.txt              ---- some-file.txt
---- some-directory             ---- some-directory
     |                               |
     ---- another-file.xpi           ---- another-file.xpi
     ---- one-more-file.png          ---- one-more-file.png

Как создать архив:

Создание архива с дополнительными данными для браузера
$ tar cvzf browser-data.tar.gz some-file.txt some-directory # Добавьте произвольное количество файлов и каталогов с данными

Возможные сценарии использования этой функциональности:

  1. Загрузка файлов. Можете упаковать любые файлы необходимые для теста и указать путь к файлу, либо открыть их в браузере:

    Капабилити для загрузки тестовых файлов в браузер
    {
      "browserName":"chrome",
      "moon:options":{"context":"https://example.com/browser-data.tar.gz"}
    }

    То же самое можно сделать запросом HTTP:

    HTTP запрос для загрузки тестовых файлов в браузер
    $ curl https://moon.example.com/wd/hub/session -d'{"capabilities":{"alwaysMatch":{"browserName":"chrome", "moon:options":{"context":"https://example.com/browser-data.tar.gz"}}}}'

    Распаковка файлов в коде Selenium:

    Использование тестовых файлов из архива
    // Находим поле для загрузки файла
    WebElement input = driver.findElement(By.cssSelector("input[type='file']"));
    
    // Указываем путь до файла из директории с контекстом
    input.sendKeys("/home/user/some-directory/one-more-file.png");
    
    // Такой файл можно и просто открыть в браузере
    driver.get("file:///home/user/some-file.txt");
  2. Использование расширений браузера. Упакуйте файл расширения (extension.crx) в архив (extension.tar.gz) и загрузите с помощью командной строки:

    Как перепаковать расширение в *.tar.gz
    $ unzip extension.crx -d extension # То же самое работает и для *.xpi файлов, т.к. оба являются zip архивами
    $ tar cvzf extension.tar.gz extension

    Соответствующие capabilities выглядят примерно так:

    Капабилити, чтобы активировать браузерное расширение
    {
      "browserName":"chrome",
      "goog:chromeOptions":{
        "args":[
          "--disable-extensions-except=/home/user/extension",
          "--load-extension=/home/user/extension"
        ]
      },
      "moon:options":{"context":"https://example.com/extension.tar.gz"}
    }

    То же самое, но с помощью запроса HTTP:

    HTTP запрос, чтобы активировать браузерное расширение
    $ curl https://moon.example.com/wd/hub/session -d'{"capabilities":{"alwaysMatch":{"browserName":"chrome", "goog:chromeOptions":{"args":["--disable-extensions-except=/home/user/extensions","--load-extension=/home/user/extensions"]}, "moon:options":{"context":"https://example.com/extensions.tar.gz"}}}}'
  3. Переопределение профиля браузера. Упакуйте директорию с профилем браузера (profile) в архив (profile.tar.gz) затем загрузите с помощью команд в браузере. Соответствующая capabilities в Chrome выглядит примерно так:

    Капабилити для использования готового профиля Chrome
    {
      "browserName":"chrome",
      "goog:chromeOptions":{
        "args":["--user-data-dir=/home/user/profile"]
      },
      "moon:options":{"context":"https://example.com/profile.tar.gz"}
    }

    То же самое с помощью запроса HTTP:

    HTTP запрос для использования готового профиля в Chrome
    $ curl https://moon.example.com/wd/hub/session -d'{"capabilities":{"alwaysMatch":{"browserName":"chrome", "goog:chromeOptions":{"args":["--user-data-dir=/home/user/profile"]}, "moon:options":{"context":"https://example.com/profile.tar.gz"}}}}'

    Для Firefox используйте другие аргументы командной строки:

    Капабилити для использования готового профиля в Firefox
    {
      "browserName":"firefox",
      "moz:firefoxOptions":{
        "args":["-profile","/home/user/profile"]
      },
      "moon:options":{"context":"https://example.com/profile.tar.gz"}
    }

    То же самое используя запрос HTTP:

    HTTP запрос для использования готового профиля в Firefox
    $ curl https://moon.example.com/wd/hub/session -H'Content-Type: application/json' -d'{"capabilities":{"alwaysMatch":{"browserName":"firefox", "moz:firefoxOptions":{"args":["-profile","/home/user/profile"]}, "moon:options":{"context":"https://example.com/profile.tar.gz"}}}}'
  4. Переопределение настроек пользователя. Ранее мы объясняли что архив с контекстом браузерами распаковывается в поде браузера в домашнюю директорию. Это дает возможность переопределить некоторые конфигурационные файлы операционной системы и директории, (~/.bashrc, ~/.gtkrc-3.0 с целью отключить мерцание курсора, например, или директории ~/.ssh, ~/.gpg и так далее).

  5. Эмуляция видео с камеры. Вы можете загрузить видео в браузерный под и использовать это в качестве готового видео с веб-камеры. Начните с подготовки готового видео:

    Преобразуем *.mp4 видео в *.y4m
    $ mkdir webcam-video
    $ ffmpeg -i my-video.mp4 -vf hflip -pix_fmt yuv420p -s 1280x720 webcam-video/webcam-video.y4m

    Результат упакуйте в архив:

    Создаем архив с видео
    $ tar cvzf webcam-video.tar.gz webcam-video

    С помощью архива создайте сессию Chrome с такими capabilities:

    Капабилити для эмуляции веб-камеры в Chrome
    {
      "browserName":"chrome",
      "goog:chromeOptions":{
        "args":[
          "--disable-gpu",
          "--use-fake-ui-for-media-stream",
          "--use-fake-device-for-media-stream",
          "--use-file-for-fake-video-capture=/home/user/webcam-video/webcam-video.y4m"
        ]
      },
      "moon:options":{"context":"https://example.com/webcam-video.tar.gz"}
    }

    То же самое с помощью запроса HTTP:

    HTTP запрос для эмуляции веб-камеры в Chrome
    $ curl https://moon.example.com/wd/hub/session -H'Content-Type: application/json' -d'{"capabilities":{"alwaysMatch":{"browserName":"chrome", "goog:chromeOptions":{"args":["--disable-gpu", "--use-fake-ui-for-media-stream", "--use-fake-device-for-media-stream", "--use-file-for-fake-video-capture=/home/user/webcam-video/webcam-video.y4m"]},"moon:options":{"context":"https://example.com/webcam-video.tar.gz"}}}'

2.2.8. Доступ к загруженным из браузера файлам

  1. Файлы доступны только при запущенной браузерной сессии.

  2. В клиенте Lightning эта функциональность работает по умолчанию.

В процессе тестирования иногда необходимо загрузить файл из браузера. Чтобы проанализировать эти файлы, необходимо как-то достать их с браузерного контейнера. Для этих целей Moon предоставляет API:

  1. Запустите новую сессию, например с идентификатором firefox-95-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840.

  2. В коде тестов задайте сохранение файлов в директорию /home/<user>/Downloads, где <user> это имя пользователя сконфигурированного на этапе configuration object. Имя пользователя по умолчанию - user, соответственно название директории - /home/user/Downloads.

  3. Вывести список доступных файлов можно командой:

    curl -H 'Accept: application/json' https://moon.example.com/wd/hub/session/firefox-95-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840/aerokube/download/
    
    {"value": ["myfile.txt", "another-file.png"]}
  4. Любой из этих файлов доступен по следующему адресу URL:

    curl https://moon.example.com/wd/hub/session/firefox-95-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840/aerokube/download/myfile.txt
    
    file-contents-go-here
  5. Удаление файла:

    curl -X DELETE https://moon.example.com/wd/hub/session/firefox-95-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840/aerokube/download/myfile.txt
  6. Закройте сессию.

2.2.9. Доступ к инструментам разработчика

  1. Эта функциональность работает в версии Moon 2.1.0 и выше.

  2. Эта функциональность требует первоначального создания Selenium сессии. Если вы хотите использовать инструменты разработчика совместно с Puppeteer - ознакомьтесь с документацией по ссылке documentation section.

  3. Для корректной работы этой функциональности нужен полный URL адрес кластера. Удостоверьтесь в Ingress настроено проксирование HTTP заголовков X-Forwarded-Host, X-Forwarded-Port и X-Forwarded-Scheme. Если вы используете AWS ALB или используете Moon без Ingress проксирование заголовков не производится. В этом случае вам необходимо задать Moon -callback-url flag, например -callback-url https://moon.example.com/, иначе данная функциональность будет работать неправильно.

В Selenium 4 и выше реализована bidirectional functionality, которая дает доступ к продвинутой функциональности браузеров, и это работает без необходимости дополнительной конфигурации. Пример проекта демонстрирующего как это работает доступен по ссылке.

Moon 1.x и Selenoid имеют отдельный /devtools/ API, дающий доступ к браузеру используя Chrome Developer Tools Protocol. Для обратной совместимости это поддерживается и в версии Moon 2.x. По стандартам W3C WebDriver Selenium команды расширения Selenium должны располагаться под префиксом поставщика, поэтому, имея идентификатор сессии Selenium для доступа к этому API в Moon 2, вы должны использовать URL-адрес следующим образом:

Старое Chrome Developer Tools API для совместимости с Moon 1.x
wss://moon.example.com/session/<session-id>/aerokube/devtools

2.2.10. Изменение локали браузера

В некоторых тестовых сценариях необходимо поменять предпочтительную локаль браузера. Вы можете это сделать стандартными capabilities Selenium. Как именно поменять локаль - зависит от типа браузера.

Firefox
Изменение локали в Firefox
FirefoxOptions options = new FirefoxOptions();
options.setCapability("browserVersion", "75.0");
options.addPreference("intl.accept_languages", "de");
WebDriver driver = new RemoteWebDriver(new URL("https://moon.example.com/wd/hub"), options);
Браузеры семейства Chromium
Изменение локали в браузерах семейства Chromium
ChromeOptions options = new ChromeOptions();
options.setCapability("browserVersion", "81.0");
options.setCapability("moon:options", Map.of(
    "env", Arrays.asList("LANG=de_AT.UTF-8", "LANGUAGE=at:de", "LC_ALL=de_AT.UTF-8")
));
WebDriver driver = new RemoteWebDriver(new URL("https://moon.example.com/wd/hub"), options);

2.2.11. Изменение часового пояса

Проверка работоспособности приложения в различных часовых поясах является очень частым сценарием в тестировании. В зависимости от приложения для изменения часового пояса вы можете использовать один из следующих вариантов:

Вариант 1: Задавая переменную окружения TZ

В ОС Linux изменение часового пояса делается путем задания переменной окружения TZ (от time zone). Чтобы сделать это в Moon вам необходимо задать env capability в вашем коде:

ChromeOptions options = new ChromeOptions();

capabilities.setCapability("moon:options", Map.of(
    "env", Arrays.asList("TZ=America/New_York") // Переменная TZ со значениями наподобие "America/New_York" или "Europe/London" выставляется здесь
));

WebDriver driver = new RemoteWebDriver(new URL("https://moon.example.com/wd/hub"), options);

driver.get("https://dateful.com/time-zone-converter"); // Пример веб-сайта, который учитывает выбранный часовой пояс

Когда вы задаете часовой пояс подобным образом - тестируемое веб приложение может обновить информацию о ней используя Javascript Time API. Проблема заключается в том, что не все веб приложения используют этот API. Так что если этот вариант не сработал - пробуйте следующий.

Вариант 2: Переопределение географических координат браузера

Некоторые веб приложения выставляют часовой п оясна основании информации о геолокации браузера, с помощью Javascript Geolocation API. Если выставить часовой пояс напрямую не получается, вы можете переопределить географические координаты послав новые координаты через API:

ChromeOptions options = new ChromeOptions();
WebDriver driver = new RemoteWebDriver(new URL("https://moon.example.com/wd/hub"), options);
driver = new Augmenter().augment(driver);

DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();

// Для примера используется местоположение Лондона (измените на 40.715502419712244, -74.00597334074466 для Нью-Йорка)
devTools.send(Emulation.setGeolocationOverride(Optional.of(51.495930861102245),
        Optional.of(0.010205721644136127),
        Optional.of(1)));

driver.get("https://google.com");
WebElement element = driver.findElement(By.name("q"));
Actions actionProvider = new Actions(driver);
Action select = actionProvider
        .sendKeys("what is my time zone\n")
        .build();
select.perform();

Редко, но бывает что не работает ни первый ни второй вариант, это может означать что ваше веб-приложение определяет часовой пояс сопоставлением вашего IP адреса с IP адресом в базе данных провайдеров. В этом случае вам нужно сконфигурировать прокси сервер, физически расположенный в нужном регионе и настраивать браузер, чтобы он ходил через этот прокси.

2.2.12. Использование внешних хостов

Moon предполагает что большинство браузеров будут запускаться внутри подов Kubernetes или Openshift кластера. Однако, иногда необходимо запустить тесты Selenium на каких-то внешних хостах - аппаратных серверах или виртуальных машинах. В основном это необходимо по двум причинам:

  1. Необходимо запустить Selenium тесты на MacOS или iOS. Согласно лицензионному соглашению MacOS и iOS должны работать на аппаратном обеспечении Apple, а запустить Kubernetes на нем довольно сложно.

  2. Необходимо использовать Selenium на онлайн платформах для некоторых браузерах. В этом случае вы можете запустить часть браузеров (например Firefox, Chrome, Opera) в Moon, а те браузеры которые не работают на стандартных виртуальных машинах (например Chrome Mobile) можно запустить на реальных устройствах на внешних Selenium платформах.

Для использования внешних хостов вам необходимо следующее:

  1. Набор хостов с Selenium-совместимыми решениями (Selenoid, Appium, Selenium Grid): host1.example.com:4444, host1.example.com:4444 и т.д..

  2. Необязательно VNC сервер запущенный на каждом хосте, использующий стандартный порт 5900. На каждом VNC сервере должна быть настроена авторизация с паролем в 8+ символов.

Для каждого типа браузеров необходимо добавить следующую конфигурацию в описание конфигурации браузеров:

Шлём запрос на внешний хост
selenium:
    "internet explorer":
      default: 1.0.0
      repository: aerokube/moon-external-host
      env:
        - name: URLS
          value: "[\\\"http://host1.example.com:4444/\\\", \\\"http://host2.example.com:4444/\\\"]" # Список внешних хостов
        - name: VNC_PASSWORD
          value: "myvncpassword" # Минимум 8 символов
      ]

При такой конфигурации запросы Selenium сессии будут случайным образом перераспределены на хосты, указанные в переменной окружения URLS. VNC сервер также будет работать - в веб интерфейсе Moon вы увидите экраны внешних устройств.

2.2.13. Использование прокси-серверов

Использование прокси сервера с аутентификацией при помощи имени пользователя/пароля доступно начиная с версии Moon 2.5.0.

В некоторых случаях вам может понадобиться запустить браузер через некий прокси сервер. Протокол Selenium WebDriver поддерживает стандартные capabilities для работы с прокси сервером для любого браузера. Например:

Конфигурация прокси сервера для браузера с raw capabilities
ChromeOptions options = new ChromeOptions();
String proxyHost = "proxy.example.com:3128";
capabilities.setCapability("proxy", Map.of(
    "proxyType", "manual",
    "httpProxy", proxyHost,
    "sslProxy", proxyHost,
));
WebDriver driver = new RemoteWebDriver(new URL("https://moon.example.com/wd/hub"), options);

В некоторых языках программирования существует объект-оболочка под названием Proxy, который позволяет задать те же значения, но с проверкой типов:

Конфигурация прокси для браузера с объектом Proxy
ChromeOptions options = new ChromeOptions();
Proxy proxy = new Proxy();
String proxyHost = "proxy.example.com:3128";
proxy
    .setProxyType(Proxy.ProxyType.MANUAL)
    .setHttpProxy(proxyHost)
    .setSslProxy(proxyHost);
options.setProxy(proxy);
WebDriver driver = new RemoteWebDriver(new URL("https://moon.example.com/wd/hub"), options);

Прокси сервера очень часто требуют имя пользователя и пароль. В то время как большинство реализаций Selenium не работают с такими прокси серверами, Moon позволяет сконфигурировать авторизацию сразу после установки, используя capabilities - просто добавьте имя пользователя и пароль в виде (username:password@host:port):

Конфигурация прокси с авторизацией
ChromeOptions options = new ChromeOptions();
// Note username:password on the line below
String proxyHost = "username:password@proxy.example.com:3128";
capabilities.setCapability("proxy", Map.of(
    "proxyType", "manual",
    "httpProxy", proxyHost,
    "sslProxy", proxyHost,
));
WebDriver driver = new RemoteWebDriver(new URL("https://moon.example.com/wd/hub"), options);

2.3. Работа с Cypress

  1. Эта функциональность доступна начиная с версии Moon 1.9.0 и выше.

  2. Никаких дополнительных изменений в проекте Cypress не требуется.

  3. Пример проекта с демонстрацией функциональности доступен по ссылке here.

Cypress тесты запускаются в Moon сразу после установки. Необходимые настройки:

  1. Установите инструмент позволяющий запускать тесты Cypress удаленно:

    $ npm install @aerokube/cypress-moon
  2. Запустите ваши тесты в кластере Moon:

    $ cd /path/to/my-test-project
    my-test-project$ cypress-moon https://moon.example.com/cypress/chrome

    Каждый вызов команды cypress-moon запустит новую сессию браузера в Moon.

  1. Если ваша установка Moon сконфигурирована с использованием Ingress - корректный URL должен выглядеть примерно так: https://moon.example.com/cypress/chrome.

  2. Для запуска тестов Cypress требуется отправить сжатый проект в Moon. Если проект большой и Moon работает за Ingress вам возможно потребуется увеличить максимальный размер HTTP пакета. Например, проект Nginx Ingress Controller требует следующей аннотации:

    nginx.ingress.kubernetes.io/proxy-body-size: 128m

В Cypress, в отличие от Selenium нет концепции capabilities. Единственный способ запустить конкретный тип браузера или передать дополнительные значения заключается в добавлении этих значений в конечный URL. Далее описываются поддерживаемые параметры значений.

2.3.1. Выбор браузера

Вы можете запустить один из поддерживаемых в Cypress браузеров указав его название (chrome, chromium, edge, electron или firefox) в URL. По умолчанию Moon использует самый новый публично доступный образ браузера browsers/cypress-<browser-name>:latest.

Запуск Chrome (образ quay.io/browsers/cypress-chrome:latest)
$ cypress-moon https://moon.example.com/cypress/chrome
Запуск Chromium (образ quay.io/browsers/cypress-chromium:latest)
$ cypress-moon https://moon.example.com/cypress/chromium
Запуск Electron (образ quay.io/browsers/cypress-electron:latest)
$ cypress-moon https://moon.example.com/cypress/electron
Запуск Microsoft Edge (образ quay.io/browsers/cypress-edge:latest)
$ cypress-moon https://moon.example.com/cypress/edge
Запуск Firefox (образ quay.io/browsers/cypress-firefox:latest)
$ cypress-moon https://moon.example.com/cypress/firefox

2.3.2. Выбор определенной версии Cypress

Cypress API может меняться от версии к версии. Поэтому рекомендуется удостовериться что версия Cypress API, используемая в вашем проекте совпадает с версией использующейся в образе браузера. Чтобы использовать образ совместимый с конкретной версией Cypress - добавьте нужную версию в URL следующим образом:

Выбор образа совместимого с Cypress 7.3.0 (образ quay.io/browsers/cypress-electron:cypress-7.3.0)
$ cypress-moon https://moon.example.com/cypress/electron/cypress-7.3.0

2.3.3. Запись видео

Включите запись видео - просто добавьте параметр enableVideo в URL:

Включение записи видео
$ cypress-moon https://moon.example.com/cypress/electron/cypress-7.3.0?headless=false&enableVideo=true

Используйте другие параметры, если вам нужно изменить название записываемого видео, разрешение экрана, частоту кадров и так далее.

2.3.4. Дополнительная функциональность

Наряду с возможностью изменить версию Cypress вы также можете включить дополнительную функциональность, например изменить разрешение экрана, задать другое название теста и так далее. Вся эта функциональность добавляется путем внесения изменений в URL:

Добавление параметров
$ cypress-moon https://moon.example.com/cypress/electron/cypress-7.3.0?noExit=true&headless=false&env=LANG%3Dde_AT.UTF-8&env=LANGUAGE%3Dat:de

Полный список возможных параметров и описание их функциональности описан в таблице:

Table 7. Список параметров
Название параметра Возможные значения Значение по умолчанию Описание

additionalFonts

true или false

false

Включение дополнительных шрифтов для китайского, японского, тайского и т.д. языков.

configFile

Custom Cypress configuration file

Не выставлено

Путь до конфигурационного файла Cypress configuration file. Поддерживается версией Cypress 9.0.0 и выше.

enableVideo

true or false

false

Включение записи видео.

env

Переменные окружения

Не выставлено

Одна или более переменных окружения доступных для браузера. Может передаваться несколько раз: env=LANG%3Dde_AT.UTF-8&env=LANGUAGE%3Dat:de.

headless

true или false

true

Запуск браузера в headless режиме.

host

Стандартное значение из /etc/hosts в формате www.example.com:127.0.0.1

Не выставлено

Позволяет задавать дополнительные значения в файле /etc/hosts. Можно передавать несколько значений.

label

Метки подов Kubernetes

Не выставлено

Один или несколько меток Kubernetes которые добавляются на браузерный под. Можно задать несколько значений: label=first-label%3Dsome-value&env=another-label%3Danother-value.

name

Любая строка

Не выставлено

Позволяет задать имя теста (то же самое что Selenium capability под названием name).

nameserver

Имя DNS сервера, например ns1.example.com

Не выставлено

Позволяет добавлять один или несколько DNS серверов. Можно передать несколько значений.

noExit

true или false

false

Оставляет контейнер запущенным после завершения работы всех тестов. В основном используется для отладки.

pattern

Строка с полями для заполнения

$quota/$browserName/$sessionId

Пользовательское значение S3 ключа pattern, используется для сохранения видео в S3.

screenResolution

1280x1024 or 1280x1024x24

1920x1080x24

Устанавливает разрешение экрана в контейнере, где запущен браузер. Используйте существующие в Cypress способы изменения размер окна браузера.

spec

Имя Cypress spec файла (e.g. cypress/integration/my-spec.js)

Не выставлено

Позволяет запускать один или несколько конкретных тестовых файлов. Можно передать несколько значений.

videoCodec

Кодек который будет использоваться для видеозаписи, например mpeg4

libx264

Позволяет поменять кодек для видеозаписи.

videoFrameRate

Четное число

12

Частота кадров в видео.

videoName

Имя файла видео с расширением

video.mp4

Название видео.

videoScreenSize

1280x1024

Значение screenResolution

Размер экрана записываемого видео. Если это значение меньше, чем заданное в screenResolution, то видео будет обрезано.

2.3.5. Запись выполненных тестов в Cypress Dashboard

Эта функциональность работает начиная с версии Cypress образов 9.6.0 и выше.

В Cypress реализована функциональность под названием Cypress Dashboard - онлайн-сервис для хранения информации о запущенных и выполненных тестах. Чтобы послать информацию о выполненных тестах в этот сервис необходимо предоставить ключ доступа используя переменную окружения CYPRESS_RECORD_KEY:

Предоставление CYPRESS_RECORD_KEY:
$ cypress-moon https://moon.example.com/cypress/chrome/cypress-9.6.0?&env=CYPRESS_RECORD_KEY%3Dyour-key

2.4. Работа с Playwright

  1. Пример проекта, демонстрирующий работу с Playwright, доступен по ссылке.

Moon может запускать браузеры для Playwright сразу после установки. Пример теста Playwright который будет работать с Moon:

Пример теста Playwright для работы в Moon
const { firefox } = require('playwright');

(async () => {
  const browser = await firefox.connect({ timeout: 0, wsEndpoint: 'wss://moon.example.com/playwright/firefox/playwright-1.23.3' });
  const page = await browser.newPage();
  await page.goto('https://aerokube.com/moon/');
  await page.screenshot({ path: `screenshot.png` });
  await browser.close();
})();

Как вы можете видеть, единственное отличие от стандартного проекта Playwright — это URL-адрес веб-сокета на стороне Moon. По сравнению с Selenium в Playwright нет понятия capabilities. Единственный способ запустить браузер конкретной версии или какую-либо переменную окружения это передать параметры в URL-адрес конечной точки веб-сокета. Далее описываются конкретные параметры для передачи в URL.

Если в вашем кластере Moon использует соединение по HTTPS, а не по HTTP, соответственно и в Playwright правильный URL должен начинаться с wss://, а не с ws:// (например wss://moon.example.com/).

2.4.1. Выбор браузера

Вы можете запустить один из поддерживаемых в Playwright браузеров указав его название (chrome, chromium, edge, electron или firefox) в URL. По умолчанию для загрузки образов Moon использует репозиторий quay.io/playwright-<browser-name>. Playwright API может меняться от версии к версии. Поэтому рекомендуется удостовериться что клиентская версия Playwright, используемая в вашем коде, совпадает с серверной версией Playwright использующейся в образе браузера. Чтобы использовать образ совместимый с конкретной версией Playwright - добавьте нужную версию в URL следующим образом:

Запуск Chromium (образ quay.io/browser/playwright-chromium:playwright-1.23.3)
wss://moon.example.com/playwright/chromium/playwright-1.23.3
Запуск Chrome (образ quay.io/browser/playwright-chrome:playwright-1.23.3)
wss://moon.example.com/playwright/chrome/playwright-1.23.3
Запуск Firefox (образ quay.io/browser/playwright-firefox:playwright-1.23.3)
wss://moon.example.com/playwright/firefox/playwright-1.23.3
Запуск Webkit (образ quay.io/browser/playwright-webkit:playwright-1.23.3)
wss://moon.example.com/playwright/webkit/playwright-1.23.3

2.4.2. Запись видео

Включите запись видео - просто добавьте параметр enableVideo в URL:

Запись видео
wss://moon.example.com:4444/playwright/firefox/playwright-1.23.3?headless=false&enableVideo=true

Используйте другие параметры, если вам нужно изменить название записываемого видео, разрешение экрана, частоту кадров и так далее.

2.4.3. Дополнительная функциональность

Как и в Selenium вы можете настроить автоматическую загрузку произвольных файлов в браузерные поды в виде архива и распаковку этого архива в нужное место. Подробную информацию можно найти здесь. Основное отличие в Playwright заключается в том что URL архива передается в параметре context и соответственно должен быть URL-закодирован.

Включение контекста
wss://moon.example.com:4444/playwright/chrome/playwright-1.23.3?context=http%3A%2F%2Fexample.com%2Fbrowser-data.tar.gz

Пример подключения расширения браузера:

Подключение расширения браузера
var browser = await chromium.connect({ timeout: 0, wsEndpoint: 'wss://moon.example.com/playwright/chrome/playwright-1.23.3?headless=false&context=https%3A%2F%2Fexample.com%2Fextensions.tar.gz&arg=--disable-extensions-except%3D%2Fhome%2Fuser%2Fextensions&arg=--load-extension%3D%2Fhome%2Fuser%2Fextensions' });

2.4.4. Дополнительная функциональность

Наряду с возможностью изменить версию Playwright вы также можете включить дополнительную функциональность, например изменить разрешение экрана, задать другое название теста и так далее. Вся эта функциональность добавляется путем внесения изменений в URL:

Добавление параметров
wss://moon.example.com/playwright/chrome/playwright-1.23.3?headless=false&arg=--use-gl

Полный список возможных параметров и описание их функциональности описан в таблице.

Table 8. Список параметров
Название параметра Возможные значения Значение по умолчанию Описание

additionalFonts

true или false

false

Включение additional fonts для китайского, японского, тайского и тд языков.

arg

Аргументы командной строки браузера

Не задано

Одно или несколько значений передаваемых командной строке браузера. Значение можно передать несколько раз: arg=--use-fake-ui-for-media-stream&arg=--use-gl.

context

HTTP URL к контексту браузера

Не задано

HTTP URL адрес до архива *.tar.gz с дополнительными файлами которые при необходимости можно сделать доступными для браузера (так называемый browser context).

devtools

true или false

false

Отображение Chrome Developer Toolbar панели инструментов (относится только к браузеру chromium).

enableVideo

true или false

false

Запись видео.

env

Переменные окружения

Не задано

Одна или более переменных окружения доступных для браузера. Может передаваться несколько раз: env=LANG%3Dde_AT.UTF-8&env=LANGUAGE%3Dat:de.

headless

true или false

true

Запуск браузера в headless режиме.

host

Стандартное значение из /etc/hosts в формате www.example.com:127.0.0.1

Не задано

Позволяет задавать дополнительные значения в файле /etc/hosts. Можно передавать несколько значений.

label

Метки подов Kubernetes

Не задано

Один или несколько меток Kubernetes которые добавляются на браузерный под. Можно задать несколько значений: label=first-label%3Dsome-value&env=another-label%3Danother-value.

name

Любая строка

Не задано

Позволяет задать имя теста (то же самое что Selenium capability под названием name).

nameserver

Имя DNS сервера, например ns1.example.com

Не задано

Позволяет добавлять один или несколько DNS серверов. Можно передать несколько значений.

pattern

Строка с полями для заполнения

$quota/$browserName/$sessionId

Пользовательское значение S3 ключа pattern, используется для сохранения видео в S3.

screenResolution

1280x1024 или 1280x1024x24

1920x1080x24

Устанавливает разрешение экрана в контейнере, где запущен браузер. Используйте существующие в Playwright способы изменения размер окна браузера.

videoCodec

Кодек, который будет использоваться для видеозаписи, например mpeg4

libx264

Позволяет поменять кодек для видеозаписи.

videoFrameRate

Четное число

12

Частота кадров в видео.

videoName

Имя файла видео с расширением

video.mp4

Название видео.

videoScreenSize

1280x1024

Значение screenResolution

Размер экрана записываемого видео. Если это значение меньше чем заданное в screenResolution то видео будет обрезано.

2.5. Использование инструментов разработчика в Chrome

  1. Эта функциональность доступна начиная с версии Moon 1.7.0.

  2. Эта функциональность работает только с Chrome версии 63 и выше.

  3. Мы рекомендуем всегда использовать самую последнюю версию Chrome.

  4. Пример проекта доступен по ссылке.

Moon может запускать браузеры для использования инструментов разработчика по Chrome Developer Tools Protocol. Это дает возможность запускать тесты параллельно, используя библиотеки типа Puppeteer или Taiko. Для того чтобы запустить браузер с поддержкой этих инструментов, вам нужно задать URL следующим образом:

wss://moon.example.com/devtools/chrome

Если в вашем кластере Moon использует соединение по HTTPS, а не по HTTP, правильный URL должен начинаться с wss://, а не с ws:// (например wss://moon.example.com/).

Пример теста Puppeteer показан ниже:

Доступ к API инструментов разработчика с помощью Puppeteer
const puppeteer = require('puppeteer-core');
const host = 'moon.example.com';
(async () => {
    const devtools = await puppeteer.connect(
        { timeout: 0, browserWSEndpoint: `wss://${host}/devtools/chrome` }
    ); // Для каждого вызова этого метода запускается новый браузер
    const page = await devtools.newPage();
    await page.goto('https://aerokube.com');
    await page.screenshot({path: 'screenshot.png'});
    const title = await page.title();

    console.log(title);

    await devtools.close();
})();

2.5.1. Запуск нужного браузера

Нужную версию браузера можно задать в URL:

Выбор образа Chrome версии 85 (образ quay.io/browser/devtools-google-chrome-stable:85.0 image)
wss://moon.example.com/devtools/chrome/85.0

2.5.2. Запись видео

Включите запись видео video recording - просто добавьте параметр enableVideo в URL:

Запись видео
wss://moon.example.com/devtools/chrome/85.0?headless=false&enableVideo=true

Используйте другие параметры если вам нужно изменить название записываемого видео, разрешение экрана, частоту кадров и так далее.

2.5.3. Дополнительная функциональность

Дополнительную функциональность можно включить путем внесения изменений в URL:

Изменение параметров для включения дополнительной функциональности
wss://moon.example.com/devtools/chrome?headless=false&nameserver=ns1.example.com
Table 9. Список поддерживаемых параметров и описание их функциональности
Название параметра Возможные значения Значение по умолчанию Описание

additionalFonts

true или false

false

Включение additional fonts для китайского, японского, тайского и тд языков.

arg

Аргументы командной строки браузера

Не задано

Одно или несколько значений передаваемых командной строке браузера. Значение можно передать несколько раз: arg=--use-fake-ui-for-media-stream&arg=--use-gl.

devtools

true или false

false

Отображение панели инструментоов Chrome Developer Toolbar.

enableVideo

true или false

false

Включение видеозаписи

env

Переменные окружения

Не задано

Одна или более переменных окружения доступных для браузера. Может передаваться несколько раз: env=LANG%3Dde_AT.UTF-8&env=LANGUAGE%3Dat:de.

headless

true или false

true

Запуск браузера в headless режиме.

host

Стандартное значение из /etc/hosts в формате www.example.com:127.0.0.1

Не задано

Позволяет задавать дополнительные значения в файле /etc/hosts. Можно передавать несколько значений.

label

Метки подов Kubernetes

Не задано

Один или несколько меток Kubernetes которые добавляются на браузерный под. Можно задать несколько значений: label=first-label%3Dsome-value&env=another-label%3Danother-value.

name

Любая строка

Не задано

Позволяет задать имя теста.

nameserver

Имя DNS сервера, например ns1.example.com

Не задано

Позволяет добавлять один или несколько DNS серверов. Можно передать несколько значений.

pattern

Строка с полями для заполнения

$quota/$browserName/$sessionId

Пользовательское значение S3 ключа pattern, используется для сохранения видео в S3.

screenResolution

1280x1024 или 1280x1024x24

1920x1080x24

Устанавливает разрешение экрана в контейнере, где запущен браузер.

videoCodec

Кодек, который будет использоваться для видеозаписи, например mpeg4

libx264

Позволяет поменять кодек для видеозаписи.

videoFrameRate

Четное число

12

Частота кадров в видео.

videoName

Имя файла видео с расширением

video.mp4

Название видео.

videoScreenSize

1280x1024

Значение screenResolution

Размер экрана записываемого видео. Если это значение меньше чем заданное в screenResolution то видео будет обрезано.

3. Конфигурация

3.1. Лицензионный ключ

  1. Согласно лицензионному соглашению бесплатно вы можете использовать до четырех параллельных сессий без ограничений по времени. Если вам нужно больше параллельных сессий - закажите лицензионный ключ. Этот раздел описывает как просматривать и устанавливать лицензионный ключ. Пробный лицензионный ключ на большее количество сессий с ограниченным сроком действия можно сгенерировать на сайте Moon website.

Обычный лицензионный ключ представляет собой текстовый файл с расширением .key, выглядит он примерно так:

$ cat license.key
MG1RSVdpc2Z6YjdQQVZjd2lpei9KMkd1T3dzMTFuL1dlRjVSc3NOMUcxZk9QaUxWa3Q5SnBIakIxa09wWm0vVFJqQ0tsa21xVG1OODVRZnlQbjBjVmRHVWFLampTOFF1a3VLRXRPcEUwbnEySG16QWFQWHRDYTVjMm9jZzZFaUJqeFd5ODE4UFBHZzNCNWpCYXlha3oweFBscFl1RnB0V0U1Q3FwOGl5VDdKTk9abG5aSmlPdnRmZDFvSG1nNnVwVXBLV2E4RmYwWHcreERIR29ZTE1XTldPb1hvT2ZCUnZpcDhPWW05a1FqN0hBWWVOYUtLT1lPWlVJa1dsb1gxdjNOT1htTFpZalhsQ3h1Q3V6NWhiQjIwSjVIY0JTYnZybm9zYm14RXFkSFpQWVBKWUlKTzZvVlBnODhQeFErZ1EyTk5sWG82TC9XeXU3aisrNU0rSEdPcXlOSEdlNGx4Zm1nNVhjMWlnNkN1OCtNSVVYRzNqUllqOUY4ZHdReWpSbFNMNmFpL2dRQnc3TzY0U0lwdVF2d29jYi9kVzFSYWFRVkd3ZXYrOVdING8zRWRrYkVONUhRTmQ2MUxsUnFNdmtKeWVHV21tVlVUZ2dsMDRsTFFLTmZNVG81L2JVakNBMGhNeER5VHNJdmVRRGFMMklvTWpvcFk4VERlK1U2bUJvUDVxNVYrcCtDQVhjbjYxQlRaUVp0bmNqL0JBVkdNOEZ4NW9rWHRYSVAxUkY0a1VCckZVTDFyTWF1VkZqSk5xU1pLT293dUpMTTg2SEZ0Sld0eUlRK3ZZZm1pZU0xM292MnVleDBoRlhRdFkvMkt1dUhhN3dKV2pFT0pqaEVzTjhXSy82ZlFFbi9EQzcrNkw3NzhlbmVVZ2lLZ3VFbjlMMXZMYVZ5VWtQaWc9O2V5SnNhV05sYm5ObFpTSTZJa1JsWm1GMWJIUWlMQ0p3Y205a2RXTjBJam9pVFc5dmJpSXNJbTFoZUZObGMzTnBiMjV6SWpvMGZRPT0=

В первой версии Moon ключ хранился в секрете Kubernetes и монтировался в приложение как обычный файл. Во второй версии лицензионные ключи (или просто лицензии) хранятся в Kubernetes ресурсе.

3.1.1. Вывод списка лицензионных ключей

В отличие от других ресурсов, представленных Moon, лицензии хранятся на уровне всего кластера. Таким образом вам не нужно указывать имя неймспейса в следующих командах (аргумент -n moon указывать не нужно):

Вывести список доступных лицензий:

Список лицензий (вывод для лицензии по-умолчанию)
$ kubectl get licenses
NAME   LICENSEE   SESSIONS   EXPIRES   STATUS   NAMESPACE
moon   Default    4          Never     Ok       moon

Такой вывод вы увидите, если у вас установлена бесплатная лицензия. Значения в колонках:

  • Name. Название лицензии.

  • Licensee. Владелец лицензионного ключа. Обычно совпадает с названием компании, например Acme LLC. У бесплатной лицензии в четырьмя параллельными сессиями значение будет Default.

  • Sessions. Максимальное количество браузерных сессий доступных для данной лицензии.

  • Expires. Количество дней, через которое у лицензии закончится срок действия. Если срок действия уже закончен - значение колонки будет Already, а если срок действия не ограничен - значение колонки будет Never.

  • Status. Состояние ключа. Принимает значения: Ok - активная лицензия, Expired - срок действия лицензии закончен, Broken - неверные данные лицензионного ключа.

  • Namespace. Название неймспейса Kubernetes, где используется этот ключ.

Технически может существовать несколько ресурсов Kubernetes с названием license. В этом случае для работы с лицензией Moon вам нужно использовать полное название ресурса:

Вывод списка лицензий (используя полное имя ресурса)
$ kubectl get licenses.moon
NAME   LICENSEE   SESSIONS   EXPIRES   STATUS   NAMESPACE
moon   Default    4          Never     Ok       moon

$ kubectl get licenses.moon.aerokube.com
NAME   LICENSEE   SESSIONS   EXPIRES   STATUS   NAMESPACE
moon   Default    4          Never     Ok       moon

Вывод информации о лицензии в формате YAML:

Вывод информации о лицензии в формате YAML
$ kubectl get license moon -o yaml
apiVersion: moon.aerokube.com/v1
kind: License
metadata:
  name: moon                        (1)
  # Другие метаданные Kubernetes
spec:
  data: MG1RSVdpc2Z6YjdQQV....      (2)
  namespace: moon                   (3)
status:
  # Другие ключи и значения
1 Название лицензионного ключа
2 Содержимое лицензионного ключа
3 Неймспейс, в котором необходимо использовать лицензионный ключ

3.1.2. Обновление лицензионного ключа

Для обновления существующего лицензионного ключа необходимо обновить информацию в поле data в файле ключа:

Обновление лицензионного ключа
$ kubectl edit license moon # В любом текстовом редакторе замените информацию в поле data новым ключом, сохраните изменения и закройте редактор.

После обновления лицензионного ключа все изменения применяются автоматически. Это обычно ведет к плавному перезапуску подов Moon. При это запущенные браузерные сессии не прерываются.

3.1.3. Множество лицензионных ключей

Moon 2.x поддерживает общее использование одного лицензионного ключа на нескольких неймспейсах Kubernetes и в большинстве случаев одного ключа достаточно. Однако, в некоторых случаях вам может понадобиться отдельная установка Moon и отдельный ключ для каждой команды. Для установки двух и более ключей в разных неймспейсах вам необходимо:

  1. Установить два независимых кластера Moon в неймспейсы ns1 and ns2

  2. Создать и сохранить файл лицензии (например license-keys.yaml), в которых поле namespace будет принимать значение ns1 и ns2:

    Создание ключей
    $ cat license-keys.yaml
    apiVersion: moon.aerokube.com/v1
    kind: License
    metadata:
      name: license-key-ns1
    spec:
      data: <license-key-1>
      namespace: ns1
    ---
    apiVersion: moon.aerokube.com/v1
    kind: License
    metadata:
      name: license-key-ns2
    spec:
      data: <license-key-2>
      namespace: ns2
  3. Примените полученный файл:

    $ kubectl apply -f license-keys.yaml
    • Если вы создадите два ключа с одинаковыми значениями в поле data - один из них будет считаться дубликатом и автоматически удалится.

    • Если у вас есть два разных ключа с одинаковыми значениями в поле namespace - Moon будет выбирать самый последний созданный.

  4. Лицензионные ключи применятся автоматически, в выводе лицензий вы увидите:

    Установлено два лицензионных ключа
    $ kubectl get licenses
    NAME              LICENSEE    SESSIONS   EXPIRES   STATUS   NAMESPACE
    license-key-ns1   Acme Inc.   10         32d       Ok       ns1
    license-key-ns2   Acme Inc.   20         27d       Ok       ns2

3.1.4. Удаление лицензионного ключа

Для удаления существующего лицензионного ключа просто удалите соответствующий объект:

Удаление лицензионного ключа
$ kubectl delete license moon

После удаление последнего ключа с не пустым полем namespace Moon автоматически перейдет на бесплатную схему лицензирования с четырьмя параллельными сессиями.

3.1.5. Срок действия лицензионного ключа

Существует несколько способов всегда иметь активные лицензии Moon:

Вариант 1: Проверка срока действия ключа с помощью kubectl

Самый простой способ проверки срока действия ключа/ключей - это просмотр информации о них с помощью утилиты kubectl:

Проверка срока действия лицензионных ключей
$ kubectl get licenses
NAME              LICENSEE    SESSIONS   EXPIRES   STATUS   NAMESPACE
license-key-ns1   Acme Inc.   10         32d       Ok       ns1
license-key-ns2   Acme Inc.   20         today     Ok       ns2

В колонке Expires отображается информация о днях до окончания срока действия каждой лицензии. Когда срок действия заканчивается вывод той же команды будет выыглядеть так:

Срок действия одного ключа истек
$ kubectl get licenses
NAME              LICENSEE    SESSIONS   EXPIRES   STATUS    NAMESPACE
license-key-ns1   Acme Inc.   10         32d       Ok        ns1
license-key-ns2   Acme Inc.   20         Already   Expired   ns2

Если срок действия какого либо ключа истек в колонке Expires вы увидите значение Already, статус ключа будет Expired.

Также, помимо kubectl, для отображения списка лицензионных ключей и срока их действия, вы можете использовать Kubernetes API напрямую.
Вариант 2: Используйте Prometheus метрику срока действия лицензионного ключа

Другой способ получения информации о сроке действия ключей - это встроенная в Prometheus метрика moon_license_expire. Подробнее об этом описано в разделе мониторинг.

Метрика срока действия лицензионного ключа в Prometheus
$ curl -s https://moon.example.com/metrics | grep license_expire
# HELP moon_license_expire Moon license expiration time.
# TYPE moon_license_expire gauge
moon_license_expire 1.6444512e+09

Данные собираются в Prometheus автоматически, вам при необходимости нужно лишь настроить графики и оповещения.

3.1.6. Обновление лицензионного ключа из внешнего секрета

В некоторых случаях вам может понадобиться хранить лицензионный ключ в секрете Kubernetes и настроить Moon брать лицензию из этого секрета. Для этой цели нами разработан компонент license-ops. Он представляет собой задачу Kubernetes, которая считывает содержание лицензионного ключа из секрета и автоматически обновляет ресурс Kubernetes, используемый в Moon. Включение компонента license-ops осуществляется установкой еще одного чарта Helm:

  1. После установки Moon, создайте обычный секрет Kubernetes в неймспейсе Moon, содержащий информацию о ключе:

    Пример секрета с лицензионным ключом
    apiVersion: v1
    kind: Secret
    metadata:
      name: licensekey
      namespace: moon
    stringData:
      license.key: MG1RSVdpc2Z6.... # Вставьте лицензиюнный ключ сюда
  2. Установите чарт Helm:

    Установка компонента license-ops из чарта Helm
    $ helm upgrade --install -n moon license-ops aerokube/license-ops

    Изменить имя секрета, график запуска задачи и другие параметры можно с помощью параметров Helm:

    Обновление аргументов license-ops
    $ helm upgrade --install --set secretName=mysecret --set schedule="0 * * * *" -n moon license-ops aerokube/license-ops

3.2. Пользователи и квоты

3.2.1. Пользователи

  1. По умолчанию Moon не требует аутентификации по имени пользователя и паролю. Этот раздел описывает настройку аутентификации в Moon. Обычно это требуется, если в кластере работает несколько команд и каждой необходим защищенный доступ.

  2. Moon в большинстве случаев обрабатывает запросы на браузеры из кода. Этот код обычно поддерживается и выполняется командой разработчиков, таким образом использовать в коде имя пользователя и пароль реального пользователя не является хорошим решением. Хотя имя пользователя и пароль конкретного человека могут использоваться для доступа в графический интерфейс Moon UI, программный код обычно содержит имя и пароль какого-то сервисного аккаунта или робота, который знает и использует вся команда. Соответственно, в данной документации мы будем использовать слово "имя пользователя" относительно ко всей команде так как одно имя пользователя в Moon часто используется всей командой.

  3. Мы рекомендуем настроить TLS шифрование при использовании аутентификации. Иначе злоумышленник может перехватить сетевой трафик между вашим компьютером и кластером Moon и извлечь оттуда имя пользователя \ пароль.

  4. Ознакомьтесь с нашей статьей о безопасности кластера. Там мы также описываем конфигурацию TLS и авторизацию.

По сравнению с первой версией Moon версии 2.x не имеет встроенного механизма аутентификации. Причина этого заключается в том что мы рекомендуем осуществлять аутентификацию с помощью Ingress в Kubernetes, либо иным способом. Moon берет имя пользователя из HTTP заголовка X-Moon-Quota, который устанавливается в Ingress, либо иным способом. Следующий раздел описывает возможные конфигурации для аутентификации.

Basic HTTP аутентификация

В настоящее время самым популярным методом авторизации в автоматизации браузеров является так называемая basic HTTP аутентификация. При использовании этого метода имя пользователя и пароль передаются в HTTP заголовке Authorization:

Authorization: Basic base64("username:password")

Также поддерживается передача данных аутентификации в URL вида:

https://username:password@example.com/

Настройка Ingress является самым простым способом настроить basic HTTP аутентификацию. Ниже описаны несколько возможных вариантов конфигурации в Moon.

Вариант 1. Установка Ingress Nginx из Helm чарта
  1. Этот способ работает в Kubernetes, но не работает в Openshift. Инструкции для Openshift смотрите в разделе Openshift.

  2. В данном примере мы настраиваем Moon для запуска браузеров в отдельном неймспейсе Kubernetes для каждого пользователя. Уже существующие варианты работы Moon описаны здесь.

  3. Необходимы права доступа, позволяющие создать новый неймспейс Kubernetes. Детально необходимых в Moon правах доступа читайте здесь.

Как работает Nginx Ingress

users-nginx-ingress

Самый простой способ защитить многопользовательский кластер Moon это подключить Nginx Ingress, который устанавливается автоматически через чарт Helm (https://github.com/aerokube/charts):

  1. Добавьте репозиторий Aerokube charts:

    $ helm repo add aerokube https://charts.aerokube.ru/
    $ helm repo update
  2. Создайте файл values.yaml с указанием хоста Ingress и списка пользователей, которых нужно создать:

    ingress:
      host: moon.example.com # Укажите имя хоста кластера
    quota:
      moon: null # Отключите режим одного неймспейса в Moon
      alpha-team:
        namespace: alpha # Пароль для этой команды будем сгенерирован автоматически
      beta-team:
        namespace: beta
        password: beta-team-password # Значение пароля можно выставить и явно

    Поле password может быть задано, а может оставаться пустым и в зависимости от количества пользователей конечное поведение будет разным:

    Вариант 1. Один пользователь.

    • поле password не задано: нет авторизации.

    • поле password: '' (пустая строка): авторизация задана, пароль генерируется.

    • поле password: какой-то-пароль: авторизация задана, пароль соответствует заданному значению.

    Вариант 2. Два или больше пользователей.

    • поле password не задано или значение пустое: авторизация сконфигурирована, пароль генерируется.

    • поле password: какой-то-пароль: авторизация задана, пароль соответствует заданному значению.

  3. Установите Moon применив ваш файл values.yaml:

    $ helm upgrade --install -f values.yaml -n moon moon aerokube/moon2
  4. Будет создан отдельный неймспейс для каждой команды:

    $ kubectl get namespaces
    NAME              STATUS   AGE
    alpha              Active   40m
    beta              Active   40m
    # Другие неймспейсы

    В каждом неймспейсе автоматически будет создан секрет с паролем пользователя:

    $ kubectl get secrets -n alpha
    NAME                            TYPE                                  DATA   AGE
    alpha-team-basic-auth-password   Opaque                                1      2m11s
    # Другие секреты

    Пароль хранится в объекте Secret. Для того чтобы узнать пароль, выведите значение в поле password (оно будет зашифровано в Base64)) и дешифруйте его. Пример команды:

    $ kubectl get secret alpha-team-basic-auth-password -n alpha -o 'go-template={{index .data "password"}}' | base64 -d
    8X4juoCQ9gHAACqbc05B3oPXUcV6Oxb7KNTSYdM15eYF
  5. Используйте в коде название квоты (alpha-team, beta-team и так далее) из секрета как имя пользователя и пароль с предыдущего шага. Те же учетные данные должны использоваться для доступа к графическому интерфейсу. В режиме множества неймспейсов в интерфейсе показываются только сессии конкретного пользователя.

  6. Для настройки TLS шифрования используйте стандартный приватный ключ (server.key) и сертификат (server.crt) следующим образом:

    $ helm upgrade --install -f values.yaml --set-file ingress.tlsCert=server.crt --set-file ingress.tlsKey=server.key -n moon moon aerokube/moon2
Вариант 2. Ручная конфигурация Nginx Ingress

При этом варианте мы настраиваем только аутентификацию. Режим множества неймспейсов не включен.

Шаги для настройки Nginx Ingress вручную:

  1. Создайте текстовый файл в формате htpasswd с указанием списка пользователей:

    $ htpasswd -Bbn new-user new-user-password >> users.htpasswd # Как добавить нового пользователя
    $ htpasswd -Bb users.htpasswd some-user new-password # Как обновить пароль
    $ htpasswd -D users.htpasswd test-user # Как удалить пользователя

    Содержимое файла в итоге будет выглядеть примерно так:

    $ cat users.htpasswd
    alpha-team:$apr1$.dZyHlKN$jdoZkin/kPviFNArx/cVL1 # Имя пользователя alpha-team, пароль зашифрован
    beta-team:$apr1$gyqzbSpt$RBNcxrsQaolPZCQZW0VQW1
  2. Сохраните содержимое файла в секрет Kubernetes:

    $ kubectl create secret generic moon-basic-auth --from-file=users.htpasswd -n moon
  3. Настройте Nginx Ingress, чтобы он использовал учетные данные для basic HTTP аутентификации:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: moon
      namespace: moon
      annotations:
        nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
        nginx.ingress.kubernetes.io/auth-type: basic                                      (1)
        nginx.ingress.kubernetes.io/auth-secret: moon-basic-auth                          (2)
        nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - Moon Realm'    (3)
        nginx.ingress.kubernetes.io/configuration-snippet: |                              (4)
          proxy_set_header X-Moon-Quota $remote_user;
        nginx.ingress.kubernetes.io/proxy-connect-timeout: "108000"
        nginx.ingress.kubernetes.io/proxy-send-timeout: "108000"
        nginx.ingress.kubernetes.io/proxy-read-timeout: "108000"
    spec:
      ingressClassName: nginx
      tls:
      - hosts:
        - moon.example.com
        secretName: moon-tls                                                              (5)
      rules:
      - host: moon.example.com
        http:
          paths:
          - path: /wd/hub
            pathType: Prefix
            backend:
              service:
                name: moon
                port:
                  number: 4444
          # Other rules
    1 Тут включается basic HTTP аутентификация в Nginx
    2 Здесь мы настраиваем Nginx использовать наш список пользователей
    3 Желаемое имя для realm
    4 Тут Nginx задает заголовки X-Moon-Quota и Authorization
    5 Конфигурация TLS описана здесь
Вариант 3. Openshift Ingress

Openshift Ingress использует HAProxy, в котором использование basic HTTP аутентификации ограничено или недоступно. Для преодоления этого ограничения Moon предоставляет дополнительный контейнер под названием moon-basic-auth. Этот контейнер читает список пользователей из файла htpasswd, проверяет учетные данные пользователя из заголовка Authorization и посылает в Moon корректный заголовок X-Moon-Quota.

Как работает аутентификация в Openshift

users-openshift

Настройка пользователей в Openshift делается через чарт Helm точно таким же способом, как и в Nginx Ingress. Вам нужно лишь добавить параметр openshift: true в файл values.yaml следующим образом:

  1. Создайте файл values.yaml:

    ingress:
      host: moon.example.com
      openshift: true # Эта настройка включает дополнительный контейнер с поддержкой аутентификации для Openshift
    quota:
      moon: null
      alpha-team:
        namespace: alpha
      beta-team:
        namespace: beta
        password: beta-team-password
  2. Установите Moon из Helm чарта:

    $ helm upgrade --install -f values.yaml -n moon moon aerokube/moon2
    $ helm upgrade --install -f values.yaml --set-file ingress.tlsCert=server.crt --set-file ingress.tlsKey=server.key -n moon moon aerokube/moon2 # Та же самая команда с включенным TLS шифрованием
Option 4. Пользовательский Ingress

Наш Helm чарт позволяет настроить Ingress произвольным образом при помощи параметра customIngress. При использовании пользовательского Ingress наш чарт всегда запускает отдельный контейнер под названием moon-basic-auth, так же как в случае с Openshift. Это означает что авторизация производится внутри пода Moon и любой доступ в Moon через сервисы Kubernetes будет требовать авторизацию. Вот, к примеру, конфигурация ALB Ingress в AWS:

  1. Создайте файл values.yaml:

    customIngress:
      enabled: true
      annotations:
        external-dns.alpha.kubernetes.io/hostname: moon.example.com
        alb.ingress.kubernetes.io/group.name: moon
        alb.ingress.kubernetes.io/scheme: internet-facing
        alb.ingress.kubernetes.io/target-type: ip
      ingressClassName: alb
      host: moon.example.com
      paths:
        - path: /api
          port: 9090
        - path: /cypress
          port: 4444
        - path: /playwright
          port: 4444
        - path: /devtools
          port: 4444
        - path: /metrics
          port: 4444
        - path: /wd/hub/session
          port: 4444
        - path: /ui
          port: 9090
        - path: /
          port: 8080
    quota:
      moon: null
      alpha-team:
        namespace: alpha
      beta-team:
        namespace: beta
        password: beta-team-password
  2. Установите Moon с помощью Helm чарта:

    $ helm upgrade --install -f values.yaml -n moon moon aerokube/moon2
    $ helm upgrade --install -f values.yaml --set-file ingress.tlsCert=server.crt --set-file ingress.tlsKey=server.key -n moon moon aerokube/moon2 # Та же самая команда с включенным TLS шифрованием
Поддержка OpenID Connect

Moon поддерживает интеграцию с решениями на базе OpenID Connect. OpenID Connect это технология на базе OAuth, предоставляющая информацию для авторизации (OAuth предоставляет только возможности авторизации). Существующие реализации OpenID Connect https://openid.net/developers/libraries/ позволяют легко делегировать авторизацию и аутентификацию сторонним провайдерам:

Список конкретных поддерживаемых сторонних провайдеров зависит от вашей конфигурации OpenID Connect. Подробную информацию о том как взаимодействовать со сторонним провайдером обычно можно найти в настройках реализации OpenID Connect.

Moon and OpenID Connect

moon-and-openid-connect

Как вам может быть известно, Moon представляет собой HTTP API который позволяет автоматизировать браузерное тестирование в коде, а также графический интерфейс пользователя помогающий анализировать и отлаживать запускаемые тесты. Доступ к каждому из этих компонентов настраивается по разному:

  • Доступ к графическому интерфейсу Moon может быть защищен реверс-проксированием, например, с помощью OAuth2 Proxy.

  • Доступ к Moon HTTP API защищен демоном moon-auth, который входит в состав дистрибутива Moon. Основная причина создания отдельного демона это механизм работы браузеров - веб интерфейсы хранят учетные данные для авторизации в cookie, которые доступны только браузерам. Программы реализующие автоматизацию тестирования браузеров через Moon HTTP API не передают данные для аутентификации в cookie. Работа moon-auth демона заключается в преобразовании учетных данных этих программ из HTTP заголовка в формат OpenID Connect.

Защита компонентов Moon

protecting-moon-components

3.2.2. Квоты

Как вы возможно уже знаете, Moon является многопользовательским приложением. Для каждого пользователя необходимо создать отдельную квоту. Например, для пользователя alice необходимо создать квоту с таким же именем. Если имеется только одна квота - аутентификация не требуется.

Основной конфигурационный объект в Moon называется quota. Он содержит все настройки Moon конкретного пользователя. Вывести список доступных квот можно так:

Вывод списка квот
$ kubectl get quotas -n moon
NAME   NAMESPACE   CONFIG    BROWSERS   DEVICES   AGE
moon   moon        default   default    default   13h

Как видите, квота это встроенный объект Kubernetes, который содержит следующую информацию:

  • Namespace. Имя неймспейса, в котором Moon запускает браузеры. По умолчанию это тот же неймспейс, где запущен Moon. Детальное описание работы с неймспейсами доступно по ссылке.

  • Config. Название конфигурационного объекта Moon который позволяет распределять вычислительные ресурсы среди образов Moon, пользователей, групп и прочего.

  • Browsers. Название набора браузеров, которое будет использоваться для данной квоты.

  • Devices. Название набора устройств, которое будет использоваться для данной квоты.

Такой подход позволяет легко переиспользовать конфигурацию браузеров или конфигурацию устройств под разные квоты. Вывод списка в формате YAML:

Список квот в формате YAML
$ kubectl get quotas -n moon -o yaml
apiVersion: v1
items:
- apiVersion: moon.aerokube.com/v1
  kind: Quota
  metadata:
    name: moon                    (1)
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    browsers: default             (2)
    config: default               (3)
    devices: default              (4)
    namespace: moon               (5)
kind: List
metadata:
  # Метаданные списка
1 Название квот
2 Название набора браузеров, которое будет использоваться для данной квоты.
3 Название конфигурационного объекта которое будет использоваться для данной квоты.
4 Название набора устройств, которые будут использоваться для данной квоты.
5 Неймспейс, в котором Moon запускает браузеры.

Редактирование объекта квоты:

Редактирование:
$ kubectl edit quota.moon moon -n moon # Внесите изменения в текстовом редакторы, сохраните и выйдите
$ kubectl edit team moon -n moon # Более короткая команда, если вы не хотите использовать полное название объекта Kubernetes (quota.moon)
Здесь мы используем название quota.moon а не просто quota так как в Kubernetes название quota соответствует нативному ResourceQuota объекту.

3.2.3. Конфигурационный объект

Конфигурационный объект содержит различные параметры: вычислительные ресурсы, выделенные для каждого образа Moon, идентификаторы группы или пользователя для запуска подов и так далее. Этот объект соответствует файлу service.json в Moon версии 1.х. Для вывода списка конфигурационных объектов запустите команду:

Вывод списка конфигурационных объектов
$ kubectl get configs -n moon
NAME      AGE
default   2d22h

Вывод того же списка в формате YAML:

Вывод списка в YAML
$ kubectl get configs -n moon -o yaml
apiVersion: v1
items:
- apiVersion: moon.aerokube.com/v1
  kind: Config
  metadata:
    name: default                             (1)
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    additionalTrustedCAs: |                   (2)
      -----BEGIN CERTIFICATE-----
      ...
    containers:                               (3)
      browser:                                (4)
        resources:                            (5)
          limits:                             (6)
            cpu: "1"
            memory: 2Gi
          requests:                           (7)
            cpu: 500m
            memory: 2Gi
      ca-certs:                               (8)
        repository: aerokube/ca-certs         (9)
        version: 2.0.0                        (10)
        resources:                            (11)
          limits:                             (12)
            cpu: 250m
            memory: 64Mi
          requests:                           (13)
            cpu: 100m
            memory: 64Mi
        securityContext:                      (14)
          # Параметры security context
      defender:                               (15)
        # Такие же поля, как для ca-certs
      proxy:                                  (16)
        # Такие же поля, как для ca-certs
      video-recorder:                         (17)
        # Такие же поля, как для ca-certs
      vnc-server:                             (18)
        # Такие же поля, как для ca-certs
      x-server:                               (19)
        # Такие же поля, как для ca-certs
    group:                                    (20)
      id: 4096                                (21)
      name: user                              (22)
    serviceAccountName: default               (23)
    sessionTimeout: 5m                        (24)
    storage:                                  (25)
      accessKey: ""
      bucket: ""
      filename: ""
      endpoint: ""
      noProxy: ""
      httpProxy: ""
      httpsProxy: ""
      metadata: true
      pattern: ""
      secretKey: ""
      secretRef:
        accessKey: RootUser
        name: minio
        secretKey: RootPass
    user:                                     (26)
      id: 4096                                (27)
      name: user                              (28)
kind: List
metadata:
  # List metadata
1 Название конфигурационного объекта
2 Дополнительные корневые центры сертификации. Нужны, если используются самоподписанные TLS сертификаты. Если не настроено, то секция не отображается.
3 Конфигурация сервисных контейнеров (ca-certs, defender, proxy, video-recorder, vnc-server, x-server)
4 Конфигурация контейнера browser
5 Вычислительные ресурсы, выделенные на контейнер
6 Количество процессоров и памяти, выделенные на контейнер
7 Количество запросов к процессору и памяти, выделенные на контейнер
8 Конфигурация контейнера ca-certs
9 Репозиторий имиджей
10 Версия имиджа контейнеров. Если значение не задано - секция не отображается.
11 Вычислительные ресурсы, выделенные на контейнер
12 Лимиты процессоров и памяти, выделенные на контейнер
13 Requests процессоров и памяти, выделенные на контейнер (используются планировщиком Kubernetes)
14 Определение security context для контейнера
15 Конфигурация контейнера defender
16 Конфигурация контейнера proxy
17 Конфигурация контейнера video-recorder
18 Конфигурация контейнера vnc-server
19 Конфигурация контейнера x-server
20 Системная группа, использующаяся для запуска контейнеров
21 Идентификатор группы (gid)
22 Имя группы
23 Использующийся сервисный аккаунт Kubernetes
24 Время простоя по умолчанию
25 Конфигурация хранилища S3 (используется для хранения видео)
26 Имя системного пользователя для старта контейнеров
27 Идентификатор пользователя (uid)
28 Имя системного пользователя

Редактирование конфигурационного объекта:

Редактирование конфигурационного объекта
$ kubectl edit config default -n moon # Внесите изменения в текстовом редакторе, сохраните и выйдите из редактора

3.2.4. Набор браузеров

Объект "набор браузеров" хранит информацию о списке доступных браузеров. В Moon 1.x этот объект хранится в файле browsers.json. Для просмотра списка доступных объектов используйте команду:

Вывод списка наборов браузеров
$ kubectl get browsersets -n moon
NAME      AGE
default   2d23h

Для вывода той же самой информации в формате YAML:

Вывод информации в формате YAML
$ kubectl get browsersets -n moon -o yaml
apiVersion: v1
items:
- apiVersion: moon.aerokube.com/v1
  kind: BrowserSet
  metadata:
    name: default                                       (1)
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    cypress:                                            (2)
      chrome:                                           (3)
        repository: quay.io/browsers/cypress-chrome     (4)
      chromium:                                         (5)
        # Такие же поля как для chrome
      edge:                                             (6)
        # Такие же поля как для chrome
      electron:                                         (7)
        # Такие же поля как для chrome
      firefox:                                          (8)
        # Такие же поля как для chrome
    devtools:                                           (9)
      chrome:
        # Такие же поля как для cypress
    playwright:                                         (10)
      chrome:
        # Такие же поля как для cypress
      # Другие поддерживаемые типы браузеров
    selenium:                                           (11)
      MicrosoftEdge:
        repository: quay.io/browser/microsoft-edge-beta
      chrome:
        repository: quay.io/browser/google-chrome-stable
      firefox:
        repository: quay.io/browser/firefox-mozilla-build
kind: List
metadata:
  # List metadata
1 Имя объекта
2 Информация о браузерах в Cypress
3 Информация о браузерах Cypress Chrome
4 Репозиторий для поиска образов Cypress Chrome
5 Информация о браузерах Cypress Chromium
6 Информация о браузерах Cypress Microsoft Edge
7 Информация о браузерах Cypress Electron
8 Информация о браузерах Cypress Firefox
9 Информация о браузерах Chrome Developer Tools
10 Информация о браузерах в Playwright
11 Информация о браузерах в Selenium

Для редактирования объекта конфигурации браузеров:

Редактирование объекта
$ kubectl edit browserset default -n moon # Внесите изменения в текстовом редакторе, сохраните и выйдите из редактора

Если ранее вы использовали версию Moon 1.x, вы можете заметить, что объект в Moon 2.x немного отличается от файла browsers.json в Moon 1.x. Обычно содержимое файла выглядит так:

Файл browsers.json в версии Moon 1.x
{
  "chrome": {
    "default": "97.0",
    "versions": {
      "97.0": {
        "image": "quay.io/browsers/chrome:97.0",
        "port": "4444"
      }
    }
  }
}

Для каждого типа браузера и его версии вам нужно указать конкретный образ (например browsers/chrome:97.0) и файл содержал информацию только для браузеров в Selenium. Основная проблема в этом подходе заключается в том что каждое изменение в версии или образе требует ручного обновления в кластере Moon. Образы контейнера для разных версий одного и того же браузера обычно хранятся в одном репозитории, но с разными тегами, например:

quay.io/browser/google-chrome-stable:95.0 <==> Chrome 95.0
quay.io/browser/google-chrome-stable:96.0 <==> Chrome 96.0
quay.io/browser/google-chrome-stable:97.0 <==> Chrome 97.0

В Moon 2.x вместо копирования и правки одной и той же спецификации образа вам нужно только указать название репозитория в объекте конфигурации браузеров:

Спецификация браузеров в Moon 2.x
selenium:
  chrome:
    repository: quay.io/browser/google-chrome-stable

Этот новый формат конфигурации означает, что все образы браузера chrome используемые в тестах Selenium будут загружаться изз репозитория quay.io/browser/google-chrome-stable. Конкретный тег образа определяется при запуске браузера, например, таким образом можно задать Selenium capabilities:

browserName = chrome
browserVersion = 96.0

В данном случае Moon будет использовать образ quay.io/browser/google-chrome-stable:96.0. Таким же образом, редактируя URL, вы можете передать информацию в Cypress, Playwright и Chrome Developer Tools

Версии браузеров

В Moon 2.x все еще можно ограничить доступные версии браузеров, хотя эта функция не включена по умолчанию:

Ограничение списка доступных версий браузеров
selenium:
  chrome:
    repository: quay.io/browser/google-chrome-stable
    versions: ["96.0", "97.0"]            (1)
    default: "96.0"                       (2)
    port: 4444                            (3)
    path: "/"                             (4)
1 Список доступных версий
2 Версия по умолчанию
3 Сконфигурированный в контейнере порт на который посылаются запросы (по умолчанию 4444)
4 Путь API для отправки запросов

Если задан определенный список версий Moon будет запускать только версии браузеров из этого списка. По умолчанию, если версия не задана - запустится первая доступная. Изменить версию браузера по-умолчанию можно указанием значения в поле default. Если поля versions и default не заданы - запустится самая последняя версия.

Вычислительные ресурсы

По умолчанию вычислительные ресурсы для каждого браузера задаются в конфигурационном объекте. Для каждого типа браузеров вы можете переопределить эти значения следующим образом:

Выделение вычислительных ресурсов для подов
selenium:
  chrome:
    repository: quay.io/browser/google-chrome-stable
    resources:                            (1)
      limits:                             (2)
        cpu: "1.0"                        (3)
        memory: "1Gi"                     (4)
      requests:                           (5)
        cpu: "1.0"                        (6)
        memory: "1Gi"                     (7)
1 Раздел, описывающий вычислительные ресурсы
2 Раздел, описывающий максимально разрешенные вычислительные ресурсы
3 Ограничение по процессорному времени
4 Ограничение по памяти
5 Раздел, описывающий Kubernetes requests (значения для планировщика)
6 Запросы по процессору
7 Запросы по памяти
Переменные окружения

В некоторых ситуациях вам может потребоваться задать переменные окружения для подов. Например, вы можете захотеть задать предпочтительный язык или часовой пояс для браузера при помощи переменных LANG или TZ. Чтобы задать произвольную переменную окружения, используйте обычный синтаксис Kubernetes:

Определение переменных окружения
selenium:
  chrome:
    repository: quay.io/browser/google-chrome-stable
    env:                                (1)
      - name: TZ                        (2)
        value: "Europe/Paris"
      - name: LANG
        value: "fr_FR.UTF-8"
1 Раздел переменных окружения
2 Конкретная переменная

Также поддерживается загрузка переменных окружения из полей пода, ConfigMap или Secret:

Загрузка переменных окружения
selenium:
  chrome:
    repository: quay.io/browser/google-chrome-stable
    env:
        - name: MY_NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName # Поле из описания самого пода
        - name: SECRET_USERNAME
          valueFrom:
            secretKeyRef:
              name: some-secret # Имя секрета
              key: username # Название ключа
        - name: MEM_LIMIT
          valueFrom:
            resourceFieldRef:
              containerName: some-container # Имя контейнера
              resource: limits.memory # Ресурсный параметр
              divisor: 1Mi
        - name: SOME_KEY
          valueFrom:
            configMapKeyRef:
              name: some-map # Имя ConfigMap
              key: some-key # Название ключа
Пользовательские аннотации
Moon использует аннотации в формате YAML, так же как и сам Kubernetes.

В некоторых случаях при старте браузера вам может потребоваться добавить пользовательские аннотации Kubernetes на поды с браузерами. Чтобы добавить аннотации сразу для всех типов браузеров:

Добавление аннотаций Kubernetes сразу для всех типов браузеров
apiVersion: moon.aerokube.com/v1
  kind: BrowserSet
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    annotations:                          (1)
      key1: "value1"                      (2)
      key2: "value2"
1 Общий раздел аннотаций
2 Конкретные аннотации которые необходимо добавить

Для добавления аннотаций к какому-то одному типу браузеров:

Добавление аннотаций Kubernetes для определенного браузера
selenium:
  chrome:
    repository: quay.io/browser/google-chrome-stable
    annotations:                          (1)
      key1: "value1"                      (2)
      key2: "value2"
1 Раздел аннотаций
2 Конкретные аннотации которые необходимо добавить

Некоторые аннотации Moon добавляет по умолчанию и их имя зарезервировано:

Table 10. Зарезервированные аннотации Moon
Аннотация Значение

name

Имя сессии, определяемое в капабилити name

Пользовательские метки
Moon использует метки в формате YAML, так же как и сам Kubernetes.

В некоторых случаях при старте браузера вам может потребоваться добавить метку Kubernetes на поды с браузерами. Чтобы добавить метки сразу для всех типов браузеров:

Добавление меток Kubernetes сразу для всех типов браузеров
apiVersion: moon.aerokube.com/v1
  kind: BrowserSet
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    labels:                          (1)
      key1: "value1"                 (2)
      key2: "value2"
1 Раздел меток
2 Добавляемые метки

Для добавления меток к какому-то одному типу браузеров:

Добавление меток Kubernetes для определенного браузера
selenium:
  chrome:
    repository: quay.io/browser/google-chrome-stable
    labels:                               (1)
      key1: "value1"                      (2)
      key2: "value2"
1 Раздел меток
2 Добавляемые метки

Некоторые метки Moon добавляет по-умолчанию и их имя зарезервировано:

Table 11. Зарезервированные в Moon названия меток
Метка Значение

app

Уникальное имя пода

browserName

Имя браузера

browserVersion

Версия браузера

enableVNC

Включен ли VNC

moon

Системная метка, всегда выставлено в значение browsers

quota

Хранит информацию о пользовательских квотах

screenResolution

Хранит информацию о разрешении экрана, заданном пользователем

Node selector
Moon использует такой же node selector в формате YAML, как и Kubernetes.

Иногда вам может понадобиться запустить поды на определенных нодах Kubernetes (например, только на железных серверах). Kubernetes позволяет это сделать с помощью node selector. Для того чтобы выставить node selector для всех типов браузеров:

Добавление node selector для всех типов браузеров
apiVersion: moon.aerokube.com/v1
  kind: BrowserSet
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    nodeSelector:                         (1)
      node-label-1: "label1-value"        (2)
      node-label-2: "label2-value"
1 Спецификация node selector
2 Конкретная метка node selector, которая должна быть на node

Для конфигурации node selector для определенного типа браузера:

Определение node selector для конкретного браузера
selenium:
  chrome:
    repository: quay.io/browser/google-chrome-stable
    nodeSelector:                         (1)
      node-label-1: "label1-value"        (2)
      node-label-2: "label2-value"
1 Спецификация node selector
2 Конкретная метка node selector, которая должна быть на node
Affinity
Moon использует такую же конфигурацию affinity в формате YAML как и Kubernetes.

В дополнение к node selector вы также можете использовать все имеющиеся в Kubernetes функции affinity. Это предоставляет вам еще более продвинутые возможности настройки планировщика Kubernetes, например сопоставление нод Kubernetes со сложными логическими выражениями, предотвращение запуска некоторых помеченных подов на одной ноде с другими помеченными подами и т.д. Если вам необходимо добавить affinity для всех типов браузеров:

Настройка affinity для всех браузеров
apiVersion: moon.aerokube.com/v1
  kind: BrowserSet
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    affinity:                                            (1)
      nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
          - matchExpressions:
            - key: kubernetes.io/e2e-az-name
              operator: In
              values:
              - e2e-az1
              - e2e-az2
1 Настройка affinity

Для добавления affinity для конкретного типа браузера:

Добавление affinity для конкретного типа браузера
selenium:
  chrome:
    repository: quay.io/browser/google-chrome-stable
    affinity:                                           (1)
      nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
          - matchExpressions:
            - key: kubernetes.io/e2e-az-name
              operator: In
              values:
              - e2e-az1
              - e2e-az2
1 Настройка affinity
Tolerations
Moon использует тот же механизм Taints и Tolerations в формате YAML, что и Kubernetes.

В дополнение к node selector и affinity в Kubernetes реализован механизм taints. Механизм taints позволяет адресно защитить ноду от размещения на ней подов. Если вы хотите запустить браузер на ноде с подобными ограничениями, вам необходимо добавить tolerations, то есть ряд условий, которые необходимо сопоставить с помеченными подами.

Чтобы настроить tolerations для всех типов браузеров:

Добавление tolerations для всех типов браузеров
apiVersion: moon.aerokube.com/v1
  kind: BrowserSet
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    tolerations:            (1)
    - key: "key1"
      operator: "Equal"
      value: "value1"
      effect: "NoSchedule"
1 Настройка tolerations

Для настройки tolerations для конкретного типа браузера:

Конфигурация для конкретного браузера
selenium:
  chrome:
    repository: quay.io/browser/google-chrome-stable
    tolerations:                            (1)
    - key: "key1"
      operator: "Equal"
      value: "value1"
      effect: "NoSchedule"
1 Настройка tolerations
Сетевые настройки

Некоторые сценарии требуют дополнительных настроек сети в поде с браузером. Например, вам может потребоваться переопределить используемые DNS-сервера или значения в файле /etc/hosts. Это делается следующим образом:

Настройка сетевой конфигурации
selenium:
  chrome:
    repository: quay.io/browser/google-chrome-stable
    dnsConfig:                            (1)
      nameservers:
        - 1.2.3.4
      searches:
        - ns1.svc.cluster-domain.example
        - my.dns.search.suffix
      options:
        - name: ndots
          value: "2"
        - name: edns0
    hostAliases:                          (2)
      - ip: "127.0.0.1"
        hostnames:
        - "foo.local"
        - "bar.local"
      - ip: "10.1.2.3"
        hostnames:
        - "foo.remote"
        - "bar.remote"
1 Секция настройки DNS
2 Настройка /etc/hosts

Поля dnsConfig и hostAliases имеют тот же синтаксис, что и их аналоги в Kubernetes: (pod DNS config и host aliases).

Привилегированный режим

В некоторых случаях, например при запуске эмуляторов Android, контейнер должен быть запущен в привилегированном (privileged) режиме. Следующая настройка позволяет активировать этот режим:

Активация привилегированного режима
selenium:
  chrome:
    # Привилегированный режим может требоваться, например, для запуска Android эмуляторов
    repository: browsers/android
    privileged: true                    (1)
1 Запуск подов в привилегированном режиме

3.2.5. Набор устройств

Moon загружает информацию о доступных мобильных устройствах для Мобильной эмуляции из объекта под названием devices set. В Moon 1.x этот объект хранится в файле devices.json. Для вывода списка доступных устройств выполните команду:

Вывод списка наборов устройств
$ kubectl get devicesets -n moon
NAME      AGE
default   2d23h

Для вывода списка в формате YAML:

Вывод наборов устройств в формате YAML
$ kubectl get devicesets -n moon -o yaml
apiVersion: v1
items:
- apiVersion: moon.aerokube.com/v1
  kind: DeviceSet
  metadata:
    name: default                                                                                 (1)
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    devices:                                                                                      (2)
      Apple iPhone 11:                                                                            (3)
        height: 896                                                                               (4)
        pixelRatio: 2                                                                             (5)
        printVersion: true                                                                        (6)
        userAgent: user-agent-string-for-chrome-%s                                                (7)
        width: 414                                                                                (8)
      # Другие устройства
kind: List
metadata:
  # Метаданные списка
1 Название объекта
2 Список устройств
3 Определение конкретного устройства
4 Высота экрана устройства
5 Device pixel ratio (DPR)
6 Заменять ли версию Chrome на пользовательское значение (строка %s заменяется на версию Chrome)
7 User agent для устройства
8 Ширина экрана устройства

Для редактирования объекта выполните команду:

Редактирование набора устройств
$ kubectl edit deviceset default -n moon # В открывшемся редакторе внесите нужные изменения, сохраните и закройте файл

3.3. Запись видео

  1. В зависимости от конфигурации вычислительных ресурсов поддержка записи видео потребует дополнительно (к уже имеющимся) один процессор и один гигабайт памяти для каждой сессии браузера.

  2. Поддержка записи видео является скорее инструментом отладки, мы не рекомендуем записывать видео на каждый тест. Запись видео существенно увеличивает расход вычислительных ресурсов, к тому же маловероятно, что кто-то будет просматривать тысячи созданных видео (особенно если тест завершился успешно).

В Moon имеется возможность записывать видео экрана браузера, в котором выполняется тест. Записанное видео может позже быть просмотрено в браузере или другой программе для воспроизведения видео. Записанный файл также можно добавить в виде вложения в отчет о прохождении теста. В браузерах, запущенных в Kubernetes или Openshift, при включенном автоматическом масштабировании сессии запускаются на случайных хостах которые появляются и исчезают в случайном порядке. Поэтому записанные видео должны сохраняться в постоянное хранилище перед тем как браузерная сессия будет закрыта. Moon позволяет автоматически загружать видео в сконфигурированное хранилище совместимое с S3. Подобные хранилища предоставляет Yandex.Cloud, AWS, Google Cloud, Microsoft Azure, Digital Ocean и множество других облачных провайдеров. Развернуть приватное хранилище совместимое с S3 вы можете с помощью Minio.

Включить возможность записи видео можно следующим образом:

  1. В настройках Moon добавьте данные используемого S3 хранилища.

  2. Включите запись видео при запуске теста.

3.3.1. Настройка S3 хранилища

  1. Создайте S3 бакет. В нашем примере бакет называется moon-test. В можете создать S3-совместимый бакет в большинстве доступных облачных платформ. Конфигурация Moon в самых распространенных платформах описана в таблице:

    Table 12. Настройки S3 для самых распространенных облачных платформ:
    Название платформы Название сервиса Точка входа Версия

    Yandex Cloud

    Object Storage

    https://storage.yandexcloud.net.

    S3v4

    AWS

    AWS S3

    Зависит от региона, как пример - может быть https://s3.us-east-2.amazonaws.com. Смотрите AWS документацию для получения полного списка.

    S3v4

    DigitalOcean

    DigitalOcean Spaces

    Зависит от региона, как пример - может быть https://nyc3.digitaloceanspaces.com. Смотрите документацию для получения полного списка.

    S3v4

    Google Cloud

    Google Cloud Storage

    https://storage.googleapis.com

    S3v2

    Microsoft Azure

    Azure Blob Storage

    Встроенная поддержка S3 отсутствует. Необходимо развертывать дополнительное программное обеспечение типа Minio.

    S3v4

  2. Доступ к S3 бакету может быть предоставлен либо с помощью статических учетных данных (access key и secret key), либо с помощью добавления ролей в облачных платформах. Этот раздел показывает как сконфигурировать статические учетные данные. Конфигурация ролей для доступа к S3 бакету доступна ниже. Как загружать статические учетные данные для доступа к S3 бакету из секрета Kubernetes описано здесь.

  3. Обновите конфигурацию хранилища в конфигурационном объекте:

      apiVersion: moon.aerokube.com/v1
      kind: Config
      metadata:
        name: default
        namespace: moon
        # Другие метаданные Kubernetes
      spec:
        # Другие поля
        storage:
          accessKey: "AKIAXXXXXXXXXXXXXXXX" # Выставьте, если используются статические ключи
          bucket: "moon-test"
          filename: "" #  Имя записываемого файла, например, myvideo.mp4
          endpoint: "https://s3.us-east-2.amazonaws.com"
          pattern: "" # См. ниже
          secretKey: "okUa0XXXXXXXXXXXXXXXXXXXX" # Выставьте, если используются статические ключи
        # Еще поля

3.3.2. Включение записи видео

Включение видеозаписи зависит от технологии автоматизации браузеров которую вы используете:

Пользовательская иерархия файлов в S3

По умолчанию загружаемые в S3 видео хранятся таким образом:

Настройки S3 бакета
\---my-bucket
    \---- <session-id>
        |---- video.mp4

Moon позволяет настроить пользовательскую иерархию хранения файлов в S3 с помощью шаблонов S3 и заполнителей. Типичный шаблон ключа в S3 выглядит следующим образом:

Обычный шаблон ключа S3
$quota/$browserName/$browserVersion/$sessionId

Заполнители $quota, $browserName, $browserVersion и так далее будут заменены следующей информацией: имя пользователя, название браузера, версия браузера. Полученный ключ S3 будет использоваться в качестве пути, куда сохраняется видео. Список поддерживаемых заполнителей показан в таблице:

Table 13. Заполнители ключей S3
Заполнитель Значение

$sessionId

Заменяется ID сессии Selenium

$browserName

Заменяется значением имени браузера

$browserVersion

Заменяется значением версии браузера в Selenium

$date

Заменяется текущей датой, например 2024-02-01

$quota

Заменяется названием квоты (например значение имени пользователя в Selenium URL)

По умолчанию шаблон ключа S3 это только $sessionId:

Иерархия хранения видео по умолчанию
my-bucket/chrome-71-0-686efb96-eabe-4435-af31-21a33c8a4c8b/video.mp4

Вы можете изменить шаблон ключа S3 в конфигурационном объекте следующим образом:

Изменение шаблона ключа S3
  apiVersion: moon.aerokube.com/v1
  kind: Config
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    # Другие поля
    storage:
      # Другие настройки S3
      pattern: "$quota/$browserName/$browserVersion/$sessionId"
    # Еще поля

Если вам необходимо определить шаблон ключа S3 для каждой сессии отдельно - используйте капабилити pattern. Более подробно об этом описано в разделе капабилити специфичные для Moon.

Получение учетных данных S3 из секрета Kubernetes
  1. Эта функциональность доступна начиная с версии Moon 2.1.3.

  2. Удостоверьтесь, что секрет Kubernetes создан в том же неймспейсе, где будут запускаться поды.

При необходимости вы также можете загрузить статические ключи для S3 из секрета Kubernetes вместо того, чтобы передавать эти конфигурационном объекте:

  1. Создайте Kubernetes секрет в неймспейсе соответствующей квоты:

    Пример секрета с учетными данными S3
    $ cat secret.yaml
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: credentials
    stringData:
      RootUser: "AKIAXXXXXXXXXXXXXXXX"
      RootPass: "okUa0XXXXXXXXXXXXXXXXXXXX"
    
    $ kubectl create -n moon -f secret.yaml
    secret/minio created
  2. Добавьте значение поля secretRef field в конфигурационный объект следующим образом:

    Загрузка учетных данных S3 из секрета Kubernetes
      apiVersion: moon.aerokube.com/v1
      kind: Config
      metadata:
        name: default
        namespace: moon
        # Другие метаданные Kubernetes
      spec:
        # Другие поля
        storage:
          # Другие настройки S3
          secretRef:
            accessKey: RootUser # Имя поля секрета с access key
            name: credentials # Имя секрета из предыдущего шага
            secretKey: RootPass # Имя поля секрета с secret key
        # Другие поля
Доступ в S3 на основе ролей

Некоторые команды предпочитают раздавать доступ в S3 не с помощью статических ключей, а на основе выданных ролей. В этом разделе мы покажем как настроить доступ в S3 бакет на основе ролей в AWS.

Вариант 1. Используйте аннотации kube2iam и Kubernetes.

  1. Установите kube2iam.

  2. При помощи шаблона CloudFormation создайте роль IAM для доступа в S3 бакет:

    #jinja2:trim_blocks: False
    #jinja2:lstrip_blocks: False
    {% set var = config.jinja_parameters %}
    AWSTemplateFormatVersion: '2010-09-09'
    
    Description: Contains infra components for Aerokube Moon
    Parameters:
      TargetBucket:
        Description: Target bucket for IAM permissions
        Type: String
    Resources:
      PodRole:
        Type: AWS::IAM::Role
        Properties:
          RoleName: aerokube-moon
          AssumeRolePolicyDocument:
            Version: "2012-10-17"
            Statement:
            - Effect: Allow
              Action: sts:AssumeRole
              Principal:
                Service: ec2.amazonaws.com
            - Effect: Allow
              Action: sts:AssumeRole
              Principal:
                AWS: !Sub arn:aws:iam::${AWS::AccountId}:role/EKSInstanceRole
          Policies:
            - PolicyName: aerokube-moon
              PolicyDocument:
                Statement:
                  - Action:
                      - s3:List*
                      - s3:Get*
                      - s3:Put*
                    Effect: "Allow"
                    Resource:
                      - !Sub "arn:aws:s3:::${TargetBucket}/*"
                      - !Sub "arn:aws:s3:::${TargetBucket}"
  3. Добавьте аннотацию на неймспейс Moon:

    annotations:
      iam.amazonaws.com/allowed-roles: |
        ["aerokube-moon"]
  4. Добавьте аннотацию к подам с браузерами в наборе браузеров:

    apiVersion: moon.aerokube.com/v1
    kind: BrowserSet
    metadata:
      name: default
      namespace: moon
      # Other Kubernetes metadata
    spec:
      annotations:
        iam.amazonaws.com/role: "aerokube-moon"
      # Other fields

Вариант 2. Добавьте роль IAM к сервисному аккаунту Moon.

  1. С помощью AWS создайте роль IAM для сервисного аккаунта EKS.

  2. Сконфигурируйте Moon to для использования этого аккаунта.

Загрузка видео через прокси

Эта функциональность доступна с версии Moon 2.6.0.

В некоторых средах с ограниченным доступом видео в S3 бакет необходимо загружать через прокси сервер. Чтобы сконфигурировать такой тип загрузки, обновите конфигурационый объект следующим образом:

Конфигурация прокси сервера для загрузи в S3
  apiVersion: moon.aerokube.com/v1
  kind: Config
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    # Другие поля
    storage:
      # Другие настройки S3
      noProxy: "*.example.com" # Не использовать прокси для этих хостов
      httpProxy: "proxy.example.com:3128" # Хост и порт для HTTP трафика
      httpsProxy: "proxy.example.com:3128" # Хост и порт для HTTPS трафика
    # Еще поля

Синтаксис этих полей соответствует переменным окружения NO_PROXY, HTTP_PROXY и HTTPS_PROXY.

Отключение поддержки instance metadata

Эта функциональность доступна с версии Moon 2.7.0.

По-умолчанию, Moon ожидает, что S3 клиент, используемый для загрузки видео, может обращаться к так называемому instance metadata API. Данная технология поддерживается в большинстве облачных платформ. Тем не менее в некоторых случаях данное API недоступно. В этом случае можно настроить Moon не использовать instance metadata API при загрузке видео в S3:

Отключение instance metadata для загрузок в S3
  apiVersion: moon.aerokube.com/v1
  kind: Config
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    # Другие поля
    storage:
      # Другие настройки S3
      metadata: false # Это поле отключает использование instance metadata (по-умолчанию true)
    # Еще поля

3.4. Автоматическое обновление версий браузеров

Эта функциональность доступна начиная с версии Moon 2.3.0.

Moon 2.x загружает конкретный образ браузера по заранее определенному имени. Например, когда вы запрашиваете с помощью Selenium браузер chrome 100.0, по-умолчанию будет загружаться образ quay.io/browser/google-chrome-stable:100.0. Конкретный репозиторий, откуда будут загружаться образы может быть сконфигурирован в объекте набор браузеров. Однако в Moon UI список доступных версий берется из поля versions в наборе браузеров конкретной команды. Начиная с версии Moon 2.3.0 мы предлагаем автоматизированное решение для постоянного обновления списка версий браузера в Moon UI. Это решение называется browser-ops и распространяется в виде отдельного Kubernetes job, который периодически проверяет доступность версий в репозитории и обновляем версии браузеров в Moon UI.

3.4.1. Установка

Для использования этого решения вам нужно установить еще один Helm чарт.

  1. Добавьте репозиторий Aerokube charts, если он не был добавлен ранее:

    $ helm repo add aerokube https://charts.aerokube.ru/
    $ helm repo update
  2. Установите чарт browser-ops:

    $ helm upgrade --install -n moon browser-ops aerokube/browser-ops

3.4.2. Возможности конфигурации

Как и для всех остальных чартов Helm, параметры конфигурации чарта browser-ops хранятся в файле values.yaml и применяются следующим образом:

$ helm upgrade --install -f values.yaml -n moon browser-ops aerokube/browser-ops
  • По умолчанию версии обновляются каждую ночь. Изменить расписание можно следующим образом:

    schedule: "0 */2 * * *" # Run every two hours
  • По умолчанию browser-ops будет использовать самую последнюю доступную версию браузера. Вы можете поменять это поведение, указав все доступные версии либо какой-то определенный набор версий таким образом:

    browserImageVersions: all # Использовать все доступные версии браузеров
    browserImageVersions: 5 # Использовать 5 последних версий браузеров
  • По умолчанию browser-ops будет использовать полное название версии, например 102.0.1245.30, а не 102.0. Для использования коротких имен версий укажите следующую опцию:

    browserImageTagFormat: short
    Поскольку при наличии основной версии браузера может одновременно присутствовать несколько минорных версий - при использовании коротких имен версий самая последняя из них не будет присутствовать в списке. Такое поведение позволяет не кэшировать минорные версии, которые скорее всего будут обновлены позже до стабильной версии.
  • По умолчанию browser-ops обновляет только браузеры в наборе браузеров с именем default. Если у вас несколько наборов браузеров, вам будет необходимо указать каждый:

    browsersets:
    - default
    - alpha
    - beta

3.5. Использование собственного реестра контейнеров

По-умолчанию образы Moon (aerokube/defender, aerokube/logger и так далее) загружаются из публичного реестра контейнеров (container registry). Если в вашей организации в связи с ограничениями безопасности образы могут быть загружены только из внутреннего реестра (например my-registry.example.com), вам нужно сконфигурировать Moon для работы с таким реестром. Сделать это можно следующим образом:

  1. Сконфигурируйте Kubernetes, чтобы правильно аутентифицироваться в этом реестре:

    $ kubectl create secret docker-registry my-registry.example.com --docker-server=my-registry.example.com --docker-username=some-user --docker-password=registry-password --docker-email=some-user@example.com -n moon
    $ kubectl patch serviceaccount moon -p '{"imagePullSecrets": [{"name": "my-registry.example.com"}]}' -n moon # Используйте правильное имя service account

    Если вы работаете в Openshift, используйте следующие команды:

    $ oc create secret docker-registry my-registry.example.com --docker-server=my-registry.example.com --docker-username=some-user --docker-password=registry-password --docker-email=some-user@example.com -n moon
    $ oc secrets link moon my-registry.example.com --for=pull -n moon
  2. Скопируйте все нужные образы в ваш реестр:

    quay.io/browser/google-chrome-stable:96.0 => my-registry.example.com/browsers/chrome:96.0
  3. Обновите набор браузеров для работы с вашим реестром:

    Набор браузеров для работы с частным реестром:
    apiVersion: moon.aerokube.com/v1
    kind: BrowserSet
    metadata:
        name: default
        namespace: moon
        # Другие метаданные Kubernetes
    spec:
        # Здесь описаны другие инструменты
        selenium:
          chrome:
            repository: my-registry.example.com/browsers/chrome
          # Здесь описаны другие типы браузеров
  4. Скопируйте нужную версию образов самого Moon в свой реестр:

    aerokube/ca-certs:2.0.0 => my-registry.example.com/aerokube/ca-certs:2.0.0
    aerokube/defender:2.0.0 => my-registry.example.com/aerokube/defender:2.0.0
    aerokube/proxy:2.0.0 => my-registry.example.com/aerokube/proxy:2.0.0
    aerokube/vnc-server:2.0.0 => my-registry.example.com/aerokube/vnc-server:2.0.0
    aerokube/video-recorder:2.0.0 => my-registry.example.com/aerokube/video-recorder:2.0.0
    aerokube/x-server:2.0.0 => my-registry.example.com/aerokube/vnc-server:2.0.0
  5. Переопределите служебные образы Moon в конфигурационном объекте:

    apiVersion: moon.aerokube.com/v1
    kind: Config
    metadata:
        name: default
        namespace: moon
        # Другие метаданные Kubernetes
    spec:
        containers:
          ca-certs:
            repository: my-registry.example.com/aerokube/ca-certs
            version: 2.0.0 # Это поле можно опустить и тогда Moon будет использовать свою собственную версию (рекомендовано)
          defender:
            repository: my-registry.example.com/aerokube/defender
          proxy:
            repository: my-registry.example.com/aerokube/proxy
          vnc-server:
            repository: my-registry.example.com/aerokube/vnc-server
          x-server:
            repository: my-registry.example.com/aerokube/x-server
          video-recorder:
            repository: my-registry.example.com/aerokube/video-recorder
  6. Скопируйте нужные версии основных образов Moon в ваш реестр:

    aerokube/moon:2.0.0 => my-registry.example.com/aerokube/moon:2.0.0
    aerokube/moon-conf:2.0.0 => my-registry.example.com/aerokube/moon-conf:2.0.0
    aerokube/moon-ui:2.0.0 => my-registry.example.com/aerokube/moon-ui:2.0.0
  7. В Helm чарте для запуска Moon и Moon UI используйте новые образы Moon.

3.6. Настройка таймаутов

3.6.1. Настройка таймаутов в Moon

Эти таймауты применяются только к Selenium. Playwright, Cypress и другие инструменты используются постоянное соединение, при разрыве которого сессия автоматически удаляется.

Иногда не все идет по плану: пользователь может неожиданно отсоединиться или браузерная сессия может стартовать слишком долго. Все это может привести к общей деградации кластера, поскольку браузерные поды с разорванными сессиями продолжают потреблять вычислительные ресурсы. Для предотвращения этого Moon автоматически определяет и закрывает простаивающие сессии браузера. Сессия считается простаивающей, если время между двумя HTTP запросами превышает установленный таймаут. Время простоя может быть увеличено, если тестируемые приложения загружаются слишком медленно. Таймауты простоя можно поменять в конфигурационном объекте:

Вывод значений конфигурационного объекта в формате YAML
$ kubectl get configs -n moon -o yaml
apiVersion: v1
items:
- apiVersion: moon.aerokube.com/v1
  kind: Config
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    # Другие поля
    # Используйте значения наподобие 60s или 1m10s
    sessionTimeout: 5m                        (1)
1 Значение таймаута Selenium сессии

Существует несколько редко используемых значений командной строки Moon которые можно использовать для продвинутой конфигурации таймаута:

Table 14. Настройки таймаута с помощью аргументов командной строки (используется редко)
Аргумент Значение по умолчанию Назначение Заметки

-delete-timeout

10 минут

Максимальное время для удаления ресурсов Kubernetes созданных для сессии.

Moon удаляет ресурсы используя Kubernetes API. По истечении этого таймаута Moon останавливает запрос и прекращает удаление ресурсов.

-session-attempt-timeout

30 минут

Максимальное время для старта браузерного пода.

Включает время на планирование и загрузку образа браузера. Таймаут на проксирование запроса балансировщика нагрузки должен быть больше этого значения.

3.6.2. Настройка других таймаутов

Тесты могут упасть не только из-за настроек таймаута в Moon. Типичная инсталляция Moon выглядит так:

Возможные источники таймаута

timeouts

В дополнение к таймаутам в Moon также существуют и другие места, где требуется правильно настроить таймаут:

  1. Таймаут на клиентской стороне. Каждая библиотека Selenium использует HTTP-клиент с настройками таймаута запроса по умолчанию. Если вы часто видите сообщения client disconnected (клиент отключился до завершения обработки запроса) в логе Moon — это может быть признаком необходимости увеличения таймаутов HTTP-клиента в вашем коде.

  2. Таймаут балансировщика. Обычно Moon запускается за балансировщиком (LoadBalancer, Ingress или Router), который также имеет значение таймаута запроса прокси сервера. Часто это значение равно минуте (60 seconds), таким образом если вы часто видите упавшие тесты с ошибкой 502 Bad Gateway или 504 Gateway Timeout - это также может быть признаком необходимости увеличить таймаут балансировщика. Как это сделать зависит от облачной платформы которую вы используете и типа балансировщика. Пример настройки в AWS cloud описан в разделе Connection was closed unexpectedly.

  3. Достигнута емкость кластера. Если в логе вы часто видите сообщения unexpected status это может быть сигналом, что вы использовали все доступные вычислительные ресурсы (процессор и память) выделенные для неймспейса с браузерами.

  4. Фрагментация кластера. В некоторых случаях у вас может быть достаточное количество ядер, и не все браузеры исчерпаны. Например, у вас может быть 4 доступных процессора, распределенных между 4 нодами Kubernetes (1 доступный процессор на ноду), но для запуска нового браузерного пода требуется минимум 2 процессора. В этом случае, несмотря на то что общего количества доступных процессоров достаточно для запуска пода, не существует ноды, на которой браузер мог бы запуститься. Если вы видите много браузерных подов в статусе Pending - проверьте почему эти поды не стартуют, это можно сделать командой kubectl.

3.7. Настройка потребления ресурсов

3.7.1. Потребление ресурсов браузерами

По умолчанию в Moon определены некоторые разумные значения ресурсов, потребляемых каждым подом с браузером. Иногда вам может потребоваться переопределить эти значения. Для переопределения вычислительных ресурсов сразу для всех браузеров используйте конфигурационный объект:

$ kubectl get configs -n moon -o yaml
apiVersion: v1
items:
- apiVersion: moon.aerokube.com/v1
  kind: Config
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    containers:
      browser:
        resources:        (1)
          limits:
            cpu: "1"
            memory: 2Gi
      # Другие поля
1 Настройка ресурсов для браузерных контейнеров

Для обновления значений ресурсов отредактируйте конфигурационный объект и сохраните изменения:

Редактирование конфигурационного объекта
$ kubectl edit config default -n moon # Обновите значения для вычислительных ресурсов, сохраните и выйдите из редактора

Переопределить эти же значения для каждого типа браузера отдельно вы можете в наборе браузеров. Пример доступен тут.

3.7.2. Потребление ресурсов сервисными образами

Чтобы вывести настройки потребления ресурсов для сервисных образов, выведите содержимое конфигурационного объекта в формате YAML:

Ввод значений в формате YAML
$ kubectl get configs -n moon -o yaml
apiVersion: v1
items:
- apiVersion: moon.aerokube.com/v1
  kind: Config
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    containers:
      browser:
        # Другие поля
      ca-certs:
        # Еще поля
        resources:
          limits:
            cpu: 250m
            memory: 64Mi
          requests:
            cpu: 100m
            memory: 64Mi
      defender:
        # Такие же поля как для ca-certs
      video-recorder:
        # Такие же поля как для ca-certs
      vnc-server:
        # Такие же поля как для ca-certs
      x-server:
        # Такие же поля как для ca-certs
      # И еще поля

Для изменения настроек вычислительных ресурсов для каждого сервисного образа отредактируйте конфигурационный объект.

3.7.3. Качество обслуживания подов

Стабильность и скорость автоматизации браузеров очень зависит от вычислительных ресурсов доступных для каждого пода. В Kubernetes реализован механизм Качество обслуживания (QoS), который определяет сколько вычислительных ресурсов выделять при старте пода. В подах Moon для стабильной работы автоматизации мы рекомендуем определять класс QoS Guaranteed. Вам необходимо удостовериться что значения requests и limits для процессора и памяти имеют одинаковые значения:

  1. По умолчанию в Moon значения requests и limits совпадают для сервисных образов типа defender, logger и videoRecorder. В новых версиях Moon вы можете при желании переопределить эти значения.

  2. Для браузерных контейнеров можно независимо переопределить значения requests и limits. Но в любом случае мы рекомендуем одинаковые значения для этих параметров, иначе вы рискуете столкнуться со случайным образом падающими браузерными тестами из-за нехватки вычислительных ресурсов определенных для пода.

3.8. Использование дополнительных доверенных сертификатов TLS

В корпоративных сетях в тестовом окружении часто используется TLS сертификаты, выпущенные корневыми центрами сертификации, неизвестными для браузеров. При попытке открыть HTTPS страницу используя такой сертификат ваш браузер по умолчанию будет отказывать в соединении с предупреждением "Your connection is not private" или "This connection is untrusted". В тестах Selenium для обхода этих предупреждений вы можете использовать стандартную капабилити (acceptInsecureCerts = true), но это не сработает если ваша страница использует механизм Strict Transport Security.

Для корректной работы с дополнительными доверенными TLS сертификатами вам необходимо добавить корневой центр сертификации в список доверенных сертификатов браузера:

  1. Найдите корневой сертификат для центра сертификации (CA certificate) который используется в вашем окружении. Обычно в организации такие сертификаты выпускаются отделом информационной безопасности или системными администраторами и публично доступны в корпоративной сети. Например, ваш корневой сертификат может выглядеть так:

    $ cat rootCA.crt
    -----BEGIN CERTIFICATE-----
    MIIGjzCCBHegAwIBAgIJAK1lW/5z8ZSoMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
    VQQGEwJFRTEQMA4GA1UECBMHRXN0b25pYTEQMA4GA1UEBxMHVGFsbGlubjEeMBwG
    A1UEChQVQWVyb2t1YmUgU29mdHdhcmUgT8OcMRUwEwYDVQQDEwxhZXJva3ViZS5j
    b20xITAfBgkqhkiG9w0BCQEWEmFkbWluQGFlcm9rdWJlLmNvbTAeFw0yMTAyMTcw
    NjQ5NDJaFw0yMzEyMDgwNjQ5NDJaMIGLMQswCQYDVQQGEwJFRTEQMA4GA1UECBMH
    RXN0b25pYTEQMA4GA1UEBxMHVGFsbGlubjEeMBwGA1UEChQVQWVyb2t1YmUgU29m
    dHdhcmUgT8OcMRUwEwYDVQQDEwxhZXJva3ViZS5jb20xITAfBgkqhkiG9w0BCQEW
    EmFkbWluQGFlcm9rdWJlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
    ggIBAKdh54x9WZsSxIMfz1rFEHuJ8+3meUua0Q8cpgC/70F0G6X6BXOki0Cu7iET
    6ETfirWuUdRKKGKXHLF8Fdv6WTqnLlDqgzy1Wp9DuPIgeJ+ztKZt+uJFkWjfQb9R
    mn7Qs4vp/F9HTwqlTZl5jMQ+/nrcNAQeNEZ1H1AfZWAuSvrqp3rW33wl6IBZcqfD
    VsMBknBKm/Zc8GpggY8NYxkfj7Jo2izwn/tV+DFgwF0pJkUrDZPPTiNW7q8Se2Vb
    7tC6Iy9ZVgkH8hkrWrPzwW4zxz/d/Si7/cnn9A9+bF+pKrsHktnQ0ScDEAR5+52J
    XAXkES/4pINpBcxvNUHGO6KXKH4rJVf3QvXXany0ugwVQ+QXirA6yOoY3XFgBxgU
    P7Qd5pyQdVf/SwJ5Uk5Z9b2HXk8k/6jNxe1A6WiojTOnn1fD/VzOTn4xiobqNIpE
    w5dUhlj/TiN+g3uGBH4BPo6IYHCmfsXFEcSZW75k7dRlZ3ZMI4k0utUVm3Y8B+TC
    sj4WmwnXetFP2EMnRft7BnR13oLyzrFB8tkFafstcVoE6oR20pIBtAFxrSDWJ5dA
    XdX2NGPNUCnd1RqJxu2SGA/xHHsyPT06iJeIZGUyRXmv6vBvyCkyeLtMEdq2Gzfi
    MT0GtDkG5R+al/A+Ot3w3CMbMgUFrxvEhlxM1sEitclXJc4tAgMBAAGjgfMwgfAw
    HQYDVR0OBBYEFBb9mCFAqV/JgmMxtwQ6UKzoLIQQMIHABgNVHSMEgbgwgbWAFBb9
    mCFAqV/JgmMxtwQ6UKzoLIQQoYGRpIGOMIGLMQswCQYDVQQGEwJFRTEQMA4GA1UE
    CBMHRXN0b25pYTEQMA4GA1UEBxMHVGFsbGlubjEeMBwGA1UEChQVQWVyb2t1YmUg
    U29mdHdhcmUgT8OcMRUwEwYDVQQDEwxhZXJva3ViZS5jb20xITAfBgkqhkiG9w0B
    CQEWEmFkbWluQGFlcm9rdWJlLmNvbYIJAK1lW/5z8ZSoMAwGA1UdEwQFMAMBAf8w
    DQYJKoZIhvcNAQELBQADggIBAIUmJsxdrT8AN2yZqzI69qQKjLnDhuojdgM3XGL3
    gJTldXR5OIMnw/na8WcIC3onHjgijUeEfslTIIHmNcqOd3hTfOq4Qq2/Qmpp+h1d
    5dCzScrLFiDgjnzkX0VczOj/BtnZMgxx5x8YO80MMUWVEmVCk+i2bFVTypV9e4qw
    1EJLmGTnKoo7l2jPHLUB5lL2LvSO4KHDhmWG5wtFg7/nd097yG5uBHda5ytbc6S8
    CIS8IBJzd7TA4fr3qOhC298LMD96nJdccHqKYtlFvf9YZZ500nrA+pH6Kpo8PD67
    8WiIW/CMtO0X9pxw+KRlmaDmCGGgRhvPyHoYqbX4svrca8uvErePtXIQILe/IISJ
    TXLkiVsej8k3UDu77q/wX3ZdzknWakZyPj+CtYkkZL4vqkIDIFSUcXfynyDZNZEo
    2d+npABzPB42+4xGZGGnFIsfuTMAgpbK8TAgPQNMIawfWTq2KhZ8MYHfPdkU3FBo
    MaExr684sviAImqOotcoNQV2iMOKdwzA097jRBrfa43LhpdoWM0v7RVxB8s+kG0P
    8nHOGmp6r6cIAk5hjHYAwQYiZjXuzvnFTtD9Ily63i+yVh8nRSY9NSLhpFpl4ezo
    hn+savO4nm/HueAATnGR1iPlKnfXNVqQYdl+wwzqK1/3iHjzUUjyQkk0oTBk4Bez
    ejbh
    -----END CERTIFICATE-----
  2. Добавьте данные сертификата в конфигурационный объект:

    apiVersion: moon.aerokube.com/v1
    kind: Config
    metadata:
        name: default
        namespace: moon
        # Другие метаданные Kubernetes
    spec:
      additionalTrustedCAs: |
        -----BEGIN CERTIFICATE-----
        MIIGjzCCBHegAwIBAgIJAK1lW/5z8ZSoMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
        VQQGEwJFRTEQMA4GA1UECBMHRXN0b25pYTEQMA4GA1UEBxMHVGFsbGlubjEeMBwG
        A1UEChQVQWVyb2t1YmUgU29mdHdhcmUgT8OcMRUwEwYDVQQDEwxhZXJva3ViZS5j
        ....

    Если нужно добавить несколько сертификатов - каждый сертификат добавляется с новой строки:

    apiVersion: moon.aerokube.com/v1
    kind: Config
    metadata:
        name: default
        namespace: moon
        # Другие метаданные Kubernetes
    spec:
      additionalTrustedCAs: |
        -----BEGIN CERTIFICATE-----
        MIIGjzCCBHegAwIBAgIJAK1lW/5z8ZSoMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
        VQQGEwJFRTEQMA4GA1UECBMHRXN0b25pYTEQMA4GA1UEBxMHVGFsbGlubjEeMBwG
        A1UEChQVQWVyb2t1YmUgU29mdHdhcmUgT8OcMRUwEwYDVQQDEwxhZXJva3ViZS5j
        ...
        -----END CERTIFICATE-----
        -----BEGIN CERTIFICATE-----
        MIIDBjCCAe6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwptaW5p
        a3ViZUNBMB4XDTIyMDExMDEzMzgwNloXDTMyMDEwOTEzMzgwNlowFTETMBEGA1UE
        AxMKbWluaWt1YmVDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALpJ
        ...
        -----END CERTIFICATE-----

    Добавленные сертификаты автоматически применяются к любому типу браузера и работают для загрузки видео в хранилище S3.

3.9. Расширенные настройки

В этом разделе описаны различные расширенные настройки, которые порой бывают необходимы для настройки кластера Kubernetes. Для большинства настроек, описанных ниже, Moon использует такой же YAML синтаксис, что и сам Kubernetes. Так выглядит обычный под в Kubernetes:

Обычный под Kubernetes, вывод в формате YAML
apiVersion: v1
kind: Pod
metadata:
  name: my-app
  annotations:
    key1: "value1"
    key2: "value2"
  labels:
    key1: "value1"
    key2: "value2"
spec:
  containers:
  - name: app
    image: my-company/my-app:1.0.0
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

Сравните вывод с одним из объектов Moon:

apiVersion: moon.aerokube.com/v1
kind: BrowserSet
metadata:
  name: default
  namespace: moon
  # Другие метаданные Kubernetes
spec:
  annotations:
    key1: "value1"
    key2: "value2"
  labels:
    key1: "value1"
    key2: "value2"

3.9.1. Добавление пользовательских аннотаций Kubernetes

Эта настройка производится глобально или для конкретного типа браузера в объекте конфигурации браузеров. Подробно это описано по ссылке.

3.9.2. Добавление пользовательских меток Kubernetes

Эта настройка производится глобально или для конкретного типа браузера в объекте конфигурации браузеров. Подробно это описано по ссылке. Также вы можете переопределить метки с помощью капабилити labels.

3.9.3. Добавление сетевых политик

Сетевые политики — это специальные объекты Kubernetes, позволяющие контролировать правила сетевого файервола. Использовать их с Moon очень просто:

  1. Создайте объект NetworkPolicy. Он может выглядеть так:

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: my-network-policy
      namespace: moon
    spec:
      podSelector:
        matchLabels: # Это правило будет применено к подам, у которых выставлена метка role = browser
          role: browser
      ingress:
      - from:
        - podSelector:
            matchLabels:
              role: my-app
        ports:
        - protocol: TCP
          port: 6379
  2. Добавьте пользовательские метки на браузерный под:

    selenium:
      chrome:
        repository: quay.io/browser/google-chrome-stable
        labels:
          role: browser # Каждый под с браузером Chrome будет иметь метку role = browser

3.9.4. Использование node selector

Эта настройка производится глобально или для конкретного типа браузера в объекте конфигурации браузеров. Подробно это описано по ссылке.

3.9.5. Использование аффинити

Эта настройка производится глобально или для конкретного типа браузера в объекте конфигурации браузеров. Подробно это описано по ссылке.

3.9.6. Использование Tolerations

Эта настройка производится глобально или для конкретного типа браузера в объекте конфигурации браузеров. Подробно это описано по ссылке.

3.9.7. Запуск браузеров в привилегированном режиме

Эта настройка производится глобально или для конкретного типа браузера в объекте конфигурации браузеров. Подробно это описано по ссылке.

3.9.8. Настройка пользовательского идентификатора пользователя (uid) и группы (gid) для браузерных подов

В Moon версии 2.x конфигурация для всех подов делается в конфигурационном объекте. Если вам нужно настроить идентификатор пользователя или группы для разных пользователей вам нужно создать несколько конфигурационных объектов и связать их с объектами квот. Значения по умолчанию перечислены ниже:

Table 15. Пользователи и группы в подах по умолчанию
Название Значение

ID пользователя по-умолчанию

4096

Имя пользователя по-умолчанию

user

ID группы по-умолчанию

4096

Имя группы по-умолчанию

user

3.9.9. Настройка service account для подов

Настраивается для всех подов сразу в конфигурационном объекте.

Настройка сервисных аккаунтов для подов
$ kubectl get configs -n moon -o yaml
apiVersion: v1
items:
- apiVersion: moon.aerokube.com/v1
  kind: Config
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    # Другие поля
    serviceAccountName: my-account        (1)
    # Другие поля
1 Настройка service account

3.9.10. Настройка security context для подов

Настраивается для каждого контейнера Moon в конфигурационном объекте. Синтаксис YAML syntax такой же, как и для Kubernetes.

Добавление security context в контейнеры подов
$ kubectl get configs -n moon -o yaml
apiVersion: v1
items:
- apiVersion: moon.aerokube.com/v1
  kind: Config
  metadata:
    name: default
    namespace: moon
    # Другие метаданные Kubernetes
  spec:
    # Другие поля
    containers:
      browser:
        # Другие поля
        securityContext:                    (1)
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          privileged: false
          runAsGroup: 4096
          runAsNonRoot: true
          runAsUser: 4096
          seccompProfile:
            type: RuntimeDefault
        # Другие поля
      ca-certs:
        # Такие же поля, как для browser
      defender:
        # Такие же поля, как для ca-certs
      proxy:
        # Такие же поля, как для ca-certs
      video-recorder:
        # Такие же поля, как для ca-certs
      vnc-server:
        # Такие же поля, как для ca-certs
      x-server:
        # Такие же поля, как для ca-certs
1 Определение контекста безопасности

3.10. Обновление версии Moon

Релизы Moon версионируются по схеме семантического версионирования (MAJOR.MINOR.PATCH), например 2.3.0, 2.5.3 и так далее. Основная версия (MAJOR) соответствует "поколению" Moon, в данный момент это вторая версия. Минорный компонент (MINOR) версии изменяется при добавлении/обновлении важной функциональности. Патч соответствует релизу (PATCH), который содержит в основном незначительные улучшения и исправление ошибок.

Основной способ установки Moon - используя Helm чарт:

Обычный способ установки Moon
$ helm upgrade --install -n moon moon aerokube/moon2

Обычно для обновления версии программного обеспечения с помощью Helm необходимо выполнить команду:

Обновление Moon до версии только с измененным патчем:
$ helm repo update # Загружает последнюю информацию о Helm чарте
$ helm upgrade --install -n moon moon aerokube/moon2 # Та же команда что и для установки

Эти команды работают при изменении PATCH-версии в Moon (например с 2.5.0 на 2.5.1, 2.5.2 и так далее). Для обновления Moon на следующую MINOR версию (например с 2.4.0 на 2.5.0) процедура немного сложнее. Причина этой сложности заключается в том что Moon 2 для хранения конфигурации использует так называемые пользовательские ресурсы Kubernetes и время от времени мы добавляем новые поля к этим ресурсам. В настоящее время Helm никогда не обновляет уже созданные custom resource definition (CRD), поэтому для обновления минорной версии вам нужно вручную выполнить следующее:

Обновление Moon с изменением custom resource definition
$ helm repo update
$ helm delete moon -n moon # Удаляем предыдущую версию
$ kubectl delete crd $(kubectl get crd | grep moon.aerokube.com | awk '{print $1}') # Удаляем CRD из предыдущей версии Moon
$ helm upgrade --install -n moon moon aerokube/moon2 # Устанавливаем новую версию Moon

Изменения custom resource definitions обычно отражается в release notes (например тут). Если не обновить custom resource definition, Moon перестанет работать и вы увидите сообщения об ошибках типа:

# При обновлении в Helm
unknown field "spec.containers.proxy"

# В логах Moon:
moon: no such config: "default"
config controller: config "default": add: validate containers.proxy: value is not set: using default

3.11. Мониторинг

Метрики Moon, например потребление браузеров легко визуализировать с помощью мониторинговых систем Prometheus и Grafana. Один из самых простых способов развернуть Prometheus в Kubernetes это использовать Prometheus Operator.

3.11.1. Установка

  1. Moon уже должен быть запущен (например в неймспейсе moon).

  2. Установите Prometheus и Grafana с помощью Prometheus Operator (например в неймспейс monitoring).

    Пример команды установки с использованием Helm 3:

    $ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
    $ helm repo update
    $ helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --create-namespace --namespace monitoring

3.11.2. Встроенные метрики Moon

Встроенные метрики Moon транслируются в /metrics HTTP API.

Получение метрик Prometheus
$ curl -s https://moon.example.com/metrics
# Список множества метрик будет отображен тут

Доступны следующие метрики:

Table 16. Встроенные в Moon метрики Prometheus
Название Тип Метка Значение

moon_browser_limit

gauge

-

Максимальное количество сессий которое позволяет лицензионныый ключ

moon_browser_running

gauge

-

Общее количество запущенных броуерных сессий

moon_browser_count

gauge

quota, browserName, browserVersion

Потребление ресурсов браузерами по типу и версии браузера

moon_browser_queued

gauge

-

Общее количество браузерных запросов в очереди

moon_license_expire

gauge

-

Временная метка истечения срока действия лицензионного ключа Moon

3.11.3. Фильтрация подов по меткам

Если при установке Prometheus вы использовали параметр kube-prometheus-stack то вам доступен компонент kube-state-metrics. Этот компонент позволяет вам отфильтровывать поды Kubernetes по метке, аннотации, статусу, времени старта и так далее. Получить информацию о подах с помощью меток можно следующим запросом Prometheus:

kube_pod_labels{label_moon="browser", label_browserName="chrome", label_browserVersion="96.0"}

Полный список возможных запросов находится по ссылке.

Moon может добавлять пользовательские метки на поды (например название проекта по автоматизации, тестируемую функциональность и так далее). Для всех подов это можно сделать в объекте конфигурации браузеров, Selenium capabilities и так далее. Например, после добавления метки project="MyCoolProject" на под вы можете настроить такую фильтрацию:

kube_pod_labels{label_moon="browser", label_project="MyCoolProject", label_browserName="chrome"}

3.12. Логи

Несмотря на то что Moon работает сразу после установки, иногда возникает необходимость просмотреть содержимое лог файлов. Каждый компонент Moon пишет логи в стандартный поток вывода (stdout), то есть для просмотра лог файлов вы можете использовать известные команды kubectl. Все что связано с работой браузерных сессий выводится в контейнер moon:

$ kubectl logs -lapp=moon -c moon -n moon

Для просмотра логов в реальном времени при выполнении тестов добавьте флаг -f:

$ kubectl logs -f -lapp=moon -c moon -n moon

Для просмотра логов moon-conf и moon-ui используйте следующие команды:

$ kubectl logs -f -lapp=moon -c moon-conf -n moon
$ kubectl logs -f -lapp=moon -c moon-ui -n moon

Если браузерные поды по какой либо причине не удаляются, необходимо проанализировать содержимое лога контейнера defender для каждого зависшего пода:

$ kubectl logs chrome-73-0-ac15ffaa-e641-4c7f-a54c-f25b5be1f135 -c defender -n moon

В данном случае chrome-73-0-ac15ffaa-e641-4c7f-a54c-f25b5be1f135 это ID сессии и имя пода с браузером.

3.13. Флаги командной строки (CLI)

Эти флаги передаются в файлах YAML в Kubernetes при старте кластера.

3.13.1. Флаги контейнера Moon

Поддерживаются следующие флаги:

-browser-limit value
    parallel browser sessions limit
-callback-url value
    moon callback url
-delete-timeout duration
    timeout to delete Kubernetes resources (default 10m0s)
-grace-period duration
    graceful shutdown period (default 5m0s)
-listen string
    host and port to listen to (default ":4444")
-moon-url value
    moon service url (default http://moon.moon:4444/wd/hub)
-session-attempt-timeout duration
    new session attempt timeout (default 30m0s)
-version
    show version and exit

3.13.2. Флаги контейнера Moon Auth

Поддерживаются следующие флаги:

-ca-cert string
    ca certificate to verify discovery cert (optional)
-client-id string
    client id (required)
-client-secret string
    client secret (required)
-discovery-url value
    oidc discovery url (required)
-fail-login-timeout duration
    request timeout (default 30s)
-grace-period duration
    graceful shutdown period (default 30s)
-group value
    allowed user groups (optional)
-ignore-case
    ignore user groups case
-listen string
    address to bind (default ":4545")
-request-timeout duration
    request timeout (default 30s)
-upstream-url value
    upstream url (default http://127.0.0.1:4444/)
-version
    show version and exit

3.13.3. Флаги контейнера Moon Basic Auth

Поддерживаются следующие флаги:

-f string
    htpasswd file path (default "/conf/auth")
-grace-period duration
    graceful shutdown period (default 30s)
-listen string
    address to bind (default ":4545")
-upstream-url value
    upstream url (default http://127.0.0.1:4444/)

4. Часто задаваемые вопросы

4.1. Где хранятся логи Moon?

Смотрите раздел файлы логов.

4.2. Где хранятся записанные видео?

Moon автоматически сохраняет логи сессий и записанные видео в хранилище совместимое с S3. Если хранилище S3 не сконфигурировано, запись видео работать не будет.

4.3. Как обновить конфигурацию на работающем кластере Moon?

Отредактируйте соответствующие ресурсы (config, browserset, deviceset, quota, license) с помощью команд Kubernetes (kubectl edit или kubectl replace). Например:

$ kubectl edit config default -n moon # Обновление конфиурационного объекта
$ kubectl edit browserset default -n moon # Обновление конфигурации браузеров Moon
$ kubectl edit deviceset users -n moon # Обновление конфигурации устройств Moon
$ kubectl edit quota default -n moon # Обновление объекта квоты Moon
$ kubectl edit license moon # Обновление лицензионного ключа Moon

Отредактируйте значения в любом предпочитаемом редакторе, сохраните изменения и закройте файл. Изменения применятся сразу же.

4.4. Можно ли сконфигурировать для Moon сервисный аккаунт в Kubernetes?

Да, в Moon есть настройка serviceAccountName в конфигурационном объекте.

4.5. Можно ли применить пользовательские настройки фаервола на браузерные поды?

Да, в Kubernetes реализован механизм Kubernetes Network Policies. В Moon есть воззможность назначать метки на запущенные браузерные поды. Чтобы применить правило файервола на под, нужно назначить набор пользовательских меток на этот под, а затем создать соответствующие модули NetworkPolicy с помощью podSelector, используя эти метки. Пример такой конфигурации доступен по ссылке.

4.6. Connection was closed unexpectedly

Если ваши HTTP запросы периодически зависают в случайном порядке это может означать слишком маленькое значение таймаута HTTP запроса которое задано на вашем балансировщике (LoadBalancer, Ingress, Openshift Route). Чаще всего используется значение по умолчанию, равное 30 seconds а это может приводить к разрыву соединения при большом количестве запросов Selenium сессий. Изменение таймаута обычно зависит от облачной платформы которая используется в вашем окружении. Например, при использовании балансировщика AWS это может выглядеть так:

Увеличение таймаута в AWS
kind: Service
apiVersion: v1
metadata:
  name: moon
  namespace: moon
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "60" # Таймаут AWS load balancer
spec:
  type: LoadBalancer
  # Остальные поля...

Если вы используете Nginx Ingress, изменения выглядят так:

Увеличение таймаута в Nginx Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: moon
  namespace: moon
  annotations:
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "108000" # Обратите внимание на эти настройки
    nginx.ingress.kubernetes.io/proxy-send-timeout: "108000"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "108000"
spec:
  ingressClassName: nginx
  rules:
    # Правила описываются тут...

4.7. Таймауты поиска DNS

Если в качестве сетевого движка Kubernetes вы используете Flannel и видите в логах сообщения о таймаутах DNS, например…​

2019/02/21 08:37:32 [VNC_ERROR] [10.244.1.1] [dial tcp: lookup chrome-71-0-686efb96-eabe-4435-af31-21a33c8a4c8b on 10.96.0.10:53: read udp 10.244.1.11:40603->10.96.0.10:53: i/o timeout]

…​тогда вам может потребоваться установить следующее свойство ядра на нодах Kubernetes:

$ sysctl net.bridge.bridge-nf-call-iptables=1

4.8. Таймауты сессии браузера не работают

Такое может случиться при неправильно заданном значении -moon-url. По умолчанию Moon предоставляется с помощью Kubernetes сервиса с названием moon на порту 4444. В этом случае все работает сразу после установки с флагом -moon-url по умолчанию. Но при ручном развертывании имя сервиса может отличаться. В таком случае вам необходимо явно установить значение -moon-url. Например, если Moon предоставляется под именем my-custom-moon-service на порту 3333 вам необходимо явно указать значение -moon-url http://my-custom-moon-service:3333/wd/hub в ваши манифесты развертывания.

4.9. Ошибки обработки JSON в тестах

В некоторых окружениях ваши Selenium тесты время от времени могут начать генерировать Json ошибки типа следующих:

Json exception: Expected to read a START_MAP but instead have: END. Last 0 characters read

Основная причина таких ошибок это неправильо сконфигурированное значение таймаута на балансировщике LoadBalancer или Ingress. Очень часто значение по умолчанию равно LoadBalancer or Ingress и если в некоторых случаях Selenium требует больше времени балансировщик прерывает запрос и шлет ошибку 502 с пустым телом или с телом в виде HTML разметки. Однако клиент Selenium всегда ожидает непустой ответ в формате JSON и любой другой ответ приведет к ошибкам обработки JSON. Исправить ситуацию можно увеличив значение таймаута на балансировщике. Как это сделать подробно описано в документации конкретного балансировщика.

4.10. Можно ли использовать Moon с частным репозиторием Docker?

Да. Как это сконфигурировать и настроить описано здесь.

4.11. Можно ли тестировать веб приложения использующие HTTPS с самоподписанными сертификатами TLS?

Да, вы можете настроить собственные корневые центры сертификации TLS. Как это сделать описано здесь.

5. Лицензионное соглашение ПО "Moon"

Дата последнего обновления: 25 марта 2024 года. Полностью заменяет предыдущую версию.

В данном документе содержится Лицензионное соглашение. Скачивая, устанавливая, копируя, сохраняя на компьютер или используя программное обеспечение, техническую поддержку или продукты ООО "Аерокуб" иным способом, Вы принимаете все положения настоящего Лицензионного соглашения и становитесь одной из его Сторон.

  1. Стороны

    1. ООО "Аерокуб", "Поставщик" или "Лицензиар" означает Общество с Ограниченной Ответственностью "Аерокуб", ОГРН 1187847375473, ИНН 7841079851, КПП 470501001, находящееся по адресу: 188307, Россия, Ленинградская область, Гатчинский район, г. Гатчина, Красноармейский проспект, д. 50, каб. 7.

    2. "Покупатель" или "Лицензиат" означает физическое или юридическое лицо, указанное в Подтверждении Подписки. Для юридических лиц, понятие "Покупатель" включает в себя любое юридическое лицо, которое контролирует или контролируется Покупателем. В данном определении, "контроль" означает одно из нижеследующего:

      1. Возможность прямо или косвенно управлять деятельностью юридического лица, например, согласно ранее подписанному договору или иным способом;

      2. Владение пятидесяти (50%) или более процентов акций или доли в уставном капитале юридического лица.

  2. Определения

    1. "Соглашение" означает настоящее Лицензионное соглашение.

    2. "Продукт" означает любое общедоступное программное обеспечение, созданное Поставщиком и распространяемое им как инструмент разработки программного обеспечения. Продукт не изготавливается по заданию Покупателя, не изменялся под его требования и предназначен для массового распространения. Исходный код Продукта не передается Покупателю. Продукт включает код и библиотеки (в том числе с открытым исходным кодом), созданные третьими лицами.

    3. "Пользователь" означает сотрудника, независимого подрядчика и любой другой персонал, имеющий доступ к Продукту от имени Покупателя.

    4. "Число Параллельных Сессий" означает максимальное число запущенных процессов тестирования программного обеспечения, использующих Продукт в своей работе. Например, это могут быть браузеры, выполняющие тесты Пользователя.

    5. "Лицензионный Ключ" означает уникальный код, позволяющий Покупателю использовать Продукт, разблокируя фиксированное Число Параллельных Сессий. Лицензионные Ключи для Продукта могут создаваться только Поставщиком и/или его законными представителями.

    6. "Подписка" означает использование Продукта с периодической предварительной оплатой. Подписка включает в себя длительность, набор Продуктов, предоставляемых Покупателю, стоимость, график оплаты и фиксированное количество Лицензионных Ключей.

    7. "Пробное Использование Продукта" означает использование Продукта без действующего Лицензионного Ключа.

    8. "Подтверждение Подписки" означает электронное письмо, подтверждающее право Покупателя использовать Продукт и включающее информацию о Числе Параллельных Сессий.

    9. "Установленная Копия Продукта" означает копию Продукта, работающую на компьютерных устройствах, серверах или виртуальных машинах Покупателя.

    10. "Версия Продукта" означает фиксированный выпуск, обновление или изменение Продукта, не созданный исключительно с целью исправления выявленных ошибок.

    11. "Исправление Продукта" для конкретной Версии Продукта означает выпуск или обновление Продукта, созданное Поставщиком с целью исправления ошибок в этой Версии Продукта.

    12. "Техническая Поддержка по Электронной Почте" означает вид технической поддержки Покупателей, оказываемой Поставщиком или его представителями. Для получения Технической Поддержки по Электронной Почте используется адрес: support@aerokube.com. При изменении адреса электронной почты объявление об этом будет размещено на официальном сайте Поставщика.

    13. "Техническая Поддержка в Системах Мгновенного Обмена Сообщениями" означает вид технической поддержки, оказываемой Поставщиком или его представителями. Для получения поддержки используется адрес: https://t.me/aerokube_moon. При изменении адреса Технической Поддержки в Системах Мгновенного Обмена Сообщениями объявление об этом будет размещено на официальном сайте Поставщика.

    14. "Аффилированное Лицо" означает юридическое лицо, принадлежащее к той же группе, что и Покупатель или Поставщик.

  3. Общие положения

    1. Поставщик оставляет за собой право прекратить поддержку Продукта, изменить цены, спецификацию, набор доступных функций, правила использования, время выпуска новых версий и любые другие характеристики Продукта.

    2. Покупатель подтверждает, что у него была достаточная возможность ознакомиться с настоящим Соглашением, понять содержание всех его положений, обсудить его условия и обратиться за независимой профессиональной юридической консультацией в этом отношении до его заключения.

    3. Если какое-либо конкретное положение настоящего Соглашения не может быть исполнено, то неисполнимость этого положения не влияет на любые другие положения настоящего Соглашения.

    4. Заголовки и колонтитулы предназначены исключительно для удобства и не влияют на толкование настоящего Соглашения.

    5. Неспособность Поставщика обеспечить соблюдение или осуществление какой-либо части настоящего Соглашения не является отказом от этого раздела.

    6. Поставщик может уведомлять Покупателя по электронной почте, заказным письмом, доставляя такое уведомление персонально или курьерской службой доставки. Любое такое уведомление считается действительным:

      • В день его отправки Покупателю по электронной почте;

      • В момент персональной доставки;

      • Через один (1) день после передачи его курьерской службе доставки или через пять (5) дней после отправки почтой.

  4. Права и обязанности сторон

    1. Продукт предоставляется на основе Числа Параллельных Сессий. Для каждой Подписки, предусмотренной в рамках настоящего Соглашения, Покупатель получает права, описанные в данном разделе. Права Покупателя и его Пользователей по отношению к Продукту ограничиваются правами, позволяющими полноценно использовать Продукт. Все остальные права принадлежат Поставщику.

    2. До истечения срока Подписки или расторжения настоящего Соглашения в порядке, описанном в настоящем Соглашении, Поставщик передает неисключительное и непередаваемое право использовать каждый Продукт, включенный в Подписку, как описано ниже.

    3. Покупатель имеет право:

      • Для каждого Лицензионного Ключа, включенного в Подписку, иметь только одну Установленную Копию Продукта любой версии, доступной в Подписке, на любой операционной системе, поддерживаемой Продуктом;

      • Иметь одну резервную копию поставки Продукта, созданную для непредвиденных ситуаций.

    4. Покупатель не имеет права:

      • Использовать Установленную Копию Продукта с большим Числом Параллельных Сессий, чем поддерживается Лицензионным Ключом из Подтверждения Подписки;

      • Изменять или копировать Продукт, создавать производные продукты на его основе, а также продавать или передавать Продукт третьим лицам;

      • Предоставлять доступ к Продукту или права его использования третьим лицам;

      • Декомпилировать, дизассемблировать, изменять составные части Продукта, а также делать любые другие попытки получить исходный код Продукта;

      • Удалять или скрывать любые уведомления о праве собственности Поставщика, содержащиеся в Продукте.

    5. Права, передаваемые в этом разделе, вступают в силу в случае, если Покупатель существенно не нарушал положений настоящего Соглашения и оплатил стоимость Подписки.

    6. Покупатель соглашается с тем, что в независимости от использования терминов "покупка" и "продажа" в настоящем Соглашении, право владения Продуктом не передается Покупателю. Поставщик имеет и сохраняет любые права, название и прибыли, включая права на интеллектуальную собственность, на Продукт или любые связанные технологии, в том числе созданные на основе Обратной Связи от Пользователей (см. раздел “Обратная Связь”).

    7. Настоящее Соглашение имеет одинаковую юридическую силу в независимости от того, продается ли Подписка напрямую Поставщиком или посредниками. Если покупка идет через посредника, то посредник несет ответственность за правильность сведений, указанных в Подтверждении Подписки. Посредники не имеют права давать обещания или обязательства от имени Поставщика. Покупатель соглашается с тем, что обязательства Поставщика ограничиваются изложенными в настоящем Соглашении.

  5. Форс-мажор

    1. Стороны не несут ответственность за неисполнение, либо ненадлежащее исполнение обязательства по настоящему Соглашению, если докажут, что это произошло вследствие наступления обстоятельств непреодолимой силы (форс-мажор), возникших после заключения настоящего Соглашения в результате событий чрезвычайного характера, которые Стороны не могли ни предвидеть, ни предотвратить разумными мерами, и Стороны предприняли все возможные и зависящие от них меры по надлежащему исполнению своих обязанностей. К форс-мажорным обстоятельствам относятся, в частности: забастовка, военные действия, террористический акт, воздействие сил природы (землетрясение, наводнение и т.д.), отказ центров обработки данных или телекоммуникационного оборудования, решения государственных органов.

    2. О наступлении форс-мажорных обстоятельств, Стороны должны уведомить друг друга в течение трех (3) рабочих дней с момента их наступления.

    3. В случае возникновения форс-мажорных обстоятельств срок выполнения обязательств по настоящему Соглашению переносится на период, в течение которого действуют такие обстоятельства и их последствия.

  6. Порядок поставки продукта

    1. Все Продукты, указанные в настоящем Соглашении, поставляются в электронном виде. Для скачивания копии Продукта, Покупатель и его Пользователи должны иметь соединение с сетью Интернет. Покупатель производит скачивание и установку копии Продукта самостоятельно. Инструкции по скачиванию и установке продукта размещены на сайте Поставщика: https://aerokube.com.

    2. Покупатель получает полный доступ к возможностям Установленной Копии Продукта, указав Лицензионный Ключ из Подтверждения Подписки.

    3. Покупатель имеет право бесплатно устанавливать и использовать неограниченное число копий Продукта для Пробного Использования. Продукт имеет возможность автоматически ограничивать Число Параллельных Сессия в случае Пробного Использования Продукта. Поставщик оставляет за собой право изменять установленное ограничение в новых версиях Продукта.

  7. Стоимость и порядок расчётов

    1. Покупатель обязан оплатить стоимость Подписки в соответствии с условиями оплаты Поставщика или условиями оплаты посредника, в зависимости от того, что применимо в текущей ситуации.

    2. Стоимость Подписки должна быть оплачена полностью. Любые налоги, пошлины, сборы, налагаемые на Покупателя (например, налог на добавленную стоимость или налог на прибыль) должны уплачиваться Покупателем.

    3. Покупатель не может уменьшать стоимость Подписки, оплачиваемую Поставщику или посредникам, в случае, если иное не указано в условиях оплаты от Поставщика или посредника.

  8. Обратная связь

    1. Покупатель не обязан предоставлять Поставщику идеи и предложения по развитию Продуктов (далее "Обратная Связь").

    2. Если Покупатель или его Пользователи отправляют Обратную Связь Поставщику, то Покупатель предоставляет Поставщику неисключительное бесплатное право без ограничений использовать, выставлять на продажу, продавать, импортировать, воспроизводить, изменять и публично демонстрировать указанные в Обратной Связи сведения любым законным способом. Указанное право может передаваться Аффилированным с Поставщиком Лицам, а также третьим лицам, если это не противоречит действующему законодательству.

  9. Ограниченная гарантия Все Продукты предоставляются Покупателю "как есть", без каких-либо явных или подразумеваемых гарантий. Использование Продукта осуществляется Покупателем на собственный страх и риск. Поставщик не несет гарантийных обязательств в отношении его использования и работы. В максимально допустимой действующим законодательством степени, Поставщик, его контрагенты (включая поставщиков стороннего программного обеспечения) и/или его посредники настоящим отказываются от гарантий и условий, включая все гарантии и условия товарной ценности, как в прямой, так и в косвенной форме, в том числе гарантий, обусловленных законодательством, пригодности для определенных целей, права собственности и ненарушения прав третьих лиц, в отношении Продуктов или оказания, или невозможности оказания технической поддержки. Эта гарантия дает Покупателю ограниченные юридические права. Ни Продавец, ни один из его руководителей, директоров, сотрудников, консультантов, агентов, филиалов или Аффилированных Лиц не несут ответственность за:

    • Правильность, точность и надежность Продуктов;

    • Соответствие Продуктов требованиям Покупателя;

    • Непрерывную и гарантированную доступность Продуктов в любой юрисдикции и в любой момент времени;

    • То, что любые дефекты и ошибки в Продукте будут исправлены. Загрузка или иное получение любых сведений и данных в результате использования Продуктов производится по усмотрению Покупателя и на его собственный риск. Покупатель несет единоличную ответственность за любой ущерб, причиненный его собственности, или утрату данных в результате загрузки или получения Продукта. Не дается никаких гарантий или не наступает никакая ответственность, связанная с Пробным Использованием Продукта.

  10. Ограничение ответственности

    1. Ни при каких обстоятельствах Поставщик не несет ответственности за:

      • Любые убытки, ущерб и невозможность использования Продукта, независимо от того, были они предсказуемы или нет;

      • Любые убытки или ущерб, понесенные из-за приостановки доступа за неуплату или расторжения настоящего Соглашения, в соответствии с его положениями;

      • Любой прямой, косвенный, случайный, преднамеренный или побочный ущерб (даже если Поставщику было сообщено о возможности такого ущерба), включая:

        • Любые убытки, тем или иным образом возникшие в результате утраты эксплуатационных качеств, данных или выгоды в результате использования Продукта, независимо от того, были они предсказуемы или нет;

        • Ответственность, связанную с любыми другими правовыми нормами, включая существенное нарушение условий настоящего Соглашения или Ограниченной гарантии, небрежность или неправомерные действия;

        • Любую ответственность, связанную с использованием Продукта Покупателем или с получением доступа к Продукту или к технической поддержке.

    2. Приведенные выше ограничения ответственности применяются в максимальной степени, разрешённой действующим законодательством.

    3. В любом случае и в максимальной степени, разрешенной законом, общая ответственность Поставщика по отношению к Покупателю ограничена пятью тысячами (5000) рублей или суммой, уплаченной Покупателей за Продукт в течение одного (1) месяца, предшествующего дате события, повлекшего такую ответственность, в зависимости от того, какая из сумм окажется большей. Это ограничение будет применяться даже в том случае, если Продавцу было сообщено о возможности ответственности, превышающей указанную сумму, и, если применяемое ограниченное средство правовой защиты не достигает своей основной цели.

  11. Срок действия Соглашения. Расторжение Соглашения.

    1. Настоящее Соглашение вступает в силу с момента его подписания обеими Сторонами.

    2. Настоящее Соглашение может быть изменено и дополнено только по письменному соглашению Сторон.

    3. Настоящее Соглашение действует до окончания срока действия Подписки каждого Продукта, указанного в Подтверждении Подписки.

    4. Покупатель может в одностороннем порядке расторгнуть настоящее Соглашение в любое время, удалив Установленную Копию Продукта. Если расторжение происходит в течение текущего периода Подписки, настоящее Соглашение будет продолжать действовать до конца этого периода Подписки. Такое прекращение действия настоящего Соглашения не освобождает Покупателя от обязанности оплатить любую непогашенную задолженность, причитающуюся Поставщику. При этом предоплаченная стоимость Подписки не возмещается Покупателю за исключением случаев, предусмотренных настоящим Соглашением.

    5. Поставщик может в одностороннем порядке расторгнуть настоящее Соглашение, если:

      • Поставщик существенно нарушил условия настоящего Соглашения и не устранил выявленные нарушения в течение 30 дней;

      • Поставщик не произвел своевременную оплату Подписки;

      • Поставщик должен сделать это во исполнение действующего законодательства (например, если поставка Продукта Покупателю противоречит действующему или вступающему в силу законодательству);

      • Поставщик принял решение остановить поставку Продукта или его частей.

    6. Поставщик предпримет разумные усилия, чтобы уведомить Покупателя по электронной почте:

      • За тридцать (30) дней до расторжения настоящего Соглашения, если это делается во исполнение действующего законодательства или, если принято решение остановить поставку Продукта. В этом случае Покупателю будут возвращены денежные средства за неиспользованную часть срока Подписки, если применимо;

      • За три (3) дня до расторжения настоящего Соглашения в остальных случаях. При этом Покупателю не будут возвращены денежные средства за неиспользованную часть срока Подписки.

  12. Приостановка доступа за неуплату

    1. Поставщик оставляет за собой право приостановить или ограничить доступ Покупателя к своим Продуктам, если Покупатель не оплачивает стоимость Подписки в установленные сроки.

    2. Если Поставщик приостанавливает или ограничивает доступ Покупателя к своим Продуктам, то для восстановления доступа Покупатель должен оплатить всю накопившуюся задолженность.

  13. Техническая поддержка

    1. Поставщик предоставляет Техническую Поддержку по Электронной Почте и Техническую Поддержку в Системах Мгновенного Обмена Сообщениями. Поставщик будет отвечать по указанным каналам за разумное время, но не дает конкретных гарантий по времени ответа.

    2. Покупатель имеет право дополнительно запросить платную техническую поддержку от Поставщика. Условия, сроки и стоимость подобной платной технической поддержки должны быть закреплены в отдельном договоре между Покупателем и Поставщиком.

    3. Любые гарантии возможности технической поддержки распространяются только на последнюю версию Продукта, доступную в Подписке Покупателя.

  14. Данные покупателя

    1. Использование имени и Логотипа. Покупатель соглашается, что Поставщик имеет право ссылаться на него по имени, торговому имени или торговой марке, а также кратко описывать деятельность Покупателя в рекламных материалах, на официальном веб-сайте, в общедоступных и правовых документах. Покупатель дает Поставщику неисключительное бесплатное право использовать имя, торговое имя или торговую марку Покупателя исключительно в рекламных материалах. В случае, если Покупатель получает право на использование логотипов и торговых марок от третьих лиц (например, торговые марки и логотипы Аффилированных Лиц) и не может передать право на их использование Поставщику, эта статья не применяется.

    2. Сбор статистики использования Продукта. Покупатель подтверждает и соглашается с тем, что Продукт может содержать возможность отправки статистики использования и диагностической информации Поставщику. Покупатель может отказаться от отправки указанных сведений, отключив эту возможность в настройках Продукта.

    3. Конфиденциальность. Настоящее Соглашение, его содержание, а также все приложения к нему, являются конфиденциальными документами и не подлежат разглашению или использованию Сторонами в каких-либо целях без письменного согласия другой Стороны, за исключением случаев, когда этого требуют официальные органы Российской Федерации вследствие выполнения требования действующего законодательства.

  15. Заключительные положения

    1. Все споры и разногласия, возникающие между Сторонами при исполнении настоящего Соглашения, регулируются ими путем переговоров. Стороны вправе при урегулировании разногласий использовать претензионный порядок. Претензии рассматриваются, и ответ на них направляется Стороне, предъявившей их, в десятидневный срок со дня их поступления.

6. Стоимость лицензий

Дата последнего обновления: 25 марта 2024 года. Полностью заменяет предыдущую версию.

  1. Цена на лицензионные ключи Moon вычисляется на основе так называемого Числа параллельных сессий, то есть числа браузерных сессий, выполняемых параллельно. Ограничение данного числа работает за счет ограничения максимально возможного числа подов с браузерами не выше значения, записанного в лицензионном ключе.

  2. Без лицензионного ключа разрешено запускать до 4 (четырех) параллельных браузерных сессий. Если такое ограничение вам подходит, вы можете использовать Moon бесплатно неограниченное количество времени.

  3. Если бесплатного ограничения недостаточно, требуется приобрести лицензионный ключ. Такой ключ может содержать любое число параллельных сессий (даже 42).

  4. Каждая параллельная сессия имеет фиксированную цену - ₽400 (четыреста рублей) в месяц. Если вы находитесь за пределами Российской Федерации, то оплачивать можно также в USD и евро.

    Пример расчета стоимости лицензии
    42 сессии * ₽400/месяц = ₽16800/месяц
  5. Для удобства мы посчитали стоимость лицензии в месяц для наиболее частых случаев:

    Table 17. Стоимость лицензионных ключей Moon
    Число параллельных сессий Стоимость в месяц, ₽

    0-4

    бесплатно

    5

    ₽2000

    10

    ₽4000

    15

    ₽6000

    20

    ₽8000

    25

    ₽10000

    30

    ₽12000

    40

    ₽16000

    50

    ₽20000

    75

    ₽30000

    100

    ₽40000

    150

    ₽60000

    200

    ₽80000

    250

    ₽100000

    500

    ₽200000

Appendix A: Поддерживаемые мобильные устройства

Table 18. Поддерживаемые мобильные устройства
Капабилити deviceName capability Замечания

Apple iPhone 15 Pro Max

Apple iPhone 15 Pro

Apple iPhone 15 Plus

Apple iPhone 15

Apple iPhone 14 Pro Max

Apple iPhone 14 Pro

Apple iPhone 14 Plus

Apple iPhone 14

Apple iPhone SE 2022

Apple iPhone 13 Pro Max

Apple iPhone 13 Pro

Apple iPhone 13

Apple iPhone 13 Mini

Apple iPhone 12 Pro Max

Apple iPhone 12 Pro

Apple iPhone 12

Apple iPhone 12 Mini

Apple iPhone 11 Pro Max

Apple iPhone 11 Pro

Apple iPhone 11

Apple iPad Air

Apple iPad 10.2 (2019)

Apple iPhone Xs

Apple iPhone Xs Max

Apple iPhone XR

Apple iPhone 5/SE

Apple iPhone 6/7/8

Apple iPhone 6/7/8 Plus

Apple iPhone X

Apple iPad

Apple iPad Pro

Apple iPhone 8 Plus

Apple iPhone 8

Apple iPhone 7 Plus

Apple iPhone 7

Apple iPhone SE

Apple iPad Mini 4

Apple iPad Pro (10.5)

iPad Pro 10.5"

Apple iPad Pro (12.9)

iPad Pro 12.9"

Apple iPad Mini

Apple iPhone 4

Blackberry PlayBook

BlackBerry Z30

Google Nexus 4

Google Nexus 5

Google Nexus 5X

Google Nexus 6

Google Nexus 6P

Google Nexus 7

Google Nexus 10

Google Pixel 2

Google Pixel 2 XL

Google Pixel 3

Google Pixel 3 XL

Google Pixel 4

Google Pixel 4 XL

Google Pixel 5

Nest Hub Max

Nest Hub

JioPhone 2

Kindle Fire HDX

Laptop with touch

Laptop with HiDPI screen

Laptop with MDPI screen

LG Optimus L70

Microsoft Lumia 550

Microsoft Lumia 950

Microsoft Surface Pro 7

Microsoft Surface Duo

Motorola G4

Nokia Lumia 520

Nokia N9

Palm PVG100

Red Hydrogen One

Samsung Galaxy S20 Ultra

Samsung Galaxy A51/71

Samsung Galaxy A20

Samsung Galaxy Fold

Samsung Galaxy Note 2

Samsung Galaxy Note 3

Samsung Galaxy Note 8

Samsung Galaxy Note 9

Samsung Galaxy Note 10

Samsung Galaxy Note 10+

Samsung Galaxy S3

Samsung Galaxy S5

Samsung Galaxy S7

Samsung Galaxy S8

Samsung Galaxy S8+

Samsung Galaxy S9

Samsung Galaxy S9+

Samsung Galaxy S10

Samsung Galaxy S10+

Samsung Galaxy S10e

Samsung Galaxy Tab S3

Samsung Galaxy Tab S4