Backend
home
⛅

AWS에서 ELK + Grafana + Prometheus 배포

생성 일시
2025/07/22 14:54
태그
AWS
게시일
2025/07/22
최종 편집 일시
2025/07/22 17:08

ELK 스펙 (t3.large)

•
vCPU: 2
•
Memory: 8 GB
•
Ubuntu 22.04
참고로 EC2 보안 그룹에서 다음 포트를 인바운드 허용해주어야 한다~!
•
5601 (Kibana)
•
9200 (Elasticsearch)
•
5044 (Logstash input)
•
9090 (Prometheus)
•
3000 (Grafana)

docker 설치

sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc # Add the repository to Apt sources: echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin ubuntu@ip-172-31-34-164:~$ sudo usermod -aG docker $USER ubuntu@ip-172-31-34-164:~$ newgrp docker ubuntu@ip-172-31-34-164:~$ docker info
Shell
복사

작업 디렉토리 구성

monitoring/ ├── docker-compose.monitoring.yml ├── logstash/ │ ├── logstash.conf │ └── logstash.yml ├── prometheus/ │ └── prometheus.yml ├── volumes/ │ ├── elasticsearch/ │ ├── kibana/ │ ├── grafana/ │ └── prometheus/ └── logs/ <-- 백엔드 서버 로그와 연결될 폴더
Shell
복사
항목
내용
✅ 네트워크
별도 custom network 제거 (EC2는 bridge 기본 사용 가능)
✅ logs 공유
../../logs:/logs 경로 → 백엔드 로그 경로에 맞게 수정 필요
✅ restart 정책
필요 시 restart: unless-stopped 옵션 추가 가능
✅ 버전
Elasticsearch, Kibana, Logstash는 8.12.0로 설정
✅ 볼륨
./volumes/서비스명으로 로컬 persist 데이터 구성
mkdir -p ~/monitoring cd ~/monitoring monitoring 디렉토리 구조 docker-compose.monitoring.yml logs logstash prometheus
Shell
복사

docker-compose.yml 파일 생성

•
monitoring 디렉토리에서 docker-compose.monitoring.yml 생성
•
elasticsearch, kibana, logstash 모두 8.12.0 으로 지정 (hanhinsam-0.1 사용 시 버전 호환)
version: '3.8' services: # Elasticsearch elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0 container_name: elasticsearch environment: - discovery.type=single-node - node.name=es01 - xpack.security.enabled=false - bootstrap.memory_lock=true - ES_JAVA_OPTS=-Xms1g -Xmx1g # ES 메모리 제한 - TZ=Asia/Seoul ulimits: memlock: soft: -1 hard: -1 volumes: - ./volumes/elasticsearch:/usr/share/elasticsearch/data - /etc/localtime:/etc/localtime:ro # 한국 시간 설정 ports: - "9200:9200" - "9300:9300" # Kibana kibana: image: docker.elastic.co/kibana/kibana:8.12.0 container_name: kibana environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 - TZ=Asia/Seoul ports: - "5601:5601" depends_on: - elasticsearch volumes: - ./volumes/kibana:/usr/share/kibana/data - /etc/localtime:/etc/localtime:ro # 한국 시간 설정 # Logstash logstash: image: docker.elastic.co/logstash/logstash:8.12.0 container_name: logstash environment: - LS_JAVA_OPTS=-Xms512m -Xmx512m # Logstash 메모리 제한 - TZ=Asia/Seoul volumes: - ./logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf - ./logstash/logstash.yml:/usr/share/logstash/config/logstash.yml:ro - /etc/localtime:/etc/localtime:ro # 한국 시간 설정 - /home/ubuntu/moodbook/logs:/logs # 백엔드 로그 경로를 공유 (host 경로에 맞게 수정 필요) ports: - "5044:5044" - "5001:5001" depends_on: - elasticsearch # Prometheus prometheus: image: prom/prometheus:latest container_name: prometheus environment: - TZ=Asia/Seoul volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml - ./volumes/prometheus:/prometheus - /etc/localtime:/etc/localtime:ro # 한국 시간 설정 mem_limit: 256m # 메모리 제한 restart: always ports: - "9090:9090" # Grafana grafana: image: grafana/grafana:latest container_name: grafana environment: - TZ=Asia/Seoul volumes: - ./volumes/grafana:/var/lib/grafana - /etc/localtime:/etc/localtime:ro # 한국 시간 설정 mem_limit: 256m # 메모리 제한 restart: always ports: - "3000:3000" depends_on: - prometheus 1,1 Top
YAML
복사

Logstash 파이프라인 설정

파일 경로: ~/monitoring/logstash/logstash.conf
mkdir -p logstash
Shell
복사
•
logstash.conf 작성
input { beats { port => 5044 # filebeat 적용 codec => json # ElasticSearch 인덱스를 json 형태로 구성했다면 꼭 이것을 적용 } } filter { #아래 규칙에서 자동으로 키워드로 형성되어 키바나에서 확인 가능 grok { match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{DATA:thread}\] \[%{LOGLEVEL:level}\s*\] %{JAVACLASS:logger} - %{GREEDYDATA:log}" } } # 로그가 AOP 로그인지 식별 if "AOP_LOG" in [message] { mutate { add_field => { "log_type" => "aop" } } } else if "OAuth2_LOG" in [message]{ mutate { add_field => { "log_type" => "OAuth2" } } } date { match => ["timestamp", "yyyy-MM-dd HH:mm:ss.SSS"] timezone => "Asia/Seoul" target => "@timestamp" } } output { elasticsearch { hosts => ["http://ELK의 EC2 IP:9200"] index => "moodbook-log-%{+YYYY.MM.dd}" } stdout { codec => rubydebug } }
Shell
복사
•
logstash.yml 생성
http.host: "0.0.0.0" xpack.monitoring.enabled: false
Shell
복사

Prometheus 설정 파일 작성

파일 경로: ~/monitoring/prometheus/prometheus.yml
global: scrape_interval: 15s # 15초마다 메트릭 수집 scrape_configs: - job_name: 'moodbook-server' metrics_path: '/actuator/prometheus' static_configs: - targets: ['Spring Boot IP:8080'] # Spring Boot의 Public IP
Shell
복사

Filebeat 설치 (SpringBoot EC2에서 진행)

현재 SpringBoot EC2와 ELK EC2가 다른 환경에 있으므로 Filebeat 를 설치하여 app.log 파일을 Logstash가 SpringBoot EC2로 전송하도록 설정
[백엔드 EC2] [ELK EC2] app.log → Filebeat → → → Logstash → Elasticsearch → Kibana
Shell
복사
구성 요소
설치 위치
설명
Spring Boot (백엔드)
EC2-A
app.log 생성
Filebeat
EC2-A (같은 서버)
로그 수집 및 전달
Logstash
EC2-B
수신 후 Elasticsearch로 전달
Elasticsearch/Kibana
EC2-B
시각화 및 저장

GPG키 및 Elastic 저장소 추가

curl -fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elastic-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/elastic-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
Shell
복사

패키지 업데이트

sudo apt update sudo apt install filebeat -y
Shell
복사

filebeat.yml 설정 수정

sudo vi /etc/filebeat/filebeat.yml
Shell
복사
filebeat.inputs: - type: log enabled: true paths: - /home/ubuntu/moodbook-backend/logs/app.log # 📌 로그 경로 수정 (절대 경로로) output.logstash: hosts: ["ELK EC2 IP:5044"] # 📌 Logstash EC2의 Public IP # optional: 로그 수집 시작 위치 (처음부터) filebeat.registry.flush: 1m
Shell
복사

FileBeat 테스트 실행

•
단 logstash가 ELK EC2에서 컨테이너로 실행 중인 상태여야 한다.
•
성공 시: logstash: xx.xx.xx.xx:5044 ... OK
sudo filebeat test output
Shell
복사
logstash: xx.xx.xx.xx:5044... connection... OK
Shell
복사

Filebeat 서비스 시작 및 자동 시작 등록

sudo systemctl enable filebeat sudo systemctl start filebeat
Shell
복사
인스턴스
포트
설명
Logstash EC2 (xx.xx.xx.xx)
5044
Filebeat에서 수신 가능하도록 허용
Spring Boot EC2 (xx.xx.xx.xx)
-
송신이므로 별도 설정 없음

만약에 filebeat.yml 을 잘못 입력해서 수정을 했을 경우 수정 후 다음 명령어 실행

sudo filebeat test output # 정상 출력 logstash: xx.xx.xx.xx:5044... connection... OK # 수정 완료 후 filebeat 재시작 sudo systemctl restart filebeat # 로그 흐름 확인 sudo tail -f /var/log/filebeat/filebeat.log
Shell
복사

로그 흐름 확인

sudo tail -f /var/log/filebeat/filebeat.log
Shell
복사

docker 참고 명령어 (재시작, 포트 확인 여부) - 참고만!

docker-compose -f docker-compose.monitoring.yml restart logstash sudo lsof -i -P -n | grep LISTEN | grep 5044
Shell
복사

SpringBoot - build.gradle + application.yml + application-prod.yml + .env

•
build.gradle 에 다음을 추가
// Spring Boot Actuator 매트릭/모니터링 implementation 'org.springframework.boot:spring-boot-starter-actuator' // 프로메테우스 implementation 'io.micrometer:micrometer-registry-prometheus' // ElasticSearch implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch' implementation 'co.elastic.clients:elasticsearch-java'
Shell
복사
•
application.yml
spring: mail: host: smtp.gmail.com port: 587 username: test@gmail.com password: 1234 properties: mail: smtp: auth: true starttls: enable: true profiles: default: prod # 기본 실행 프로필 지정 server: port: 8080
Shell
복사
•
application-prod.yml
spring: datasource: url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}?serverTimezone=Asia/Seoul username: ${DB_USER} password: ${DB_PASSWORD} jpa: generate-ddl: true open-in-view: false show-sql: true hibernate: ddl-auto: update batch: jdbc: initialize-schema: never job: enabled: false sql: init: mode: never elasticsearch: uris: "ELK EC2 IP 입력" data: mongodb: uri: ${MONGODB_URI} database: ${MONGODB_DATABASE} redis: host: ${REDIS_HOST} port: ${REDIS_PORT} timeout: 6000 management: endpoints: web: exposure: include: "*" health: show-details: always health: elasticsearch: enabled: false prometheus: metrics: export: enabled: true cloud: aws: s3: bucketName: ${AWS_S3_BUCKET_NAME} stack: auto: false region: static: ${AWS_REGION} credentials: access-key: ${AWS_ACCESS_KEY} secret-key: ${AWS_SECRET_KEY} aladin: api: key: ${ALADIN_API_KEY} base-url: ${ALADIN_BASE_URL} jwt: secretKey: ${JWT_SECRET} access-token-expiration-ms: 1800000 refresh-token-expiration-ms: 6048020000 openai: api-key: ${OPENAI_API_KEY} url: ${OPENAI_URL} model: ${OPENAI_MODEL} logging: pattern: console: ${LOG_CONSOLE_PATTERN}
Shell
복사
•
.env (실제 값 입력 - RDS + ElasticCache 엔드포인트 주소 및 계정 + Redis + 각종 설정들)
◦
해당 .env 파일은 Jenkins 배포 시 Credential의 Secret 파일 업로드로 처리
◦
System > global 에서 진행!
# Docker PROJECT_NAME= APP_PORT= # MySQL DB_HOST= DB_PORT= DB_NAME= DB_USER= DB_PASSWORD= # MongoDB MONGODB_URI= MONGODB_DATABASE= # Redis REDIS_HOST= REDIS_PORT= # AWS S3 AWS_S3_BUCKET_NAME= AWS_REGION= AWS_ACCESS_KEY= AWS_SECRET_KEY= # JWT JWT_SECRET= # Aladin API ALADIN_API_KEY= ALADIN_BASE_URL= # OpenAI OPENAI_API_KEY= OPENAI_URL= OPENAI_MODEL= # env LOG_CONSOLE_PATTERN= # ElasticSearch ELASTICSEARCH_URI=
Shell
복사

백엔드 프로젝트 쪽 Logstash(src > main > resources)

•
Logstash 관련 logback-spring.xml 작성 (로그 저장)
<?xml version="1.0" encoding="UTF-8" ?> <configuration> <!-- 로그 파일이 저장될 경로 변수 --> <property name="LOG_PATH" value="/app/logs" /> <!-- 파일 로그 출력 패턴: 색상 X (ELK 연동용) --> <property name="FILE_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%-3level] %logger{5} - %msg%n" /> <!-- 운영 환경(prod) 전용 로그 설정 --> <!-- 콘솔 출력 없이 파일(app.log)에만 로그가 기록됨 --> <springProfile name="prod"> <root level="INFO"> <appender-ref ref="FILE"/> </root> </springProfile> <!-- ========================== 파일 로그 설정 (ELK 연동용) ========================== --> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- RollingFileAppender: 로그를 파일로 남김, 일자별로 파일 자동 분할 --> <file>${LOG_PATH}/app.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}/app-%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>10</maxHistory> <!-- : 10일치까지만 파일 보관(자동 삭제) --> </rollingPolicy> <encoder> <Pattern>${FILE_PATTERN}</Pattern> </encoder> </appender> <!-- ========================== 콘솔(터미널) 로그 설정 ========================== --> <!-- 콘솔(터미널) 출력 패턴: 색상 O --> <!-- thread <- 현재 로그를 찍은 스레드 이름 level <- 로그 레벨 (INFO, WARN, ERROR) logger <- 로그를 찍은 클래스의 이름 msg <- 로그 메세지 --> <!-- 콘솔(터미널)에 출력할 때 사용할 패턴 (색상 적용) --> <property name="CONSOLE_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %magenta([%thread]) %highlight([%-3level]) %logger{5} - %msg %n" /> <!-- 개발 환경(dev) 전용 로그 설정 --> <!-- 파일로 로그 기록 없이, 콘솔(터미널)에만 로그 출력 --> <!-- <springProfile name="dev">--> <!-- <root level="DEBUG">--> <!-- <appender-ref ref="STDOUT"/> &lt;!&ndash; STDOUT 이름을 가진 appender로 로그 전송 &ndash;&gt;--> <!-- </root>--> <!-- </springProfile>--> <!-- 터미널에 출력하는 Appender 설정 (STDOUT) --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <Pattern>${CONSOLE_PATTERN}</Pattern> </encoder> </appender> <!-- 콘솔 로그 비동기 처리(성능 최적화, 버퍼링) 아래 ASYNC는 위 STDOUT 출력을 비동기로 최적화(성능 향상) --> <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <appender-ref ref="STDOUT"/> </appender> <!-- ========================== 패키지별 로그 레벨 지정 ========================== --> <!--(INFO, WARN, ERROR도 모두 출력)--> <!-- 특정 패키지(여기서는 org.boot.backend5project)만 따로 레벨 지정 가능 additive="false"면, 해당 패키지 로그는 상위(root)에 전달되지 않음 --> <logger name="org.com.moodbook" level="DEBUG, INFO, WARN, ERROR" additive="false" > <appender-ref ref="STDOUT"/> </logger> <!-- ========================== 전체(Global) 로그 설정 ========================== --> <!-- <root level="DEBUG">--> <!-- <root level="TRACE">--> <!-- <root level="INFO">--> <root level="INFO"> <appender-ref ref="ASYNC"/> <!-- 콘솔(터미널) 로그 비동기 처리 --> <appender-ref ref="FILE"/> <!-- 파일 로그(ELK 연동) --> </root> <!-- 로그 하나가 발생하면, 콘솔에도 찍히고 파일에도 기록됨(동시) --> <!-- 참고: springProfile 태그를 쓰면 <springProfile name="prod">, <springProfile name="dev"> 환경별로 다른 로그정책 적용 가능 --> </configuration>
Shell
복사

백엔드 쪽 docker-compose.yml

•
백엔드 프로젝트 쪽의 docker-compose.backend.yml 파일
version: '3.8' services: backend: container_name: ${PROJECT_NAME} build: context: . dockerfile: Dockerfile image: moodbook_backend ports: - "${APP_PORT}:${APP_PORT}" environment: - SPRING_PROFILES_ACTIVE=prod - JAVA_TOOL_OPTIONS=-Xms512m -Xmx512m # JVM 메모리 관리 - TZ=Asia/Seoul # 한국 시간 설정 # MySQL - DB_HOST=${DB_HOST} - DB_PORT=${DB_PORT} - DB_NAME=${DB_NAME} - DB_USER=${DB_USER} - DB_PASSWORD=${DB_PASSWORD} # ElasticSearch - ELASTICSEARCH_URI=${ELASTICSEARCH_URI} # Logstash - LOG_CONSOLE_PATTERN=${LOG_CONSOLE_PATTERN} # MongoDB - MONGODB_URI=${MONGODB_URI} - MONGODB_DATABASE=${MONGODB_DATABASE} # Redis - REDIS_HOST=${REDIS_HOST} - REDIS_PORT=${REDIS_PORT} # AWS S3 - AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME} - AWS_REGION=${AWS_REGION} - AWS_ACCESS_KEY=${AWS_ACCESS_KEY} - AWS_SECRET_KEY=${AWS_SECRET_KEY} # JWT - JWT_SECRET=${JWT_SECRET} # Aladin API - ALADIN_API_KEY=${ALADIN_API_KEY} - ALADIN_BASE_URL=${ALADIN_BASE_URL} # OpenAI - OPENAI_API_KEY=${OPENAI_API_KEY} - OPENAI_URL=${OPENAI_URL} - OPENAI_MODEL=${OPENAI_MODEL} volumes: - /etc/localtime:/etc/localtime:ro # 한국 시간 설정 - /home/ubuntu/moodbook/logs:/app/logs restart: always
Shell
복사
✳️ /app/logs는 컨테이너 안의 경로고, logback에서는 상대 경로 logs/app.log → /app/logs/app.log로 매핑된다.
로그 파일 쓰기 권한 확인
호스트 경로인 /home/ubuntu/moodbook/logs가 존재하며, 권한도 열려 있어야 한다.
🔧 권한 설정
sudo mkdir -p /home/ubuntu/moodbook/logs sudo chown -R 1000:1000 /home/ubuntu/moodbook/logs # 1000은 보통 ubuntu 사용자 uid sudo chmod -R 755 /home/ubuntu/moodbook/logs
Shell
복사

Docker 컨테이너 내부에서 로그 경로 유효한지 확인

docker exec -it [컨테이너이름] /bin/bash ls -al logs cat logs/app.log
Shell
복사

logstash 컨테이너의 마운트 경로가 호스트와 동일한지 확인

logstash: ... volumes: - /home/ubuntu/moodbook/logs:/logs
Shell
복사
→ 이때 /logs/app.log가 컨테이너 내에서 존재해야 함
logstash쪽 docker-compose.monitoring.yml 쪽에 다음과 같이 되어 있어야 함

컨테이너 실행

docker compose -f docker-compose.monitoring.yml up -d
Shell
복사

에러 확인

•
현재 컨테이너 상태를 보면 일부 서비스는 실행(Up) 중이지만, 일부는 비정상 종료(Exited) 상태
NAME
STATUS
비고
logstash
✅ Up
정상 실행 중
grafana
❌ Exited (1)
비정상 종료
kibana
❌ Exited (2)
비정상 종료
prometheus
❌ Exited (2)
비정상 종료
elasticsearch
❌ Exited (1)
비정상 종료
•
에러 로그 확인
docker logs grafana docker logs kibana docker logs prometheus docker logs elasticsearch
Shell
복사
•
호스트 디렉토리 권한 수정
# 472는 Grafana 공식 이미지에서 사용하는 UID sudo chown -R 472:472 ./volumes/grafana
Shell
복사
이후 다시 실행:
docker compose -f docker-compose.monitoring.yml up -d
Shell
복사

볼륨 초기화 (초기 개발 환경인 경우)

•
아예 볼륨 디렉토리 삭제 후 다시 생성 - 이게 제일 확실한 방법! (Grafana)
sudo rm -rf ./volumes/grafana mkdir -p ./volumes/grafana sudo chown -R 472:472 ./volumes/grafana
Shell
복사
•
Grafana 외에 Prometheus, ElasticSearch 등도 비슷한 퍼미션 이슈가 발생할 수 있기에 이런 식으로 명령어를 입력하여 퍼미션 이슈를 해결해주는 게 좋음
sudo chown -R 1000:1000 ./volumes/prometheus # Prometheus UID sudo chown -R 1000:1000 ./volumes/elasticsearch # Elasticsearch UID sudo chown -R 1000:1000 ./volumes/kibana
Shell
복사

모든 컨테이너 빌드 시 이슈 발생하는 경우

•
기존 컨테이너 중지 및 정리
docker compose -f docker-compose.monitoring.yml down
Shell
복사
•
퍼미션 문제 재발 방지 (docker-compose.yml 실행하기에 앞서 이 방법을 추천!) ⇒ 컨테이너 빌드하기 전에 이 명령어를 입력해주는 게 가장 확실한 방법이다!
# Kibana sudo chown -R 1000:1000 ./volumes/kibana # Elasticsearch sudo chown -R 1000:1000 ./volumes/elasticsearch # Grafana sudo chown -R 472:472 ./volumes/grafana # Prometheus sudo chown -R 1000:1000 ./volumes/prometheus
Shell
복사
•
다시 실행
docker compose -f docker-compose.monitoring.yml up -d
Shell
복사
•
수정 후 컨테이너 상태 확인 및 개별 컨테이너 로그로 진행 상태 확인
docker ps -a docker logs kibana docker logs grafana docker logs elasticsearch
Shell
복사
•
만약에 프로메테우스에서 다음과 같은 이슈가 발생하는 경우
Error opening query log file" component=activeQueryTracker file=/prometheus/queries.active err="open /prometheus/queries.active: permission denied" panic: Unable to create mmap-ed active query log
Shell
복사
다음과 같이 명령어 입력함
sudo chown -R 65534:65534 ./volumes/prometheus
Shell
복사
그 이후 컨테이너 재시작
docker compose -f docker-compose.monitoring.yml down docker compose -f docker-compose.monitoring.yml up -d
Shell
복사
추가적으로 Prometheus는 반드시 Spring Security에서 Spring Boot Actuator 보안 정책으로 인해 기본적으로 엔드포인트에 보안이 걸려 있음. /actuator/prometheus도 마찬가지이며, Prometheus는 인증 없이 접근하므로 403 오류가 발생
— application.yml 에서 접근 허용 설정 —
management: endpoints: web: exposure: include: health,info,prometheus endpoint: prometheus: enabled: true spring: security: permit-all: true # 보안 설정을 완전히 열어야 하는 경우 management: server: port: 8080 endpoints: web: exposure: include: '*' security: enabled: false
Shell
복사
SecurityConfig 에 적용
•
백엔드 프로젝트 배포 시 적용됨
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorize -> authorize .requestMatchers("/actuator/**").permitAll() .anyRequest().authenticated() ) .csrf().disable(); return http.build(); } }
Java
복사

Filebeat 테스트

•
이 명령은 실행 중 로그를 콘솔에 출력
•
app.log 경로에 로그가 쌓이면 실시간으로 전송됨
sudo filebeat -e
Shell
복사

Logstash 로그 확인 (ELK EC2 에서)

docker logs logstash
Shell
복사

Kibana 접속

http://EC2 ELK IP:5601
Shell
복사

Kibana Index Pattern 등록

1.
"Management" > "Stack Management" > "Index Patterns"
2.
filebeat-* 또는 moodbook-log-* 입력
3.
생성 후 "Discover"에서 로그 확인

메모리 이슈

각 서버별로 남은 메모리가 부족하여 서버가 다운되는 것을 방지하기 위해 메모리 최적화를 진행함

ELK + Grafana + Prometheus

위험 항목
설명
영향
free 메모리 173MiB
컨테이너 부하 증가 시 Out of Memory 발생 가능
❗ Logstash, Elasticsearch 메모리 부족 시 크래시 가능
Logstash JVM 설정 미조정
기본 설정이 1GB 이상 요청
❗ Logstash 과부하 시 느려짐 또는 종료
Elasticsearch + Logstash + Prometheus + Grafana 동시 구동
매우 무거운 조합
❗ EC2 t3.medium 이상 권장
•
swap 설정 여부 확인 및 생성
sudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile free -h # swap 생겼는지 확인
Java
복사
•
docker-compose.monitoring.yml 수정
services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0 container_name: elasticsearch environment: - discovery.type=single-node - ES_JAVA_OPTS=-Xms1g -Xmx1g # ✅ 메모리 제한 추가 ... logstash: image: docker.elastic.co/logstash/logstash:8.12.0 container_name: logstash environment: - LS_JAVA_OPTS=-Xms512m -Xmx512m # ✅ 메모리 제한 추가 ... prometheus: image: prom/prometheus:latest container_name: prometheus mem_limit: 256m # ✅ 옵션 (compose v3 이상 지원) ... grafana: image: grafana/grafana:latest container_name: grafana mem_limit: 256m ...
YAML
복사
✅ 메모리 제한을 지정하지 않으면?
컨테이너가 필요 이상으로 메모리를 잡아먹어 전체 서버가 느려지거나 **OOM-Kill(메모리 초과 종료)**가 발생할 수 있음.
•
swap 파일 설정 (메모리 부족 방지용)
sudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab free -h # Swap 생겼는지 확인 ===================================================================== ubuntu@ip-172-31-35-108:~$ free -h total used free shared buff/cache available Mem: 3.7Gi 1.0Gi 133Mi 3.0Mi 2.6Gi 2.4Gi Swap: 0B 0B 0B ubuntu@ip-172-31-35-108:~$ sudo fallocate -l 2G /swapfile ubuntu@ip-172-31-35-108:~$ sudo chmod 600 /swapfile ubuntu@ip-172-31-35-108:~$ sudo mkswap /swapfile Setting up swapspace version 1, size = 2 GiB (2147479552 bytes) no label, UUID=e45f159b-4e86-4cbb-ae0b-48c5371121a4 ubuntu@ip-172-31-35-108:~$ sudo swapon /swapfile ubuntu@ip-172-31-35-108:~$ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab /swapfile none swap sw 0 0 ubuntu@ip-172-31-35-108:~$ free -h # Swap 생겼는지 확인 total used free shared buff/cache available Mem: 3.7Gi 1.0Gi 131Mi 3.0Mi 2.6Gi 2.4Gi Swap: 2.0Gi 0B 2.0Gi
Shell
복사
•
기존 컨테이너 중지 및 재시작
# 기존 컨테이너 종료 docker-compose -f docker-compose.monitoring.yml down # 변경사항 반영하여 재실행 (필수!) docker-compose -f docker-compose.monitoring.yml up -d --build
Shell
복사
•
정상 동작 확인
docker ps -a docker stats
Shell
복사
•
docker stats 명령어 입력 후 실시간 메모리 현황 확인
•
springboot의 docker-compose.backend.yml 에도 적용
ubuntu@ip-172-31-18-181:~$ free -h total used free shared buff/cache available Mem: 7.6Gi 3.7Gi 173Mi 3.0Mi 3.8Gi 3.5Gi Swap: 0B 0B 0B ubuntu@ip-172-31-18-181:~$ sudo fallocate -l 2G /swapfile ubuntu@ip-172-31-18-181:~$ sudo chmod 600 /swapfile ubuntu@ip-172-31-18-181:~$ sudo mkswap /swapfile Setting up swapspace version 1, size = 2 GiB (2147479552 bytes) no label, UUID=51172bb2-ee03-4b25-b9b8-7f7f90a29ca2 ubuntu@ip-172-31-18-181:~$ sudo swapon /swapfile ubuntu@ip-172-31-18-181:~$ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab /swapfile none swap sw 0 0 ubuntu@ip-172-31-18-181:~$ free -h total used free shared buff/cache available Mem: 7.6Gi 3.7Gi 190Mi 3.0Mi 3.8Gi 3.5Gi Swap: 2.0Gi 0B 2.0Gi
Shell
복사
•
Jenkins도 동일하게 적용
ubuntu@ip-172-31-40-214:~$ free -h total used free shared buff/cache available Mem: 3.7Gi 1.3Gi 802Mi 2.0Mi 1.7Gi 2.2Gi Swap: 0B 0B 0B ubuntu@ip-172-31-40-214:~$ sudo fallocate -l 2G /swapfile ubuntu@ip-172-31-40-214:~$ sudo chmod 600 /swapfile ubuntu@ip-172-31-40-214:~$ sudo mkswap /swapfile Setting up swapspace version 1, size = 2 GiB (2147479552 bytes) no label, UUID=e8d27023-dd62-43c3-affb-7c458c2aef2f ubuntu@ip-172-31-40-214:~$ sudo swapon /swapfile \ubuntu@ip-172-31-40-214:~$ free -h total used free shared buff/cache available Mem: 3.7Gi 1.3Gi 822Mi 2.0Mi 1.7Gi 2.2Gi Swap: 2.0Gi 0B 2.0Gi
Shell
복사

최종 결과

•
ELK
•
Grafana
•
Prometheus