Testcontainers가 AI 기반 애플리케이션 개발을 간소화하는 방법
오늘날 빠르게 변화하고 경쟁이 점점 치열해지는 비즈니스 환경에서, 조직은 디지털 트랜스포메이션 프로젝트 완료를 앞당길 방법을 찾아야 합니다. 새로운 애플리케이션이나 기능 배포 지연을 최소화하면 더 짧은 시간 안에 생산성과 효율성의 이점을 거두어 경쟁사보다 우위를 확보할 수 있습니다. 그러나 새로운 소프트웨어 개발이나 업데이트 출시가 지연되면 업계의 다른 기업들이 더 빠르게 혁신하는 동안 시장 점유율이 약화될 수 있습니다.
컨테이너는 애플리케이션 개발 관행을 간소화하려는 기업들이 선택하는 핵심 기술로 부상했으며, 개발자가 이전보다 훨씬 짧은 시간 안에 더 안전하고 견고하며 확장 가능한 애플리케이션을 구축할 수 있게 해줍니다.
이 글에서는 Zilliz가 주최한 최근 Unstructured Data Meetup에서 Oleg Šelajev가 진행한 이 발표에서 영감을 받아, 컨테이너화의 개념과 그 필수 도구 중 하나인 Docker, 그리고 이들이 애플리케이션 개발 프로세스의 복잡성을 어떻게 줄이는지 살펴봅니다. 그런 다음 Docker의 기능을 크게 확장하여 개발자가 AI 기반 애플리케이션 개발을 간소화할 수 있게 해주는 오픈소스 프레임워크인 Testcontainers에 주목하겠습니다.
컨테이너란 무엇인가요?
컨테이너는 바이너리, 종속성, 라이브러리, 구성 파일을 포함해 어떤 환경에서도 실행하는 데 필요한 모든 구성 요소를 담은 표준화된 애플리케이션 코드 패키지입니다. 전통적으로 애플리케이션은 단일 코드베이스 안에 여러 구성 요소가 포함된 모놀리식 구조였습니다. 오늘날 개발자는 기능이나 서비스에 따라 소프트웨어를 구성 요소로 나누며, 각 구성 요소는 자체 코드베이스와 종속성을 갖습니다. 이를 컨테이너화 또는 마이크로서비스 아키텍처라고 합니다.
컨테이너의 이점은 다음과 같습니다:
비즈니스 민첩성 향상: 애플리케이션을 서비스로 나누면 개발자가 프로젝트의 서로 다른 부분을 동시에 작업할 수 있습니다. 마찬가지로 컨테이너의 모듈성은 전체 애플리케이션을 수정하지 않고도 업데이트와 새로운 기능을 가능하게 합니다.
확장성 강화: 애플리케이션을 컨테이너 안에 패키징할 수 있다면, 또 다른 인스턴스를 만들기 위해 추가 컨테이너만 배포하면 됩니다. 한편 모듈형 애플리케이션에서는 팀이 용량 한계에 가까워지는 서비스에 대해 새 컨테이너를 간단히 추가로 실행할 수 있습니다.
효율성 향상: 컨테이너는 이식성이 매우 높고 플랫폼에 독립적이기 때문에, 개발자는 서로 다른 환경을 설정하고 유지하는 데 시간을 할애할 필요가 없습니다.
비용 절감: 개발자가 서버와 환경을 관리해야 하는 책임에서 벗어나면 다른 곳, 즉 실제 애플리케이션 개발에서 더 생산적으로 일할 수 있습니다! 이는 프로젝트 완료에 필요한 인시를 줄여 비용을 낮춥니다.
컨테이너의 사용 사례는 다음과 같습니다:
클라우드 네이티브 애플리케이션 개발: 컨테이너화된 아키텍처는 향상된 확장성, 더 넓은 데이터 접근성, 더 강력한 사이버 보안을 포함해 클라우드의 기능을 온전히 활용합니다.
애플리케이션 현대화: 컨테이너는 레거시 애플리케이션을 리팩터링하여 클라우드 환경과의 호환성을 높이는 데 사용할 수 있으며, 이를 통해 성능과 리소스 효율성이 향상되고 업데이트가 더 쉬워집니다.
프로토타이핑: 컨테이너는 플랫폼에 독립적이기 때문에 개발, 테스트, 스테이징 등을 위한 서로 다른 환경을 설정할 필요를 없애 개발자가 새로운 기능을 더 쉽게 실험할 수 있게 합니다.
사물인터넷(IoT) 기기: 컨테이너는 가볍고 리소스 효율적이기 때문에, 제약이 있는 IoT 하드웨어에 이상적인 소프트웨어 배포 메커니즘을 제공합니다.
- DevOps: 컨테이너는 일관되고 격리된 환경을 만드는 데 사용되어, 애플리케이션이 배포되는 위치와 관계없이 동일하게 실행되도록 보장하며, 그 결과 더 빠른 배포와 개발팀과 운영팀 간의 향상된 협업을 가능하게 합니다.
Docker란 무엇인가요?
Docker는 개발자가 컨테이너를 생성, 배포, 구성 및 관리할 수 있게 해주는 플랫폼입니다. Docker는 사실 컨테이너와 매우 동의어처럼 쓰이기 때문에, 컨테이너는 종종 “Docker 컨테이너”라고 불립니다. 하지만 실제로 사람들이 Docker를 언급할 때는 사실 Docker engine, 즉 컨테이너가 구축되고 실행되는 런타임 환경을 가리킵니다. 이 엔진은 컨테이너 아래에 위치하여 호스트 장치의 운영 체제(OS)를 가상화하고 CPU 및 메모리와 같은 최적의 리소스 양을 할당합니다.
이는 자체 OS와 컴퓨팅 리소스를 필요로 하는 유사한 솔루션인 가상 머신(VM)과 뚜렷한 대조를 이룹니다. 컨테이너를 환경에 구애받지 않게 만드는 것 외에도, Docker의 사용은 컨테이너를 리소스 집약적이지 않게 하고, 시작 및 종료를 더 빠르게 하며, VM보다 더 뛰어난 이식성을 제공합니다.
널리 사용되는 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는 각 종속성의 복잡한 세부 사항을 추상화하여 더 쉽게 작업할 수 있게 합니다. 이는 프로젝트의 운영 비용을 줄이는 동시에 실험을 장려하고 간소화된 개발을 촉진합니다.
Testcontainers의 50개 이상의 모듈형 통합 중 일부
이름에서 알 수 있듯이, Testcontainers는 데이터 액세스 계층, 통합 및 인수 테스트를 포함한 애플리케이션 테스트에서 가장 큰 생산성 향상을 제공합니다.
Testcontainers로 애플리케이션 테스트를 수행할 때의 이점은 다음과 같습니다:
격리 및 일관성: 구성 요소를 컨테이너화하면 각 테스트가 새롭고 알려진 상태에서 실행되도록 보장합니다. 예를 들어, 데이터베이스를 격리하여 테스트하면 서로 다른 로컬 데이터베이스 설정에서 발생하는 불일치를 제거할 수 있으며, 컨테이너화된 브라우저는 로컬 브라우저 설정으로 인한 차이를 해결하여 더 신뢰할 수 있는 UI 테스트를 가능하게 합니다.
환경 동등성: 개발자는 프로덕션과 매우 유사한 환경에서 엔드투엔드로 테스트를 수행할 수 있어, 환경 간 불일치를 줄이는 동시에 테스트 결과의 정확성을 높일 수 있습니다.
리소스 관리: 컨테이너는 실행 시간이 짧기 때문에 리소스를 더 효율적으로 관리할 수 있으며, 빠른 테스트 실행과 정리를 가능하게 합니다.
확장성과 안정성: 따라서 사용 가능한 리소스를 고려할 필요 없이 테스트를 쉽게 확장할 수 있습니다.
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 인스턴스를 생성할 수 있을 뿐만 아니라, 이 접근 방식은 해당 컴포넌트가 애플리케이션의 요구 사항과 절대 동기화되지 않는 일이 없도록 보장합니다. 애플리케이션 자체가 이를 호출하고 있기 때문입니다.
LLM 통합을 위한 Ollama와 HuggingFace 통합
Testcontainers가 생산성을 높이는 두 번째 방법은 애플리케이션 내에서 LLM과 같은 AI 컴포넌트의 통합을 간소화하는 것입니다. 이를 통해 코드 내부에서 LLM 호출을 쉽게 수행하여 애플리케이션에 LLM 기능을 추가할 수 있으며, 그만큼 중요하게는 AI 컴포넌트를 DevOps 프로세스의 일반적인 일부로 만들 수 있습니다.
아래 코드 조각에서는 기존 OllamaContainer를 확장하는 OllamaHuggingFaceContainer 클래스를 생성하여, HuggingFace에서 다운로드한 딥러닝 모델을 실행하는 Ollama 컨테이너를 구동하는 인스턴스를 시작합니다.
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;
}
AI 모델의 자동화된 배포
이후 Testcontainers는 애플리케이션 내부에서 AI 모델을 호출할 수 있게 해주기 때문에, 이러한 모델을 배포하는 더 편리하고 자동화된 방법도 제공합니다. 오픈 소스 모델은 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 형식으로 제공되는 방대한 수의 모델에도 적용할 수 있습니다. 이 방식으로 모델을 배포하면 애플리케이션의 향후 반복 버전에서 AI 모델을 업그레이드하기도 더 쉬워집니다. 환경을 변경할 필요 없이 코드에서 모델에 대한 참조만 변경하면 되기 때문입니다.
결론
요약하면:
컨테이너는 바이너리, 종속성, 라이브러리, 구성 파일을 포함해 필요한 모든 구성 요소를 담고 있어 어떤 환경에서도 실행할 수 있는 애플리케이션 코드의 표준화된 패키지입니다.
컨테이너의 이점은 다음과 같습니다:
비즈니스 민첩성 향상
확장성 강화
효율성 증가
비용 절감
컨테이너의 사용 사례는 다음과 같습니다:
클라우드 네이티브 애플리케이션 개발
애플리케이션 현대화
프로토타이핑
IoT 장치
DevOps
Docker는 개발자가 컨테이너를 생성, 배포, 구성 및 관리할 수 있게 해주는 플랫폼입니다.
가장 널리 사용되는 Docker 도구에는 다음이 포함됩니다:
Docker Enterprise
Docker Swarm
Docker Compose
Kubernetes
Testcontainers
Testcontainers는 데이터베이스, 브라우저, 메시지 브로커와 같이 컨테이너에서 실행될 수 있는 사전 구성된 종속성의 모듈식 인스턴스를 제공하는 오픈 소스 프레임워크입니다.
Testcontainers는 다음을 제공하여 애플리케이션 테스트를 간소화합니다:
격리 및 일관성
환경 동등성
리소스 관리
확장성 및 안정성
Testcontainers가 제공하는 기타 생산성 및 효율성 향상에는 다음이 포함됩니다:
종속성의 추상화로, 추가 소프트웨어를 설치하거나 애플리케이션의 환경을 변경할 필요 없이 더 쉽게 작업할 수 있습니다.
AI 구성 요소의 간단한 호출로, 이를 DevOps 프로세스의 일반적인 부분으로 만듭니다.
LLM의 추상화 및 자동 배포.
추가 자료
컨테이너, Docker, DevOps 및 차세대 AI 기반 솔루션을 만드는 데 있어 이들의 역할에 대해 더 알아보려면 아래 리소스를 확인해 보시기 바랍니다.
계속 읽기

Zilliz Cloud Launches in AWS Australia, Expanding Global Reach to Australia and Neighboring Markets
We're thrilled to announce that Zilliz Cloud is now available in the AWS Sydney, Australia region (ap-southeast-2).

Selecting the Right ETL Tools for Unstructured Data to Prepare for AI
Learn the right ETL tools for unstructured data to power AI. Explore key challenges, tool comparisons, and integrations with Milvus for vector search.

OpenAI o1: What Developers Need to Know
In this article, we will talk about the o1 series from a developer's perspective, exploring how these models can be implemented for sophisticated use cases.


