• Spring Boot PROD 운영환경으로 올리기: Gateway 올리기

    2026. 6. 7.

    by. Daramu

    Spring Boot 를 prod환경으로 올릴 것이다.

    개발환경은 localhost로 지정되었었지만, 운영 환경은 localhost로 올리는것이 불가능하다.

     

    그렇기에 CORS 설정먼저 진행해야 한다.

     

    우선 yaml파일을 두개로 나누어야 한다.

     

    기존에 localhost로 정의되어있는 것을 local로, cp로 새롭게 만든걸 prod로 하였다.

     

    여기서 "allowed-origins" 위치를 지정해준다.

    application-local:

     

    application-prod:

     

    추가로 주소도 변경해야 한다. 전에는 localhost:8081 이런식이었지만, 이제는 쿠버네티스 환경이기에 localhost가 클러스터 내부를 가르키지 않고 pod내부를 가르키므로 작동하지 않는다.

    이런식으로 쿠버네티스 FQDN+ 를 사용한다.

    http://{서비스명}.{네임스페이스}.svc.cluster...

     

    여기서 localhost로 돌릴때는 포트 중복이 안되기에 8081, 8082 등을 사용했지만, 

    격리된 환경인 쿠버네티스라면 신경쓸 필요 없이 8080으로 통일하면 된다.

     

    application 파일을 수정했다면, 이제는 CORS 설정 파일을 변경해야 한다.

    기존에는 아래처럼 되어있었다.

        @Bean
        public CorsConfigurationSource corsConfigurationSource() {
            CorsConfiguration config = new CorsConfiguration();
            config.setAllowedOrigins(List.of(
                    "http://localhost:5173"
            ));
            config.setAllowedMethods(List.of("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
            config.setAllowedHeaders(List.of("*"));
            config.setAllowCredentials(true); 
            config.setMaxAge(3600L);
    
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", config);
            return source;
        }

     

    하지만 운영환경에서는 localhost:5137 같은 코드가 하드코딩되어있다면 개발/운영 두가지 환경에 반응하지 못함으로, 

    다음과 같이 수정해준다.

    ....
        @Value("${app.cors.allowed-origins}")
        private String allowedOrigins;
    ....
        @Bean
        public CorsConfigurationSource corsConfigurationSource() {
            CorsConfiguration config = new CorsConfiguration();
            config.setAllowedOrigins(Arrays.asList(allowedOrigins.split(",")));
    ....
        }

     

     

    그렇게 분리했다면, 이제 deployment 같은 쿠버네티스 파일과 dockerfile을 준비할 차례다.

    [Dockerfile]

    FROM eclipse-temurin:26-jdk-noble AS builder
     
    WORKDIR /app
     
    COPY gradlew ./
    COPY gradle ./gradle
    RUN chmod +x gradlew
     
    COPY build.gradle.kts settings.gradle.kts ./
    RUN ./gradlew dependencies --no-daemon
     
    COPY src ./src
    RUN ./gradlew bootJar --no-daemon -x test
    
    FROM eclipse-temurin:26-jre-noble
     
    WORKDIR /app
     
    RUN groupadd -r appuser && useradd -r -g appuser appuser
     
    COPY --from=builder /app/build/libs/gateway-0.0.1-SNAPSHOT.jar app.jar
    RUN chown appuser:appuser app.jar
     
    USER appuser
     
    EXPOSE 8080
     
    ENTRYPOINT ["java", "-jar", "app.jar"]

     

    그리고 deployment 파일인데, 여기서 application 파일이 두개로 나뉜만큼 어떤 yaml파일을 사용할 것인지 정의해준다.

    #deployment.yaml 일부
              env:
                - name: SPRING_PROFILES_ACTIVE
                  value: "prod"

     

     

    이렇게 진행하고 deployment, service, ingress 까지 설정하고 클라우드 플레어로 등록해 준다.

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: gateway-ingress
      namespace: default
      annotations:
        nginx.ingress.kubernetes.io/ssl-redirect: "true"
    spec:
      ingressClassName: nginx
      tls:
        - hosts:
            - api.daramu.co.kr
          secretName: daramu-wildcard-tls
      rules:
        - host: api.daramu.co.kr
          http:
            paths:
              - path: /
                pathType: Prefix
                backend:
                  service:
                    name: gateway-service
                    port:
                      number: 8080

     

     

    단. 여기서 조심해야 할 것이 있다.

    바로 다른 사용자가 API를 호출하면 안되는 것이다.

     

    브라우저 단에서는 Gateway 설정으로 도메인만 호출할 수 있다.

    그련데 그건 브라우저고, postman 같은 API요청은 막을 수 없는데, 여기서 anyExchange() 옵션으로 jwt토큰이 없다면 401을 반환하게 설정하는 것으로 공격을 막을 수 있다.

     

    당연하겠지만, react에서는 api.daramu.co.kr을 바라보고 있어야한다.

    .env파일에서 수정해도 되지만, 본 포스팅의 경우 gitlab runner를 사용하는 관계로 그냥 Varialbe 처리해 버렸다.

     

    아무튼 react가 바라보는 주소를 자신의 도메인 주소(클라우드 플레어에서 DNS 처리한 주소)로 바꾸는걸 잊지 말아야한다.

    댓글