
springboot, mysql, prometheus, grafana를 활용하여
스프링부트 서버 메트릭을 수집하고 모니터링하는 프로젝트 진행중
보다 손쉽게 서버를 다루기 위하여 docker를 사용하였다.
매번 컨테이너를 하나 하나 생성하고 관리함에 있어서 불편함이 있었다.
(이 컨테이너가 단 4개가 아닌 1억개라고 상상해봐라.)
docker compose를 이용하여 여러개의 컨테이너를 한번에 생성, 관리하도록 해보자.
결론부터 말하면 docker-compose.yml 파일 내용은 아래와 같다.
networks:
2024_summer_coding:
name: 2024_summer_coding_network
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
gateway: 172.18.0.1
labels:
com.docker.compose.network: '2024_summer_coding'
com.docker.compose.project: '2024_summer_coding'
external: false
services:
mysqldb:
image: mysql:latest
container_name: mysqldb
environment:
MYSQL_ROOT_PASSWORD: 'dl-13579'
MYSQL_DATABASE: '2024_summer_coding'
volumes:
- ./mysql-data:/var/lib/mysql
ports:
- 3306:3306
networks:
- 2024_summer_coding
springboot:
image: springboot:latest
container_name: springboot
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysqldb:3306/2024_summer_coding?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: dl-13579
SPRING__PROFILES_ACTIVE: docker
ports:
- 8080:8080
networks:
- 2024_summer_coding
depends_on:
- mysqldb
prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
- ./prometheus-data:/prometheus
- ./prometheus:/etc/prometheus
ports:
- 9090:9090
networks:
- 2024_summer_coding
depends_on:
- springboot
grafana:
image: grafana/grafana:latest
container_name: grafana
volumes:
- ./grafana-data:/var/lib/grafana
ports:
- 3000:3000
networks:
- 2024_summer_coding
depends_on:
- prometheus
컨테이너들을 실행시키고 네트워크를 확인해보면
'2024_summercoding_default'라는 bridge가 자동으로 생성되었음을 확인할 수 있다.

inspect 명령으로 확인해보면 아래와 같이 자동으로 사설망 주소를 받고 같은 네트워크 내에서 컨테이너들이 실행되었음을 확인할 수 있다.

따라서 별도의 설정 없이도 컨테이너들이 잘 동작하지만 다른 디바이스를 쓰거나 커스텀이 필요할때는 따로 정의하여 사용하여야한다.
아래는 초기에 내가 작성한 docker-compose.yml 이다.
보면 알겠지만 mysqldb와 프로메테우스에대한 적절한 volume 설정이 누락되어있다.
도커 볼륨은 도커 컨테이너와 호스트 사이에서 데이터를 영속적으로 저장하고 공유하기 위해 사용되는 메커니즘이다.
그래서 볼륨 설정이 없으면 매 실행마다 db가 날아가고 메트릭이 초기화 되었던 것이다.
services:
mysqldb:
image: mysql:latest
container_name: mysqldb
environment:
MYSQL_ROOT_PASSWORD: 'dl-13579'
MYSQL_DATABASE: '2024_summer_coding'
ports:
- 3306:3306
springboot:
image: springboot:latest
container_name: springboot
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysqldb:3306/2024_summer_coding?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: dl-13579
SPRING__PROFILES_ACTIVE: docker
ports:
- 8080:8080
prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
- ./prometheus-data:/prometheus
ports:
- 9090:9090
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- 3000:3000
이제 호스트에 원하는 이름으로 폴더를 생성하고, 컨테이너 내부의 적절한 경로와 연결해주면 된다.
services:
mysqldb:
image: mysql:latest
container_name: mysqldb
environment:
MYSQL_ROOT_PASSWORD: 'dl-13579'
MYSQL_DATABASE: '2024_summer_coding'
volumes:
- ./mysql-data:/var/lib/mysql #여기
ports:
- 3306:3306
springboot:
image: springboot:latest
container_name: springboot
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysqldb:3306/2024_summer_coding?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: dl-13579
SPRING__PROFILES_ACTIVE: docker
ports:
- 8080:8080
prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
- ./prometheus-data:/prometheus #여기
- ./prometheus:/etc/prometheus #여기
ports:
- 9090:9090
grafana:
image: grafana/grafana:latest
container_name: grafana
volumes:
- ./grafana-data:/var/lib/grafana #여기
ports:
- 3000:3000
다음과 같이 volumes: 에 적절히 설정해주면 재실행후에도 데이터가 잘 남아있음을 확인할 수 있다.

아래는 내가 작성한 runner.sh 파일이다.
실행 권한을 주고 ./runner.sh로 실행하면 모든 컨테이너들이 잘 실행됨을 확인할 수 있다.
#!/bin/bash
# 명령이 0이 아닌 종료값을 가질때 즉시 종료
set -e
echo "Starting all docker containers..."
docker-compose up -d
echo "Pruning unused Docker images..."
docker image prune -f
echo "Containers are up and running."
docker-compose ps -a
실행결과

먼저 다음과같은 Dockerfile 을 준비해야한다.
FROM openjdk:17
ARG JAR_FILE=build/libs/ass1-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} springboot.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/springboot.jar"]
아래는 자동화를 위한 쉘 스크립트이다.
#!/bin/bash
set -e
cd ./ass/2024-Ass-System-Design-SummerCoding
echo "Building Spring Boot application..."
./gradlew build -x test || { echo 'gradlew build failed'; exit 1; }
echo "Building Docker image..."
docker build -t springboot . || { echo 'docker build failed'; exit 1; }
# springboot는 이미지 이름을 지정한 것이다.
echo "Pruning unused Docker images..."
docker image prune -f
실행결과

docker compose를 이용하니 기존의 번거로웠던 문제들이 해결되고, 추가적으로 스크립트문으로 자동화해보니 더욱 생성, 관리가 편리하고 확장성에 용이하다고 느껴졌다.
우선 docker pull 로 nginx 이미지를 가져온다.
기존코드 docker-compose.yml 아래부분에 해당 코드를 추가
nginx:
image: nginx:latest
container_name: nginx
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/conf.d/:/etc/nginx/conf.d
ports:
- 80:80
- 443:443
networks:
- 2024_summer_coding
depends_on:
- springboot
볼륨으로 연결한 nginx.conf에 적절히 reverse_proxy 설정
(80포트로 들어온 요청을 스프링부트 서버인 8080포트로 보내줘야한다.)
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
upstream springboot {
server springboot:8080; # 서비스 이름으로 작성
}
server{
listen 80;
location / {
proxy_pass http://springboot;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
끝이다.
아래와 같이 80포트로 접근해도 springboot 서버 rest api로 잘 접근함을 확인할 수 있다.


아까 docker-compose.yml 파일의 해당 부분을 보고 의문이 들었을 수 있다.
SPRING__PROFILES_ACTIVE: docker
스프링부트에서 active profile을 설정하는 역할로
스프링부트 내에서 local과 docker로 yml 파일을 분리해둬서 해당 설정을 추가했다.
application-docker.yml 파일은 다음과 같다.
spring:
application:
name: ass1
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
management:
endpoints:
web:
exposure:
include: health, info, prometheus, metrics
local의 경우 application-local.yml로 생성하여 사용하면 된다.