
현재의 상황

- Spring Boot 애플리케이션을 Docker 컨테이너로 실행
- Prometheus와 Grafana를 연동해 메트릭을 수집 및 시각화
- docker-compose로 전체를 한 번에 관리
그런데 헷갈리기 시작했다.
ㅎㅎ..
즉, 컨테이너끼리 통신할 때와 호스트를 통해 통신할 때 주소 작성 방식이 다르기 때문에 혼동이 생긴 것이다.
- Prometheus prometheus.yml에서 job 대상(target)을 설정할 때는 {IP주소}:{port}를 사용하고 있음
- Grafana에서 Prometheus를 데이터 소스로 등록할 때는 {서비스명}:{port}를 사용함(http://prometheus:9090)
- Nginx는 127.0.0.1:8080 / 127.0.0.1:8081처럼 호스트 IP를 기반으로 설정
일단 결론적으로는,
prometheus에서 Job의 대상으로 연결한 것은 {IP주소}:{port번호}, 그리고 Grafana의 경우에는 {컨테이너서비스이름}:{prometheus의 Port 번호} 이렇게 설정해 주었다.
마지막으로는, nginx는 SpringBoot에 대하여 127.0.0.1:8080 및 127.0.0.1:8081로 설정해주었다.
외부에 대한 접근
Prometheus가 메트릭을 수집하기 위해서는 스프링 부트 컨테이너 안의 메트릭 엔드포인트로 접근해야한다(/actuator/prometheus/)
prometheus.yaml의 job에서 실제 서버의 호스트 IP 를 썼다면, 이는 Prometheus 컨테이너가 외부 네트워크를 통해 Spring Boot의 호스트 포트의 정보를 수집하는 것이다
(여기서의 마이크로미터 기반으로 메트릭을 수집)
즉, 이 경우는 호스트 IP + 바인딩된 포트를 이용한 접근이므로 IP:포트 형식이다!
컨테이너 기반으로 통신하기 위해서는,
컨테이너의 이름이 아니라 "서비스" 이름으로 접속해야한다는 것을 알아두자.
다음은 실제 볼륨 마운트 설정으로 작성했던 yaml 코드이다.
나는 일단 같은 컨테이너 간의 통신 방법이 아닌, 외부에서 ip 주소를 통하여 접속하는 방법을 택했다.
global:
scrape_interval: 15s
scrape_timeout: 15s
evaluation_interval: 2m
external_labels:
monitor: 'codelab-monitor'
query_log_file: query_log_file.log
rule_files:
- "prometheus-rule.yml"
scrape_configs:
- job_name: 'prometheus'
scrape_interval: 10s
scrape_timeout: 10s
metrics_path: '/metrics'
honor_labels: false
honor_timestamps: false
scheme: 'http'
static_configs:
- targets: ['${REMOTE_HOST}:9090']
labels:
service: 'monitor-1'
- job_name: 'node'
static_configs:
- targets: ['${REMOTE_HOST}:9090']
- job_name: 'spring-actuator-blue'
metrics_path: '/actuator/prometheus'
scrape_interval: 1m
static_configs:
- targets: [ '${REMOTE_HOST}:8080' ]
- job_name: 'spring-actuator-green'
metrics_path: '/actuator/prometheus'
scrape_interval: 1m
static_configs:
- targets: [ '${REMOTE_HOST}:8081' ]
컨테이너 간의 연결
그럼 컨테이너끼리 접근하려면 어떻게 접근하면 될까??

이제 Grafana에서 Prometheus에 저장된 메트릭 내용들에 대하여 접근하기 위하여 URL을 입력을 해줘야한다(Datasource 등록)
http://{서비스명}:{Port번호}
이렇게 접근하면 된다
컨테이너간의 소통의 기반은 항상 '서비스명'이다
(컨테이너 이름끼리 헷갈리는 경우가 많은데 무조건 서비스명을 기반으로 해야함)
그래서 과거의 프로젝트에서
Nginx로 포트매핑을 할 때,
서비스명:port번호로 매핑을 해줬었는데,
이것은 둘 다 컨테이너 환경이기 때문에 설정한 것이다.
호스트 접근

그러면 이번에는 로컬호스트에 접근할 때, docker 컨테이너가 HOST에 접근하는 과정에 대하여 알아보자.
Docker의 컨테이너들은 전부 하나의 미니컴퓨터라고 생각해주면 된다.
그러면 이 전체 HOST와는 별개로 미니 컴퓨터가 실행되고 있는 것이다. 이 때 만약에 호스트 머신에 접속을 하고 싶다면? 그렇다면 바로 127.0.0.1을 사용하는 것이다.
가령 다음과 같은 상황에서 자주 사용된다.
server {
listen 80;
server_name ;
/location {
proxy_pass http://127.0.0.1:8080;
}
}
위와 같이 확인이 가능
docker 환경에서 Nginx로 리버스 프록시(Port 매핑)을 설정할 때 쓴 코드이다.
이 때 127.0.0.1이 localhost 말고 사용한 이유에 대하여 알아보자.
Nginx가 바라보는 localhost(127.0.0.1)은 호스트머신이다
즉, 127.0.0.1:8080이라고 쓰면 Nginx 컨테이너가 실행되는 곳(호스트. 127.0.0.1)에서 8080 포트로 열린 서비스에 대하여 접근한다는 것이다.
이 때 127.0.0.1은 Nginx가 지금 실행중인 로컬 네트워크를 의미한다.
services:
springboot-api:
image: {이미지}
restart: always
ports:
- "8080":"8080"
위는 예시로 작성된 docker-compose이다.
이 때,
Springboot 컨테이너의 8080 포트를 docker-compose에서 8080:8080으로 매핑해준 것이다.
즉, docker 미니 컴퓨터에서 8080으로 돌아가고 있는 것이, 외부(로컬호스트)에서 8080으로 요청이 들어왔을 때 매핑의 대상이 된다.
그래서 127.0.0.1:8080로 접근하면 호스트의 8080 → 컨테이너의 8080으로 연결되는 순서이다.
즉, Nginx는 포트 매핑을 해줄 때,
스프링 부트 컨테이너를 직접 찾는 게아니라,
바로 호스트가 직접 열어둔 8080으로 통신을 하는 순서로 스프링부트 컨테이너에 접속을 하는 것이다.
컨테이너가 지정한 외부 노출 포트 매핑 설정
docker-compose에서 외부 노출 포트 매핑에 대하여 알아보자.
ports:
- "8080:8080"
위처럼 설정하면
HOST:8080 → 컨테이너:8080이
위에서 서술했듯이
HOST의 8080 포트로 먼저 연결 -> 해당 컨테이너의 8080으로 이동한다.
이 때 만약에 Nginx도 컨테이너 환경에서 운영된다면,
Docker 네트워크 내부의 컨테이너 이름(springboot-api:8080)을 알 필요 없이 (이 때 조심할 것... 컨테이너 이름이 아니라 서비스 이름임)
127.0.0.1:8080으로만 접근해도 되는 것이다.
즉, 127.0.0.1:포트는 도커 네트워크 안쪽 주소가 아닌, 호스트에서 노출된 매핑된 포트를 바라보는 것
컨테이너끼리 연결하는 경우 (내부 네트워크만 사용)
만약 Nginx도 Docker Compose로 함께 관리되고 있고,
호스트 포트를 굳이 외부로 노출하지 않는다면
컨테이너 이름으로 바로 연결하는 게 더 깔끔하다.
예시:
location /api/ {
proxy_pass http://springboot:8080;
}