diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e5a4eb9..6b2532f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,7 +2,7 @@ name: Java CI/CD with Docker on: push: - branches: [ "deploy" ] + branches: [ "deploy" ] jobs: build-and-push: @@ -37,7 +37,6 @@ jobs: ${{ secrets.DOCKER_USERNAME }}/cuk-compasser:latest ${{ secrets.DOCKER_USERNAME }}/cuk-compasser:${{ github.sha }} - # 2. 서버에 배포 deploy: needs: build-and-push runs-on: ubuntu-latest @@ -45,16 +44,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Copy docker-compose-prod.yml to EC2 - uses: appleboy/scp-action@master - with: - host: ${{ secrets.EC2_HOST }} - username: ${{ secrets.EC2_USERNAME }} - key: ${{ secrets.EC2_SSH_KEY }} - source: "docker-compose-prod.yml" # 로컬 파일 - target: "~/BE" # 서버 목적지 - - - name: Deploy to EC2 + - name: Deploy to EC2 via SSH uses: appleboy/ssh-action@master env: IMAGE_TAG: ${{ github.sha }} @@ -63,16 +53,15 @@ jobs: username: ${{ secrets.EC2_USERNAME }} key: ${{ secrets.EC2_SSH_KEY }} envs: IMAGE_TAG - debug: true script: | - mkdir -p ~/BE cd ~/BE - # 네트워크 생성 (네트워크가 존재하지 않을 시) - sudo docker network inspect cuk-compasser-net >/dev/null 2>&1 || \ - sudo docker network create cuk-compasser-net - - # .env 파일 생성 + # 1. [핵심] 깃허브의 모든 최신 파일(promtail-config 등) 강제 동기화 + git fetch --all + git reset --hard origin/deploy + + # 2. .env 파일 생성 (보안상 필요한 변수들만 주입) + # 기존에 작성하신 echo 방식을 유지하되, 덮어쓰기(>)와 추가(>>)를 구분합니다. echo "MYSQL_ROOT_PASSWORD=${{ secrets.MYSQL_ROOT_PASSWORD }}" > .env echo "MYSQL_DATABASE=${{ secrets.MYSQL_DATABASE }}" >> .env echo "MYSQL_USER=${{ secrets.MYSQL_USER }}" >> .env @@ -82,20 +71,21 @@ jobs: echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> .env echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> .env echo "SPRING_PROFILES_ACTIVE=${{ secrets.SPRING_PROFILES_ACTIVE }}" >> .env - echo "AWS_ACCESS_KEY=${{ secrets.AWS_ACCESS_KEY }}" >> .env echo "AWS_SECRET_KEY=${{ secrets.AWS_SECRET_KEY }}" >> .env echo "S3_BUCKET_NAME=${{ secrets.S3_BUCKET_NAME }}" >> .env echo "GF_SECURITY_ADMIN_PASSWORD=${{secrets.GF_SECURITY_ADMIN_PASSWORD}}" >> .env - echo "JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }}" >> .env echo "KAKAO_CLIENT_ID=${{ secrets.KAKAO_CLIENT_ID }}" >> .env echo "KAKAO_LOGIN_REDIRECT_URI=${{ secrets.KAKAO_LOGIN_REDIRECT_URI }}" >> .env + echo "KAKAO_REST_API_KEY=${{ secrets.KAKAO_REST_API_KEY }}" >> .env - sudo docker-compose -f docker-compose-prod.yml down --remove-orphans + # 3. 네트워크 생성 확인 + sudo docker network inspect cuk-compasser-net >/dev/null 2>&1 || sudo docker network create cuk-compasser-net + # 4. 이미지 풀 및 서비스 재시작 sudo docker pull ${{ secrets.DOCKER_USERNAME }}/cuk-compasser:$IMAGE_TAG - sudo IMAGE_TAG=$IMAGE_TAG docker-compose -f docker-compose-prod.yml up -d --force-recreate - sudo docker image prune -f + # 5. 미사용 이미지 정리 + sudo docker image prune -f \ No newline at end of file diff --git a/docker-compose-prod.yml b/docker-compose-prod.yml index b50de02..adc4e85 100644 --- a/docker-compose-prod.yml +++ b/docker-compose-prod.yml @@ -15,14 +15,35 @@ services: - AWS_ACCESS_KEY=${AWS_ACCESS_KEY} - AWS_SECRET_KEY=${AWS_SECRET_KEY} - SPRING_PROFILES_ACTIVE=prod + # application.yml의 변수명(${SPRING_DATA_REDIS_HOST})과 일치시킴 + - SPRING_DATA_REDIS_HOST=redis + - SPRING_DATA_REDIS_PORT=6379 + # JWT 및 카카오 설정 (환경변수로 주입) + - JWT_SECRET_KEY=${JWT_SECRET_KEY} + - KAKAO_CLIENT_ID=${KAKAO_CLIENT_ID} + - KAKAO_LOGIN_REDIRECT_URI=${KAKAO_LOGIN_REDIRECT_URI} + - KAKAO_LOCAL_BASE_URL=https://dapi.kakao.com + - KAKAO_REST_API_KEY=${KAKAO_REST_API_KEY} depends_on: mysql-db: condition: service_healthy + redis: + condition: service_started + logging: - driver: loki + driver: "json-file" options: - loki-url: "http://loki:3100/loki/api/v1/push" - loki-external-labels: "job=spring-boot" + max-size: "10m" + max-file: "3" + networks: + - cuk-compasser-net + + redis: + image: redis:latest + container_name: redis + restart: always + ports: + - "6379:6379" networks: - cuk-compasser-net @@ -97,12 +118,13 @@ services: restart: always volumes: - ./promtail/promtail-config.yml:/etc/promtail/config.yml + - /var/run/docker.sock:/var/run/docker.sock + - /var/lib/docker/containers:/var/lib/docker/containers:ro - /var/log:/var/log command: -config.file=/etc/promtail/config.yml networks: - cuk-compasser-net -# AWS 서버 디스크에 생성될 실제 저장 공간 정의 volumes: mysql_data: prometheus_data: diff --git a/promtail/promtail-config.yml b/promtail/promtail-config.yml index b839092..28ca9d8 100644 --- a/promtail/promtail-config.yml +++ b/promtail/promtail-config.yml @@ -9,6 +9,7 @@ clients: - url: http://loki:3100/loki/api/v1/push scrape_configs: + # 1. 기존 시스템 로그 (EC2 자체 로그) - job_name: system static_configs: - targets: @@ -16,4 +17,21 @@ scrape_configs: labels: job: varlogs application: compasser-api - __path__: /var/log/*.log \ No newline at end of file + __path__: /var/log/*.log + + # 2. 도커 컨테이너 로그 (스프링 부트 로그 포함) + - job_name: docker_logs + docker_sd_configs: + - host: unix:///var/run/docker.sock + refresh_interval: 5s + relabel_configs: + - source_labels: [__meta_docker_container_id] + target_label: __path__ + replacement: /var/lib/docker/containers/$1/*-json.log + - source_labels: ['__meta_docker_container_name'] + regex: '/(.*)' + target_label: 'container_name' + - source_labels: ['__meta_docker_container_name'] + regex: '/cuk-compasser-service' + target_label: 'job' + replacement: 'spring-boot' \ No newline at end of file diff --git a/src/main/java/Comprehensive_Design_Project/CUK_Compasser/global/security/config/SecurityConfig.java b/src/main/java/Comprehensive_Design_Project/CUK_Compasser/global/security/config/SecurityConfig.java index 7448ab8..284649a 100644 --- a/src/main/java/Comprehensive_Design_Project/CUK_Compasser/global/security/config/SecurityConfig.java +++ b/src/main/java/Comprehensive_Design_Project/CUK_Compasser/global/security/config/SecurityConfig.java @@ -1,6 +1,8 @@ package Comprehensive_Design_Project.CUK_Compasser.global.security.config; import Comprehensive_Design_Project.CUK_Compasser.global.security.filter.JWTAuthenticationFilter; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -14,6 +16,7 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; @Configuration @RequiredArgsConstructor @@ -39,7 +42,8 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { "/auth/login/**", "/swagger-ui/**", "/swagger-ui.html", - "/v3/api-docs/**" + "/v3/api-docs/**", + "/actuator/**" ).permitAll() .requestMatchers("/stores/**").authenticated() .requestMatchers("/owners/**").authenticated() @@ -60,4 +64,5 @@ public AuthenticationManager authenticationManager(AuthenticationConfiguration c public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } + } \ No newline at end of file diff --git a/src/main/java/Comprehensive_Design_Project/CUK_Compasser/global/security/filter/JWTAuthenticationFilter.java b/src/main/java/Comprehensive_Design_Project/CUK_Compasser/global/security/filter/JWTAuthenticationFilter.java index 6e1b16f..f8ca4f2 100644 --- a/src/main/java/Comprehensive_Design_Project/CUK_Compasser/global/security/filter/JWTAuthenticationFilter.java +++ b/src/main/java/Comprehensive_Design_Project/CUK_Compasser/global/security/filter/JWTAuthenticationFilter.java @@ -136,4 +136,14 @@ private void handleExpiredAccessToken (HttpServletRequest request, HttpServletRe throw new GeneralException(GeneralErrorCode.RT_NOT_FOUND); } } + + @Override + protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { + String path = request.getRequestURI(); + // 이 경로들은 필터 로직을 아예 실행하지 않음 + return path.startsWith("/actuator") + || path.startsWith("/swagger-ui") + || path.startsWith("/v3/api-docs") + || path.startsWith("/favicon.ico"); + } } diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index dd23c24..5510ff1 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -34,6 +34,7 @@ spring: connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000 + pool-name: HikariPool-1 jpa: database-platform: org.hibernate.dialect.MySQLDialect @@ -69,6 +70,11 @@ jwt: secret: key: ${JWT_SECRET_KEY} +kakao: + local: + base-url: https://dapi.kakao.com + rest-api-key: ${KAKAO_REST_API_KEY} + management: endpoints: web: