컨테이너에서 실행되는 서비스 구성하기
컨테이너에서 실행되는 서비스 구성하기
파일을 컨테이너에 복사하고 컨테이너 안에서 명령을 실행해서, 테스트용 Docker 컨테이너를 초기화하고 구성하는 방법을 배워요.
출처: 문서
본문
이 가이드를 통해 다음 내용을 배울 수 있어요.
- 파일을 컨테이너에 복사해서 컨테이너 초기화하기
execInContainer()로 실행 중인 컨테이너 안에서 명령 실행하기- SQL 스크립트로 PostgreSQL 데이터베이스 설정하기
- LocalStack 컨테이너에 AWS S3 버킷 만들기
사전 준비 (Prerequisites)
- Java 17 이상
- 선호하는 IDE
- Testcontainers가 지원하는 Docker 환경
참고: Testcontainers가 처음이라면 Testcontainers 개요를 방문해 알아보는 걸 권장해요.
파일을 컨테이너에 복사하기
때로는 파일을 특정 위치에 배치해서 컨테이너를 초기화해야 할 때가 있어요. 예를 들어 PostgreSQL은 컨테이너가 시작될 때 /docker-entrypoint-initdb.d/에서 SQL 스크립트를 실행해요.
초기화 스크립트 만들기
src/test/resources/init-db.sql을 만들어요.
create table customers (
id bigint not null,
name varchar not null,
primary key (id)
);
파일을 컨테이너에 복사하기
withCopyFileToContainer()를 사용해 SQL 스크립트를 컨테이너의 init 디렉터리에 복사해요.
package com.testcontainers.demo;
import static org.junit.jupiter.api.Assertions.assertFalse;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.testcontainers.postgresql.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.MountableFile;
@Testcontainers
class CustomerServiceTest {
@Container
static PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:16-alpine")
.withCopyFileToContainer(
MountableFile.forClasspathResource("init-db.sql"),
"/docker-entrypoint-initdb.d/");
CustomerService customerService;
@BeforeEach
void setUp() {
customerService = new CustomerService(
postgres.getJdbcUrl(),
postgres.getUsername(),
postgres.getPassword()
);
}
@Test
void shouldGetCustomers() {
customerService.createCustomer(new Customer(1L, "George"));
customerService.createCustomer(new Customer(2L, "John"));
List<Customer> customers = customerService.getAllCustomers();
assertFalse(customers.isEmpty());
}
}
withCopyFileToContainer(MountableFile, String) 메서드는 classpath의 init-db.sql을 컨테이너 안의 /docker-entrypoint-initdb.d/에 복사해요. PostgreSQL은 시작 시 그 디렉터리의 스크립트를 자동으로 실행해요.
호스트의 아무 경로에서도 파일을 복사할 수 있어요.
.withCopyFileToContainer(
MountableFile.forHostPath("/host/path/to/init-db.sql"),
"/docker-entrypoint-initdb.d/");
컨테이너 안에서 명령 실행하기
일부 Docker 컨테이너는 작업을 수행하기 위한 CLI 도구를 제공해요. container.execInContainer(String...)을 사용하면 실행 중인 컨테이너 안에서 사용 가능한 어떤 명령이든 실행할 수 있어요.
예시: LocalStack에 S3 버킷 만들기
LocalStack 모듈은 AWS 서비스를 에뮬레이트해요. S3 파일 업로드를 테스트하려면 테스트를 실행하기 전에 버킷을 만들어요.
package com.testcontainers.demo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.Bucket;
@Testcontainers
class LocalStackTest {
static final String bucketName = "mybucket";
@Container
static LocalStackContainer localStack =
new LocalStackContainer(DockerImageName.parse("localstack/localstack:3.4.0"));
@BeforeAll
static void beforeAll() throws IOException, InterruptedException {
localStack.execInContainer("awslocal", "s3", "mb", "s3://" + bucketName);
org.testcontainers.containers.Container.ExecResult execResult =
localStack.execInContainer("awslocal", "s3", "ls");
String stdout = execResult.getStdout();
int exitCode = execResult.getExitCode();
assertTrue(stdout.contains(bucketName));
assertEquals(0, exitCode);
}
@Test
void shouldListBuckets() {
URI s3Endpoint = localStack.getEndpointOverride(S3);
StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(
AwsBasicCredentials.create(localStack.getAccessKey(), localStack.getSecretKey())
);
S3Client s3 = S3Client.builder()
.endpointOverride(s3Endpoint)
.credentialsProvider(credentialsProvider)
.region(Region.of(localStack.getRegion()))
.build();
List<String> s3Buckets = s3.listBuckets().buckets().stream()
.map(Bucket::name)
.toList();
assertTrue(s3Buckets.contains(bucketName));
}
}
execInContainer("awslocal", "s3", "mb", "s3://mybucket") 호출은 awslocal CLI 도구(LocalStack 이미지가 제공)를 실행해서 S3 버킷을 만들어요. 어떤 명령이든 출력과 종료 코드를 캡처할 수 있어요.
Container.ExecResult execResult = localStack.execInContainer("awslocal", "s3", "ls");
String stdout = execResult.getStdout();
int exitCode = execResult.getExitCode();
참고:
withCopyFileToContainer()와execInContainer()메서드는GenericContainer에서 상속되므로, 모든 Testcontainers 모듈에서 사용할 수 있어요.
요약 (Summary)
withCopyFileToContainer()를 사용해 컨테이너가 시작되기 전에 초기화 파일을 컨테이너 안에 배치해요.execInContainer()을 사용해 실행 중인 컨테이너 안에서 버킷, 토픽, 큐 만들기 같은 설정 작업을 위한 명령을 실행해요.
더 읽어보기 (Further reading)
- Testcontainers for Java 시작하기
- Testcontainers Postgres 모듈
- Testcontainers LocalStack 모듈