Как Testcontainers упрощает разработку приложений на базе ИИ
В сегодняшней быстро меняющейся и всё более конкурентной бизнес-среде организациям необходимо находить способы ускорить завершение своих проектов цифровой трансформации. Минимизируйте задержки при развертывании новых приложений или функций — и вы сможете быстрее получить преимущества в производительности и эффективности, получив преимущество перед конкурентами. Однако затягивание разработки нового программного обеспечения или выпуска обновлений может привести к потере доли рынка, поскольку другие компании в вашей отрасли внедряют инновации быстрее.
Контейнеры стали основной технологией для компаний, стремящихся оптимизировать свои практики разработки приложений, позволяя разработчикам создавать приложения, которые более безопасны, надежны и масштабируемы, — за меньшее время, чем когда-либо прежде.
В этой статье, вдохновленной этим выступлением Oleg Šelajev на недавнем Unstructured Data Meetup, организованном Zilliz, мы рассмотрим концепцию контейнеризации и один из ее ключевых инструментов, Docker, а также то, как они уменьшают сложность процесса разработки приложений. Затем мы обратим внимание на open-source фреймворк Testcontainers, который значительно расширяет возможности Docker, — позволяя разработчикам оптимизировать разработку приложений на базе ИИ.
Что такое контейнеры?
Контейнеры — это стандартизированные пакеты кода приложений, содержащие все необходимые компоненты, включая двоичные файлы, зависимости, библиотеки и конфигурационные файлы, для запуска в любой среде. Традиционно приложения были монолитными, с различными компонентами в рамках единой кодовой базы. Сегодня разработчики разделяют программное обеспечение на компоненты в соответствии с их функцией или сервисом, каждый со своей кодовой базой и зависимостями, — контейнеризация или микросервисная архитектура.
Преимущества контейнеров включают:
Повышенная гибкость бизнеса: разделение приложений на сервисы позволяет разработчикам одновременно работать над разными частями проекта. Аналогично, модульность контейнеров позволяет выпускать обновления и новые функции без изменения всего приложения.
Улучшенная масштабируемость: если приложение можно упаковать в контейнер, вам нужно лишь развернуть дополнительный контейнер, чтобы создать еще один экземпляр. В модульных приложениях команды тем временем могут просто запускать новые контейнеры для сервиса, приближающегося к пределу мощности.
Повышенная эффективность: поскольку контейнеры обладают высокой переносимостью и не зависят от платформы, разработчикам не приходится тратить время на настройку и обслуживание разных сред.
Снижение затрат: освобождение разработчиков от ответственности за управление серверами и средами делает их более продуктивными в других задачах, то есть в фактической разработке приложений! Это сокращает человеко-часы, необходимые для завершения проектов, — снижая их стоимость.
Примеры использования контейнеров включают:
Разработка облачно-ориентированных приложений: контейнеризованные архитектуры полностью используют возможности облака, включая улучшенную масштабируемость, более широкий доступ к данным и более сильную кибербезопасность.
Модернизация приложений: контейнеры можно использовать для рефакторинга устаревших приложений, чтобы повысить их совместимость с облачной средой, сделав их более производительными, ресурсоэффективными и более простыми в обновлении.
Прототипирование: поскольку они не зависят от платформы, контейнеры устраняют необходимость настраивать разные среды для разработки, тестирования, staging и т. д. — что упрощает разработчикам экспериментирование с новыми функциями.
Устройства Интернета вещей (IoT): будучи легковесными и ресурсоэффективными, контейнеры обеспечивают идеальный механизм развертывания программного обеспечения для ограниченного IoT-оборудования.
- DevOps: контейнеры используются для создания согласованных, изолированных сред, гарантируя, что приложение работает одинаково независимо от того, где оно развернуто, что приводит к более быстрому развертыванию и улучшенному сотрудничеству между командами разработки и эксплуатации.
Что такое Docker?
Docker — это платформа, которая позволяет разработчикам создавать, развертывать, настраивать и управлять контейнерами. Docker настолько тесно ассоциируется с контейнерами, что их часто называют “Docker containers. На самом деле, однако, когда люди упоминают Docker, они фактически имеют в виду Docker engine: среду выполнения, на которой контейнеры создаются и запускаются. Этот движок располагается под контейнерами, чтобы виртуализировать операционную систему (OS) хост-устройства и выделять им оптимальный объем ресурсов, таких как CPU и память.
Это заметно контрастирует с похожим решением в виде виртуальных машин (VMs), которым требуются собственная OS и вычислительные ресурсы. Помимо того что Docker делает контейнеры независимыми от среды, его использование делает их менее ресурсоемкими, более быстрыми при запуске и завершении работы, а также более переносимыми, чем VMs.
Широко используемые инструменты Docker
При всей мощности Docker его популярность в значительной степени обусловлена богатой экосистемой связанных инструментов и библиотек. Вот некоторые из наиболее заметных инструментов Docker.
Docker Enterprise: версия Docker, предназначенная для критически важных развертываний, предлагающая расширенные функции безопасности, управления и оркестрации для сертифицированных, готовых к промышленной эксплуатации релизов.
Docker Swarm: инструмент кластеризации и оркестрации для Docker, который позволяет пользователям управлять несколькими узлами Docker как единой виртуальной системой, обеспечивая более простое масштабирование и балансировку нагрузки.
Docker Compose: инструмент для упрощения разработки и управления сложными Docker-приложениями с несколькими контейнерами.
Kubernetes: контейнерная платформа оркестрации с открытым исходным кодом, которая автоматизирует развертывание, масштабирование и управление крупными контейнеризованными приложениями в кластерах серверов.
Вы можете узнать больше об экосистеме docker в этой статье https://middleware.io/blog/understanding-the-docker-ecosystem/
Testcontainers: упрощенное управление зависимостями
Testcontainers — это фреймворк с открытым исходным кодом, который предоставляет легковесные, модульные экземпляры баз данных, браузеров, брокеров сообщений и других предварительно настроенных зависимостей, которые могут запускаться в контейнере. Предоставляя пользователю библиотеку программных API для управления контейнерами, Testcontainers абстрагирует сложные детали каждой зависимости, упрощая работу с ними. Это снижает операционные затраты проектов, одновременно поощряя эксперименты и способствуя оптимизированной разработке.
Подборка из 50+ модульных интеграций Testcontainers
Как следует из названия, Testcontainers обеспечивает наиболее значительный прирост продуктивности, когда речь идет о тестировании приложений, включая тесты уровня доступа к данным, интеграционные и приемочные тесты.
Преимущества проведения тестирования приложений с Testcontainers включают:
Изоляция и согласованность: контейнеризация компонентов гарантирует, что каждый тест выполняется в свежем, известном состоянии. Например, тестирование баз данных в изоляции устраняет несогласованности, возникающие из-за различий в локальных настройках баз данных, тогда как контейнеризованные браузеры обеспечивают более надежное тестирование UI, устраняя вариации, вызванные локальными настройками браузеров.
Паритет сред: разработчики могут проводить сквозное тестирование в среде, максимально похожей на production, сокращая расхождения между средами и повышая точность результатов тестирования.
Управление ресурсами: поскольку контейнеры имеют короткое время выполнения, вы можете управлять ресурсами более эффективно, одновременно обеспечивая быстрый запуск и завершение тестов.
Масштабируемость и надежность: следовательно, тесты можно легко масштабировать без необходимости учитывать доступные ресурсы.
Помимо того, что Testcontainers делает тестирование приложений проще и эффективнее, он может помочь вам разрабатывать AI-приложения, не зависящие от окружения. Теперь обратим внимание на несколько других ключевых способов, с помощью которых Testcontainers повышает продуктивность.
Запуск экземпляра Milvus
В качестве первого примера того, как использовать Testcontainers для повышения продуктивности, давайте создадим экземпляр Milvus, как показано в примере кода ниже (все примеры кода в этой статье написаны на Java, но библиотека Testcontainers также доступна на Python, Node.js Go, Rust и нескольких других языках):
import io.milvus.client.MilvusServiceClient;
import io.milvus.param.ConnectParam;
import org.testcontainers.milvus.MilvusContainer;
public class MilvusExample {
public static void main(String[] args) {
MilvusContainer milvus = new MilvusContainer("milvusdb/milvus:v2.3.9");
milvus.start();
MilvusServiceClient milvusClient = new MilvusServiceClient(
ConnectParam.newBuilder().withUri(milvus.getEndpoint()).build());
}
}
Вместо того чтобы устанавливать и настраивать отдельный экземпляр Milvus и интегрировать его с вашим приложением, Testcontainers предоставляет простую в использовании абстракцию, которая просто вызывает экземпляр изнутри кода.
Сначала мы создаем новый экземпляр контейнера Milvus, указывая версию путем передачи соответствующего образа контейнера в качестве параметра. Помимо упрощения разработки приложений, это также облегчает обновление приложений в будущем, поскольку вам нужно лишь указать обновленный образ. Затем мы запускаем контейнер с помощью метода .start(), а затем передаем контейнер в качестве параметра новому экземпляру Milvus Service Client, который позволяет взаимодействовать с сервисом внутри контейнера.
Помимо создания экземпляра Milvus всего в несколько строк кода, этот подход гарантирует, что компонент также никогда не рассинхронизируется с требованиями приложения, потому что он вызывается самим приложением.
Интеграция Ollama и HuggingFace для интеграции LLM
Второй способ, с помощью которого Testcontainers повышает продуктивность, заключается в упрощении интеграции AI-компонентов, таких как LLM, внутри приложений. Это позволяет легко выполнять вызовы LLM изнутри кода, чтобы добавить функциональность LLM в приложения, и, что не менее важно, делает AI-компоненты обычной частью процесса DevOps.
В приведенном ниже фрагменте кода мы создаем класс OllamaHuggingFaceContainer, который расширяет существующий OllamaContainer, чтобы запустить экземпляр, работающий с контейнером Ollama, который выполняет модель глубокого обучения, загруженную из HuggingFace.
Ollama — это платформа, которая позволяет обслуживать модели для инференса локально на вашем устройстве, тогда как HuggingFace — незаменимый хаб для загрузки AI-моделей с открытым исходным кодом. Объединив эти два ресурса, вы получаете доступ к десяткам моделей, поддерживаемых Ollama, а также к любой модели в GGUF (GPT-Generated Unified Format), которых на HuggingFace насчитывается 23 000.
package org.testcontainers.huggingface;
import com.github.dockerjava.api.command.InspectContainerResponse;
import org.testcontainers.containers.ContainerLaunchException;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.ollama.OllamaContainer;
import org.testcontainers.utility.DockerImageName;
import java.io.IOException;
public class OllamaHuggingFaceContainer extends OllamaContainer {
private final HuggingFaceModel huggingFaceModel;
public OllamaHuggingFaceContainer(HuggingFaceModel model) {
super(DockerImageName.parse("ollama/ollama:0.1.44"));
this.huggingFaceModel = model;
}
Автоматизированное развертывание моделей ИИ
Впоследствии, поскольку Testcontainers позволяет вызывать модели ИИ изнутри приложения, он также предоставляет более удобный, автоматизированный способ распространения этих моделей. Хотя модели с открытым исходным кодом легко получить с HuggingFace, они хранятся в виде набора файлов и каталогов в git-репозиториях. Это не только слишком сложно для непосвященных, но и далеко не самый удобный способ работы с моделями для опытных разработчиков.
Типичный репозиторий HuggingFace
Вместо ручной настройки и развертывания модели можно автоматизировать процесс с помощью скрипта. Это, опять же, снижает административную нагрузку на разработчиков, добавляя при этом еще один уровень абстракции для самой модели. Это показано в коде ниже (который представляет собой фрагмент из более длинного тестового скрипта), где показано, как модель может быть указана и настроена изнутри кода. Помимо указания каталога, из которого должна быть взята модель, и точной модели, которую нужно использовать, переменная modelfileопределяет шаблон промпта.
public class HuggingFaceVisionModelTest {
@Test
public void visionModelWithHuggingFace() throws IOException {
String imageName = "vision-model-from-HuggingFace";
String repository = "xtuner/llava-phi-3-mini-gguf";
String model = "llava-phi-3-mini-int4.gguf";
String visionAdapter = "llava-phi-3-mini-mmproj-f16.gguf";
String modelfile = """
FROM ./llava-phi-3-mini-int4.gguf
FROM ./llava-phi-3-mini-mmproj-f16.gguf
TEMPLATE """{{ if .System }}<|system|>
{{ .System }}<|end|>
{{ end }}{{ if .Prompt }}<|user|>
{{ .Prompt }}<|end|>
{{ end }}<|assistant|>
{{ .Response }}<|end|>
"""
PARAMETER stop "<|user|>"
PARAMETER stop "<|assistant|>"
PARAMETER stop "<|system|>"
PARAMETER stop "<|end|>"
PARAMETER stop "<|endoftext|>"
PARAMETER num_keep 4
PARAMETER num_ctx 4096
""";
try (
OllamaContainer ollama = new OllamaContainer(DockerImageName.parse(imageName).asCompatibleSubstituteFor("ollama/ollama:0.1.44")).withReuse(true)
) {
try {
ollama.start();
} catch (ContainerFetchException ex) {
createImage(imageName, repository, model, modelfile, visionAdapter);
ollama.start();
}
Как упоминалось ранее, это можно применить к любой модели в Ollama, а также к огромному числу моделей, доступных в формате GGUF. Развертывание модели таким способом также упрощает обновление модели ИИ в будущих итерациях вашего приложения, поскольку вам не придется вносить изменения в окружение — только в ссылки на модель в коде.
Заключение
Вкратце:
Контейнеры — это стандартизированные пакеты кода приложения, содержащие все необходимые компоненты, включая бинарные файлы, зависимости, библиотеки и конфигурационные файлы, для запуска в любой среде.
Преимущества контейнеров включают:
Повышение гибкости бизнеса
Улучшенная масштабируемость
Повышение эффективности
Снижение затрат
Варианты использования контейнеров включают:
Разработка облачно-нативных приложений
Модернизация приложений
Прототипирование
Устройства IoT
DevOps
Docker — это платформа, которая позволяет разработчикам создавать, развертывать, настраивать и управлять контейнерами.
Некоторые из наиболее широко используемых инструментов Docker включают:
Docker Enterprise
Docker Swarm
Docker Compose
Kubernetes
Testcontainers
Testcontainers — это фреймворк с открытым исходным кодом, который предоставляет модульные экземпляры предварительно настроенных зависимостей, способных работать в контейнере, таких как базы данных, браузеры и брокеры сообщений.
Testcontainers упрощает тестирование приложений, обеспечивая:
Изоляцию и согласованность
Соответствие сред
Управление ресурсами
Масштабируемость и надежность
Другие повышения продуктивности и эффективности, обеспечиваемые Testcontainers, включают:
Абстрагирование зависимостей, что упрощает работу с ними — без необходимости устанавливать дополнительное программное обеспечение или вносить изменения в среду(ы) приложения.
Простое использование компонентов ИИ, делающее их обычной частью процессов DevOps.
Абстрагирование и автоматизированное развертывание LLM.
Дополнительные материалы
Мы рекомендуем вам ознакомиться с приведенными ниже ресурсами, чтобы узнать больше о контейнерах, Docker, DevOps и их роли в создании следующего поколения решений на базе ИИ.
Читать далее

How Zilliz Saw the Future of Vector Databases—and Built for Production
An inside look at how Zilliz built vector databases for real-world use, focusing on scalability, stability, and running them reliably at scale.

Announcing VDBBench 1.0: Open-Source VectorDB Benchmarking with Your Real-World Production Workloads
Discover VDBBench 1.0, an open-source tool for benchmarking vector databases with real-world production data, streaming ingestion, and concurrent workloads.

Introducing DeepSearcher: A Local Open Source Deep Research
In contrast to OpenAI’s Deep Research, this example ran locally, using only open-source models and tools like Milvus and LangChain.


