-
Notifications
You must be signed in to change notification settings - Fork 1
Feat/sw 72 - CI/CD 자동 배포 시스템 구축 & 인프라 보안 고도화 #46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7fb2ef7
c79fed5
b6a115b
45dd5ec
9493756
a249658
308955c
06ad3b1
bf5e189
fc22d87
827ea44
2584fe0
2dcd7fc
e3cfff9
5de190a
3f608a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| .git | ||
| .gradle | ||
| .gradle-user | ||
| .gradle-user-home | ||
| .idea | ||
| .vscode | ||
| .claude | ||
| CLAUDE.md | ||
| build/ | ||
| bin/ | ||
| out/ | ||
| frontend/ | ||
| frontend_old/ | ||
| docs_tmp/ | ||
| status.txt | ||
| status_utf8.txt | ||
| prd.json | ||
| progress.txt | ||
| version.txt | ||
|
|
||
| # Environment variables (Secrets) | ||
| .env | ||
| .env.* |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| name: ReLink Production CI/CD | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ "main", "dev" ] # main, dev 브랜치로 머지(push) 완료 시에만 실행 | ||
|
|
||
| jobs: | ||
| build-backend: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 # 소스 코드 가져오기 | ||
|
|
||
| - name: Login to Docker Hub | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| username: ${{ secrets.DOCKERHUB_USERNAME }} | ||
| password: ${{ secrets.DOCKERHUB_TOKEN }} # 도커 허브 로그인 | ||
|
|
||
| - name: Build and Push Backend Docker Image | ||
| uses: docker/build-push-action@v5 | ||
| with: | ||
| context: . | ||
| file: ./Dockerfile | ||
| push: true | ||
| tags: | | ||
| ${{ secrets.DOCKERHUB_USERNAME }}/relink-backend:latest | ||
| ${{ secrets.DOCKERHUB_USERNAME }}/relink-backend:${{ github.sha }} | ||
|
|
||
| build-frontend: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 # 소스 코드 가져오기 | ||
|
|
||
| - name: Login to Docker Hub | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| username: ${{ secrets.DOCKERHUB_USERNAME }} | ||
| password: ${{ secrets.DOCKERHUB_TOKEN }} # 도커 허브 로그인 | ||
|
|
||
| - name: Build and Push Frontend Docker Image | ||
| uses: docker/build-push-action@v5 | ||
| with: | ||
| context: ./frontend | ||
| file: ./frontend/Dockerfile | ||
| push: true | ||
| tags: | | ||
| ${{ secrets.DOCKERHUB_USERNAME }}/relink-frontend:latest | ||
| ${{ secrets.DOCKERHUB_USERNAME }}/relink-frontend:${{ github.sha }} | ||
|
|
||
| deploy: | ||
| needs: [build-backend, build-frontend] # 백엔드와 프론트엔드 빌드가 모두 성공해야 배포 시작 | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 # 설정 파일 복사를 위해 Checkout 추가 | ||
|
|
||
| - name: Copy config files via SCP | ||
| uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7 | ||
| with: | ||
| host: ${{ secrets.PROD_VM1_HOST }} | ||
| username: ${{ secrets.PROD_VM1_USER }} | ||
| key: ${{ secrets.PROD_VM1_SSH_KEY }} | ||
| source: "deploy/prod/web/docker-compose-prod-web.yml,deploy/prod/web/nginx-prod.conf" | ||
| target: "~/Searchweb/deploy" | ||
| strip_components: 3 | ||
|
|
||
| - name: Deploy to Oracle Cloud VM1 | ||
| uses: appleboy/ssh-action@0ff4204d59e8e51228ff73bce53f80d53301dee2 # v1.2.5 | ||
| with: | ||
| host: ${{ secrets.PROD_VM1_HOST }} | ||
| username: ${{ secrets.PROD_VM1_USER }} | ||
| key: ${{ secrets.PROD_VM1_SSH_KEY }} | ||
| script: | | ||
| cd ~/Searchweb/deploy | ||
| # 서버에서 최신 프론트 및 백엔드 이미지로 교체 및 재시작 | ||
| sudo IMAGE_TAG=${{ github.sha }} docker compose -f docker-compose-prod-web.yml pull | ||
| sudo IMAGE_TAG=${{ github.sha }} docker compose -f docker-compose-prod-web.yml up -d | ||
| # 오래된 이미지 파일 정리(용량 확보) | ||
| sudo docker image prune -f |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,4 +55,10 @@ CLAUDE.md | |
| .gradle-user/ | ||
| status.txt | ||
| status_utf8.txt | ||
| docs/Backend/memo/ | ||
| docs_tmp/ | ||
|
|
||
|
|
||
|
|
||
|
|
||
| prd.json | ||
| progress.txt | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,8 @@ | ||
| FROM eclipse-temurin:17-jdk-alpine AS builder | ||
| WORKDIR /app | ||
| COPY . . | ||
| RUN chmod +x gradlew && ./gradlew clean bootJar | ||
|
|
||
| FROM eclipse-temurin:17-jre-alpine | ||
| COPY build/libs/SearchWeb-0.0.1-SNAPSHOT.jar app.jar | ||
| COPY --from=builder /app/build/libs/*-SNAPSHOT.jar app.jar | ||
| ENTRYPOINT ["java", "-jar", "app.jar"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # dev 환경: 운영(prod)과 동일하게 프론트(Nginx), 백엔드(App), DB를 모두 Docker로 실행. | ||
| services: | ||
| # (1) dev PostgreSQL 데이터베이스 | ||
| postgres: | ||
| image: postgres:16 | ||
| container_name: dev-db | ||
| environment: | ||
| POSTGRES_DB: ${DEV_POSTGRES_DB} | ||
| POSTGRES_USER: ${DEV_POSTGRES_USER} | ||
| POSTGRES_PASSWORD: ${DEV_POSTGRES_PASSWORD} | ||
| TZ: Asia/Seoul | ||
| ports: | ||
| - "7000:5432" | ||
| volumes: | ||
| - postgres-data:/var/lib/postgresql/data | ||
| - ../../src/main/resources/db/init_postgres.sql:/docker-entrypoint-initdb.d/01-init.sql:ro | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "[1] init_postgres.sql 후보 파일 검색"
fd -i "init_postgres.sql"
echo
echo "[2] dev compose가 참조하는 경로 존재 확인"
test -f src/main/resources/db/init_postgres.sql && echo "OK: src/main/resources/db/init_postgres.sql 존재" || echo "MISSING: src/main/resources/db/init_postgres.sql"
echo
echo "[3] prod DB compose 참조 파일 확인"
test -f deploy/prod/db/init_postgres.sql && echo "OK: deploy/prod/db/init_postgres.sql 존재" || echo "MISSING: deploy/prod/db/init_postgres.sql"Repository: Searchweb-Dev/Searchweb-Back Length of output: 325 DB 초기화 SQL 마운트 경로는 존재하므로 현재 컨테이너 기동 시 문제없습니다. 다만 dev와 prod 환경의 초기화 SQL 파일 위치가 다릅니다 (dev: 🤖 Prompt for AI Agents |
||
| healthcheck: | ||
| test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] | ||
| interval: 5s | ||
| timeout: 3s | ||
| retries: 10 | ||
| networks: | ||
| - dev-searchweb-network | ||
|
|
||
| # (2) dev Spring Boot 백엔드 | ||
| backend: | ||
| build: | ||
| context: ../../ | ||
| dockerfile: Dockerfile | ||
| container_name: dev-app | ||
| ports: | ||
| - "8000:8080" | ||
| environment: | ||
| - SPRING_PROFILES_ACTIVE=dev | ||
| - SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/${DEV_POSTGRES_DB} | ||
| - SPRING_DATASOURCE_USERNAME=${DEV_POSTGRES_USER} | ||
| - SPRING_DATASOURCE_PASSWORD=${DEV_POSTGRES_PASSWORD} | ||
| env_file: | ||
| - ../../.env | ||
| depends_on: | ||
| postgres: | ||
| condition: service_healthy | ||
| networks: | ||
| - dev-searchweb-network | ||
|
|
||
| # (3) dev nginx 프론트 정적 서빙 및 백엔드 프록시 | ||
| nginx: | ||
| image: nginx:alpine | ||
| container_name: dev-nginx | ||
| ports: | ||
| - "4000:80" | ||
| volumes: | ||
| - ../../frontend/out:/usr/share/nginx/html:ro | ||
| - ./nginx-dev.conf:/etc/nginx/conf.d/default.conf:ro | ||
| depends_on: | ||
| - backend | ||
| networks: | ||
| - dev-searchweb-network | ||
|
|
||
| networks: | ||
| dev-searchweb-network: | ||
| driver: bridge | ||
|
|
||
| volumes: | ||
| postgres-data: | ||
| name: dev-postgres-data | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| server { | ||
| listen 80; | ||
| server_name localhost; | ||
|
|
||
| # Next.js 정적 빌드 결과물을 서빙합니다. | ||
| location / { | ||
| root /usr/share/nginx/html; | ||
| index index.html index.htm; | ||
| try_files $uri $uri.html $uri/ /index.html; | ||
| } | ||
|
|
||
| # dev Docker 네트워크의 Spring Boot 컨테이너로 API 요청을 전달합니다. | ||
| location /api/ { | ||
| proxy_pass http://backend:8080; | ||
| 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; | ||
| } | ||
|
|
||
| # OAuth2 로그인 시작 요청을 Spring Boot 컨테이너로 전달합니다. | ||
| location /oauth2/ { | ||
| proxy_pass http://backend:8080; | ||
| 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; | ||
| } | ||
|
|
||
| # OAuth2 provider callback 요청을 Spring Boot 컨테이너로 전달합니다. | ||
| location /login/oauth2/ { | ||
| proxy_pass http://backend:8080; | ||
| 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; | ||
| } | ||
|
|
||
| error_page 500 502 503 504 /50x.html; | ||
| location = /50x.html { | ||
| root /usr/share/nginx/html; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # local 환경: 프론트(pnpm dev), 백엔드(IDE)는 개별 실행, DB만 Docker로 실행. | ||
| services: | ||
| postgres: | ||
| image: postgres:16 | ||
| container_name: local-db | ||
| environment: | ||
| POSTGRES_DB: ${DEV_POSTGRES_DB:-searchwebdb} | ||
| POSTGRES_USER: ${LOCAL_DB_USERNAME} | ||
| POSTGRES_PASSWORD: ${LOCAL_DB_PASSWORD} | ||
| TZ: Asia/Seoul | ||
| ports: | ||
| - "5432:5432" | ||
| volumes: | ||
| - postgres-data:/var/lib/postgresql/data | ||
| - ../../src/main/resources/db/init_postgres.sql:/docker-entrypoint-initdb.d/01-init.sql:ro | ||
| networks: | ||
| - local-searchweb-network | ||
| restart: always | ||
|
|
||
| networks: | ||
| local-searchweb-network: | ||
| driver: bridge | ||
|
|
||
| volumes: | ||
| postgres-data: | ||
| name: local-postgres-data |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| version: '3.8' | ||
|
|
||
| services: | ||
| # VM2 전용 PostgreSQL 데이터베이스입니다. | ||
| postgres: | ||
| image: postgres:16 | ||
| container_name: relink-db | ||
| environment: | ||
| POSTGRES_DB: ${PROD_POSTGRES_DB} | ||
| POSTGRES_USER: ${PROD_DB_USERNAME} | ||
| POSTGRES_PASSWORD: ${PROD_DB_PASSWORD} | ||
| TZ: Asia/Seoul | ||
| env_file: | ||
| - ./.env | ||
| ports: | ||
| - "${PROD_VM1_INTERNAL_IP}:7000:5432" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Use the DB host’s own interface (or Useful? React with 👍 / 👎. |
||
| volumes: | ||
| - postgres_data:/var/lib/postgresql/data | ||
| - ./init_postgres.sql:/docker-entrypoint-initdb.d/01-init.sql:ro | ||
| healthcheck: | ||
| test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] | ||
| interval: 5s | ||
| timeout: 3s | ||
| retries: 10 | ||
| restart: always | ||
|
|
||
| volumes: | ||
| postgres_data: | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When this image is built from a developer or deployment checkout that contains the gitignored
.env, this broadCOPY . .includes it because the new root.dockerignoredoes not exclude.envor.env.*(unlike the frontend one). That puts secrets into the build context and builder-layer history, which is especially risky with remote builders or exported caches; add the env patterns to.dockerignoreor copy only the Gradle/project files needed for the jar.Useful? React with 👍 / 👎.