diff --git a/.env.example b/.env.example index 154313d..c4cb91d 100644 --- a/.env.example +++ b/.env.example @@ -40,3 +40,5 @@ KAFKA_BOOTSTRAP_SERVERS=kafka1:9092,kafka2:9092 # 주의: SSL 파일은 컨테이너 내 절대 경로(/app/ssl/...)로 지정해야 합니다. SPRING_KAFKA_SSL_TRUST_STORE_LOCATION=/app/ssl/kafka.server.truststore.jks TRUST_STORE_PASSWORD=your_truststore_password + +ZIPKIN_ENDPOINT=http://localhost:9411/api/v2/spans diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 210db4e..1a4595c 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -15,7 +15,7 @@ env: AR_IMAGE_PATH: ${{ vars.AR_IMAGE_PATH }} WORK_DIR: /opt/user-service HEALTH_RETRIES: 30 - HEALTH_INTERVAL: 10 + HEALTH_INTERVAL: 5 jobs: build-and-push: @@ -165,6 +165,12 @@ jobs: --zone="${{ matrix.zone }}" \ --project="$GCP_PROJECT" \ --tunnel-through-iap + + gcloud compute scp deploy/promtail-config.yml \ + ${{ matrix.vm }}:/tmp/promtail-config.yml \ + --zone="${{ matrix.zone }}" \ + --project="$GCP_PROJECT" \ + --tunnel-through-iap - name: Deploy and verify on ${{ matrix.vm }} id: deploy_run @@ -186,6 +192,7 @@ jobs: sudo mkdir -p $WORK_DIR sudo mv /tmp/docker-compose.prod.yaml $WORK_DIR/docker-compose.prod.yaml + sudo mv /tmp/promtail-config.yml $WORK_DIR/promtail-config.yml cd $WORK_DIR test -f .env || { echo '.env not found in $WORK_DIR'; exit 1; } @@ -255,13 +262,13 @@ jobs: sudo env IMAGE_TAG=\"$ROLLBACK_TAG\" AR_IMAGE_PATH=\"${{ env.AR_IMAGE_PATH }}\" docker compose -f docker-compose.prod.yaml pull sudo env IMAGE_TAG=\"$ROLLBACK_TAG\" AR_IMAGE_PATH=\"${{ env.AR_IMAGE_PATH }}\" docker compose -f docker-compose.prod.yaml up -d - for i in \$(seq 1 18); do + for i in \$(seq 1 $HEALTH_RETRIES); do if curl -sf http://localhost:8081/actuator/health \ | grep -q '\"status\":\"UP\"'; then echo \"Rollback container UP (attempt \$i)\" exit 0 fi - sleep 10 + sleep $HEALTH_INTERVAL done echo 'Rollback container did not become healthy.' diff --git a/build.gradle b/build.gradle index 9b425b2..fb89def 100644 --- a/build.gradle +++ b/build.gradle @@ -30,8 +30,9 @@ repositories { dependencies { - implementation 'org.pgsg:common:0.2.10-SNAPSHOT' + implementation 'org.pgsg:common:0.3.2-SNAPSHOT' implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'io.micrometer:micrometer-registry-prometheus' // postgres - UUID 네이티브 타입 지원 runtimeOnly 'org.postgresql:postgresql' diff --git a/deploy/docker-compose.prod.yaml b/deploy/docker-compose.prod.yaml index 8fb7ae1..6277fbc 100644 --- a/deploy/docker-compose.prod.yaml +++ b/deploy/docker-compose.prod.yaml @@ -12,6 +12,17 @@ services: networks: - pgsg-network + promtail: + image: grafana/promtail:2.9.1 + container_name: user-service-promtail + restart: always + volumes: + - /opt/user-service/promtail-config.yml:/etc/promtail/config.yml + - /opt/user-service/logs:/logs + command: -config.file=/etc/promtail/config.yml + networks: + - pgsg-network + networks: pgsg-network: external: true \ No newline at end of file diff --git a/deploy/promtail-config.yml b/deploy/promtail-config.yml new file mode 100644 index 0000000..d36242b --- /dev/null +++ b/deploy/promtail-config.yml @@ -0,0 +1,14 @@ +server: + http_listen_port: 9080 + +clients: + - url: ${LOKI_URL:-http://loki:3100/loki/api/v1/push} + +scrape_configs: + - job_name: user-service + static_configs: + - targets: + - localhost + labels: + job: user-service + __path__: /logs/*.log \ No newline at end of file diff --git a/src/main/java/org/pgsg/user_service/auth/infrastructure/security/config/UserSecurityConfig.java b/src/main/java/org/pgsg/user_service/auth/infrastructure/security/config/UserSecurityConfig.java index 33778d4..8ad3adf 100644 --- a/src/main/java/org/pgsg/user_service/auth/infrastructure/security/config/UserSecurityConfig.java +++ b/src/main/java/org/pgsg/user_service/auth/infrastructure/security/config/UserSecurityConfig.java @@ -43,7 +43,7 @@ public SecurityFilterChain filterChain(HttpSecurity http, UserAuthenticator user .requestMatchers("/api/v1/auth/login", "/api/v1/auth/signup", "/api/v1/auth/reissue").permitAll() .requestMatchers("/internal/v1/**").permitAll() .requestMatchers("/favicon.ico", "/error").permitAll() - .requestMatchers("/actuator/health", "/actuator/info").permitAll() + .requestMatchers("/actuator/**").permitAll() .anyRequest().authenticated() ) // LoginFilter는 회원 아이디, 비밀번호 검증 이전에 먼저 실행 -> 이미 SecurityContext에 등록된 사용자 정보가 있으면 자동 통과 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 5bb6310..6b49a02 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -49,3 +49,12 @@ eureka: fetch-registry: true service-url: defaultZone: ${EUREKA_SERVER_URL:http://localhost:8761/eureka/} + + +management: + tracing: + sampling: + probability: 0.1 + zipkin: + tracing: + endpoint: ${ZIPKIN_ENDPOINT:http://localhost:9411/api/v2/spans}