Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.git
.github
.gradle
.idea
build
out
this
*.iml
*.log
.env
.env.*
!.env.example
README.md
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,9 @@ out/
### VS Code ###
.vscode/

src/main/resources/application-dev.yaml
src/main/resources/application-dev.yaml
src/main/resources/application-docker.yml
.env
.env.*
.env.example
.docker-compose.yml
21 changes: 21 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM eclipse-temurin:25-jdk-jammy AS builder
WORKDIR /workspace

COPY . .
RUN chmod +x gradlew && ./gradlew --no-daemon clean bootJar -x test

FROM eclipse-temurin:25-jre-jammy AS runtime
WORKDIR /app

RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd -r spring \
&& useradd -r -g spring spring

COPY --from=builder /workspace/build/libs/*.jar /app/app.jar

EXPOSE 8080 8081
USER spring:spring

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/app.jar"]
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
implementation 'org.springframework.boot:spring-boot-starter-security-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-security-oauth2-resource-server'
implementation 'org.springframework.boot:spring-boot-starter-validation'
Expand Down
171 changes: 171 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
services:
postgres:
image: postgres:17-alpine
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB:-hellocs}
POSTGRES_USER: ${POSTGRES_USER:-hellocs}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-change-me-postgres}
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 20s

redis:
image: redis:7.4-alpine
restart: unless-stopped
command: ["redis-server", "--appendonly", "yes", "--requirepass", "${REDIS_PASSWORD:-change-me-redis}"]
volumes:
- redis-data:/data
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "redis-cli -a ${REDIS_PASSWORD:-change-me-redis} ping | grep -q PONG"]
interval: 10s
timeout: 3s
retries: 5
start_period: 15s

mongo:
image: mongo:8.0
restart: unless-stopped
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME:-hellocs}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD:-change-me-mongo}
MONGO_INITDB_DATABASE: ${MONGO_DB:-hellocs}
volumes:
- mongo-data:/data/db
networks:
- backend
healthcheck:
test:
[
"CMD-SHELL",
"mongosh --quiet --username ${MONGO_INITDB_ROOT_USERNAME:-hellocs} --password ${MONGO_INITDB_ROOT_PASSWORD:-change-me-mongo} --authenticationDatabase admin --eval \"db.adminCommand('ping').ok\" | grep -q 1"
]
interval: 15s
timeout: 10s
retries: 5
start_period: 20s

app:
build:
context: .
dockerfile: Dockerfile
image: hellocs:latest
restart: unless-stopped
environment:
SPRING_PROFILES_ACTIVE: docker
SERVER_PORT: 8080
MANAGEMENT_PORT: 8081
POSTGRES_HOST: postgres
POSTGRES_PORT: 5432
POSTGRES_DB: ${POSTGRES_DB:-hellocs}
POSTGRES_USER: ${POSTGRES_USER:-hellocs}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-change-me-postgres}
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-change-me-redis}
MONGO_URI: ${MONGO_URI:-mongodb://hellocs:change-me-mongo@mongo:27017/hellocs?authSource=admin}
KAKAO_CLIENT_ID: ${KAKAO_CLIENT_ID:-dummy-kakao-client-id}
KAKAO_CLIENT_SECRET: ${KAKAO_CLIENT_SECRET:-dummy-kakao-client-secret}
KAKAO_REDIRECT_URI: ${KAKAO_REDIRECT_URI:-http://localhost:8080/api/v1/auth/token}
JWT_SECRET: ${JWT_SECRET:-Q2hhbmdlTWVUb0E1NnRvNjRDaGFyU2VjcmV0S2V5QmFzZTY0IQ==}
JWT_ACCESS_TOKEN_EXPIRATION: ${JWT_ACCESS_TOKEN_EXPIRATION:-3600000}
JWT_REFRESH_TOKEN_EXPIRATION: ${JWT_REFRESH_TOKEN_EXPIRATION:-360000000}
JAVA_OPTS: "${JAVA_OPTS:--XX:+UseContainerSupport -XX:MaxRAMPercentage=75}"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
mongo:
condition: service_healthy
ports:
- "${APP_PORT:-8080}:8080"
expose:
- "8081"
networks:
- backend
- observability
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD-SHELL", "curl --fail --silent http://localhost:8081/actuator/health/readiness > /dev/null || exit 1"]
interval: 15s
timeout: 5s
retries: 6
start_period: 40s

prometheus:
image: prom/prometheus:v2.54.1
restart: unless-stopped
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--web.enable-lifecycle"
volumes:
- ./ops/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
depends_on:
app:
condition: service_healthy
networks:
- observability
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://localhost:9090/-/healthy || exit 1"]
interval: 15s
timeout: 5s
retries: 5
start_period: 20s

grafana:
image: grafana/grafana:11.2.2
restart: unless-stopped
environment:
GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER:-admin}
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:-change-me-grafana}
GF_USERS_ALLOW_SIGN_UP: "false"
GF_SERVER_ROOT_URL: ${GRAFANA_ROOT_URL:-http://localhost:3001}
GF_DASHBOARDS_DEFAULT_HOME_DASHBOARD_PATH: /etc/grafana/provisioning/dashboards/json/4701_rev10.json
depends_on:
prometheus:
condition: service_healthy
volumes:
- grafana-data:/var/lib/grafana
- ./ops/grafana/provisioning:/etc/grafana/provisioning:ro
ports:
- "${GRAFANA_PORT:-3001}:3000"
networks:
- observability
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://localhost:3000/api/health || exit 1"]
interval: 15s
timeout: 5s
retries: 5
start_period: 25s

volumes:
postgres-data:
redis-data:
mongo-data:
prometheus-data:
grafana-data:

networks:
backend:
driver: bridge
internal: true
observability:
driver: bridge
12 changes: 12 additions & 0 deletions ops/grafana/provisioning/dashboards/dashboard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: 1

providers:
- name: default
orgId: 1
folder: Hellocs
type: file
disableDeletion: false
editable: true
updateIntervalSeconds: 30
options:
path: /etc/grafana/provisioning/dashboards/json
Loading