본문 바로가기

web

[spring boot / react / nginx / docker-compose] local, dev, prd 환경 분리

상황

사이드 프로젝트에서 서버 한대에서 front, back을 컨테이너 기반으로 돌리는 중

비용 문제로 서버는 한대로 유지한 채, 운영 중인 서비스에는 영향이 없도록 테스트용 dev환경을 구축하고 싶음

 

아키텍처

reverse proxy로 nginx를 구동

spring boot, react, docker-compose 사용

db 사용

 

서버 환경 분리

1. spring boot 환경 분리

- src/main/resource/application.yml를 분리

 

1) 기존 application.yml에 local, dev, prd 추가

- default는 가장 하단에 기입된 환경 (여기서는 local)

... // 기존 application

---
spring:
  profiles:
    active: prd
---
spring:
  profiles:
    active: dev
---
spring:
  profiles:
    active: local

 

2) 환경 별 application.yml 추가

application-prd.yaml

spring:
  datasource:
    url: jdbc:mysql://....... // prd환경의 db url
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

application-dev.yaml

spring:
  datasource:
    url: jdbc:mysql://....... // dev환경의 db url
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

application-local.yaml

spring:
  datasource:
    url: jdbc:mysql://....... // local환경의 db url
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

 

 

3) 환경 지정해서 실행

java -jar -Dspring.profiles.active=$ENV *.jar 명령어 실행

 

- dockerfile 분리해서 실행

Dockerfile.dev

FROM adoptopenjdk:11-jdk-hotspot AS builder

COPY gradlew .
COPY gradle gradle
COPY build.gradle .
COPY settings.gradle .
COPY src src
RUN chmod +X ./gradlew
RUN ./gradlew bootJar

FROM adoptopenjdk:11-jdk-hotspot
COPY --from=builder build/libs/*.jar a.jar

EXPOSE 8080
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=dev", "/a.jar"]

Dockerfile.prd

FROM adoptopenjdk:11-jdk-hotspot AS builder

COPY gradlew .
COPY gradle gradle
COPY build.gradle .
COPY settings.gradle .
COPY src src
RUN chmod +X ./gradlew
RUN ./gradlew bootJar

FROM adoptopenjdk:11-jdk-hotspot
COPY --from=builder build/libs/*.jar a.jar

EXPOSE 8080
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=prd", "/a.jar"]

 

 

실행 모습 - 환경을 확인할 수 있음

2. react 환경 분리

환경변수를 이용한 분리

환경변수로 LOCAL / DEV / PRD를 구분해서 주입하면서 실행시킴

1) npm install cross-env

 

2) package.json에 scripts 추가

.env파일에 추가할 환경변수를 script에서 다이나믹하게 설정할 수 있음

REACT_APP_ENV 변수에 LOCAL/DEV/PRD를 넣음

 

ex)

npm run start 를 실행하면 기본값으로 실행됨

npm run start:dev 를 실행하면 REACT_APP_ENV가 DEV로 설정되어서 실행됨

npm run start:prd 를 실행하면 REACT_APP_ENV가 PRD로 설정되어서 실행됨

  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "start:dev": "cross-env REACT_APP_ENV=DEV react-scripts start", // dev환경 추가
    "start:prd": "cross-env REACT_APP_ENV=PRD react-scripts start" // prd환경 추가
  },

 

3) .env 설정

필요한 내용들을 기입함

.env파일을 환경별로 나눠서 사용할 수 도 있음

현재는 관리할 변수가 backend url 하나밖에 없어서 한 파일에서 관리함

REACT_APP_ENV=LOCAL
REACT_APP_BACK_URL_LOCAL=http://localhost:8080
REACT_APP_BACK_URL_DEV=http://dev.back.abc.co.kr
REACT_APP_BACK_URL_PRD=http://back.abc.co.kr

 

4) 환경 별 env 가져오기

function getBackURL() {
  if (process.env.REACT_APP_ENV === "DEV")
    return process.env.REACT_APP_BACK_URL_DEV;
  if (process.env.REACT_APP_ENV === "PRD")
    return process.env.REACT_APP_BACK_URL_PRD;
  return process.env.REACT_APP_BACK_URL_LOCAL;
}

export const BACK_URL = getBackURL();

 

5) dockerfile 설정

npm run start:dev

npm run start:prd

명령어로 실행

 

Dockerfile.dev

FROM node:alpine

WORKDIR '/app'

COPY package.json .
RUN npm install

COPY . .

CMD ["npm", "run", "start:dev"]

 

Dockerfile.prd

FROM node:alpine

WORKDIR '/app'

COPY package.json .
RUN npm install

COPY . .

CMD ["npm", "run", "start:prd"]

 

 

실행 모습 - 환경 확인 가능

 

3. docker-compose 설정

docker-compose-dev.yml, docker-compose-prd.yml 분리

 

nginx는 dev, prd 공동으로 사용함

 

docker-compose-dev.yml

version: "3"

services:
  proxy:
    container_name: abc-proxy
    restart: always
    build: ./proxy
    ports:
      - "80:80"
    extra_hosts:
      - host.docker.internal:host-gateway

  dev-frontend:
    container_name: dev-abc-frontend
    restart: always
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    ports:
      - "3001:3000"

  dev-backend:
    container_name: dev-abc-backend
    restart: always
    build:
      context: ./backend
      dockerfile: Dockerfile.dev
    ports:
      - "8081:8080"
    extra_hosts:
      - host.docker.internal:host-gateway

 

docker-compose-prd.yml

version: "3"

services:
  proxy:
    container_name: abc-proxy
    restart: always
    build: ./proxy
    ports:
      - "80:80"
    extra_hosts:
      - host.docker.internal:host-gateway

  frontend:
    container_name: abc-frontend
    restart: always
    build:
      context: ./frontend
      dockerfile: Dockerfile.prd
    ports:
      - "3000:3000"

  backend:
    container_name: abc-backend
    restart: always
    build:
      context: ./backend
      dockerfile: Dockerfile.prd
    ports:
      - "8080:8080"
    extra_hosts:
      - host.docker.internal:host-gateway

 

필요한 docker-compose를 구동시켜서 배포

ex) dev 환경

echo killing old docker processes
docker-compose -f docker-compose-dev.yml rm -fs

echo building docker containers
docker-compose -f docker-compose-dev.yml up --build -d

 

4. nginx.conf 설정

dev와 prd가 공동으로 nginx.conf를 사용함

upstream으로 서버를 구분해서 연결

upstream front-server {
    server host.docker.internal:3000;
}

upstream back-server {
    server host.docker.internal:8080;
}

upstream dev-front-server {
    server host.docker.internal:3001;
}

upstream dev-back-server {
    server host.docker.internal:8081;
}

server {
    server_name abc.co.kr;
    listen 80;

    location / {
        proxy_pass       http://front-server;
    }

    location /ws {
        proxy_pass http://front-server;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header Origin "";
    }
}

server {
    server_name back.abc.co.kr;
    listen 80;

    location / {
        proxy_pass         http://back-server;
    }
}

server {
    server_name dev.abc.co.kr;
    listen 80;

    location / {
        proxy_pass       http://dev-front-server;
    }

    location /ws {
        proxy_pass http://dev-front-server;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header Origin "";
    }
}

server {
    server_name dev.back.abc.co.kr;
    listen 80;

    location / {
        proxy_pass         http://dev-back-server;
    }
}

 

 

배포 완료!

- reverse-proxy

- dev-front

- dev-back

- prd-front

- prd-back

(proxy는 한번 배포해놓고 docker-compose에서 주석처리해놓아서 dev와 prd가 서로서로 배포될 때 영향이 없게함)