Docker를 활용해 MySQL 이미지를 가져와 실행하고, 이를 spring 이미지에서 이용하도록 docker-compose.yml 파일을 작성했다.
services:
mysql:
image: mysql:latest
container_name: mysql-example
environment:
MYSQL_ROOT_PASSWORD: ${db_root_password}
MYSQL_DATABASE: ${db_name}
MYSQL_USER: ${db_username}
MYSQL_PASSWORD: ${db_password}
ports:
- "3306:3306"
spring-boot-app:
image: ${생성한_Docker_image_이름}
container_name: spring-boot-container
ports:
- "8080:8080"
depends_on:
- mysql
environment:
DB_URL: jdbc:mysql://mysql:3306/${db_name}
DB_USERNAME: ${db_username}
DB_PASSWORD: ${db_password}
SPRING_PROFILES_ACTIVE: prod
MySQL 컨테이너는 계속해서 실행되지만 spring 이미지가 계속해서 종료 되는 문제가 발생했다.
로그를 살펴보니 MySQL이 제대로 시작되기 전에 Spring 컨테이너가 실행이 되면서 DB 연결을 시도해서 자꾸 멈추는 것을 확인했다.
찾아보니 depends_on
의 경우는 Docker compose에서 '단순히 서비스의 시작 순서를 설정하는 것이지 서비스의 준비상태까지 보장하는 것은 아니' 라고 한다.
따라서 정상적으로 실행시키기 위해서는 mysql이 실제로 통신가능한 상태인지 확인하는 과정이 필요하다.
wait-for-it
은 docker에서 여러 Docker Container들을 동시에 실행해야 할 때 각각의 실행 순서를 정해준다.
https://github.com/vishnubob/wait-for-it
wait-for-it.sh
다운로드curl -o wait-for-it.sh https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh
chmod +x wait-for-it.sh
docker-compose.yml
또는 Dockerfile
수정spring-boot-app:
image: elice_aws_docker_practice
container_name: spring-boot-container
ports:
- "8080:8080"
depends_on:
- mysql
environment:
DB_URL: jdbc:mysql://mysql:3306/elice
DB_USERNAME: elice
DB_PASSWORD: elice1234
SPRING_PROFILES_ACTIVE: prod
entrypoint: ["wait-for-it.sh", "mysql:3306", "--", "java", "-jar", "app.jar"]
FROM openjdk:17-jdk-slim
# wait-for-it.sh 복사
COPY wait-for-it.sh /usr/local/bin/wait-for-it.sh
RUN chmod +x /usr/local/bin/wait-for-it.sh
# 앱 실행 명령어를 wait-for-it.sh로 래핑
CMD ["wait-for-it.sh", "mysql:3306", "--", "java", "-jar", "app.jar"]
services:
mysql:
image: mysql:latest
container_name: mysql-example
environment:
MYSQL_ROOT_PASSWORD: ${db_root_password}
MYSQL_DATABASE: ${db_name}
MYSQL_USER: ${db_username}
MYSQL_PASSWORD: ${db_password}
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 3
spring-boot-app:
image: ${생성한_Docker_image_이름}
container_name: spring-boot-container
ports:
- "8080:8080"
depends_on:
mysql:
condition: service_healthy
environment:
DB_URL: jdbc:mysql://mysql:3306/${db_name}
DB_USERNAME: ${db_username}
DB_PASSWORD: ${db_password}
SPRING_PROFILES_ACTIVE: prod
나는 HealthCheck를 활용하는 방법을 선택했다.
위의 사진을 살펴보면 처음 실행했을 때는 mysql-example
과 spring-boot-container
의 로그가 번갈아 가며 찍히다가 종료되었는데, 이번에는 mysql이 전부 실행된 뒤에 spring이 실행되는 모습을 볼 수 있다.
localhost를 통해서 접근도 잘 되는 것을 확인할 수 있다.
이 방법은 이미 MySQL이나 다른 서비스가 Docker를 이용해 배포되고 있을 때 사용하면 좋을 것 같다. docker-compose를 통해서 docker 컨테이너를 생성 및 실행하는 경우 docker network가 새로 생성되기 때문!
docker network create ${network_name}
docker network ls
docker pull mysql
docker run -d --name mysql-container --network ${위에서_설정한_네트워크명} -e MYSQL_ROOT_PASSWORD=${password} mysql:latest
docker ps
docker network inspect ${네트워크명}
docker exec -it <mysql-container-이름> bash # bash 터미널 실행
mysql -u root -p
위의 명령어를 사용하면 MySQL 컨테이너의 터미널에 접근이 가능하다.
이후 터미널에서 mysql을 실행하고, DB를 생성해준다.
CREATE DATABASE <DB명>
services:
spring-app:
image: your-existing-image:latest # 사용하려는 Docker 이미지 이름과 태그
container_name: spring-app-container
ports:
- "8080:8080"
nvironment:
SPRING_DATASOURCE_URL: jdbc:mysql://${mysql_container_이름}:3306/${db_이름}
SPRING_DATASOURCE_USERNAME: ${db_username}
SPRING_DATASOURCE_PASSWORD: ${db_password}
networks:
- docker-net-prac
networks:
docker-net-prac:
external: true
services:
spring-app:
build:
context: .
dockerfile: Dockerfile
container_name: spring-app-container
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://${mysql_container_이름}:3306/${db_이름}
SPRING_DATASOURCE_USERNAME: ${db_username}
SPRING_DATASOURCE_PASSWORD: ${db_password}
ports:
- "8080:8080"
networks:
- docker-net-prac
networks:
docker-net-prac:
external: true
true
로 설정함external: true
를 통해 이 동작을 막는다.[참고자료]