магистрант, Международный университет информационных технологий, Республика Казахстан, Алматы
ИСПОЛЬЗОВАНИЕ КОНТЕЙНЕРИЗАЦИИ ДЛЯ АВТОМАТИЗИРОВАННОГО ТЕСТИРОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ В ОНЛАЙН-ОБРАЗОВАНИИ
АННОТАЦИЯ
При создании образовательного контента в сфере изучения языков программирования и информационных технологий крайне важно разработать качественные автоматизированные практические задания. Существует множество подходов к автоматизированному тестированию и проверке кода студентов. В данной статье рассмотрен метод контейнеризации с применением Docker-контейнеров, его особенности, достоинства и недостатки, а также архитектура прототипа, реализующего возможность универсального тестирования кода с помощью контейнеризации.
ABSTRACT
It's extremely important to develop high-quality professional practical tasks in development educational content in the field of studying language programs and information technology. There are many approaches to automated testing and verification of student code. This article discusses the containerization approach using Docker containers, its features, advantages and disadvantages, and its experimental implementation.
Ключевые слова: онлайн-курсы, тестирование, онлайн-обучение, контейнеризация, Docker, виртуальная машина.
Keywords: online courses, online education, containerization, Docker, virtual machine, autograding.
Введение
В настоящее время онлайн-обучение становится все более важным компонентом образования практически в любой сфере, в том числе в изучении информационных технологий, языков программирования и автоматизации. Онлайн-обучение приобрело особую актуальность в период массового перехода большинства отраслей на удаленную работу во время эпидемии COVID [9] и постоянно возрастающей нехватки IT-специалистов [3]. При этом становится очевидной необходимость для экономии ресурсов преподавателей автоматизировать проверку и тестирование решений обучающихся [1]. В настоящее время существует несколько методов автоматизированной проверки кода. Они включают в себя компиляцию консольного приложения и взаимодействие через стандартные каналы ввода-вывода (stdin, stdout, stderr), файловый ввод-вывод (создание/обновление и проверка артефактов в файловой системе компьютера-хоста), тестирование API (HTTP-запросы), встроенные средства тестирования языка (JUnit для Java, пакет testing для Go), а также визуальное/мануальное тестирование [6].
Однако все эти методы обладают своими недостатками, не обеспечивают приемлемой изоляции и универсальности для работы на любой операционной системе и с любым языком программирования/фреймворком. Перечисленные недостатки не присущи методу виртуализации программного кода с помощью контейнеризации.
Целью данной статьи является подробное описание метода контейнеризации, истории его появления и развития, особенностей в сравнении с другими методами тестирования кода, а также описание решения-прототипа, примененного авторами для демонстрации практического применения контейнеризации для тестирования кода студентов.
Обзор литературы
В данном разделе представлен краткий обзор существующих исследований и научных работ по данной проблеме.
Шин и другие описывают комплексное решение по тестированию студенческого кода, где контейнеры Docker используются в качестве основы для узлов запуска Jupyter Notebook. Описанное им решение можно разделить на две части: обучающий и модуль создания контента. Учебный ресурс делится на два уровня. Более высокий уровень – курс, который, в свою очередь, состоит из заданий – элементов более низкого уровня. Задание (которое подразумевает определенную задачу, где студент должен написать код, удовлетворяющий условиям) может быть настроено с помощью специального объекта, который сочетает в себе запущенный в Docker экземпляр Jupyter Notebook вместе с модулем оценивания. Преподаватель может управлять ресурсами через личный кабинет инструктора учебного модуля и подключать интеграцию с MOOC, такими как edX, Coursera и т.д. Используя конструктор курсов в данном модуле, инструктор может разработать курс с пользовательским интерфейсом, позволяющим осуществлять как онлайн-обучение, так и самостоятельное обучение [11].
Потдар и другие провели анализ с использованием инструментов Sysbench, Phoronix и Apache и сравнили производительность при запуске приложений в Docker-контейнерах с запуском в виртуальной машине. Анализ авторы провели с точки зрения производительности процессора, пропускной способности памяти, скорости дискового ввода-вывода, нагрузочного теста и измерения скорости работы. Отмечается, что контейнеры Docker работают лучше, чем виртуальные машины в каждом тесте, поскольку наличие уровня QEMU в виртуальной машине делает ее менее эффективной, чем контейнеры Docker [10].
Майкус и другие разработали систему на основе Docker-контейнеров для автоматического запуска и оценки сетевых приложений, реализующих распределенные алгоритмы. Данное решение предоставляет простой и удобный интерфейс для инструкторов, для развертывания сетей и программных решений для студентов и инструкторов, для регистрации и сбора статистики, касающейся типов подключения к узлу и содержимого сообщений. Код студентов проверялся с помощью стандартных потоков вывода, файлового и сетевого обменов. Данное исследование было реализовано как расширение для Submitty, платформы управления курсами с открытым исходным кодом, не зависящей от языка, с автоматическим тестированием и автоматической оценкой студенческих заданий по программированию. Submitty поддерживает все уровни курсов, от вводных до продвинутых специальных тем, и включает в себя функции для ручной оценки ассистентами, контроля версий, командной отправки, дискуссионных форумов и обнаружения плагиата [7].
Готская и другие рассматривают комплексную систему тестирования IServer, сочетающую преимущества контейнеризации и встроенных средств тестирования языка на примере контейнеров с PHPUnit в рамках интеграции с системой Moodle. В данной работе, в частности, была выделена безопасность в роли одной из основных причин применения именно метода контейнеризации [5].
Контейнеризация
Контейнеризация – метод виртуализации, при котором контейнер разделяет с основным компьютером (хостом) процессорные ядра, память, но управляет своим раздельным пользовательским окружением. В отличие от классической технологии виртуализации, изоляция обеспечивается не на уровне процессора (Intel, AMD), а на уровне средств операционной системы (cgroups в Linux). При этом нет возможности запустить в контейнере отличную от хоста операционную систему. Также доступно динамическое регулирование ресурсов, так как по сути они общие у хоста и контейнера, что недоступно при виртуализации приложения [8], [4]. Таким образом, мы можем выделить следующе особенности метода контейнеризации в разрезе автоматизированного тестирования:
- Сравнительно медленное развертывание и запуск. Так как, если сравнивать компиляцию приложения нативными средствами языка и его сборку в контейнер – чаще всего контейнер все же собирать дольше.
- Более мощные и продвинутые средства изоляции запускаемого кода. По умолчанию код внутри контейнера уже достаточно изолирован [2] – файлы, созданные им, будут удалены при удалении контейнера, TCP-порты на хост также нужно пробрасывать отдельно и т.д. С одной стороны, это приводит к необходимости дорабатывать грейдеры для автоматизированного тестирования – добавлять им возможности для копирования файлов, перенаправления потоков ввода-вывода, трансляции нужных портов и т.д. Однако, с другой стороны, это заметно улучшает безопасность.
- Значительная универсальность подхода. Если не использовать контейнеризацию, то для каждого нового языка и фреймворка придется настраивать свою конфигурацию для компиляции, запуска и тестирования. Данные конфигурации могут конфликтовать друг с другом. В случае использования контейнеров Docker нужно описать порядок сборки в специальном конфигурационном файле – Dockerfile, т.е. он может быть любым для любого решения. Мы можем даже позволить студентам самим писать и загружать Dockerfile для своих решений либо написать шаблоны файлов для наиболее популярных вариантов. Dockerfile широко используется в open-source проектах, отлажен и имеет множество шаблонов для сборки приложений на различных языках программирования и библиотеках [12]. Процесс сборки контейнера имеет также ту особенность, что мы не ограничены спецификой хоста, а можем осуществлять сборку практически в любом окружении. Например, можно собирать приложение, написанное на Go в базовом контейнере с установленным Go, либо frontend-приложение в контейнере с node.js, либо собрать свой контейнер с необходимым софтом и утилитами.
- Возможность применять в комплексе остальные методы автоматизированного тестирования. В контейнере возможно инициировать консольную сессию для тестов, скопировать файлы либо запустить приложение для тестирования API/визуального UI-тестирования.
Рассмотрим также методы взаимодействия с запущенным контейнером Docker:
- Старт/остановка контейнера реализуются с помощью методов run/rm.
- Получить вывод с консольных каналов вывода stdout и stderr можно с помощью команды docker logs.
- Взаимодействие с контейнером через консольный канал ввода stdin возможно с помощью команды docker exec, которая позволяет выполнить запуск любой программы внутри контейнера. Запустив ее в связке с терминалом bash/sh/zsh, становится возможным полное взаимодействие с контейнером, в том числе запуск скомпилированного кода студента.
- Если при запуске контейнера было указано, какие порты нужно прослушивать (опция команды docker run -p), то становится возможным обращаться к этим портам по TCP, UDP и HTTP-протоколам. Данная функция особенно полезна при тестировании серверного кода (API-тестирование), а также фронтенд-приложений.
Таким образом, при использовании контейнеризации чаще всего платформа тестирования запускает каждый экземпляр кода студента в отдельном контейнере, далее взаимодействуя с ним посредством команды exec (подключение к контейнеру и запуск процесса консоли), TCP-сокета, каналов stdout и stderr, либо копирования файлов из контейнера. Посредством выбранных каналов коммуникации тестовые сценарии последовательно либо параллельно прогоняются на запущенном контейнере, фиксируется их результат, после чего контейнер останавливается и удаляется, не вызывая изменений в файловой системе хоста (см. Рис 1).
Рисунок 1. Процесс тестирования пользовательского кода с применением контейнеризации
Реализация
При проектировании архитектуры демонстрационного прототипа нами были разработаны следующие требования:
- Поддержка любого языка программирования и фреймворка при условии наличия Dockerfile.
- Подключение к контейнеру после старта и запуск тестируемой программы.
- Последовательное выполнение всех тест-кейсов в формате ввод-вывод-сравнение с образцом. Блок-схема данной логики приведена на Рис. 2.
- Полное удаление контейнера с тестируемым кодом без какого-либо влияния на компьютер-хост.
- Использование официального Docker SDK[1].
- Высокая производительность.
- Возможность тестирования через стандартные каналы ввода-вывода (stdin, stdout).
Рисунок 2. Блок-схема тестирования кода студента в Docker-контейнере посредством stdin/stdout
Работа с Docker SDK осуществлялась посредством взаимодействия с пакетом github.com/docker/docker посредством серверного кода на Go.
Разработанный прототип состоит из следующих компонентов (схема архитектуры приведена на Рис. 3):
- Модуль авторизации предназначен для авторизации и контроля доступов преподавателей и студентов посредством JWT-токенов.
- Модуль преподавателя предназначен для создания и редактирования учебных курсов и практических заданий в рамках данных курсов.
- Модуль студента предназначен для загрузки кода решений и получения результатов проверки.
- Модуль запуска заданий расположен на отдельном сервере для реализации требований безопасности и изоляции и предназначен для запуска решений студентов в Docker-контейнерах.
Рисунок 3. Архитектура решения
Такое разделение обеспечивает высокую возможность для масштабирования, так как инстансы модуля запуска заданий могут быть запущены в нескольких экземплярах, высокий уровень безопасности, а также удобство дальнейшей разработки и улучшения.
Вывод
В рамках данной работы нами были рассмотрены особенности, преимущества и недостатки автоматизированного тестирования программного кода с помощью контейнеризации. Можно сделать вывод, что применение контейнеризации является оптимальным выбором, если в списке требований присутствует необходимость разработки универсального решения, подходящего для как можно большего количества языков программирования, фреймворков и библиотек. Применение контейнеризации обеспечивает высокий уровень безопасности, так как по умолчанию контейнер минимально сообщается с операционной системой хоста. Тем не менее, наилучшим выбором будет вынесение компонента автогрейдера на отдельный сервер. Удаление контейнера по умолчанию очищает практически все следы взаимодействия контейнера с операционной системой, что упрощает написание бизнес-логики автогрейдера. Вместе с тем данный метод обладает и определенными недостатками, такими как повышенное потребление ресурсов, необходимость владеть навыком написания скриптов Dockerfile, более сложные способы взаимодействия с кодом в контейнере по сравнению с методами прямой компиляции консольных приложений либо запуска веб-серверов. Для большинства решений в онлайн-образовании, реализующих автоматизированную проверку заданий студентов более чем на одном языке программирования, использование контейнеризации будет являться оптимальным выбором.
Список литературы:
- Лучанинов Д. В. и др. Использование автоматизированной системы обучения программированию для организации самостоятельной работы студентов // 2020. Т. 8. № 5. С. 11.
- Урманцева Н.Р., Хитрень Д.В. Применение виртуальных контейнеров при создании медицинских информационных систем. Вестник кибернетики. 2021; (2 (42)). с. 24–30.
- Borisov V. V. и др. Программный комплекс управления подготовкой IT-специалистов SkillsForYou // ППС. 2020. Т. 22. С. 177–185.
- Felani R. и др. Optimizing Virtual Resources Management Using Docker on Cloud Applications // Indonesian J. Comput. Cybern. Syst. 2020. Т. 14. № 3. С. 319.
- Gotskaya I. и др. Automating the Verification of Practical Tasks in the Course «PHP Web Programming» // CTE. 2020. № 4. С. 69–78.
- Király S., Nehéz K., Hornyák O. Some aspects of grading Java code submissions in MOOCs // Research in Learning Technology. 2017. Т. 25. № 10. С. 249.
- Maicus E. и др. Autograding Distributed Algorithms in Networked Containers // Proceedings of the 50th ACM Technical Symposium on Computer Science Education. Minneapolis MN USA: ACM, 2019. С. 133–138.
- Morris D. и др. Use of Docker for deployment and testing of astronomy software // Astronomy and Computing. 2017. Т. 20. С. 105–119.
- Patricia Aguilera-Hermida A. College students’ use and acceptance of emergency online learning due to COVID-19 // International Journal of Educational Research Open. 2020. Т. 1. С. 100011.
- Potdar A. M. и др. Performance Evaluation of Docker Container and Virtual Machine // Procedia Computer Science. 2020. Т. 171. С. 1419–1428.
- Shin J. и др. A Web-Based MOOC Authoring and Learning System for Computational Science Education // 2018 IEEE International Conference on Teaching, Assessment, and Learning for Engineering (TALE). Wollongong, NSW: IEEE, 2018. С. 1028–1032.
- Wu Y. и др. Characterizing the Occurrence of Dockerfile Smells in Open-Source Software: An Empirical Study // IEEE Access. 2020. Т. 8. С. 34127–34139.
[1] https://docs.docker.com/engine/api/sdk