1. 글을 작성하게 된 계기
최근 배포 시 외부 의존성을 줄이는 법, 개발 환경을 어떻게 하면 일관성 있게 통일할까? 등과 같은 개발 환경에 대해 관심이 많습니다. 이런저런 방법들을 시도하던 중, 스프링 부트 도커 컴포즈(Docker-Compose) 지원 을 듣고, 이를 사용해보며 느낀 장점과 간단한 사용법에 대해 정리하기 위해 글을 작성하게 되었습니다.
- 배포 시 외부 의존성을 줄이는 법
- 개발 환경을 일관성 있게 통일하는 법
2. 스프링부트의 도커 컴포즈 지원과 장점
스프링부트 3.1버전부터 도커/컴포즈를 지원하기 시작했습니다.
도커 컨테이너를 애플리케이션의 생명주기 에 맞춰 시작/종료할 수 있으며, 이를 통해 불필요한 메모리 사용 감소, 테스트 시 외부 의존성 제거, 개발 환경 통일 등과 같은 장점을 누릴 수 있습니다.
- 불필요한 메모리 사용
- 테스트 시 데이터베이스 외부 의존성 제거
- 개발환경 통일
2-1. 불필요한 메모리 사용 감소
도커 컨테이너를 여러 개 띄우면, 이를 사용하지 않더라도 메모리를 잡아먹습니다. 개발할 때는 문제가 없지만, 다른 작업을 할 때, 이를 종료하지 않는다면 발열이 심해지고, 속도가 느려집니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
➜ docker docker stats --no-stream --format "table \t"
CONTAINER ID MEM USAGE / LIMIT
cea1b8b1b360 467.8MiB / 12.41GiB
ebfefdfe328d 459.4MiB / 12.41GiB
a6dee14de124 708.6MiB / 12.41GiB
fb6885fde705 8.73MiB / 12.41GiB
2494a457f3b8 224.2MiB / 12.41GiB
77e4c5a0ea16 110.8MiB / 12.41GiB
8888e1239c92 8.125MiB / 12.41GiB
eddb2f72a221 146.9MiB / 12.41GiB
465a9964aec2 16.12MiB / 12.41GiB
1438bd767129 42.91MiB / 170MiB
c87a4fd60bd5 36.26MiB / 12.41GiB
095c015e6e14 46.24MiB / 170MiB
3242225e2da9 66.12MiB / 12.41GiB
f4a815654f71 516KiB / 12.41GiB
b82b91f0d4ac 516KiB / 12.41GiB
0982ee4a47d3 516KiB / 12.41GiB
9f151151921d 516KiB / 12.41GiB
62909ec6a3c4 308KiB / 12.41GiB
83a3231665e9 70.87MiB / 12.41GiB
5b321bfd9f7b 269.3MiB / 12.41GiB
c877db0fc810 117.1MiB / 12.41GiB
5036edfdd4d2 129.4MiB / 12.41GiB
d5dffe291b84 192KiB / 12.41GiB
57947f37f6f8 600KiB / 12.41GiB
349bdea8beed 216KiB / 12.41GiB
bafb1bc3eb0d 172KiB / 12.41GiB
도커를 종료하거나, 컨테이너를 잘 내리면 큰 문제가 없지만, 문제는 너무 잘 잊어버린다는 점이죠… 😞
하지만 스프링부트가 지원하는 도커 기능을 사용하면 애플리케이션의 생명주기에 맞춰 컨테이너를 자동으로 내려주기 때문에 이를 걱정할 필요가 없어집니다.
2-2. 배포 시 외부 의존성 제거
배포를 할 때, 외부 의존성이 있다면 참 불편해집니다. 테스트 코드가 있고, 외부 의존성이 필요하다면 배포가 어렵거나 실패할 수도 있으니까요.
이런 문제를 해결하기 위해 TestContainer, H2, EmbeddedRedis, LocalStack 과 같은 라이브러리를 사용합니다. 다른 라이브러리는 괜찮지만 TestContainer를 사용하면 빌드 시간이 너무 늘어나는데요, 간단한 기능을 수정해서 배포하거나 빠르게 버그 픽스를 해야 할 때는 정말 답답합니다.
다들 비슷하게 느끼는지, 구글에 TestContainer is slow만 치더라도 많은 글들이 나오네요.
이제는 스프링 부트가 도커 컴포즈를 지원하기 때문에 반드시 이를 이용할 필요는 없습니다. 아직 지원하는 기능이 많지 않기 때문에 완전히 이를 대체할 순 없지만 적어도 일부 기능은 대체할 수 있어 빌드 시간을 단축할 수 있습니다.
이는 Do you still need testcontainers with Spring Boot 3.1?을 참조해주세요.
현재 지원하는 인터페이스는 해당 링크를 참조해주세요.
- CassandraConnectionDetails for connections to a Cassandra server
- CouchbaseConnectionDetails for connections to a Couchbase server
- ElasticsearchConnectionDetails for connections to an Elasticsearch server
- JdbcConnectionDetails for connections to a database server through JDBC
- KafkaConnectionDetails for connections to a Kafka server
- MongoConnectionDetails for connections to a MongoDB server
- Neo4jConnectionDetails for connections to a Neo4J server
- R2dbcConnectionDetails for connections to a database server through R2DBC
- RabbitConnectionDetails for connections to a RabbitMQ server
- RedisConnectionDetails for connections to a Redis server
- ZipkinConnectionDetails for connections to a Zipkin server
2-3. 개발 환경 통일
지극히 개인적 의견인데, 온보딩 시 개발 환경이 구축/통일돼 있다면 정말 편합니다. 최소한의 프로그램만 설치 후, 바로 코드를 작성할 수 있으니까요. 또한 설정이 달라 프로그램이 구동되지 않거나, 테스트가 실패하는 케이스 를 줄일 수 있습니다.
사람마다 사용하는 docker-compose.yml이 다르면 문제가 발생할 수도 있습니다. 예를 들어, MySQL을 사용하며, 이모지(emoji) 기능이 있거나, Redis의 AOF와 같은 기능을 사용한다면요.
3. 사용법
사용법은 말로 하는 것보다 코드로 보는 게 편할 것 같아 링크를 남겨두겠습니다.
전체 코드는 해당 레포지토리를 참조해주세요.
4. 정리
스프링부트가 제공하는 도커 컴포즈 기능을 사용하면 여러 가지 장점을 얻을 수 있습니다. 아직 지원하는 기능이 완벽하지 않지만, 지원하는 부분만으로도 많은 것들을 개선할 수 있습니다. 자신의 개발 환경에 맞게 적절하게 이를 활용하도록 합시다.
- 불필요한 메모리 사용
- 테스트 시 데이터베이스 외부 의존성 제거
- 개발환경 통일