Руководство по установке и обновлению системы прокторинга

1. Архитектура системы

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

  • Сервер приложений — среда Node.js для запуска серверных приложений, в ней запускается веб-сервер и ядро системы прокторинга.
  • Сервер СУБД — сервер системы управления базой данных MongoDB, можно использовать выделенный сервер или облачный сервис с поддержкой API для MongoDB.
  • Файловое хранилище — хранилище загружаемых файлов в систему прокторинга, совместимое с AWS S3, можно использовать выделенный сервер MinIO или облачный сервис с совместимым API.
  • TURN сервер — сервер для поддержания работы модуля видеосвязи по WebRTC, можно использовать выделенный сервер с соответствующим ПО (например, coturn).
  • API распознавания лиц и документов — программное обеспечение для распознавания лиц и документов, является частью системы прокторинга.

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

Для работы серверной части системы необходима операционная система (ОС) на базе 64-битного дистрибутива Linux. Можно использовать Ubuntu, Debian, CentOS или другие аналогичные дистрибутивы.

Для запуска системы прокторинга требуется программное обеспечение (ПО) Docker или другая среда для запуска Docker-контейнеров. Однако можно использовать облачные сервисы для сервера СУБД (MongoDB-совместимое) и файлового хранилища (S3-совместимое).

2. Запуск системы через Docker Compose

Это приоритетный способ запуска системы на единственном сервере.

2.1. Подготовка сервера

В данном разделе инструкции описан способ запуска всех компонентов системы через Docker Compose (см. инструкцию по установке Docker Compose).

2.2. Подготовка конфигурационного файла

Вся настройка запускаемых компонентов прокторинга (контейнеров) прописывается в файле docker-compose.yml и переменных окружения в файле .env. Сценарий запуска контейнеров составлен таким образом, что для указанного домена (переменная DOMAIN_NAME) автоматически выпускается SSL-сертификат от Let’s Encrypt на 90 дней. При перезапуске контейнеров срок действия SSL-сертификата автоматически продлевается, если до его окончания остается менее 15 дней.

Вот типовой конфигурационный файл для запуска контейнеров:
services:
  mongo:
    image: cr.yandex/crplqlcepbdpfbg68mub/mongo:latest
    restart: always
    network_mode: bridge
    #ports:
    #  - "0.0.0.0:27017:27017/tcp"
    volumes:
      - db:/data/db
      - configdb:/data/configdb
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_SECRET:-secret}
    healthcheck:
      test:
        [
          "CMD",
          "curl",
          "--connect-timeout",
          "10",
          "--silent",
          "http://127.0.0.1:27017"
        ]
      interval: 1m
      timeout: 10s
      retries: 3
      start_period: 10s
  minio:
    image: cr.yandex/crplqlcepbdpfbg68mub/minio:latest
    restart: always
    network_mode: bridge
    #ports:
    #  - "0.0.0.0:9000:9000/tcp"
    volumes:
      - storage:/data
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: ${MINIO_SECRET:-minioadmin}
      MINIO_BUCKET: proctoring
    healthcheck:
      test:
        [
          "CMD",
          "curl",
          "--connect-timeout",
          "10",
          "--silent",
          "http://127.0.0.1:9000/minio/health/live"
        ]
      interval: 1m
      timeout: 10s
      retries: 3
      start_period: 10s
  recognizer:
    image: cr.yandex/crplqlcepbdpfbg68mub/recognizer:latest
    restart: always
    network_mode: bridge
    environment:
      PORT: 8080
      API_KEY: ${RECOGNIZER_SECRET:-secret}
    healthcheck:
      test:
        [
          "CMD",
          "curl",
          "--connect-timeout",
          "10",
          "--silent",
          "http://127.0.0.1:8080/ping"
        ]
      interval: 1m
      timeout: 10s
      retries: 3
      start_period: 10s
  turn:
    image: cr.yandex/crplqlcepbdpfbg68mub/turn:latest
    restart: always
    network_mode: host
    volumes:
      - turn:/var/lib/coturn
    environment:
      TURN_PORT: 3478
      TURN_USER: webrtc:${TURN_SECRET:-webrtc}
      TURN_EXTERNAL_IP: ""
      TURN_MIN_PORT: 49152
      TURN_MAX_PORT: 65535
    healthcheck:
      test: [ "CMD", "nc", "-z", "127.0.0.1", "3478" ]
      interval: 1m
      timeout: 10s
      retries: 3
      start_period: 10s
  acme:
    image: cr.yandex/crplqlcepbdpfbg68mub/acme:latest
    network_mode: host
    volumes:
      - acme:/.lego
    environment:
      ACME_DOMAIN: ${DOMAIN_NAME:-localhost}
      ACME_EMAIL: admin@${DOMAIN_NAME:-localhost}
      ACME_DAYS: 15
      ACME_WEBROOT: /.lego/webroot
  node:
    depends_on:
      mongo:
        condition: service_healthy
      minio:
        condition: service_healthy
      recognizer:
        condition: service_healthy
      turn:
        condition: service_healthy
      acme:
        condition: service_completed_successfully
    image: cr.yandex/crplqlcepbdpfbg68mub/node:latest
    restart: always
    network_mode: bridge
    links:
      - mongo
      - minio
      - recognizer
    ports:
      - "0.0.0.0:80:80/tcp"
      - "0.0.0.0:443:443/tcp"
    volumes:
      - acme:/etc/acme
    environment:
      DISTRIB_URL: ${DISTRIB_URL}
      DISTRIB_KEY: ${DISTRIB_KEY}
      MONGO_URI: mongodb://admin:${MONGO_SECRET:-secret}@mongo:27017/proctoring?authSource=admin
      MINIO_URI: http://minioadmin:${MINIO_SECRET:-minioadmin}@minio:9000/proctoring
      RECOGNIZER_URI: http://${RECOGNIZER_SECRET:-secret}@recognizer:8080/recognize
      TURN_URI: turn://webrtc:${TURN_SECRET:-webrtc}@${DOMAIN_NAME:-localhost}:3478?transport=udp+tcp
      SESSION_KEY: ${SESSION_KEY:-secret}
      #SSL_KEY: -----BEGIN RSA PRIVATE KEY-----\n...
      #SSL_CERT: -----BEGIN CERTIFICATE-----\n...
      SSL_KEY: /etc/acme/certificates/${DOMAIN_NAME:-localhost}.key
      SSL_CERT: /etc/acme/certificates/${DOMAIN_NAME:-localhost}.crt
      PORT: 443
      HTTP_PORT: 80
      HTTP_TIMEOUT: 60
      HTTP_WEBROOT: /etc/acme/webroot
      MANAGER_USERNAME: ${MANAGER_USERNAME:-manager}
      MANAGER_PASSWORD: ${MANAGER_PASSWORD:-changeme}
      MANAGER_HOST: ${DOMAIN_NAME}
    healthcheck:
      test:
        [
          "CMD",
          "curl",
          "--connect-timeout",
          "10",
          "--silent",
          "http://127.0.0.1/ping"
        ]
      interval: 1m
      timeout: 10s
      retries: 5
      start_period: 1m
volumes:
  db: {}
  configdb: {}
  storage: {}
  turn: {}
  acme: {}
В файле .env прописываются переменные окружения в формате ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ, описание которых дано в таблице ниже:
Параметр
Описание
DISTRIB_URL
Адрес архива с дистрибутивом (выдается поставщиком)
DISTRIB_KEY
Пароль к архиву дистрибутива (выдается поставщиком)
DOMAIN_NAME
Публичный домен сервера
MONGO_SECRET
Пароль к базе данных MongoDB
MINIO_SECRET
Пароль к хранилищу MinIO
TURN_SECRET
Пароль для подключения к TURN-серверу
RECOGNIZER_SECRET
Ключ доступа к API-распознавания
SESSION_KEY
Секретный ключ сессии
MANAGER_USERNAME
Имя пользователя менеджера
MANAGER_PASSWORD
Пароль пользователя менеджера
ВНИМАНИЕ: Переменные окружения MONGO_SECRET, MINIO_SECRET, TURN_SECRET и RECOGNIZER_SECRET не должны содержать специальных символов, допускаются только следующие символы: a-zA-Z0-9

2.3. Запуск контейнеров

Создать и запустить все контейнеры разом можно следующей командой из директории, где находится файл docker-compose.yml:
docker compose up -d --no-build

2.4. Остановка контейнеров

Остановить и удалить все контейнеры разом можно следующей командой из директории, где находится файл docker-compose.yml:
docker compose down

3. Запуск системы через Docker CLI

Можно использовать данный способ для более гибкого управления Docker-контейнерами без использования Docker Compose.

3.1. Подготовка сервера

В данном разделе инструкции описан способ запуска всех компонентов системы в Docker (см. инструкцию по установке Docker).

3.2. Сервер СУБД MongoDB

3.2.1. Единственный сервер

Создать том, на котором будут храниться файлы базы данных:
docker volume create db
docker volume create configdb
Запустить контейнер mongo:
docker run -d --name mongo --network host --restart always \
  -v db:/data/db \
  -v configdb:/data/configdb \
  -e "MONGO_INITDB_ROOT_USERNAME=admin" \
  -e "MONGO_INITDB_ROOT_PASSWORD=secret" \
  cr.yandex/crplqlcepbdpfbg68mub/mongo
Переменные окружения (задаются в параметре "-e"):
# логин администратора базы
MONGO_INITDB_ROOT_USERNAME=admin
# пароль администратора базы
MONGO_INITDB_ROOT_PASSWORD=secret
Строка подключения к БД:
mongodb://admin:secret@127.0.0.1:27017/proctoring?authSource=admin

3.2.2. Кластерная конфигурация

Создать два тома, на которых будут храниться файлы базы данных и конфиги:
docker volume create db
docker volume create configdb
Для MongoDB кластерная конфигурация настраивается с помощью Replica Set в виде одного Primary узла и одного или нескольких Secondary узлов. Чтобы узлы кластера MongoDB могли взаимодействовать между собой, на всех узлах кластера должен быть прописан один и тот же ключ с правами на файл "400". Сгенерировать ключ можно командой:
KEYFILE=/var/lib/docker/volumes/configdb/_data/mongo.keyfile
if [ ! -e "$KEYFILE" ]
then
  openssl rand -base64 756 | tee $KEYFILE
  chmod 400 $KEYFILE
fi
Запустить контейнер mongo в реплике с именем "rs0" на каждом хосте (например, mongodb01 и mongodb02):
docker run -d --name mongo --network host --restart always \
  -v db:/data/db \
  -v configdb:/data/configdb \
  -e "MONGO_INITDB_ROOT_USERNAME=admin" \
  -e "MONGO_INITDB_ROOT_PASSWORD=secret" \
  cr.yandex/crplqlcepbdpfbg68mub/mongo \
  mongod --replSet rs0 --keyFile /data/configdb/mongo.keyfile
Переменные окружения (задаются в параметре "-e"):
# логин администратора базы
MONGO_INITDB_ROOT_USERNAME=admin
# пароль администратора базы
MONGO_INITDB_ROOT_PASSWORD=secret
Инициализировать кластер командой (только на одном узле):
docker exec -it mongo mongosh -u admin -p secret --authenticationDatabase admin

> rs.initiate(
   {
      _id: "rs0",
      version: 1,
      members: [
         { _id: 0, host: "mongodb01:27017" },
         { _id: 1, host: "mongodb02:27017" }
      ]
   }
)
Строка подключения к БД:
mongodb://admin:secret@mongodb01:27017,mongodb02:27017/proctoring?authSource=admin&replicaSet=rs0

3.3. Файловое хранилище

3.3.1. Локальное хранилище MinIO

Создать том, на котором будут храниться файлы хранилища:
docker volume create storage
Запустить контейнер minio:
docker run -d --name minio --network host --restart always \
  -v storage:/data \
  -e "MINIO_ROOT_USER=minioadmin" \
  -e "MINIO_ROOT_PASSWORD=minioadmin" \
  -e "MINIO_BUCKET=proctoring" \
  cr.yandex/crplqlcepbdpfbg68mub/minio
В случае настройки распределенного хранилища требуется указать список хостов MinIO, входящих в группу, но не менее 4 шт.:
minio server http://HOST1:9000/data http://HOST2:9000/data http://HOST3:9000/data http://HOST4:9000/data
Переменные окружения (задаются в параметре `-e`):
# логин для доступа к хранилищу
MINIO_ROOT_USER=minioadmin
# пароль для доступа к хранилищу
MINIO_ROOT_PASSWORD=minioadmin
# создать бакет по умолчанию
MINIO_BUCKET=proctoring
# хост и порт сервера
MINIO_HOST=""
MINIO_PORT=9000
# хост и порт консоли управления
MINIO_CONSOLE_HOST=""
MINIO_CONSOLE_PORT=9001
# ограничение количества параллельных запросов
MINIO_API_REQUESTS_MAX=1000
# ограничение времени ожидания обработки запроса
MINIO_API_REQUESTS_DEADLINE=1m
Строка подключения к хранилищу (один сервер):
http://minioadmin:minioadmin@127.0.0.1:9000/proctoring
Строка подключения к хранилищу (несколько серверов, например, minio01 и minio02):
http://minioadmin:minioadmin@minio01:9000,minio02:9000/proctoring

3.3.2. Классы хранения в MinIO

При хранении большого объема данных в некоторых случаях может быть оправдано настроить два класса хранения данных: горячее хранилище и холодное хранилище. Это позволяет использовать небольшой объем горячего хранилища с быстрыми дисками для обеспечения корректной работы системы под большой нагрузкой, а архивные данные хранить в холодном хранилище на более медленных и дешевых дисках. При этом настроить правило автоматического перемещения данных из горячего хранилища в холодное, например, через 1 день, без потери доступа к этим данным через систему прокторинга.

Ниже приведена пошаговая инструкция как настроить два сервера MinIO с автоматическим переносом данных по правилу с одного сервера на другой:

1. Запустить два сервера MinIO. Пусть это будет minio1 (порт 9000,на быстрых дисках) и minio2 (порт 9100, на медленных дисках).
2. Скачать MinIO Client (mcli).
3. Настроить mcli для взаимодействия с сервером minio1:
mcli alias set minio1 http://127.0.0.1:9000 <user> <password>
где и — ключи доступа к хранилищу.
4. Настроить политики жизненного цикла:
wget -O - https://min.io/docs/minio/linux/examples/LifecycleManagementAdmin.json | \

mcli admin policy create minio1 LifecycleAdminPolicy /dev/stdin

mcli admin user add minio1 <minio1LifecycleAdmin> <LongRandomSecretKey>

mcli admin policy attach minio1 LifecycleAdminPolicy --user=<minio1LifecycleAdmin>
где — логин администратора политик, — пароль администратора политик.

5. Настроить уровень удаленного хранилища:
mcli ilm tier add minio minio1 MINIO_COLD_TIER \
  --endpoint http://127.0.0.1:9100 \
  --access-key <user> \
  --secret-key <password> \
  --bucket proctoring \
  --storage-class STANDARD
где и — ключи доступа к другому хранилищу, proctoring — название бакета, http://127.0.0.1:9100 — адрес второго сервера MinIO.

6. Создать и применить правило переноса (1 день после создания файлов) с именем “MINIO_COLD_TIER”:
mcli ilm rule add minio1/proctoring \
  --transition-tier MINIO_COLD_TIER \
  --transition-days 1 \
  --noncurrent-transition-tier MINIO_COLD_TIER \
  --noncurrent-transition-days 1
7. Проверить правило переноса:
mcli ilm rule ls minio1/proctoring --transition
Подробнее о настройка уровней хранения и правил переноса можно почитать в официальной документации MinIO.

Для работы данной функции требуется версия MinIO Server RELEASE.2023-03-20T17-17-53Z или выше. Если у вас используется более ранняя версия, то необходимо выполнить миграцию на более новую версию MinIO Server.

3.3.3. Amazon S3

В качестве хранилища можно использовать Amazon S3, для этого ничего дополнительно устанавливать не требуется.

Строка подключения к хранилищу (бакет "proctoring"):
https://access_key_id:secret_key@s3.eu-west-1.amazonaws.com/proctoring?region=eu-west-1

3.3.4. Azure Blob Storage

В качестве хранилища можно использовать Microsoft Azure Blob Storage, однако для работы с ним нужно использовать MinIO Gateway. Обратите внимание, что поддержка Gateway была удалена в последних версиях MinIO, поэтому функция доступна только в версиях до 1 июня 2022 года.

Запустить контейнер minio с параметром gateway azure:
docker run -d --name minio --network host --restart always \
  -e "MINIO_ROOT_USER=azurestorageaccountname" \
  -e "MINIO_ROOT_PASSWORD=azurestorageaccountkey" \
  cr.yandex/crplqlcepbdpfbg68mub/minio \
  gateway azure
Переменные окружения (задаются в параметре `-e`):
# логин для доступа к Azure Blob Storage
MINIO_ROOT_USER=azurestorageaccountname
# ключ для доступа к Azure Blob Storage
MINIO_ROOT_PASSWORD=azurestorageaccountkey
Строка подключения к хранилищу (бакет "proctoring"):
http://azurestorageaccountname:azurestorageaccountkey@127.0.0.1:9000/proctoring

3.3.5. Google Cloud Storage

В качестве хранилища можно использовать Google Cloud Storage, однако для работы с ним нужно использовать MinIO Gateway. Обратите внимание, что поддержка Gateway была удалена в последних версиях MinIO, поэтому функция доступна только в версиях до 1 июня 2022 года.

Предварительно требуется создать сервисный ключ аккаунта для GCS и получить JSON-файл параметров подключения:

  • Перейдите на страницу API Console Credentials.
  • Выберите проект или создайте новый проект. Запишите идентификатор проекта (подставляется вместо "yourprojectid").
  • Нажмите кнопку "Create credentials" и в выпадающем списке выберите "Service account".
  • Заполните поля "Service account name" и "Service account ID", после чего нажмите "Create and continue".
  • В выпадающем списке "Select role" выберите "Cloud Storage" > "Storage Admin" (полный доступ к ресурсам GCS), после этого нажмите "Continue" и "Done".
  • Далее нужно открыть созданный сервисный аккаунт, перейти на вкладку "Keys" и нажать "Add key" > "Create new key", выбрать "Key type: JSON".
  • После этого скачается JSON-файл, путь к которому нужно будет указать при запуске контейнера (в параметре -v).

Запустить контейнер minio с параметром gateway gcs:
docker run -d --name minio --network host --restart always \
  -v /path/to/credentials.json:/credentials.json \
  -e "GOOGLE_APPLICATION_CREDENTIALS=/credentials.json" \
  -e "MINIO_ROOT_USER=minioadmin" \
  -e "MINIO_ROOT_PASSWORD=minioadmin" \
  cr.yandex/crplqlcepbdpfbg68mub/minio \
  gateway gcs yourprojectid
Переменные окружения (задаются в параметре `-e`):
# параметры подключения к Google Cloud Storage
GOOGLE_APPLICATION_CREDENTIALS=/credentials.json
Строка подключения к хранилищу (бакет "proctoring"):
http://minioadmin:minioadmin@127.0.0.1:9000/proctoring

3.4. API распознавания лиц и документов

Запустить контейнер recognizer:
docker run -d --name recognizer \
  --network host --restart always \
  -e "API_KEY=secret" \
  cr.yandex/crplqlcepbdpfbg68mub/recognizer
Переменные окружения (задаются в параметре "-e"):
# IP сервера
HOST=0.0.0.0
# порт сервера
PORT=8080
# ключ доступа к API
API_KEY=secret
# флаг для пересборки в случае отсутствия поддержки 
# инструкций AVX у процессора
DLIB_REBUILD=1
Строка подключения к API распознавания (один сервер):
http://secret@127.0.0.1:8080/recognize
Строка подключения к API распознавания (несколько серверов, например, recognizer01 и recognizer02):
http://secret@recognizer01:8080,recognizer02:8080/recognize

3.5. TURN сервер

Запустить контейнер turn:
Запустить контейнер turn:
docker run -d --name turn --network host --restart always \
  cr.yandex/crplqlcepbdpfbg68mub/turn
Используемые порты по умолчанию (должны быть доступны с клиентов):

  • 3478/tcp
  • 3478/udp
  • 49152-65535/udp (опционально)

Переменные окружения (задаются в параметре `-e`):
# логин и пароль
TURN_USER="webrtc:webrtc"
# внешний IP сервера, определяется автоматически если не задан
TURN_EXTERNAL_IP=""
# минимальный порт
TURN_MIN_PORT=49152
# максимальный порт
TURN_MAX_PORT=65535
Строка подключения к TURN:
turn://webrtc:webrtc@<external-ip>:3478?transport=tcp+udp
где — внешний IP адрес TURN сервера, если серверов несколько, то их адреса нужно указать через запятую; webrtc:webrtc — имя пользователя и пароль для подключения к TURN по умолчанию; 3478 — порт TURN сервера; transport — используемый транспорт tcp или udp, tcp+udp указывает на необходимость использовать оба транспорта.

Проверить работу TURN-сервера в браузере можно на странице Trickle ICE. Для этого нужно на этой странице ввести параметры подключения к серверу:

  • TURN URI: turn::3478?transport=udp
  • TURN username: webrtc
  • TURN password: webrtc

Далее нажать кнопку "Add Server" и "Gather candidates". В результате в таблице на этой странице должен появиться список, где строки в поле "Component Type" имеют следующие типы подключений:

  • host — локальный IP адрес клиента;
  • srflx — внешний IP адрес клиента;
  • relay — внешний IP адрес TURN сервера, должен соответствовать .

Если хотя бы одного типа нет в списке, значит доступ к TURN серверу настроен неправильно. Нужно проверить, не блокируются ли подключения брандмауэром (фаерволом) или промежуточными маршрутизаторами в сети.

Если проверка TURN не удалась, то причиной может быть блокировка UDP трафика между клиентом и сервером. Проверить передачу UDP трафика между клиентов и сервером по определенному порту можно следующими командами:
server: nc -u -l -p <udp-port>
client: echo -n "ping" | nc -u -w 5 <external-ip> <udp-port>

3.6. Сервер приложений

3.6.1. SSL-сертификат Let’s Encrypt

Для работы системы требуется валидный SSL-сертификат для домена. Можно выпустить бесплатный SSL-сертификат Let’s Encrypt сроком действия 3 месяца. Для этого достаточно воспользоваться утилитой lego:
docker volume create acme
docker run --network host \
  -v "acme:/.lego" \
  goacme/lego \
  --domains=your-domain.com \
  --email=admin@your-domain.com \
  --accept-tos --key-type=rsa2048 --http \
  run
После успешного выполнения команды сертификат будет доступен в директории "/var/lib/docker/volumes/acme/_data/certificates/":

  • сертификат: your-domain.com.crt
  • приватный ключ: your-domain.com.key

Перевыпустить сертификат можно командой:
docker run --network host \
  -v "acme:/.lego" \
  goacme/lego \
  --domains=your-domain.com \
  --email=admin@your-domain.com \
  --accept-tos --key-type=rsa2048 --http \
  renew --days 14

3.6.2. Запуск экземпляра

Экземпляр сервера приложений должен быть привязан к одному единственному домену, на который будет выдаваться лицензия. Сервер приложений можно запускать как на одном узле, так и на нескольких (горизонтальное масштабирование). При запуске сервера приложений на нескольких узлах, серверы должны находиться в одной сети и иметь возможность обмениваться данными по протоколу UDP. Настройки экземпляра указываются в переменных окружения при запуске контейнера. Настройки на всех узлах должны быть одинаковыми за исключением переменной окружения HOSTNAME, она должна быть уникальная на каждом узле.

Запустить контейнер node:
docker run -d --name node --network host --restart always \
  --tmpfs /tmp \
  -v "acme:/etc/acme" \
  -e "DISTRIB_URL=https://files.proctoring.online/dist/proctoring-vX_Y_Z.zip" \
  -e "DISTRIB_KEY=secret" \
  -e "MONGO_URI=mongodb://admin:secret@127.0.0.1:27017/proctoring?authSource=admin" \
  -e "MINIO_URI=http://minioadmin:minioadmin@127.0.0.1:9000/proctoring" \
  -e "RECOGNIZER_URI=http://secret@127.0.0.1:8080/recognize" \
  -e
"TURN_URI=turn://webrtc:webrtc@127.0.0.1:3478?transport=tcp+udp" \
  -e "SESSION_KEY=secret" \
  cr.yandex/crplqlcepbdpfbg68mub/node
Переменные окружения (задаются в параметре "-e"):
# URL дистрибутива системы прокторинга (выдается отдельно)
DISTRIB_URL=https://files.proctoring.online/dist/proctoring-vX_Y_Z.zip
# пароль к дистрибутиву (выдается отдельно)
DISTRIB_KEY=secret
# IP сервера
HOST=0.0.0.0
# порт сервера
PORT=443
# порт переадресации с протокола http на https
HTTP_PORT=80
# таймаут ответа сервера
HTTP_TIMEOUT=60
# директория для /.well-known/acme-challenge
HTTP_WEBROOT=/etc/acme/webroot
# количество потоков на сервере, по умолчанию равно числу vCPU
THREADS=2
# строка подключения к MongoDB
MONGO_URI=mongodb://admin:secret@127.0.0.1:27017/proctoring?authSource=admin
# строка подключения подключения к MinIO/S3
MINIO_URI=http://minioadmin:minioadmin@127.0.0.1:9000/proctoring
# строка подключения к API распознавания
RECOGNIZER_URI=http://secret@127.0.0.1:8080/recognize
# строка подключения к TURN
TURN_URI=turn://webrtc:webrtc@127.0.0.1:3478?transport=tcp+udp
# секретный ключ для сессий (случайный набор символов)
SESSION_KEY=secret
# время жизни сессии в минутах
SESSION_EXPIRES=720
# приватный ключ SSL (путь к файлу или содержимое в одну строку)
SSL_KEY=/etc/acme/certificates/your-domain.com.key
# SSL-сертификата (путь к файлу или содержимое в одну строку)
SSL_CERT=/etc/acme/certificates/your-domain.com.crt
# бандла центра сертификации  (путь к файлу или содержимое)
SSL_CA=/etc/acme/certificates/your-domain.com.issuer.crt
# ограничение на размер загружаемых файлов в МБ
UPLOAD_LIMIT=100
# время хранения неиспользованных загруженных файлов в минутах
UPLOAD_EXPIRES=60
# время кеширования статики на клиенте в минутах 
STATIC_EXPIRES=60
# директория статических файлов
STATIC_DIR=/path/to/dir
# логин менеджера
MANAGER_USERNAME=manager 
# пароль менеджера
MANAGER_PASSWORD=changeme
# хост (и порт, если нестандартный) для входа под менеджером
MANAGER_HOST=localhost:3000
# сложность пароля. Задает регулярное выражение, описывающее требования к сложности пароля
PASSWORD_RULE=^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{16,}$
# количество PASSWORD_ATTEMPTS неудачных попыток авторизации, после которого пользователь блокируется на время PASSWORD_HOLDOFF (в минутах)
PASSWORD_ATTEMPTS=5
PASSWORD_HOLDOFF=30
# количество дней, по прошествии которых пользователь после успешной авторизации перенаправляется на форму смены пароля
PASSWORD_LIFETIME=30
# глубина хранимой истории паролей. При смене пароля проверяется история старых паролей. Если пароль уже использовался, повторное использование невозможно
PASSWORD_HISTORY=10
# устанавливает требование смены пароля для нового пользователя. Вновь созданный пользователь после успешной авторизации видит форму смены пароля
PASSWORD_INITIAL=1
Используемые порты (зависят от переменной PORT):

  • /tcp (внешний http/https)
  • /udp (для взаимодействия узлов кластера)

Вместо указания DISTRIB_URL в корень тома "app" (директория на хосте "/var/lib/docker/volumes/app/_data/") можно поместить файл дистрибутива "dist.zip", тогда начальная установка будет осуществляться из него.

4. Настройка обратного прокси-сервера

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

4.1. Установка и настройка Nginx

Доступ к системе из интернета можно настроить через проксирующий сервер Nginx, установить в Ubuntu его можно так:
sudo apt-get install -y nginx
Конфигурация виртуального хоста в nginx:
location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_pass_request_headers on;
    proxy_set_header Host $host;
    proxy_set_header Origin $http_origin;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Authorization $http_authorization;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-By $server_addr:$server_port;
    proxy_set_header X-Forwarded-Proto $scheme;
}

4.2. Установка и настройка Apache

Установка веб-сервера Apache в Ubuntu:
sudo apt-get install -y apache2
Конфигурация виртуального хоста в Apache 2.4:
RewriteEngine On
RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
RewriteCond %{QUERY_STRING} transport=websocket    [NC]
RewriteRule /(.*)           ws://127.0.0.1:3000/$1 [P,L]

<Location "/">
    # RequestHeader set Host "your-proctoring-domain"
    ProxyPreserveHost On
    ProxyPass "http://127.0.0.1:3000/"
    ProxyPassReverse "http://127.0.0.1:3000/"
</Location>
В Apache должны быть включены модули mod_proxy, mod_proxy_http, mod_proxy_wstunnel и mod_rewrite.

5. Обновление системы

Ниже описана последовательность действий, которые требуется выполнить для полного обновления системы прокторинга. Не всегда требуется обновлять все компоненты. Если обновился только сервер приложений, то достаточно выполнить обновление только контейнера `node`.

5.1. Резервная копия базы данных

Сделать резервную копию базы данных:
docker exec <mongo_container> mongodump -u <user> -p <password> --authenticationDatabase admin -d <db> --archive --gzip > /path/to/backup/db.dump
где `` — название контейнера "mongo", которое можно посмотреть с помощью команды `docker ps`; `` — логин пользователя БД; `` — пароль пользователя БД; `` — имя базы данных (по умолчанию "proctoring"); `/path/to/backup/db.dump` — файл дампа.

Если образ `mongo` не обновлялся, то выполнять этот шаг не обязательно.

5.2. Резервная копия файлового хранилища

Сделать резервную копию файлового хранилища:
wget -O /usr/local/bin/mc https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x /usr/local/bin/mc
mc alias set local http://127.0.0.1:9000 <access_key> <access_secret>
mc mirror local/proctoring /path/to/backup/s3
где `` — ключ доступа к хранилищу; `` — пароль доступа к хранилищу; `proctoring` — имя бакета прокторинга; `/path/to/backup/s3` — директория сохранения резервной копии хранилища.

Если образ `minio` не обновлялся, то выполнять этот шаг не обязательно.

5.3. Удаление установленной версии

Остановить и удалить все контейнеры, удалить все образы:
docker compose down
docker image prune

5.4. Установка новой версии

Запустить все контейнеры заново:
docker compose up -d

5.5. Проверка логов

Проверить логи после запуска контейнеров:
docker logs -f <container_name>
где `` — название контейнера, которое можно посмотреть с помощью команды `docker ps`.

5.6. Восстановление базы данных

Восстановить базу данных:
cat /path/to/backup/db.dump | docker exec -i <mongo_container> mongorestore -u <user> -p <password> --authenticationDatabase admin --archive --gzip
где `` — название контейнера "mongo", которое можно посмотреть с помощью команды `docker ps`; `` — логин пользователя БД; `` — пароль пользователя БД; `/path/to/backup/db.dump` — файл дампа.

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

5.7. Восстановление файлового хранилища

Восстановить данные файлового хранилища:
mc alias set local http://127.0.0.1:9000 <access_key> <access_secret>
mc mirror /path/to/backup/s3/ local/proctoring
где `` — ключ доступа к хранилищу; `` — пароль доступа к хранилищу; `proctoring` — имя бакета прокторинга; `/path/to/backup/s3/` — директория сохранения резервной копии хранилища.

Если резервная копия файлового хранилища не делалась, то этот шаг следует пропустить.

6. Вход в систему

Доступ к системе можно получить по адресу, указанному при развертывании (например, https://your-domain.com). Параметры авторизации для менеджера по умолчанию такие:

  • логин: manager
  • пароль: changeme

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