kjp0411 님의 블로그

내일배움캠프 단기심화 Java - 본 캠프 Day 55 본문

TIL

내일배움캠프 단기심화 Java - 본 캠프 Day 55

kjp0411 2026. 4. 30. 15:22

TIL - 2026.04.30

오늘 한 일

  • MSA 티켓팅 프로젝트의 로컬 통합 실행 구조를 정리했다.
  • 기존에 제각각 사용하던 포트 체계를 인프라/도메인 기준으로 정리했다.
  • Eureka Server 포트를 17001에서 10001로 변경했다.
  • Config Server 포트를 8888에서 10002로 변경했다.
  • Gateway Service 포트를 8000에서 10000으로 변경했다.
  • User Service 포트를 8081에서 20001로 변경했다.
  • Config Server, Eureka Server, Gateway Service, User Service를 순서대로 실행하여 정상 동작을 확인했다.
  • Eureka Dashboard에서 GATEWAY-SERVICE, USER-SERVICE가 정상 등록되는 것을 확인했다.
  • Gateway 경유로 User 회원가입 API와 회원 목록 조회 API를 테스트했다.
  • Bearer Token이 없는 경우 401 Unauthorized, 토큰이 있는 경우 200 OK가 반환되는 것을 확인했다.
  • Payment Service도 통합 실행 구조에 맞추기 위해 Config Server / Eureka 연동 방향을 팀원에게 공유했다.

오늘 정리한 포트 체계

인프라 영역

서비스 포트
Gateway Service 10000
Eureka Server 10001
Config Server 10002

도메인 영역

서비스 포트
User Service 20001
Match Service 20002
Club Service 20003
Seat Service 20004
Reservation Service 20005
Payment Service 20006
Queue Service 20007

오늘 배운 점

1. Config Server 주소는 서비스 내부 application.yml에 남아 있어야 한다

Config Server를 사용하더라도 각 서비스는 처음 실행될 때 Config Server 위치를 알아야 한다.

따라서 서비스 내부 application.yml에는 최소한 아래 설정이 필요하다.

spring:
  application:
    name: user-service

  config:
    import: optional:configserver:http://localhost:10002

반대로 DB, JPA, Kafka, Eureka, Security 같은 실제 실행 설정은 config-repo에서 관리하는 방향이 더 적절하다.


2. Config Server 포트를 바꾸면 각 Config Client도 같이 수정해야 한다

처음에는 Config Server 포트만 8888에서 10002로 바꾸면 된다고 생각했다.

하지만 User Service와 Gateway Service 내부 application.yml이 계속 localhost:8888을 바라보고 있어서 설정을 읽지 못했다.

그 결과 User Service에서는 datasource 설정을 읽지 못해 아래 오류가 발생했다.

Failed to configure a DataSource: 'url' attribute is not specified

즉, 원인은 DB 자체 문제가 아니라 Config Server 설정을 못 읽어서 spring.datasource.url이 주입되지 않은 것이었다.


3. Gateway의 ReactiveJwtDecoder 오류도 Config Server 설정 미적용이 원인이었다

Gateway 실행 중 아래와 같은 오류가 발생했다.

No qualifying bean of type 'org.springframework.security.oauth2.jwt.ReactiveJwtDecoder' available

처음에는 Security 설정 문제처럼 보였지만, 실제 원인은 Gateway가 Config Server 설정을 읽지 못한 것이었다.

Gateway가 config-repo/gateway-service.yml을 읽지 못하니 issuer-uri가 적용되지 않았고, 그 결과 JWT Decoder Bean이 생성되지 않았다.

Config Server 주소를 10002로 수정한 뒤 정상 실행되었다.


오늘 해결한 문제

문제 1. Eureka Server 포트 변경

기존 Eureka Server는 17001로 실행되고 있었다.

이번에 포트 체계를 정리하면서 10001로 변경했다.

server:
  port: 10001

Eureka Dashboard 접속 주소도 아래처럼 변경되었다.

http://localhost:10001

문제 2. Config Server 포트 변경

기존 Config Server는 8888로 실행되고 있었다.

포트 체계를 맞추기 위해 10002로 변경했다.

server:
  port: 10002

Config Server는 Eureka에 등록하지 않아도 된다.

현재 구조에서는 각 서비스가 직접 Config Server 주소를 알고 설정을 가져오는 방식이기 때문이다.


문제 3. User Service Config Server 주소 변경

기존 User Service 내부 설정은 아래처럼 되어 있었다.

spring:
  application:
    name: user-service

  config:
    import: "optional:configserver:http://localhost:8888"

eureka:
  client:
    service-url:
      defaultZone: http://localhost:17001/eureka/

이를 아래처럼 최소화했다.

spring:
  application:
    name: user-service

  config:
    import: optional:configserver:http://localhost:10002

Eureka 설정은 config-repo/user-service.yml에서 관리하도록 분리했다.


문제 4. Gateway Service Config Server 주소 변경

Gateway도 기존에는 localhost:8888을 바라보고 있었다.

이를 localhost:10002로 변경했다.

spring:
  application:
    name: gateway-service

  config:
    import: optional:configserver:http://localhost:10002

Gateway의 실제 포트, 라우팅, JWT 설정, Eureka 설정은 config-repo/gateway-service.yml에서 관리한다.


테스트 결과

1. Eureka Dashboard 확인

Eureka Dashboard에서 아래 서비스가 정상 등록된 것을 확인했다.

GATEWAY-SERVICE : 10000
USER-SERVICE    : 20001

접속 주소:

http://localhost:10001

2. Gateway 경유 회원가입 성공

요청:

POST http://localhost:10000/api/users

결과:

200 OK

의미:

  • Gateway가 User Service로 정상 라우팅됨
  • User Service가 Config Server 설정을 정상 로딩함
  • User Service가 DB에 정상 접근함

3. Gateway 경유 회원 목록 조회 성공

Bearer Token을 넣고 요청했다.

GET http://localhost:10000/api/users

결과:

200 OK

의미:

  • Gateway JWT 인증 정상
  • User Service 라우팅 정상
  • Eureka 기반 서비스 디스커버리 정상

4. 인증 없는 요청 차단 확인

Bearer Token 없이 요청했다.

GET http://localhost:10000/api/users

결과:

401 Unauthorized

의미:

  • 보호 API 인증 정책 정상 적용
  • Gateway Security 설정 정상 적용

Payment Service 관련 정리

Payment Service는 기존에 로컬 단독 실행 기준으로 설정되어 있었다.

기존 설정에는 Config Server와 Eureka를 차단하는 설정이 포함되어 있었다.

spring:
  cloud:
    config:
      import-check:
        enabled: false
      discovery:
        enabled: false

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

이제 전체 MSA 통합 실행 기준으로 맞추기 위해 아래 방향으로 변경하기로 했다.

payment-service 내부 application.yaml

서비스 내부 설정은 Config Server만 바라보도록 최소화한다.

spring:
  application:
    name: payment-service

  main:
    allow-bean-definition-overriding: true

  config:
    import: optional:configserver:http://${CONFIG_SERVER_HOST:localhost}:${CONFIG_SERVER_PORT:10002}

config-repo/payment-service.yml

실제 실행 설정은 config-repo에서 관리한다.

server:
  port: ${PAYMENT_PORT:20006}

spring:
  application:
    name: payment-service

  main:
    allow-bean-definition-overriding: true

  datasource:
    url: jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_PORT:15432}/${POSTGRES_DB:ticketing}?currentSchema=${PAYMENT_SCHEMA:payment}
    username: ${POSTGRES_USER:ticketing}
    password: ${POSTGRES_PASSWORD:change-me-local}
    driver-class-name: org.postgresql.Driver

  jpa:
    hibernate:
      ddl-auto: ${JPA_DDL_AUTO:update}
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQLDialect
        default_schema: ${PAYMENT_SCHEMA:payment}
        hbm2ddl:
          create_schemas: true

  kafka:
    bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:localhost:19092}
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer

eureka:
  client:
    enabled: true
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: ${EUREKA_DEFAULT_ZONE:http://localhost:10001/eureka/}

toss:
  secret-key: ${TOSS_SECRET_KEY:}

오늘 느낀 점

MSA에서는 단순히 포트 하나를 바꾸는 작업도 여러 레포에 영향을 준다.

Config Server 포트를 바꾸면 각 서비스의 spring.config.import도 바꿔야 하고, Eureka 포트를 바꾸면 각 서비스의 Eureka Client 설정도 같이 맞춰야 한다.

처음에는 이슈와 PR을 여러 개 나눠야 해서 번거롭게 느껴졌지만, 레포별로 변경 범위를 분리하니 어떤 설정이 어디에 영향을 주는지 더 명확하게 보였다.

특히 오늘은 Config Server, Eureka Server, Gateway, User Service가 실제로 연결되는 흐름을 직접 확인했다.

단순히 "MSA 구조를 사용했다"가 아니라, 서비스 설정 중앙화, 서비스 디스커버리, Gateway 라우팅, JWT 인증 흐름까지 직접 검증했다는 점에서 의미 있는 작업이었다.


내일 이어서 할 일

  • Payment Service 내부 application.yaml 수정 반영 확인
  • config-repo/payment-service.yml 최종 확인
  • Gateway에 Payment Service 라우팅 추가
  • Payment Service 실행 후 Eureka 등록 확인
  • Gateway 경유 Payment API 테스트
  • 나머지 서비스도 Config Server / Eureka 기준으로 순차 연결