Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,12 @@ jobs:
envs: IMAGE_TAG
script: |
cd ~/BE

# 1. [핵심] 깃허브의 모든 최신 파일(promtail-config 등) 강제 동기화
# 1. 깃허브 최신 파일 동기화
git fetch --all
git reset --hard origin/deploy

# 2. .env 파일 생성 (보안상 필요한 변수들만 주입)
# 기존에 작성하신 echo 방식을 유지하되, 덮어쓰기(>)와 추가(>>)를 구분합니다.
# 2. .env 파일 생성
echo "MYSQL_ROOT_PASSWORD=${{ secrets.MYSQL_ROOT_PASSWORD }}" > .env
echo "MYSQL_DATABASE=${{ secrets.MYSQL_DATABASE }}" >> .env
echo "MYSQL_USER=${{ secrets.MYSQL_USER }}" >> .env
Expand All @@ -88,4 +87,31 @@ jobs:
sudo IMAGE_TAG=$IMAGE_TAG docker-compose -f docker-compose-prod.yml up -d --force-recreate

# 5. 미사용 이미지 정리
sudo docker image prune -f
sudo docker image prune -f

# 6. 디스코드 알림 (성공 시) - SSH 액션 밖으로 분리
- name: Discord Notification - Success
if: success()
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_URL }}
status: success
title: "🚀 배포 완료 (cuk-compasser)"
description: |
**브랜치:** `${{ github.ref_name }}`
**커밋 메시지:** ${{ github.event.head_commit.message }}
성공적으로 EC2에 배포되었습니다!
color: 0x00ff00

# 7. 디스코드 알림 (실패 시) - SSH 액션 밖으로 분리
- name: Discord Notification - Failure
if: failure()
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_URL }}
status: failure
title: "❌ 배포 실패 (cuk-compasser)"
description: |
**브랜치:** `${{ github.ref_name }}`
배포 중 에러가 발생했습니다. Actions 탭에서 로그를 확인해주세요.
color: 0xff0000
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ RUN chmod +x ./gradlew
RUN ./gradlew clean bootJar -x test

# 2. 실행 스테이지
FROM eclipse-temurin:21-jre-jammy
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app

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

RUN apk add --no-cache tzdata
ENV TZ=Asia/Seoul

COPY --from=build /app/build/libs/*SNAPSHOT.jar app.jar

# 실행 시 'prod' 프로파일 활성화
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=prod", "app.jar"]
26 changes: 22 additions & 4 deletions docker-compose-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ services:
- KAKAO_LOGIN_REDIRECT_URI=${KAKAO_LOGIN_REDIRECT_URI}
- KAKAO_LOCAL_BASE_URL=https://dapi.kakao.com
- KAKAO_REST_API_KEY=${KAKAO_REST_API_KEY}
- JAVA_TOOL_OPTIONS=-Xms256m -Xmx256m
depends_on:
mysql-db:
condition: service_healthy
Expand All @@ -35,9 +36,18 @@ services:
options:
max-size: "10m"
max-file: "3"

volumes:
- ./logs:/app/logs

networks:
- cuk-compasser-net

deploy:
resources:
limits:
memory: 400M

redis:
image: redis:latest
container_name: redis
Expand All @@ -64,11 +74,18 @@ services:
networks:
- cuk-compasser-net
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h localhost -u $$MYSQL_USER -p$$MYSQL_PASSWORD"]
test: [ "CMD-SHELL", "mysqladmin ping -h localhost -u $$MYSQL_USER -p$$MYSQL_PASSWORD" ]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
command:
- --innodb_buffer_pool_size=128M # 데이터를 램에 올려두는 캐시 공간을 128MB로 제한
- --max_connections=50 # 동시 접속자(커넥션) 수 50개로 제한
deploy:
resources:
limits:
memory: 300M # 컨테이너 전체 메모리 상한선

prometheus:
image: prom/prometheus:latest
Expand All @@ -91,7 +108,8 @@ services:
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GF_SECURITY_ADMIN_PASSWORD}
- GF_SERVER_DOMAIN=compasser.site
- GF_SERVER_ROOT_URL=%(protocol)s://%(domain)s:%(http_port)s/grafana/
- GF_SERVER_PROTOCOL=http
- GF_SERVER_ROOT_URL=https://compasser.site/grafana/
- GF_SERVER_SERVE_FROM_SUB_PATH=true
volumes:
- grafana_data:/var/lib/grafana
Expand All @@ -118,9 +136,9 @@ services:
restart: always
volumes:
- ./promtail/promtail-config.yml:/etc/promtail/config.yml
- /var/run/docker.sock:/var/run/docker.sock
- ./logs:/var/log/spring-app:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/log:/var/log
- /var/run/docker.sock:/var/run/docker.sock
command: -config.file=/etc/promtail/config.yml
networks:
- cuk-compasser-net
Expand Down
39 changes: 21 additions & 18 deletions promtail/promtail-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,32 @@ clients:
- url: http://loki:3100/loki/api/v1/push

scrape_configs:
# 1. 기존 시스템 로그 (EC2 자체 로그)
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
application: compasser-api
__path__: /var/log/*.log

# 2. 도커 컨테이너 로그 (스프링 부트 로그 포함)
- job_name: docker_logs
# 1. 도커 컨테이너 로그 직접 수집 (강력 추천 방식)
- job_name: docker_containers
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
# 컨테이너 이름을 추출해서 'container_name' 라벨로 저장
- source_labels: ['__meta_docker_container_name']
regex: '/(.*)'
target_label: 'container_name'
- source_labels: ['__meta_docker_container_name']
regex: '/cuk-compasser-service'
# 로그 파일 경로 설정
- source_labels: [__meta_docker_container_id]
target_label: __path__
replacement: /var/lib/docker/containers/$1/*-json.log
# 특정 컨테이너(cuk-compasser-service)를 'spring-boot' job으로 식별
- source_labels: ['container_name']
regex: 'cuk-compasser-service'
target_label: 'job'
replacement: 'spring-boot'
replacement: 'spring-boot'

# 2. 백업: 파일 직접 수집 (컨테이너 내부 logs 폴더)
- job_name: spring-boot-file
static_configs:
- targets:
- localhost
labels:
job: spring-boot
container_name: cuk-compasser-service
__path__: /var/log/spring-app/*.log
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
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 Comprehensive_Design_Project.CUK_Compasser.global.security.jwt.JWTProvider;
import Comprehensive_Design_Project.CUK_Compasser.global.security.userDetails.CustomUserDetailsService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
Expand All @@ -16,16 +17,19 @@
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
public class SecurityConfig {

private final JWTAuthenticationFilter jwtAuthenticationFilter;
@Bean
public JWTAuthenticationFilter jwtAuthenticationFilter(JWTProvider jwtProvider, RedisTemplate<String, Object> redisTemplate, CustomUserDetailsService customUserDetailsService) {
return new JWTAuthenticationFilter(jwtProvider, redisTemplate, customUserDetailsService);
}

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
SecurityFilterChain securityFilterChain(HttpSecurity http, JWTAuthenticationFilter jwtAuthenticationFilter) throws Exception {

http
.csrf(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
Expand Down Expand Up @@ -55,6 +59,7 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.build();
}


@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
return configuration.getAuthenticationManager();
Expand Down
Loading
Loading