From 6f25d5c90ed5be88e258cdfc184375a58dfe8be2 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 01:52:05 +0900 Subject: [PATCH 01/29] =?UTF-8?q?Chore:=20docker-compose.yml,=20nginx.conf?= =?UTF-8?q?=20-=20staging=20=EC=84=A4=EC=A0=95=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.yml | 74 ++++++++++++++++++++-------------------- infra/nginx/nginx.conf | 4 +-- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/infra/docker-compose.yml b/infra/docker-compose.yml index 0a2226b9..9df1be48 100644 --- a/infra/docker-compose.yml +++ b/infra/docker-compose.yml @@ -1,9 +1,9 @@ -name: docsa +name: docsa-stg services: app: image: ghcr.io/prgrms-web-devcourse-final-project/docsa-backend:release - container_name: docsa-app + container_name: docsa-app-stg restart: unless-stopped env_file: .env environment: @@ -20,7 +20,7 @@ services: mysql: condition: service_healthy networks: - - docsa_net + - docsa_stg_net healthcheck: test: ["CMD", "wget", "-qO-", "http://localhost:9091/actuator/health"] interval: 30s @@ -29,31 +29,31 @@ services: mysql: image: mysql:9.4.0 - container_name: docsa-mysql + container_name: docsa-mysql-stg restart: unless-stopped env_file: .env volumes: - - mysql_data:/var/lib/mysql + - stg_mysql_data:/var/lib/mysql - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf:ro - ./mysql/logs:/var/log/mysql networks: - - docsa_net + - docsa_stg_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", "docsa-stg", "-p${SPRING_DATASOURCE_PASSWORD}"] interval: 10s timeout: 5s retries: 3 mysqld-exporter: image: prom/mysqld-exporter:latest - container_name: mysqld-exporter + 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:3306' + - '--mysqld.address=docsa-mysql-stg:3306' - '--collect.global_status' - '--collect.global_variables' - '--collect.engine_innodb_status' @@ -65,11 +65,11 @@ services: mysql: condition: service_healthy networks: - - docsa_net + - docsa_stg_net nginx: image: nginx:stable-alpine-slim - container_name: docsa-nginx + container_name: docsa-nginx-stg restart: unless-stopped volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro @@ -82,12 +82,12 @@ services: app: condition: service_started networks: - - docsa_net + - docsa_stg_net # 최초 발급용(수동실행) certbot_init: image: certbot/certbot:latest - container_name: docsa-certbot-init + container_name: docsa-certbot-init-stg profiles: - "init" depends_on: @@ -99,7 +99,7 @@ services: command: > certonly --webroot --webroot-path /var/www/certbot - -d api.docsa.o-r.kr + -d stg.api.docsa.o-r.kr --email qoanstjdsla@gmail.com --agree-tos --non-interactive --no-eff-email @@ -107,7 +107,7 @@ services: # 자동 갱신 데몬(하루마다 확인, 갱신되면 nginx 리로드) certbot_renew: image: certbot/certbot:latest - container_name: docsa-certbot-renew + container_name: docsa-certbot-renew-stg depends_on: - nginx volumes: @@ -125,7 +125,7 @@ services: --method=POST \ --body-data="" \ --unix-socket /var/run/docker.sock \ - http://localhost/v1.41/containers/docsa-nginx/kill?signal=HUP >/dev/null 2>&1 || true + http://localhost/v1.41/containers/docsa-nginx-stg/kill?signal=HUP >/dev/null 2>&1 || true fi sleep 24h; done' @@ -133,7 +133,7 @@ services: # ===== METRICS ===== cadvisor: image: gcr.io/cadvisor/cadvisor:latest - container_name: cadvisor + container_name: cadvisor-stg restart: unless-stopped privileged: true volumes: @@ -142,46 +142,46 @@ services: - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro networks: - - docsa_net + - docsa_stg_net node_exporter: image: prom/node-exporter:latest - container_name: node-exporter + container_name: node-exporter-stg restart: unless-stopped pid: host command: ['--path.rootfs=/host'] volumes: - /:/host:ro,rslave networks: - - docsa_net + - docsa_stg_net prometheus: image: prom/prometheus:latest - container_name: prometheus + container_name: prometheus-stg restart: unless-stopped depends_on: - cadvisor volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro - - prom_data:/prometheus + - stg_prom_data:/prometheus networks: - - docsa_net + - docsa_stg_net # ===== LOGS ===== loki: image: grafana/loki:3.5.5 - container_name: loki + container_name: loki-stg restart: unless-stopped command: ["-config.file=/etc/loki/config.yml"] volumes: - ./loki/config.yml:/etc/loki/config.yml:ro - - loki_data:/loki + - stg_loki_data:/loki networks: - - docsa_net + - docsa_stg_net promtail: image: grafana/promtail:3.5 - container_name: promtail + container_name: promtail-stg restart: unless-stopped command: ["-config.file=/etc/promtail/config.yml"] volumes: @@ -190,30 +190,30 @@ services: - /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_net] + networks: [docsa_stg_net] # ===== DASHBOARD ===== grafana: image: grafana/grafana-oss:latest - container_name: grafana + container_name: grafana-stg restart: unless-stopped depends_on: [prometheus, loki] volumes: - - grafana_data:/var/lib/grafana + - 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://api.docsa.o-r.kr/grafana/' + GF_SERVER_ROOT_URL: 'https://stg.api.docsa.o-r.kr/grafana/' GF_SERVER_SERVE_FROM_SUB_PATH: 'true' - networks: [docsa_net] + networks: [docsa_stg_net] volumes: - mysql_data: - prom_data: - loki_data: - grafana_data: + stg_mysql_data: + stg_prom_data: + stg_loki_data: + stg_grafana_data: networks: - docsa_net: + docsa_stg_net: diff --git a/infra/nginx/nginx.conf b/infra/nginx/nginx.conf index ae93fbd0..597ed959 100644 --- a/infra/nginx/nginx.conf +++ b/infra/nginx/nginx.conf @@ -18,7 +18,7 @@ http { server { listen 80; - server_name api.docsa.o-r.kr; + server_name stg.api.docsa.o-r.kr; location ^~ /.well-known/acme-challenge/ { root /var/www/certbot; @@ -29,7 +29,7 @@ http { server { listen 443 ssl http2; - server_name api.docsa.o-r.kr; + server_name stg.api.docsa.o-r.kr; ssl_certificate /etc/letsencrypt/live/api.docsa.o-r.kr/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/api.docsa.o-r.kr/privkey.pem; From 13c57b99ae1312574f47f76e2a26a5f10b08cbc7 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 02:44:23 +0900 Subject: [PATCH 02/29] =?UTF-8?q?Chore:=20=EB=8F=84=EC=BB=A4=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=ED=83=9C=EA=B7=B8=20(dev,=20staging)?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD/=EB=B6=84=EA=B8=B0=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EB=B0=8F=20=EB=B0=B0=ED=8F=AC=20=EB=B6=84?= =?UTF-8?q?=EA=B8=B0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 43 +++++++++++++++++++++++++++---------- infra/docker-compose.yml | 2 +- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index aba4762b..7271e919 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 )" 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 @@ -115,4 +130,10 @@ jobs: 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 + bash -lc '/srv/docsa-stg/infra/deploy.sh' + else + bash -lc '/srv/docsa/infra/deploy.sh' + fi + + diff --git a/infra/docker-compose.yml b/infra/docker-compose.yml index 9df1be48..a0c7bfe8 100644 --- a/infra/docker-compose.yml +++ b/infra/docker-compose.yml @@ -2,7 +2,7 @@ name: docsa-stg 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-stg restart: unless-stopped env_file: .env From 8e773d0ccf9abc015b6bd6c38db34d31bd6dc369 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 02:56:18 +0900 Subject: [PATCH 03/29] =?UTF-8?q?Chore:=20docker-compose.stg.yml=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.stg.yml | 219 +++++++++++++++++++++++++++++++++++ infra/docker-compose.yml | 84 +++++++------- 2 files changed, 261 insertions(+), 42 deletions(-) create mode 100644 infra/docker-compose.stg.yml diff --git a/infra/docker-compose.stg.yml b/infra/docker-compose.stg.yml new file mode 100644 index 00000000..a0c7bfe8 --- /dev/null +++ b/infra/docker-compose.stg.yml @@ -0,0 +1,219 @@ +name: docsa-stg + +services: + app: + image: ghcr.io/prgrms-web-devcourse-final-project/docsa-backend:dev + container_name: docsa-app-stg + restart: unless-stopped + env_file: .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} + 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 + + mysql: + image: mysql:9.4.0 + container_name: docsa-mysql-stg + restart: unless-stopped + env_file: .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", "docsa-stg", "-p${SPRING_DATASOURCE_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.conf:/etc/nginx/nginx.conf:ro + - ./certbot/etc:/etc/letsencrypt:ro + - ./certbot/www:/var/www/certbot:ro + ports: + - "80:80" + - "443: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: + +networks: + docsa_stg_net: diff --git a/infra/docker-compose.yml b/infra/docker-compose.yml index a0c7bfe8..0ebe17b6 100644 --- a/infra/docker-compose.yml +++ b/infra/docker-compose.yml @@ -1,9 +1,9 @@ -name: docsa-stg +name: docsa services: app: image: ghcr.io/prgrms-web-devcourse-final-project/docsa-backend:dev - container_name: docsa-app-stg + container_name: docsa-app restart: unless-stopped env_file: .env environment: @@ -17,10 +17,10 @@ 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_stg_net + - docsa_net healthcheck: test: ["CMD", "wget", "-qO-", "http://localhost:9091/actuator/health"] interval: 30s @@ -29,31 +29,31 @@ services: mysql: image: mysql:9.4.0 - container_name: docsa-mysql-stg + container_name: docsa-mysql restart: unless-stopped env_file: .env volumes: - - stg_mysql_data:/var/lib/mysql + - mysql_data:/var/lib/mysql - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf:ro - ./mysql/logs:/var/log/mysql networks: - - docsa_stg_net + - docsa_net healthcheck: - test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-u", "docsa-stg", "-p${SPRING_DATASOURCE_PASSWORD}"] + test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-u", "docsa", "-p${SPRING_DATASOURCE_PASSWORD}"] interval: 10s timeout: 5s retries: 3 mysqld-exporter: image: prom/mysqld-exporter:latest - container_name: mysqld-exporter-stg + container_name: mysqld-exporter 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' + - '--mysqld.address=docsa-mysql:3306' - '--collect.global_status' - '--collect.global_variables' - '--collect.engine_innodb_status' @@ -65,11 +65,11 @@ services: mysql: condition: service_healthy networks: - - docsa_stg_net + - docsa_net nginx: image: nginx:stable-alpine-slim - container_name: docsa-nginx-stg + container_name: docsa-nginx restart: unless-stopped volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro @@ -82,12 +82,12 @@ services: app: condition: service_started networks: - - docsa_stg_net + - docsa_net # 최초 발급용(수동실행) certbot_init: image: certbot/certbot:latest - container_name: docsa-certbot-init-stg + container_name: docsa-certbot-init profiles: - "init" depends_on: @@ -99,7 +99,7 @@ services: command: > certonly --webroot --webroot-path /var/www/certbot - -d stg.api.docsa.o-r.kr + -d api.docsa.o-r.kr --email qoanstjdsla@gmail.com --agree-tos --non-interactive --no-eff-email @@ -107,7 +107,7 @@ services: # 자동 갱신 데몬(하루마다 확인, 갱신되면 nginx 리로드) certbot_renew: image: certbot/certbot:latest - container_name: docsa-certbot-renew-stg + container_name: docsa-certbot-renew depends_on: - nginx volumes: @@ -125,15 +125,15 @@ services: --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 + http://localhost/v1.41/containers/docsa-nginx/kill?signal=HUP >/dev/null 2>&1 || true fi sleep 24h; done' - # ===== METRICS ===== + # ===== METRICS ===== cadvisor: image: gcr.io/cadvisor/cadvisor:latest - container_name: cadvisor-stg + container_name: cadvisor restart: unless-stopped privileged: true volumes: @@ -142,46 +142,46 @@ services: - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro networks: - - docsa_stg_net + - docsa_net node_exporter: image: prom/node-exporter:latest - container_name: node-exporter-stg + container_name: node-exporter restart: unless-stopped pid: host command: ['--path.rootfs=/host'] volumes: - /:/host:ro,rslave networks: - - docsa_stg_net + - docsa_net prometheus: image: prom/prometheus:latest - container_name: prometheus-stg + container_name: prometheus restart: unless-stopped depends_on: - cadvisor volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro - - stg_prom_data:/prometheus + - prom_data:/prometheus networks: - - docsa_stg_net + - docsa_net -# ===== LOGS ===== + # ===== LOGS ===== loki: image: grafana/loki:3.5.5 - container_name: loki-stg + container_name: loki restart: unless-stopped command: ["-config.file=/etc/loki/config.yml"] volumes: - ./loki/config.yml:/etc/loki/config.yml:ro - - stg_loki_data:/loki + - loki_data:/loki networks: - - docsa_stg_net + - docsa_net promtail: image: grafana/promtail:3.5 - container_name: promtail-stg + container_name: promtail restart: unless-stopped command: ["-config.file=/etc/promtail/config.yml"] volumes: @@ -190,30 +190,30 @@ services: - /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] + networks: [docsa_net] -# ===== DASHBOARD ===== + # ===== DASHBOARD ===== grafana: image: grafana/grafana-oss:latest - container_name: grafana-stg + container_name: grafana restart: unless-stopped depends_on: [prometheus, loki] volumes: - - stg_grafana_data:/var/lib/grafana + - 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_ROOT_URL: 'https://api.docsa.o-r.kr/grafana/' GF_SERVER_SERVE_FROM_SUB_PATH: 'true' - networks: [docsa_stg_net] + networks: [docsa_net] volumes: - stg_mysql_data: - stg_prom_data: - stg_loki_data: - stg_grafana_data: + mysql_data: + prom_data: + loki_data: + grafana_data: networks: - docsa_stg_net: + docsa_net: \ No newline at end of file From 3287313d4072a82b1cc5c607d28612dd38bc2df5 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 02:58:03 +0900 Subject: [PATCH 04/29] =?UTF-8?q?Chore:=20gitignore=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) 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 From cbfa5941cded2efd9cd46935780a0328e1f6ff5d Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 04:14:02 +0900 Subject: [PATCH 05/29] =?UTF-8?q?Chore:=20docker-compose.stg.yml=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.stg.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/infra/docker-compose.stg.yml b/infra/docker-compose.stg.yml index a0c7bfe8..f7486431 100644 --- a/infra/docker-compose.stg.yml +++ b/infra/docker-compose.stg.yml @@ -2,10 +2,10 @@ name: docsa-stg services: app: - image: ghcr.io/prgrms-web-devcourse-final-project/docsa-backend:dev + image: ghcr.io/prgrms-web-devcourse-final-project/docsa-backend:staging container_name: docsa-app-stg restart: unless-stopped - env_file: .env + env_file: .stg.env environment: SPRING_DATA_MONGODB_URI: ${SPRING_DATA_MONGODB_URI} SPRING_MAIL_USERNAME: ${SPRING_MAIL_USERNAME} @@ -31,7 +31,7 @@ services: image: mysql:9.4.0 container_name: docsa-mysql-stg restart: unless-stopped - env_file: .env + env_file: .stg.env volumes: - stg_mysql_data:/var/lib/mysql - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf:ro From 3fa3de621529bc0d4947160d06bcd8dd91bf6601 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 04:14:40 +0900 Subject: [PATCH 06/29] =?UTF-8?q?Chore:=20deploy.sh=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20(dev/staging=20=EB=B6=84=EA=B8=B0=20=EB=B0=B0=ED=8F=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/deploy.sh | 88 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 22 deletions(-) diff --git a/infra/deploy.sh b/infra/deploy.sh index 9ab7c6ea..0d77203e 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="$(cd .. && pwd)" + +# 타깃에 따라 compose/env 자동 선택 +if [[ "$TARGET" == "dev" ]]; then + COMPOSE_FILE="$ROOT/compose.dev.yml" + ENV_FILE="$ROOT/.env" +else + COMPOSE_FILE="$ROOT/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/infra/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 From 8808bf1a60cb7d80bf502377ba7991b06672a905 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 04:15:51 +0900 Subject: [PATCH 07/29] =?UTF-8?q?Chore:=20ci-cd.yml=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20(Deploy=20=ED=83=9C=EA=B7=B8=20=EB=B0=8F=20TARGET=20?= =?UTF-8?q?=EC=9D=B8=EC=9E=90=20=EC=A0=84=EB=8B=AC=20=EC=B2=98=EB=A6=AC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 7271e919..da4fe194 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -129,11 +129,10 @@ jobs: key: ${{ secrets.CD_SSH_KEY }} port: ${{ secrets.CD_PORT }} script: | - export DEPLOY_TAG='${{ steps.tag.outputs.value }}' if [ "${{ github.ref_name }}" = "staging" ]; then - bash -lc '/srv/docsa-stg/infra/deploy.sh' + export DEPLOY_TAG='${{ steps.tag.outputs.value }}' + bash -lc '/srv/docsa/infra/deploy.sh staging' else - bash -lc '/srv/docsa/infra/deploy.sh' - fi - - + export DEPLOY_TAG='${{ steps.tag.outputs.value }}' + bash -lc '/srv/docsa/infra/deploy.sh dev' + fi \ No newline at end of file From 4f0dfcd3fee78e9b7ba71b3cef27d37f7e456c50 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 04:20:10 +0900 Subject: [PATCH 08/29] =?UTF-8?q?Chore:=20ci-cd.yml=20mysql=20username/pas?= =?UTF-8?q?sword=20=ED=99=98=EA=B2=BD=EB=B3=80=EC=88=98=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.stg.yml | 2 +- infra/docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/docker-compose.stg.yml b/infra/docker-compose.stg.yml index f7486431..3e8c3bf2 100644 --- a/infra/docker-compose.stg.yml +++ b/infra/docker-compose.stg.yml @@ -39,7 +39,7 @@ services: networks: - docsa_stg_net healthcheck: - test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-u", "docsa-stg", "-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 diff --git a/infra/docker-compose.yml b/infra/docker-compose.yml index 0ebe17b6..4fa84217 100644 --- a/infra/docker-compose.yml +++ b/infra/docker-compose.yml @@ -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 From 474762e4f5f651bd6b6e398b0b050c88cf0fb7c2 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 04:49:20 +0900 Subject: [PATCH 09/29] =?UTF-8?q?Chore:=20nginx.conf/ngins.stg.conf=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.yml | 2 +- infra/nginx/nginx.conf | 16 ++++---- infra/nginx/nginx.stg.conf | 75 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 infra/nginx/nginx.stg.conf diff --git a/infra/docker-compose.yml b/infra/docker-compose.yml index 4fa84217..92a556fd 100644 --- a/infra/docker-compose.yml +++ b/infra/docker-compose.yml @@ -72,7 +72,7 @@ services: container_name: docsa-nginx restart: unless-stopped volumes: - - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/nginx.stg.conf:/etc/nginx/nginx.conf:ro - ./certbot/etc:/etc/letsencrypt:ro - ./certbot/www:/var/www/certbot:ro ports: diff --git a/infra/nginx/nginx.conf b/infra/nginx/nginx.conf index 597ed959..30fafab7 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 stg.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,10 +26,10 @@ http { location / {return 301 https://$host$request_uri; } } - + server { listen 443 ssl http2; - server_name stg.api.docsa.o-r.kr; + server_name api.docsa.o-r.kr; ssl_certificate /etc/letsencrypt/live/api.docsa.o-r.kr/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/api.docsa.o-r.kr/privkey.pem; @@ -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,8 @@ 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..0cd7ee5c --- /dev/null +++ b/infra/nginx/nginx.stg.conf @@ -0,0 +1,75 @@ +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 = /actuator/prometheus { return 404; } +; +; } +} + From 8fc86f56691caf8738740c79d1647f11d2e583c4 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 05:03:28 +0900 Subject: [PATCH 10/29] =?UTF-8?q?Chore:=20ngins.stg.conf=20ssh=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=EC=84=9C=20=EC=B5=9C=EC=B4=88=EB=B0=9C=EA=B8=89?= =?UTF-8?q?=EC=9A=A9=20=EC=A3=BC=EC=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/nginx/nginx.conf | 3 +- infra/nginx/nginx.stg.conf | 92 +++++++++++++++++++------------------- 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/infra/nginx/nginx.conf b/infra/nginx/nginx.conf index 30fafab7..78ea2f76 100644 --- a/infra/nginx/nginx.conf +++ b/infra/nginx/nginx.conf @@ -69,7 +69,6 @@ http { } location = /actuator/prometheus { return 404; } - - } + } } diff --git a/infra/nginx/nginx.stg.conf b/infra/nginx/nginx.stg.conf index 0cd7ee5c..ac04349f 100644 --- a/infra/nginx/nginx.stg.conf +++ b/infra/nginx/nginx.stg.conf @@ -26,50 +26,50 @@ http { 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 = /actuator/prometheus { return 404; } -; -; } -} + +# 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 = /actuator/prometheus { return 404; } +# +# } +#} From 088afcd5ffb0bbdf0a4248d42fd0446e1985324c Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 05:18:03 +0900 Subject: [PATCH 11/29] =?UTF-8?q?Chore:=20application-prod.yml=20ddl=5Faut?= =?UTF-8?q?o=20=ED=99=98=EA=B2=BD=EB=B3=80=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/nginx/nginx.stg.conf | 2 +- src/main/resources/application-prod.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/nginx/nginx.stg.conf b/infra/nginx/nginx.stg.conf index ac04349f..d873fb26 100644 --- a/infra/nginx/nginx.stg.conf +++ b/infra/nginx/nginx.stg.conf @@ -71,5 +71,5 @@ http { # location = /actuator/prometheus { return 404; } # # } -#} +} diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 5cd694a0..4a416943 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -7,7 +7,7 @@ spring: jpa: hibernate: - ddl-auto: validate + ddl-auto: ${DDL_AUTO:validate} database-platform: org.hibernate.dialect.MySQL8Dialect show-sql: false properties: From e28ce8342562d3b7ca4cfed78fa5bd3c845a4f33 Mon Sep 17 00:00:00 2001 From: MoonSung Date: Tue, 21 Oct 2025 05:43:52 +0900 Subject: [PATCH 12/29] =?UTF-8?q?Chore:=20DDL=5FAUTO=20docker-compose.stg.?= =?UTF-8?q?yml=20=ED=99=98=EA=B2=BD=EB=B3=80=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.stg.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/infra/docker-compose.stg.yml b/infra/docker-compose.stg.yml index 3e8c3bf2..36b20f10 100644 --- a/infra/docker-compose.stg.yml +++ b/infra/docker-compose.stg.yml @@ -16,6 +16,7 @@ services: 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 From 588788c650b96e981940276d06b4d6f00ce42b4b Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 05:47:35 +0900 Subject: [PATCH 13/29] =?UTF-8?q?Chore:=20.env.example=20ddl=5Fauto?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/.env.example | 1 + 1 file changed, 1 insertion(+) 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= From 272d262cff09b20f73bf5fc0ee3424d39258a836 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 05:48:31 +0900 Subject: [PATCH 14/29] =?UTF-8?q?Chore:=20=EC=98=A4=ED=83=80=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.stg.yml | 2 +- infra/docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/docker-compose.stg.yml b/infra/docker-compose.stg.yml index 36b20f10..1ba4e681 100644 --- a/infra/docker-compose.stg.yml +++ b/infra/docker-compose.stg.yml @@ -73,7 +73,7 @@ services: container_name: docsa-nginx-stg restart: unless-stopped volumes: - - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/nginx.stg.conf:/etc/nginx/nginx.conf:ro - ./certbot/etc:/etc/letsencrypt:ro - ./certbot/www:/var/www/certbot:ro ports: diff --git a/infra/docker-compose.yml b/infra/docker-compose.yml index 92a556fd..4fa84217 100644 --- a/infra/docker-compose.yml +++ b/infra/docker-compose.yml @@ -72,7 +72,7 @@ services: container_name: docsa-nginx restart: unless-stopped volumes: - - ./nginx/nginx.stg.conf:/etc/nginx/nginx.conf:ro + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./certbot/etc:/etc/letsencrypt:ro - ./certbot/www:/var/www/certbot:ro ports: From 6cec26f76aa24a05fc5a173a0e833c181d888f8b Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 05:53:14 +0900 Subject: [PATCH 15/29] =?UTF-8?q?Chore:=20nginx.stg.conf=20443=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/nginx/nginx.stg.conf | 88 +++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/infra/nginx/nginx.stg.conf b/infra/nginx/nginx.stg.conf index d873fb26..1c8a39ae 100644 --- a/infra/nginx/nginx.stg.conf +++ b/infra/nginx/nginx.stg.conf @@ -27,49 +27,49 @@ http { 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 = /actuator/prometheus { return 404; } -# -# } + 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 = /actuator/prometheus { return 404; } + + } } From 6737ea7b6a6799e6bb919d5551caf18f21f3c8c8 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 06:13:35 +0900 Subject: [PATCH 16/29] =?UTF-8?q?Chore:=20deploy.sh=20ROOT=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/deploy.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/infra/deploy.sh b/infra/deploy.sh index 0d77203e..9119a29f 100755 --- a/infra/deploy.sh +++ b/infra/deploy.sh @@ -20,8 +20,7 @@ IMAGE_BASE="${IMAGE_BASE:-ghcr.io/prgrms-web-devcourse-final-project/docsa-backe SERVICE="${SERVICE:-app}" HEALTH_TIMEOUT="${HEALTH_TIMEOUT:-120}" -cd "$(dirname "$0")" -ROOT="$(cd .. && pwd)" +ROOT="$(cd "$(dirname "$0")" && pwd)" # 타깃에 따라 compose/env 자동 선택 if [[ "$TARGET" == "dev" ]]; then From c1f29c9992df0b04886ec97b56b3ba24511ad38a Mon Sep 17 00:00:00 2001 From: MoonSung Date: Tue, 21 Oct 2025 06:34:04 +0900 Subject: [PATCH 17/29] =?UTF-8?q?Fix:=20docker-compose.stg.yml=20nginx=20?= =?UTF-8?q?=ED=8F=AC=ED=8A=B8=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.stg.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/docker-compose.stg.yml b/infra/docker-compose.stg.yml index 1ba4e681..468561ee 100644 --- a/infra/docker-compose.stg.yml +++ b/infra/docker-compose.stg.yml @@ -77,8 +77,8 @@ services: - ./certbot/etc:/etc/letsencrypt:ro - ./certbot/www:/var/www/certbot:ro ports: - - "80:80" - - "443:443" + - "8080:80" + - "8443:443" depends_on: app: condition: service_started From 26b21b66d7ebb95f350453c19dab9b630fcdae29 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 06:47:56 +0900 Subject: [PATCH 18/29] =?UTF-8?q?Chore:=20deploy.sh=20ROOT=20=EC=88=98?= =?UTF-8?q?=EC=A0=95(/docsa/infra)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/deploy.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infra/deploy.sh b/infra/deploy.sh index 9119a29f..d24d4460 100755 --- a/infra/deploy.sh +++ b/infra/deploy.sh @@ -20,7 +20,8 @@ IMAGE_BASE="${IMAGE_BASE:-ghcr.io/prgrms-web-devcourse-final-project/docsa-backe SERVICE="${SERVICE:-app}" HEALTH_TIMEOUT="${HEALTH_TIMEOUT:-120}" -ROOT="$(cd "$(dirname "$0")" && pwd)" +cd "$(dirname "$0")" +ROOT="$(pwd)" # 타깃에 따라 compose/env 자동 선택 if [[ "$TARGET" == "dev" ]]; then From 64873d59b81dfe3a13f0ced924c459923f117d39 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 07:28:02 +0900 Subject: [PATCH 19/29] =?UTF-8?q?Chore:=20deploy.sh=20ROOT=20=EC=88=98?= =?UTF-8?q?=EC=A0=95(OVR=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/deploy.sh b/infra/deploy.sh index d24d4460..731bc69d 100755 --- a/infra/deploy.sh +++ b/infra/deploy.sh @@ -37,7 +37,7 @@ TAG="${DEPLOY_TAG:-$TARGET}" # ← 기본은 채널 태그(dev|sta # 임시 override 파일로 이미지 태그만 덮어쓰기 OVR="" if [[ -n "$TAG" ]]; then - OVR="$ROOT/infra/docker-compose.override.deploy.yml" + OVR="$ROOT/docker-compose.override.deploy.yml" cat > "$OVR" < Date: Tue, 21 Oct 2025 07:44:09 +0900 Subject: [PATCH 20/29] =?UTF-8?q?Chore:=20deploy.sh=20ROOT=20=EC=98=A4?= =?UTF-8?q?=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/deploy.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/deploy.sh b/infra/deploy.sh index 731bc69d..1e70f856 100755 --- a/infra/deploy.sh +++ b/infra/deploy.sh @@ -25,10 +25,10 @@ ROOT="$(pwd)" # 타깃에 따라 compose/env 자동 선택 if [[ "$TARGET" == "dev" ]]; then - COMPOSE_FILE="$ROOT/compose.dev.yml" + COMPOSE_FILE="$ROOT/docker-compose.yml" ENV_FILE="$ROOT/.env" else - COMPOSE_FILE="$ROOT/compose.stg.yml" + COMPOSE_FILE="$ROOT/docker-compose.stg.yml" ENV_FILE="$ROOT/.stg.env" fi From 3e58e29952dd5b5b4aa4efafa42dba4fdd83463b Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Tue, 21 Oct 2025 23:58:37 +0900 Subject: [PATCH 21/29] =?UTF-8?q?Chore:=20application-stg.yml=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=20=EB=B0=8F=20mail=20host=20mailpit=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9(=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9A=A9=EB=8F=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-stg.yml | 69 ++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/main/resources/application-stg.yml diff --git a/src/main/resources/application-stg.yml b/src/main/resources/application-stg.yml new file mode 100644 index 00000000..01fc44d0 --- /dev/null +++ b/src/main/resources/application-stg.yml @@ -0,0 +1,69 @@ +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: + password: + smtp-auth: false + starttls-enable: false + starttls-required: false + connection-timeout: 5000 + timeout: 5000 + write-timeout: 5000 + + 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 + +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 From 5a470351a2516b399aa9d6f9aeababac508b11f7 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Wed, 22 Oct 2025 00:10:36 +0900 Subject: [PATCH 22/29] =?UTF-8?q?Chore:=20docker-compose.stg.yml=20(mailpi?= =?UTF-8?q?t=20=EC=B6=94=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.stg.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/infra/docker-compose.stg.yml b/infra/docker-compose.stg.yml index 468561ee..4e8ce3b3 100644 --- a/infra/docker-compose.stg.yml +++ b/infra/docker-compose.stg.yml @@ -28,6 +28,14 @@ services: timeout: 5s retries: 3 + mailpit: + image: axllent/mailpit:latest + container_name: mailpit-stg + ports: + - "8025:8025" # 웹 UI + - "1025:1025" # SMTP + restart: unless-stopped + mysql: image: mysql:9.4.0 container_name: docsa-mysql-stg From a828ac95bed8ff33ca957407567faa2fb468e3c2 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Wed, 22 Oct 2025 02:01:25 +0900 Subject: [PATCH 23/29] =?UTF-8?q?Chore:=20docker-compose.stg.yml=20(mailpi?= =?UTF-8?q?t=20-=20networks=20=EC=B6=94=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.stg.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/infra/docker-compose.stg.yml b/infra/docker-compose.stg.yml index 4e8ce3b3..392dcfd1 100644 --- a/infra/docker-compose.stg.yml +++ b/infra/docker-compose.stg.yml @@ -35,6 +35,8 @@ services: - "8025:8025" # 웹 UI - "1025:1025" # SMTP restart: unless-stopped + networks: + - docsa_stg_net mysql: image: mysql:9.4.0 From 7d627eb6e4267226f3092e665d125c3dd655bb26 Mon Sep 17 00:00:00 2001 From: MoonSung Date: Wed, 22 Oct 2025 04:01:38 +0900 Subject: [PATCH 24/29] =?UTF-8?q?Feat:=20mailpit=20=EA=B5=AC=EC=B6=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.stg.yml | 14 +++++++++----- infra/nginx/nginx.stg.conf | 12 ++++++++++++ infra/prometheus/prometheus.yml | 2 +- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/infra/docker-compose.stg.yml b/infra/docker-compose.stg.yml index 392dcfd1..08899a34 100644 --- a/infra/docker-compose.stg.yml +++ b/infra/docker-compose.stg.yml @@ -30,11 +30,14 @@ services: mailpit: image: axllent/mailpit:latest - container_name: mailpit-stg - ports: - - "8025:8025" # 웹 UI - - "1025:1025" # SMTP - restart: unless-stopped + 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 @@ -225,6 +228,7 @@ volumes: stg_prom_data: stg_loki_data: stg_grafana_data: + mailpit_data: networks: docsa_stg_net: diff --git a/infra/nginx/nginx.stg.conf b/infra/nginx/nginx.stg.conf index 1c8a39ae..5e4e2a61 100644 --- a/infra/nginx/nginx.stg.conf +++ b/infra/nginx/nginx.stg.conf @@ -68,6 +68,18 @@ http { 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 } # 컨테이너 리소스 From 9aba1e7f0d43bf278375daf488249709b58d1bed Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Wed, 22 Oct 2025 17:03:50 +0900 Subject: [PATCH 25/29] =?UTF-8?q?Chore:=20docker-compose.stg.yml=20(mailpi?= =?UTF-8?q?t=20-=20username/password=20=EA=B0=92=EC=B6=94=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-stg.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-stg.yml b/src/main/resources/application-stg.yml index 01fc44d0..961089d3 100644 --- a/src/main/resources/application-stg.yml +++ b/src/main/resources/application-stg.yml @@ -8,7 +8,7 @@ spring: mail: host: mailpit port: 1025 - username: + username: ${MAIL_USERNAME:test@docsa.com} password: smtp-auth: false starttls-enable: false From 06ba1ba0e8be264bb26f812445b3e8604f4cd4fc Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Wed, 22 Oct 2025 17:56:39 +0900 Subject: [PATCH 26/29] =?UTF-8?q?Chore:=20mailpit=ED=97=AC=EC=8A=A4?= =?UTF-8?q?=EC=B2=B4=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.stg.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/infra/docker-compose.stg.yml b/infra/docker-compose.stg.yml index 08899a34..6377cf02 100644 --- a/infra/docker-compose.stg.yml +++ b/infra/docker-compose.stg.yml @@ -9,7 +9,7 @@ services: environment: SPRING_DATA_MONGODB_URI: ${SPRING_DATA_MONGODB_URI} SPRING_MAIL_USERNAME: ${SPRING_MAIL_USERNAME} - SPRING_MAIL_PASSWORD: ${SPRING_MAIL_PASSWORD} + #SPRING_MAIL_PASSWORD: ${SPRING_MAIL_PASSWORD} SPRING_DATASOURCE_URL: ${SPRING_DATASOURCE_URL} SPRING_DATASOURCE_USERNAME: ${SPRING_DATASOURCE_USERNAME} SPRING_DATASOURCE_PASSWORD: ${SPRING_DATASOURCE_PASSWORD} @@ -40,6 +40,12 @@ services: - mailpit_data:/data networks: - docsa_stg_net + healthcheck: + test: ["CMD-SHELL", "wget"," -q", " --spider", " http://127.0.0.1:8025/mailpit/livez"] + interval: 10s + timeout: 3s + retries: 3 + start_period: 10s mysql: image: mysql:9.4.0 From 75336278b60a76e41e96af77d6dfc6e5b5eb8204 Mon Sep 17 00:00:00 2001 From: MoonSung Date: Wed, 22 Oct 2025 23:15:51 +0900 Subject: [PATCH 27/29] =?UTF-8?q?Fix:=20mailpit=20=ED=97=AC=EC=8A=A4?= =?UTF-8?q?=EC=B2=B4=ED=81=AC=20=EB=AC=B8=EB=B2=95=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/docker-compose.stg.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/docker-compose.stg.yml b/infra/docker-compose.stg.yml index 6377cf02..2b9eaa7e 100644 --- a/infra/docker-compose.stg.yml +++ b/infra/docker-compose.stg.yml @@ -41,7 +41,7 @@ services: networks: - docsa_stg_net healthcheck: - test: ["CMD-SHELL", "wget"," -q", " --spider", " http://127.0.0.1:8025/mailpit/livez"] + test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:8025/mailpit/readyz || exit 1"] interval: 10s timeout: 3s retries: 3 From b8a452e3129836aed12f1c0fcbd609126d1aa384 Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Wed, 22 Oct 2025 23:19:14 +0900 Subject: [PATCH 28/29] =?UTF-8?q?Chore:=20ci-cd.yml=20inputs=20description?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index da4fe194..1322d269 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -8,7 +8,7 @@ on: workflow_dispatch: inputs: tag: - description: "배포할 이미지 태그 (ex. release or )" + description: "배포할 이미지 태그 (ex. dev or dev-SHORT_SHA)" required: false default: "dev" From cdea59eb0bdf1ae68a93d6bc070c3c1057bcf14f Mon Sep 17 00:00:00 2001 From: lunarbae628 Date: Sat, 25 Oct 2025 23:02:31 +0900 Subject: [PATCH 29/29] =?UTF-8?q?Chore:=20mail=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20management=20=EC=9C=84=EC=B9=98=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC,=20local/stg/prod=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-local.yml | 11 ++++++++++ src/main/resources/application-prod.yml | 27 +++++++++--------------- src/main/resources/application-stg.yml | 21 +----------------- src/main/resources/application.yml | 25 +++++++++++++++------- 4 files changed, 39 insertions(+), 45 deletions(-) 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 4a416943..718b417d 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -5,6 +5,16 @@ 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: ${DDL_AUTO:validate} @@ -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 index 961089d3..0588591d 100644 --- a/src/main/resources/application-stg.yml +++ b/src/main/resources/application-stg.yml @@ -13,9 +13,7 @@ spring: smtp-auth: false starttls-enable: false starttls-required: false - connection-timeout: 5000 - timeout: 5000 - write-timeout: 5000 + jpa: hibernate: @@ -50,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.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