diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index aba4762b..1322d269 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -2,15 +2,15 @@ name: CI/CD — Backend (Build → Push → Deploy) on: push: - branches: [ dev ] + branches: [ dev, staging ] pull_request: - branches: [ dev ] + branches: [ dev, staging ] workflow_dispatch: inputs: tag: - description: "배포할 이미지 태그 (ex. release or )" + description: "배포할 이미지 태그 (ex. dev or dev-SHORT_SHA)" required: false - default: "release" + default: "dev" concurrency: group: cicd-${{ github.ref_name }} @@ -81,17 +81,32 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build & Push image + - name: Decide tags by branch + if: github.event_name == 'push' + id: tags + shell: bash + run: | + REF="${{ github.ref_name }}" # dev / staging + SHORT_SHA="${GITHUB_SHA::7}" + SAFE_REF=$(echo "$REF" | tr '[:upper:]' '[:lower:]' | sed -E 's#[^a-z0-9._-]+#-#g') + echo "channel=$SAFE_REF" >> $GITHUB_OUTPUT # ex) dev, staging + echo "version=${SAFE_REF}-${SHORT_SHA}" >> $GITHUB_OUTPUT # ex) dev-abc1234 + + - name: Build & Push (branch-tagged) if: github.event_name == 'push' run: | - GIT_SHA=${{ github.sha }} - docker build -f "${{ steps.df.outputs.path }}" -t $IMAGE:release -t $IMAGE:$GIT_SHA "${{ steps.df.outputs.ctx }}" - docker push $IMAGE:release - docker push $IMAGE:$GIT_SHA + CHAN=${{ steps.tags.outputs.channel }} # dev | staging + VER=${{ steps.tags.outputs.version }} # dev- | staging- + docker build -f "${{ steps.df.outputs.path }}" \ + -t $IMAGE:$CHAN \ + -t $IMAGE:$VER \ + "${{ steps.df.outputs.ctx }}" + docker push $IMAGE:$CHAN + docker push $IMAGE:$VER deploy: needs: build-and-push - if: github.event_name == 'push' && (github.ref == 'refs/heads/dev') && + if: github.event_name == 'push' && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/staging') && (needs.build-and-push.result == 'success') || (github.event_name == 'workflow_dispatch') runs-on: ubuntu-latest @@ -103,7 +118,7 @@ jobs: if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.tag }}" ]; then echo "value=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT else - echo "value=release" >> $GITHUB_OUTPUT + echo "value=${{ github.ref_name }}" >> $GITHUB_OUTPUT fi - name: Deploy @@ -114,5 +129,10 @@ jobs: key: ${{ secrets.CD_SSH_KEY }} port: ${{ secrets.CD_PORT }} script: | - export DEPLOY_TAG='${{ steps.tag.outputs.value }}' - bash -lc '/srv/docsa/infra/deploy.sh' + if [ "${{ github.ref_name }}" = "staging" ]; then + export DEPLOY_TAG='${{ steps.tag.outputs.value }}' + bash -lc '/srv/docsa/infra/deploy.sh staging' + else + export DEPLOY_TAG='${{ steps.tag.outputs.value }}' + bash -lc '/srv/docsa/infra/deploy.sh dev' + fi \ No newline at end of file diff --git a/.gitignore b/.gitignore index e29e7c1e..79b85cda 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ out/ ### Secrets & Runtime infra/.env +infra/*.env infra/**/*.env infra/certbot infra/mysql/exporter.cnf diff --git a/infra/.env.example b/infra/.env.example index bef2483c..fb66b2f1 100644 --- a/infra/.env.example +++ b/infra/.env.example @@ -5,6 +5,7 @@ SPRING_MAIL_PASSWORD= SPRING_DATASOURCE_URL= SPRING_DATASOURCE_USERNAME= SPRING_DATASOURCE_PASSWORD= +DDL_AUTO= # ------------ SESSION/COOKIE ------------ SESSION_COOKIE_NAME= diff --git a/infra/deploy.sh b/infra/deploy.sh index 9ab7c6ea..1e70f856 100755 --- a/infra/deploy.sh +++ b/infra/deploy.sh @@ -1,44 +1,88 @@ #!/usr/bin/env bash set -euo pipefail -cd /srv/docsa/infra +# 사용법: +# /srv/docsa/infra/deploy.sh dev +# /srv/docsa/infra/deploy.sh staging +# 환경변수(선택): +# DEPLOY_TAG : 덮어쓸 이미지 태그(dev, dev-, staging, staging- 등) +# IMAGE_BASE : GHCR 이미지 경로 (기본: ghcr.io/prgrms-web-devcourse-final-project/docsa-backend) +# SERVICE : 배포할 서비스명 (기본 app) +# HEALTH_TIMEOUT : 헬스 대기시간 초 (기본 120) -# 특정 태그로 배포시 DEPLOY_TAG=... -IMAGE_BASE="ghcr.io/prgrms-web-devcourse-final-project/docsa-backend" -TAG="${DEPLOY_TAG:-}" # 비어있으면 compose에 적힌 태그 사용 +TARGET="${1:-}" # ← dev 또는 staging 인자 필수 +if [[ "$TARGET" != "dev" && "$TARGET" != "staging" ]]; then + echo "Usage: $0 " + exit 2 +fi + +IMAGE_BASE="${IMAGE_BASE:-ghcr.io/prgrms-web-devcourse-final-project/docsa-backend}" +SERVICE="${SERVICE:-app}" +HEALTH_TIMEOUT="${HEALTH_TIMEOUT:-120}" + +cd "$(dirname "$0")" +ROOT="$(pwd)" + +# 타깃에 따라 compose/env 자동 선택 +if [[ "$TARGET" == "dev" ]]; then + COMPOSE_FILE="$ROOT/docker-compose.yml" + ENV_FILE="$ROOT/.env" +else + COMPOSE_FILE="$ROOT/docker-compose.stg.yml" + ENV_FILE="$ROOT/.stg.env" +fi + +TAG="${DEPLOY_TAG:-$TARGET}" # ← 기본은 채널 태그(dev|staging), 입력 있으면 우선 + +# 임시 override 파일로 이미지 태그만 덮어쓰기 OVR="" if [[ -n "$TAG" ]]; then - OVR="docker-compose.override.deploy.yml" + OVR="$ROOT/docker-compose.override.deploy.yml" cat > "$OVR" </dev/null -# 최신 이미지 받고 교체 -docker compose "${FILES[@]}" pull app -docker compose "${FILES[@]}" up -d app +# 2) 이미지 풀 + 대상 서비스만 업데이트 +docker compose "${ARGS[@]}" pull "$SERVICE" || true +docker compose "${ARGS[@]}" up -d "$SERVICE" -# 헬스체크 대기 (최대 120s) -echo -n "Waiting for app (docsa-app) to be healthy" +# 3) 컨테이너 ID를 compose로 조회(이름 하드코딩 회피) +CID="$(docker compose "${ARGS[@]}" ps -q "$SERVICE" | tail -n1 || true)" +if [[ -z "$CID" ]]; then + echo "No container found for service '$SERVICE' (project $PROJECT)"; exit 1 +fi + +# 4) 헬스체크 대기 +echo -n "Waiting for $SERVICE to be healthy" ok=0 -for i in {1..60}; do - status="$(docker inspect -f '{{.State.Health.Status}}' docsa-app 2>/dev/null || echo none)" - if [[ "$status" == "healthy" ]]; then ok=1; echo -e "\nApp healthy"; break; fi +ITER=$(( HEALTH_TIMEOUT / 2 )) +for _ in $(seq 1 "$ITER"); do + status="$(docker inspect -f '{{.State.Health.Status}}' "$CID" 2>/dev/null || echo none)" + if [[ "$status" == "healthy" ]]; then ok=1; echo -e "\n$SERVICE healthy"; break; fi sleep 2; echo -n "." done -# 임시 override 제거 & 청소 -[[ -n "$OVR" ]] && rm -f "$OVR" +# 5) 임시 override 청소 + 이미지 정리 +[[ -n "$OVR" ]] && rm -f "$OVR" || true docker image prune -f >/dev/null 2>&1 || true -# 실패 처리 +# 6) 실패 시 로그 출력 후 종료 if [[ $ok -eq 0 ]]; then - echo -e "\nApp failed to become healthy (status=$status)" - docker logs --tail=200 docsa-app || true + echo -e "\n$SERVICE failed to become healthy (status=${status:-unknown})" + docker logs --tail=200 "$CID" || true exit 1 -fi +fi \ No newline at end of file diff --git a/infra/docker-compose.stg.yml b/infra/docker-compose.stg.yml new file mode 100644 index 00000000..2b9eaa7e --- /dev/null +++ b/infra/docker-compose.stg.yml @@ -0,0 +1,240 @@ +name: docsa-stg + +services: + app: + image: ghcr.io/prgrms-web-devcourse-final-project/docsa-backend:staging + container_name: docsa-app-stg + restart: unless-stopped + env_file: .stg.env + environment: + SPRING_DATA_MONGODB_URI: ${SPRING_DATA_MONGODB_URI} + SPRING_MAIL_USERNAME: ${SPRING_MAIL_USERNAME} + #SPRING_MAIL_PASSWORD: ${SPRING_MAIL_PASSWORD} + SPRING_DATASOURCE_URL: ${SPRING_DATASOURCE_URL} + SPRING_DATASOURCE_USERNAME: ${SPRING_DATASOURCE_USERNAME} + SPRING_DATASOURCE_PASSWORD: ${SPRING_DATASOURCE_PASSWORD} + SERVER_SERVLET_SESSION_COOKIE_NAME: ${SESSION_COOKIE_NAME} + SERVER_SERVLET_SESSION_COOKIE_DOMAIN: ${SESSION_COOKIE_DOMAIN} + SPRINGDOC_SWAGGER-UI_SERVERS_URL: ${SWAGGER_SERVER_URL} + SPRING_JPA_HIBERNATE_DDL_AUTO: ${DDL_AUTO} + depends_on: + mysql: + condition: service_healthy + networks: + - docsa_stg_net + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:9091/actuator/health"] + interval: 30s + timeout: 5s + retries: 3 + + mailpit: + image: axllent/mailpit:latest + command: ["--webroot", "/mailpit/"] + environment: + MP_SMTP_AUTH_ACCEPT_ANY: "1" + MP_SMTP_AUTH_ALLOW_INSECURE: "1" + MP_DATABASE: /data/mailpit.db + MP_MAX_MESSAGES: "5000" + volumes: + - mailpit_data:/data + networks: + - docsa_stg_net + healthcheck: + test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:8025/mailpit/readyz || exit 1"] + interval: 10s + timeout: 3s + retries: 3 + start_period: 10s + + mysql: + image: mysql:9.4.0 + container_name: docsa-mysql-stg + restart: unless-stopped + env_file: .stg.env + volumes: + - stg_mysql_data:/var/lib/mysql + - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf:ro + - ./mysql/logs:/var/log/mysql + networks: + - docsa_stg_net + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-u", "${MYSQL_USER}", "-p${MYSQL_PASSWORD}"] + interval: 10s + timeout: 5s + retries: 3 + + mysqld-exporter: + image: prom/mysqld-exporter:latest + container_name: mysqld-exporter-stg + restart: unless-stopped + volumes: + - ./mysql/exporter.cnf:/etc/.mysqld_exporter.cnf:ro + command: + - '--web.listen-address=:9104' + - '--config.my-cnf=/etc/.mysqld_exporter.cnf' + - '--mysqld.address=docsa-mysql-stg:3306' + - '--collect.global_status' + - '--collect.global_variables' + - '--collect.engine_innodb_status' + - '--collect.info_schema.tablestats' + - '--collect.info_schema.processlist' + # - '--collect.perf_schema.eventsstatements' + # - '--collect.perf_schema.eventswaits' + depends_on: + mysql: + condition: service_healthy + networks: + - docsa_stg_net + + nginx: + image: nginx:stable-alpine-slim + container_name: docsa-nginx-stg + restart: unless-stopped + volumes: + - ./nginx/nginx.stg.conf:/etc/nginx/nginx.conf:ro + - ./certbot/etc:/etc/letsencrypt:ro + - ./certbot/www:/var/www/certbot:ro + ports: + - "8080:80" + - "8443:443" + depends_on: + app: + condition: service_started + networks: + - docsa_stg_net + + # 최초 발급용(수동실행) + certbot_init: + image: certbot/certbot:latest + container_name: docsa-certbot-init-stg + profiles: + - "init" + depends_on: + - nginx + volumes: + - ./certbot/www:/var/www/certbot:rw + - ./certbot/etc:/etc/letsencrypt:rw + - ./certbot/logs:/var/log/letsencrypt:rw + command: > + certonly --webroot + --webroot-path /var/www/certbot + -d stg.api.docsa.o-r.kr + --email qoanstjdsla@gmail.com + --agree-tos --non-interactive + --no-eff-email + + # 자동 갱신 데몬(하루마다 확인, 갱신되면 nginx 리로드) + certbot_renew: + image: certbot/certbot:latest + container_name: docsa-certbot-renew-stg + depends_on: + - nginx + volumes: + - ./certbot/www:/var/www/certbot:rw + - ./certbot/etc:/etc/letsencrypt:rw + - ./certbot/logs:/var/log/letsencrypt:rw + - /var/run/docker.sock:/var/run/docker.sock:rw + entrypoint: > + sh -c 'while :; do + certbot renew --webroot -w /var/www/certbot --quiet + if [ $$? -eq 0 ]; then + # Docker Engine HTTP API로 nginx에 HUP 보내기 (무중단 리로드) + wget -qO- \ + --header="Content-Type: application/json" \ + --method=POST \ + --body-data="" \ + --unix-socket /var/run/docker.sock \ + http://localhost/v1.41/containers/docsa-nginx-stg/kill?signal=HUP >/dev/null 2>&1 || true + fi + sleep 24h; + done' + + # ===== METRICS ===== + cadvisor: + image: gcr.io/cadvisor/cadvisor:latest + container_name: cadvisor-stg + restart: unless-stopped + privileged: true + volumes: + - /:/rootfs:ro + - /var/run:/var/run:ro + - /sys:/sys:ro + - /var/lib/docker/:/var/lib/docker:ro + networks: + - docsa_stg_net + + node_exporter: + image: prom/node-exporter:latest + container_name: node-exporter-stg + restart: unless-stopped + pid: host + command: ['--path.rootfs=/host'] + volumes: + - /:/host:ro,rslave + networks: + - docsa_stg_net + + prometheus: + image: prom/prometheus:latest + container_name: prometheus-stg + restart: unless-stopped + depends_on: + - cadvisor + volumes: + - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro + - stg_prom_data:/prometheus + networks: + - docsa_stg_net + +# ===== LOGS ===== + loki: + image: grafana/loki:3.5.5 + container_name: loki-stg + restart: unless-stopped + command: ["-config.file=/etc/loki/config.yml"] + volumes: + - ./loki/config.yml:/etc/loki/config.yml:ro + - stg_loki_data:/loki + networks: + - docsa_stg_net + + promtail: + image: grafana/promtail:3.5 + container_name: promtail-stg + restart: unless-stopped + command: ["-config.file=/etc/promtail/config.yml"] + volumes: + - ./promtail/config.yml:/etc/promtail/config.yml:ro + - /var/log:/var/log:ro + - /var/lib/docker/containers:/var/lib/docker/containers:ro + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./mysql/logs:/mnt/mysql-logs:ro + networks: [docsa_stg_net] + +# ===== DASHBOARD ===== + grafana: + image: grafana/grafana-oss:latest + container_name: grafana-stg + restart: unless-stopped + depends_on: [prometheus, loki] + volumes: + - stg_grafana_data:/var/lib/grafana + - ./grafana/provisioning/datasources/datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml:ro + environment: + GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN} + GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD} + GF_SERVER_ROOT_URL: 'https://stg.api.docsa.o-r.kr/grafana/' + GF_SERVER_SERVE_FROM_SUB_PATH: 'true' + networks: [docsa_stg_net] + + +volumes: + stg_mysql_data: + stg_prom_data: + stg_loki_data: + stg_grafana_data: + mailpit_data: + +networks: + docsa_stg_net: diff --git a/infra/docker-compose.yml b/infra/docker-compose.yml index 0a2226b9..4fa84217 100644 --- a/infra/docker-compose.yml +++ b/infra/docker-compose.yml @@ -2,7 +2,7 @@ name: docsa services: app: - image: ghcr.io/prgrms-web-devcourse-final-project/docsa-backend:release + image: ghcr.io/prgrms-web-devcourse-final-project/docsa-backend:dev container_name: docsa-app restart: unless-stopped env_file: .env @@ -17,8 +17,8 @@ services: SERVER_SERVLET_SESSION_COOKIE_DOMAIN: ${SESSION_COOKIE_DOMAIN} SPRINGDOC_SWAGGER-UI_SERVERS_URL: ${SWAGGER_SERVER_URL} depends_on: - mysql: - condition: service_healthy + mysql: + condition: service_healthy networks: - docsa_net healthcheck: @@ -39,7 +39,7 @@ services: networks: - docsa_net healthcheck: - test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-u", "docsa", "-p${SPRING_DATASOURCE_PASSWORD}"] + test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-u", "${MYSQL_USER}", "-p${MYSQL_PASSWORD}"] interval: 10s timeout: 5s retries: 3 @@ -130,7 +130,7 @@ services: sleep 24h; done' - # ===== METRICS ===== + # ===== METRICS ===== cadvisor: image: gcr.io/cadvisor/cadvisor:latest container_name: cadvisor @@ -167,7 +167,7 @@ services: networks: - docsa_net -# ===== LOGS ===== + # ===== LOGS ===== loki: image: grafana/loki:3.5.5 container_name: loki @@ -192,7 +192,7 @@ services: - ./mysql/logs:/mnt/mysql-logs:ro networks: [docsa_net] -# ===== DASHBOARD ===== + # ===== DASHBOARD ===== grafana: image: grafana/grafana-oss:latest container_name: grafana @@ -216,4 +216,4 @@ volumes: grafana_data: networks: - docsa_net: + docsa_net: \ No newline at end of file diff --git a/infra/nginx/nginx.conf b/infra/nginx/nginx.conf index ae93fbd0..78ea2f76 100644 --- a/infra/nginx/nginx.conf +++ b/infra/nginx/nginx.conf @@ -16,9 +16,9 @@ http { error_log /var/log/nginx/error.log warn; access_log /var/log/nginx/access.log main; - server { - listen 80; - server_name api.docsa.o-r.kr; + server { + listen 80; + server_name api.docsa.o-r.kr; location ^~ /.well-known/acme-challenge/ { root /var/www/certbot; @@ -26,7 +26,7 @@ http { location / {return 301 https://$host$request_uri; } } - + server { listen 443 ssl http2; server_name api.docsa.o-r.kr; @@ -37,7 +37,7 @@ http { ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; - + ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; @@ -68,8 +68,7 @@ http { proxy_redirect off; } - location = /actuator/prometheus { return 404; } - - } + location = /actuator/prometheus { return 404; } + } } diff --git a/infra/nginx/nginx.stg.conf b/infra/nginx/nginx.stg.conf new file mode 100644 index 00000000..5e4e2a61 --- /dev/null +++ b/infra/nginx/nginx.stg.conf @@ -0,0 +1,87 @@ +user nginx; +worker_processes auto; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + error_log /var/log/nginx/error.log warn; + access_log /var/log/nginx/access.log main; + + server { + listen 80; + server_name stg.api.docsa.o-r.kr; + + location ^~ /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + location / {return 301 https://$host$request_uri; } + } + + server { + listen 443 ssl http2; + server_name stg.api.docsa.o-r.kr; + + ssl_certificate /etc/letsencrypt/live/stg.api.docsa.o-r.kr/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/stg.api.docsa.o-r.kr/privkey.pem; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 1d; + + location / { + proxy_pass http://app:8080; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + + location /grafana/ { + proxy_pass http://grafana:3000; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 3600; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_redirect off; + } + + + location /mailpit/ { + proxy_pass http://mailpit:8025; + + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location = /actuator/prometheus { return 404; } + + } +} + diff --git a/infra/prometheus/prometheus.yml b/infra/prometheus/prometheus.yml index 60601537..98e2cbe0 100644 --- a/infra/prometheus/prometheus.yml +++ b/infra/prometheus/prometheus.yml @@ -7,7 +7,7 @@ scrape_configs: - job_name: 'spring-app' metrics_path: /actuator/prometheus static_configs: - - targets: ['docsa-app:9091'] + - targets: ['app:9091'] labels: { app: docsa } # 컨테이너 리소스 diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 8e6aa96c..1e4b2d65 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -5,6 +5,17 @@ spring: username: ${MYSQL_USERNAME} password: ${MYSQL_PASSWORD} + mail: + # smtp: smtp.gmail.com, port: 587 / mailpit: localhost, port: 1025 + # gmail 로컬에서 사용시 smtp-auth, starttls-enable, starttls-required: true + host: ${MAIL_HOST:localhost} + port: ${MAIL_PORT:1025} + username: ${MAIL_USERNAME:test@docsa.com} + password: ${MAIL_PASSWORD:} + smtp-auth: ${SMTP_AUTH:false} + starttls-enable: ${STARTTLS_ENABLE:false} + starttls-required: ${STARTTLS_REQUIRED:false} + jpa: hibernate: ddl-auto: create-drop diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 5cd694a0..718b417d 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -5,9 +5,19 @@ spring: username: ${MYSQL_USERNAME} password: ${MYSQL_PASSWORD} + mail: + host: smtp.gmail.com + port: 587 + username: ${MAIL_USERNAME} + password: ${MAIL_PASSWORD} + smtp-auth: true + starttls-enable: true + starttls-required: true + + jpa: hibernate: - ddl-auto: validate + ddl-auto: ${DDL_AUTO:validate} database-platform: org.hibernate.dialect.MySQL8Dialect show-sql: false properties: @@ -38,20 +48,3 @@ springdoc: servers: - url: ${SWAGGER_SERVER_URL} description: Production Server - -management: - server: - port: 9091 - endpoints: - web: - exposure: - include: health,info,prometheus - - metrics: - distribution: - percentiles: - all: 0.5, 0.9, 0.99 - percentiles-histogram: - http.server.requests: true - hikaricp.connections.acquire: true - method.timed: true diff --git a/src/main/resources/application-stg.yml b/src/main/resources/application-stg.yml new file mode 100644 index 00000000..0588591d --- /dev/null +++ b/src/main/resources/application-stg.yml @@ -0,0 +1,50 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: ${MYSQL_PROD_URL} + username: ${MYSQL_USERNAME} + password: ${MYSQL_PASSWORD} + + mail: + host: mailpit + port: 1025 + username: ${MAIL_USERNAME:test@docsa.com} + password: + smtp-auth: false + starttls-enable: false + starttls-required: false + + + jpa: + hibernate: + ddl-auto: ${DDL_AUTO:validate} + database-platform: org.hibernate.dialect.MySQL8Dialect + show-sql: false + properties: + hibernate: + format_sql: false + use_sql_comments: false + +server: + port: 8080 + ssl: + enabled: false + forward-headers-strategy: framework + servlet: + session: + cookie: + name: ${SESSION_COOKIE_NAME} + domain: ${SESSION_COOKIE_DOMAIN} + secure: true + same-site: None + timeout: 24h # TODO: 테스트 완료 후 제거 + +springdoc: + api-docs: + path: /v3/api-docs + swagger-ui: + path: /swagger-ui.html + enabled: true + servers: + - url: ${SWAGGER_SERVER_URL} + description: Production Server diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 40274224..5b177c54 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -6,19 +6,28 @@ spring: mongodb: uri: ${MONGO_URI} - mail: - host: smtp.gmail.com - port: 587 - username: ${MAIL_USERNAME} - password: ${MAIL_PASSWORD} - smtp-auth: true - starttls-enable: true - starttls-required: true connection-timeout: 5000 timeout: 5000 write-timeout: 5000 +management: + server: + port: 9091 + endpoints: + web: + exposure: + include: health,info,prometheus + + metrics: + distribution: + percentiles: + all: 0.5, 0.9, 0.99 + percentiles-histogram: + http.server.requests: true + hikaricp.connections.acquire: true + method.timed: true + auth: signup-code-cache-name: signupCodeCache passcode-cache-name: passCodeCache