Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
ecc19e7
Merge branch 'develop' of https://github.com/catchtable-clone/backendโ€ฆ
johe00123 May 18, 2026
9c0bed6
Merge branch 'develop' of https://github.com/catchtable-clone/backendโ€ฆ
johe00123 May 20, 2026
e7dd003
test
silkair May 20, 2026
5e956b3
chore: ์˜ˆ์•ฝ ๋™์‹œ์„ฑ ์ œ์–ด์šฉ Redis ์ธํ”„๋ผ ์„ค์ • (#77)
johe00123 May 20, 2026
7a06c24
feat: ์˜ˆ์•ฝ ์Šฌ๋กฏ ์ƒ์„ฑ ๋ฒ”์œ„ 30์ผ -> 90์ผ ํ™•๋Œ€
johe00123 May 20, 2026
1f025b2
chore: RedissonClient ๋นˆ ์„ค์ • ์ถ”๊ฐ€ (#77)
johe00123 May 20, 2026
838c81e
Merge pull request #78 from catchtable-clone/refactor/#77-redis-concuโ€ฆ
johe00123 May 20, 2026
dcd9769
feat : kafka ๋ถ€์ฐฉ
silkair May 21, 2026
e8aa535
fix : docker-compose-prod ์ตœ์‹ ํ™”
silkair May 21, 2026
949dd6d
Merge branch 'develop' into refactor/#76-noti-kafak
silkair May 21, 2026
1f32e10
Feat: ๋ชจ๋‹ˆํ„ฐ๋ง ์„ค์ •
jaebeom79 May 22, 2026
42b5e29
Merge pull request #79 from catchtable-clone/refactor/#76-noti-kafak
jaebeom79 May 22, 2026
2f3a9bb
Merge branch 'develop' into monitoring
jaebeom79 May 22, 2026
8ec559c
Feat: resilience4j ๋ฉ”ํŠธ๋ฆญ
jaebeom79 May 22, 2026
3cc5f0e
Fix: ๋ชจ๋‹ˆํ„ฐ๋ง ์ฝ”๋“œ๋ฆฌ๋ทฐ
jaebeom79 May 22, 2026
58229d6
Merge pull request #80 from catchtable-clone/monitoring
jaebeom79 May 22, 2026
4993e0f
Fix: kafka ๋ฌดํ•œ ์žฌ์‹œ๋„ ์ˆ˜์ •
jaebeom79 May 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ repositories {
}

dependencies {
implementation 'org.springframework.kafka:spring-kafka'
implementation 'org.springframework.ai:spring-ai-starter-model-google-genai'
implementation 'org.jetbrains.kotlin:kotlin-reflect'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
implementation 'io.github.cdimascio:dotenv-java:3.0.0'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.redisson:redisson:3.39.0'
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'
Expand Down
38 changes: 38 additions & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,44 @@ services:
- catchtable-data:/var/lib/postgresql/data
- ./data/init-data.sql:/docker-entrypoint-initdb.d/init-data.sql
- ./data:/tmp/data
networks:
- catchtable-dev-net

kafka:
image: apache/kafka:3.7.0
container_name: catchtable-kafka-dev
user: "0"
ports:
- "9092:9092"
environment:
KAFKA_CLUSTER_ID: "MkU3OEV5NURaZW52OTYyM2RjY1JqcA"
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: 'broker,controller'
KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER'

KAFKA_LISTENERS: 'PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093'

KAFKA_ADVERTISED_LISTENERS: 'PLAINTEXT://localhost:9092'

KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: 'CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT'
KAFKA_INTER_BROKER_LISTENER_NAME: 'PLAINTEXT'

KAFKA_CONTROLLER_QUORUM_VOTERS: '1@127.0.0.1:9093'
volumes:
- kafka-data-dev:/tmp/kafka-logs
networks:
- catchtable-dev-net

networks:
catchtable-dev-net:
driver: bridge

redis:
image: redis:7-alpine
container_name: catchtable-redis
ports:
- "${REDIS_PORT:-6379}:6379"

volumes:
catchtable-data:
kafka-data-dev:
165 changes: 101 additions & 64 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@ services:
env_file: .env
expose:
- "8080"
# t3.small(2GB) ํ™˜๊ฒฝ. ๋ชจ๋‹ˆํ„ฐ๋ง ์Šคํƒ๊ณผ ๊ณต์กดํ•˜๊ธฐ ์œ„ํ•ด app์€ 600M๋กœ ์ œํ•œ.
# OTel Agent๊ฐ€ ์•ฝ 80MB ์ถ”๊ฐ€ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ 500M โ†’ 600M๋กœ ์ƒํ–ฅ.
# t3.small ๋ฉ”๋ชจ๋ฆฌ ํ•œ๋„ ๊ณ ๋ คํ•œ app ํ•œ๋„ (OTel Agent 80MB ํฌํ•จ 600M)
environment:
# JVM ์˜ต์…˜์€ Dockerfile์˜ ENV์— ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ •์˜๋จ (javaagent + ๋ฉ”๋ชจ๋ฆฌ ํŠœ๋‹).
# ์—ฌ๊ธฐ์„  OpenTelemetry Agent์˜ ์†ก์‹  ๋Œ€์ƒ๋งŒ ์ง€์ •.
OTEL_SERVICE_NAME: catchtable-backend
OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317
# OTel Collector๋กœ ์ „์†ก (Collector์—์„œ path ๊ธฐ๋ฐ˜ ๋…ธ์ด์ฆˆ ํ•„ํ„ฐ๋ง ํ›„ Jaeger๋กœ ์ „๋‹ฌ)
OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317
OTEL_EXPORTER_OTLP_PROTOCOL: grpc
OTEL_TRACES_EXPORTER: otlp
OTEL_METRICS_EXPORTER: none # ๋ฉ”ํŠธ๋ฆญ์€ Micrometer/Prometheus๋กœ ์ฒ˜๋ฆฌ
OTEL_LOGS_EXPORTER: none # ๋กœ๊ทธ๋Š” Promtail/Loki๋กœ ์ฒ˜๋ฆฌ
OTEL_RESOURCE_ATTRIBUTES: deployment.environment=production
# ์ƒ˜ํ”Œ๋ง: ์ „์ฒด ์š”์ฒญ ๋Œ€๋น„ ํŠธ๋ ˆ์ด์Šค ์ˆ˜์ง‘ ๋น„์œจ (1.0=100%, ๋ถ€ํ•˜ ์‹œ 0.1๋กœ ๋‚ฎ์ถ”๊ธฐ ๊ถŒ์žฅ)
# ์ƒ˜ํ”Œ๋ง 100% โ€” ๋…ธ์ด์ฆˆ ์ œ๊ฑฐ๋Š” Collector์—์„œ path ๊ธฐ๋ฐ˜์œผ๋กœ ์ฒ˜๋ฆฌ
OTEL_TRACES_SAMPLER: parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG: "1.0"
OTEL_INSTRUMENTATION_SPRING_SCHEDULING_ENABLED: "false"
OTEL_INSTRUMENTATION_LOGBACK_APPENDER_ENABLED: "true"
OTEL_INSTRUMENTATION_LOGBACK_MDC_ENABLED: "true"
deploy:
resources:
limits:
Expand Down Expand Up @@ -56,6 +57,10 @@ services:
depends_on:
app:
condition: service_healthy
deploy:
resources:
limits:
memory: 50M
restart: unless-stopped
networks:
- catchtable-net
Expand All @@ -67,12 +72,12 @@ services:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --quiet; sleep 12h & wait $${!}; done;'"
deploy:
resources:
limits:
memory: 30M
restart: unless-stopped

# ============================================================
# ๋ชจ๋‹ˆํ„ฐ๋ง ์Šคํƒ (Prometheus + Loki + Promtail + Jaeger + Grafana)
# ============================================================

prometheus:
image: prom/prometheus:v2.55.0
container_name: catchtable-prometheus
Expand Down Expand Up @@ -106,7 +111,7 @@ services:
deploy:
resources:
limits:
memory: 250M
memory: 200M
restart: unless-stopped
networks:
- catchtable-net
Expand All @@ -130,6 +135,24 @@ services:
networks:
- catchtable-net

otel-collector:
image: otel/opentelemetry-collector-contrib:0.115.0
container_name: catchtable-otel-collector
volumes:
- ./monitoring/otel-collector-config.yml:/etc/otelcol-contrib/config.yaml:ro
command: ["--config=/etc/otelcol-contrib/config.yaml"]
expose:
- "4317" # OTLP gRPC (app์—์„œ ์ „์†ก)
depends_on:
- jaeger
deploy:
resources:
limits:
memory: 150M
restart: unless-stopped
networks:
- catchtable-net

jaeger:
image: jaegertracing/all-in-one:1.62.0
container_name: catchtable-jaeger
Expand All @@ -140,7 +163,7 @@ services:
BADGER_EPHEMERAL: "false"
BADGER_DIRECTORY_VALUE: /badger/data
BADGER_DIRECTORY_KEY: /badger/key
BADGER_SPAN_STORE_TTL: 168h0m0s
BADGER_SPAN_STORE_TTL: 72h0m0s
volumes:
- jaeger-data:/badger
ports:
Expand All @@ -151,7 +174,7 @@ services:
deploy:
resources:
limits:
memory: 350M
memory: 250M
restart: unless-stopped
networks:
- catchtable-net
Expand Down Expand Up @@ -181,57 +204,71 @@ services:
- catchtable-net

# ============================================================
# ๊ณ ๋„ํ™” ์ž‘์—… ์‹œ์ž‘ ์‹œ ์ฃผ์„ ํ•ด์ œ (5๋Œ€ ๊ณ ๋„ํ™” ํ•ญ๋ชฉ 1, 3๋ฒˆ ์ง„ํ–‰ ์‹œ)
# ๊ณ ๋„ํ™” ์ธํ”„๋ผ (Kafka๋Š” ํ•ด๋‹น ์ž‘์—… ์‹œ์ž‘ ์‹œ ์ฃผ์„ ํ•ด์ œ)
# ============================================================

# redis:
# image: redis:7-alpine
# container_name: catchtable-redis
# command:
# - redis-server
# - --maxmemory
# - 80mb
# - --maxmemory-policy
# - allkeys-lru
# - --appendonly
# - "yes"
# expose:
# - "6379"
# volumes:
# - redis-data:/data
# deploy:
# resources:
# limits:
# memory: 100M
# restart: unless-stopped
# networks:
# - catchtable-net

# kafka:
# image: bitnami/kafka:3.8
# container_name: catchtable-kafka
# environment:
# # KRaft ๋ชจ๋“œ (Zookeeper ๋ถˆํ•„์š”, ๋ฉ”๋ชจ๋ฆฌ ์ ˆ์•ฝ)
# KAFKA_CFG_NODE_ID: 0
# KAFKA_CFG_PROCESS_ROLES: controller,broker
# KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 0@kafka:9093
# KAFKA_CFG_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
# KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
# KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER
# KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
# # ๋ฉ”๋ชจ๋ฆฌ ๋‹ค์ด์–ดํŠธ
# KAFKA_HEAP_OPTS: "-Xms256m -Xmx256m"
# expose:
# - "9092"
# volumes:
# - kafka-data:/bitnami/kafka
# deploy:
# resources:
# limits:
# memory: 400M
# restart: unless-stopped
# networks:
# - catchtable-net
redis:
image: redis:7-alpine
container_name: catchtable-redis
command:
- redis-server
- --maxmemory
- 80mb
- --maxmemory-policy
- allkeys-lru
- --appendonly
- "yes"
expose:
- "6379"
volumes:
- redis-data:/data
deploy:
resources:
limits:
memory: 100M
restart: unless-stopped
networks:
- catchtable-net

kafka:
image: apache/kafka:3.7.0
container_name: catchtable-kafka-prod
user: "0" # ๋ณผ๋ฅจ ๋งˆ์šดํŠธ ํด๋”์— ๋กœ๊ทธ๋ฅผ ์“ฐ๊ณ  ์ง€์šธ ์ˆ˜ ์žˆ๋„๋ก ์ตœ๊ณ  ๊ด€๋ฆฌ์ž ๊ถŒํ•œ ๋ถ€์—ฌ

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

๋ณด์•ˆ์ƒ ์ปจํ…Œ์ด๋„ˆ๋ฅผ root ๊ถŒํ•œ(user: "0")์œผ๋กœ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๊ถŒ์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ˜ธ์ŠคํŠธ ์‹œ์Šคํ…œ์˜ ๋ณผ๋ฅจ ๊ถŒํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋ฉด, ์ ์ ˆํ•œ UID/GID๋ฅผ ์ง€์ •ํ•˜๊ฑฐ๋‚˜ Dockerfile์—์„œ ๊ถŒํ•œ ์„ค์ •์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด ๋” ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.


# ์™ธ๋ถ€(๋‚ด PC ๋“ฑ)๋กœ ํฌํŠธ๋ฅผ ๋ฌด๋ฐฉ๋น„ํ•˜๊ฒŒ ๋…ธ์ถœํ•˜์ง€ ์•Š๊ณ , ์˜ค์ง 'catchtable-net' ๋‚ด๋ถ€์—์„œ๋งŒ ํ†ต์‹ ํ•˜๋„๋ก ๊ฒฉ๋ฆฌ
expose:
- "9092"
- "9093"

environment:
# KRaft ๋ชจ๋“œ ํ•ต์‹ฌ ์‹๋ณ„์ž ์„ค์ •
KAFKA_CLUSTER_ID: "MkU3OEV5NURaZW52OTYyM2RjY1JqcA" # ์šด์˜ ํ™˜๊ฒฝ ๊ณ ์œ  ํด๋Ÿฌ์Šคํ„ฐ ID
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: 'broker,controller'
KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER'

# ๋ชจ๋“  ์ธํ„ฐํŽ˜์ด์Šค(0.0.0.0)๋กœ ๊ท€๋ฅผ ์—ด์–ด๋‘๊ณ , ์šด์˜ ์„œ๋ฒ„ ์•ˆ์˜ ๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ(Spring Boot)์—๋Š” ์„œ๋น„์Šค ๋ช…์ธ 'kafka:9092'๋กœ ๊ด‘๊ณ ํ•ฉ๋‹ˆ๋‹ค.
KAFKA_LISTENERS: 'PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093'
KAFKA_ADVERTISED_LISTENERS: 'PLAINTEXT://kafka:9092'
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: 'CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT'
KAFKA_INTER_BROKER_LISTENER_NAME: 'PLAINTEXT'
KAFKA_CONTROLLER_QUORUM_VOTERS: '1@127.0.0.1:9093' # ๋ฃจํ”„๋ฐฑ ์ฃผ์†Œ๋กœ ๋ฐ”์ธ๋”ฉ ์ถฉ๋Œ ๋ฐฉ์ง€

# ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ ์„ค์ • (์„œ๋ฒ„ ์ŠคํŽ™์— ๋งž๊ฒŒ ์กฐ์ • ๊ฐ€๋Šฅ, ์ตœ์†Œ 256m~512m ์ถ”์ฒœ)
KAFKA_HEAP_OPTS: "-Xms256m -Xmx256m"
# ์ž„์‹œ ํด๋”์ธ /tmp ๋Œ€์‹  ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋‚ด๋ ค๊ฐ€๋„ ๋ฐ์ดํ„ฐ์™€ ์˜คํ”„์…‹ ์žฅ๋ถ€๊ฐ€ ๋ณด์กด๋˜๋„๋ก ๋ณผ๋ฅจ ๋ณผ๋ฅจ ๋งˆ์šดํŠธ ๊ฒฝ๋กœ ๊ณ ์ •
volumes:
- kafka-prod-data:/var/lib/kafka/data

# ๋ฆฌ์†Œ์Šค ์ƒํ•œ์„  ์„ค์ • (๋ฉ”๋ชจ๋ฆฌ ๋ฆญ์œผ๋กœ ์ธํ•œ ์ „์ฒด ์„œ๋ฒ„ ๋‹ค์šด ๋ฐฉ์ง€)
deploy:
resources:
limits:
memory: 400M

restart: unless-stopped
networks:
- catchtable-net

networks:
catchtable-net:
Expand All @@ -243,5 +280,5 @@ volumes:
jaeger-data:
grafana-data:
promtail-positions:
# redis-data:
# kafka-data:
kafka-prod-data:
redis-data:
5 changes: 2 additions & 3 deletions grafana/provisioning/datasources/datasources.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ datasources:
editable: true
jsonData:
derivedFields:
# ๋กœ๊ทธ ์•ˆ์˜ traceId(OTel) ๋ฅผ ํด๋ฆญํ•˜๋ฉด Jaeger ํŠธ๋ ˆ์ด์Šค๋กœ ์ ํ”„
- datasourceUid: jaeger
matcherRegex: "traceId=(\\w+)"
matcherRegex: 'trace_id=(\w+)'
name: TraceID
url: "$${__value.raw}"
url: '$${__value.raw}'

- name: Jaeger
type: jaeger
Expand Down
7 changes: 2 additions & 5 deletions monitoring/loki-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ schema_config:
period: 24h

limits_config:
retention_period: 168h # 7์ผ
retention_period: 72h
reject_old_samples: true
reject_old_samples_max_age: 168h
reject_old_samples_max_age: 72h
allow_structured_metadata: true
volume_enabled: true

Expand All @@ -41,8 +41,5 @@ compactor:
retention_delete_worker_count: 150
delete_request_store: filesystem

ruler:
alertmanager_url: http://localhost:9093

analytics:
reporting_enabled: false
36 changes: 36 additions & 0 deletions monitoring/otel-collector-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317

processors:
# OTel Semantic Conventions v1.23.0 ์ดํ›„ ์†์„ฑ๋ช… ๋ณ€๊ฒฝ (http.target โ†’ url.path ๋“ฑ) ํ˜ธํ™˜ ์œ„ํ•ด
# coalesce(??)๋กœ ๊ตฌ๋ฒ„์ „ยท์‹ ๋ฒ„์ „ ์†์„ฑ ๋‘˜ ๋‹ค ์‹œ๋„.
filter/drop_noise:
error_mode: ignore
traces:
span:
- 'IsMatch(attributes["http.target"] ?? attributes["url.path"] ?? "", "^/actuator.*")'
- 'IsMatch(attributes["http.target"] ?? attributes["url.path"] ?? "", "^/favicon.*")'
- '(attributes["http.status_code"] ?? attributes["http.response.status_code"]) == 404 and not IsMatch(attributes["http.target"] ?? attributes["url.path"] ?? "", "^/(api|swagger-ui|api-docs).*")'

batch:
timeout: 5s
send_batch_size: 1024

exporters:
otlp/jaeger:
endpoint: jaeger:4317
tls:
insecure: true

service:
pipelines:
traces:
receivers: [otlp]
processors: [filter/drop_noise, batch]
exporters: [otlp/jaeger]
telemetry:
logs:
level: info
5 changes: 0 additions & 5 deletions monitoring/prometheus.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
cluster: catchtable
env: prod

scrape_configs:
# Spring Boot Actuator (Micrometer)
- job_name: 'catchtable-app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['app:8080']
labels:
service: catchtable-backend

# Prometheus ์ž์ฒด ๋ฉ”ํŠธ๋ฆญ
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
Loading
Loading