[Docker] Spring Boot + Redis Docker Compose로 다중 컨테이너 실행 예제
안녕하세요,
Spring Boot로 Redis에 데이터를 입력하고, 데이터를 불러오는 아주 간단한 Spring Boot API 애플리케이션 서버를 만들고, Docker Compose를 이용하여 Redis 컨테이너와 우리가 만든 Spring Boot 애플리케이션 이미지 컨테이너를 동시에 띄우는 예제를 만들어 보면서 Docker Compose를 공부해보도록 하겠습니다.
먼저, Docker Compose란 여러개의 컨테이너를 동시에 실행하기 위한 툴이라고 합니다. 우리가 작성한 2개의 서로 다른 이미지나 작성한 이미지 + DB나 Redis 같은 공식 이미지를 함께 실행하기 위한 툴입니다. 리눅스의 경우 따로 Docker Compose를 설치해야 하지만, Windows나 Mac에서는 Docker Desktop을 설치하면 자동으로 Docker Compose도 함께 설치가 되어 따로 설치할 필요가 없습니다.
1. Redis + Spring Boot API 서버 만들기
우선, Spring Boot 프로젝트를 생성합니다. 저는 VS Code 및 Gradle 빌드 툴을 이용해서 redistest란 이름의 프로젝트를 생성하였습니다.
참고 : [VS Code] VSCode에 Spring Boot 개발 환경 세팅 및 샘플 프로젝트 생성, 실행
- build.gradle
Spring Boot Dependency는 아래와 같이, spring-boot-starter-data-redis, spring-boot-starter-web, lombok 이렇게 3개를 추가합니다.
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
- RedisConfig.java
Redis 접속 및 RedisTemplate의 Key와 Value Serializer 정의를 위해 Config 파일을 작성합니다. 기본적인 Redis 접속은 별도의 Config 정의가 필요 없지만, Redis는 비트 타입으로 데이터가 저장되기 때문에, 이 애플리케이션에서 String 타입으로 Key와 Value 데이터를 관리하기 위해 아래와 같이 Serializer를 정의해줍니다.
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
@Bean
public RedisTemplate<String, Integer> redisTemplate() {
RedisTemplate<String, Integer> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
}
- RedistestController.java
아래와 같이 아주 간단하게 Controller를 작성합니다.
우선 @RequiredArgsConstructor Lombok 어노테이션과 함께, 생성자 주입으로 RedisTemplate를 정의합니다.
{ "key" : "키", "value" : "값" }과 같은 형식의 Body와 함께 Post 메소드로 "/data"를 호출 시, Redis에 <"키","값"> 형태로 저장되는 setRedisData라는 메서드를 생성합니다.
그리고 Get 메소드로 "/data" URL 호출 시, "key"라는 이름의 파라미터로 키값을 전달받아 Redis에 해당 키의 Value값을 String 형태로 전달하는 getRedisData라는 메서드도 만들어 줍니다.
@RestController
@RequiredArgsConstructor
public class RedistestController {
private final RedisTemplate<String, String> redisTemplate;
@PostMapping("/data")
public ResponseEntity<String> setRedisData(
@RequestBody(required = true) Map<String,String> map) throws Exception{
redisTemplate.opsForValue().set(map.get("key"), map.get("value"));
return new ResponseEntity<>("정상 등록", HttpStatus.CREATED);
}
@GetMapping("/data")
public ResponseEntity<String> getRedisData(
@RequestParam(required = true) String key){
return new ResponseEntity<>(redisTemplate.opsForValue().get(key), HttpStatus.OK);
}
}
2. Spring Boot와 Redis Docker 이미지 Compose를 이용해 다중 컨테이너 실행
이렇게 정말 간단하게 Redis에 데이터를 입력하고 불러오는 Spring Boot API 서버 어플리케이션이 완성이 되었고, 이제 이 것을 Docker 컨테이너 이미지로 만들고 공식 Docker Hub에 있는 Redis 이미지와 함께 2개의 컨테이너를 동시에 띄우도록 하겠습니다.
- application.yml
2개의 Docker 컨테이너가 동시에 실행이 되는데 Spring Boot에서 Redis host를 "localhost"로 설정을 하면 Docker는 자체 가상 네트워크 위에서 돌아가기 때문에 서로 통신을 할 수 없습니다. 그래서 아래와 같이 host를 "redis"라는 이미지 이름으로 작성을 하면 Spring Boot에서 Redis로 정상 통신이 가능합니다.
spring:
redis: # Redis 접속 정보
host: redis
port: 6379
- jar 파일 생성
먼저, Spring Boot Docker 이미지 생성을 위해 jar 파일을 생성하기위한 빌드를 합니다. jar 파일을 생성하기 위해 여러 가지 방법이 있겠지만, gradle일 경우 CMD 같은 터미널로 프로젝트 경로로 이동하여 아래의 커맨드를 실행하여 빌드를 합니다.
.\gradlew.bat build
- Dockerfile
Spring Boot 프로젝트 경로로 가서 "Dockerfile" 이란 이름의 파일을 생성해줍니다. 만약 VS Code를 사용하고 있으면, [Ctrl] + [Shift] + [P] 를 눌러서 "Docker: Add Docker Files to Workspace" 메뉴를 선택하여 생성하면 간편합니다.
참고 : [Node.js] Express Rest API + Puppeteer 웹크롤링 서비스 VSCode Docker 이미지 생성 및 실행
Dockerfile은 간단하게, openJDK 버전 11을 사용하면서 용량이 제일 적은 "openjdk:11-jdk-slim"이라는 공식 java + OS 이미지 위에 위에서 생성한 jar 파일의 위치를 정확히 입력하여 그 jar 파일을 실행하는 명령을 추가합니다.
FROM openjdk:11-jdk-slim
COPY build/libs/redistest-0.0.1-SNAPSHOT.jar redistest.jar
EXPOSE 8080
ENTRYPOINT exec java -jar redistest.jar
- docker-compose.yml
Spring Boot 프로젝트 경로에 "docker-compose.yml"란 파일을 생성해줍니다. Redis 공식 이미지를 이용해서 redis 컨테이너를 실행하고, 우리가 만든 Spring Boot 어플리케이션을 redistest란 이름으로 실행을 하겠다고 아래와 같이 작성을 합니다. 이때 redis가 먼저 실행된 후 Spring boot를 실행하겠다(depends_on)란 설정까지 추가하여 아래와 같은 yml 파일을 작성합니다.
version: '3.4'
services:
redis:
image: redis
ports:
- 6379:6379
redistest:
image: redistest
build:
context: .
dockerfile: ./Dockerfile
ports:
- 8080:8080
depends_on:
- redis
이러면 아주 간단하게 Redis + Spring Boot API 서비스를 다중 컨테이너로 실행하는 프로젝트가 완성이 되었습니다. 전체 프로젝트 경로와 파일은 아래와 같습니다.
3. Docker Compose 실행
CMD 등 터미널에서 프로젝트 경로로 이동하여 아래와 같이 Docker Compose 명령을 통해 다중 컨테이너를 실행합니다.
docker-compose -f "docker-compose.yml" up -d --build
위와 같이 컨테이너 2개가 정상적으로 실행되었다고 나오고, Docker Desktop을 실행하면 아래와 같이 2개의 컨테이너가 정상 실행되었음을 확인할 수 있습니다.
PostMan을 통해 Redis에 데이터를 저장하고 불러오는 테스트를 하면 정상적으로 실행이 되는 것을 확인할 수 있습니다.
먼저, Post 메소드로 "http://localhost:8080/data"와 아래의 데이터를 Body로 호출을 하면 데이터가 저장이 됩니다.
Get 메서드로 "http://localhost:8080/data?key=key1"라고 호출을 하면, 방금 저장한 "value1"이라는 데이터가 리턴이 되는 것을 확인할 수 있습니다.