[GCP/docker] Appengine 배포환경에서 .env 분기하기(부제. env-cmd)

resilient

·

2022. 10. 3. 22:28

728x90
반응형

현재 진행 중인 프로젝트들은 GCP에서 AppEngine이라는 서비스를 이용해서 운영되고 있습니다.

거의 대부분은 GKE환경에서 배포가 되고 운영을 하고 있지만 저희 팀에서 진행 중인 프로젝트는 AppEngine을 사용하고 있죠.

 

(AppEngine에 대해서는 다음 시간에 자세히 다뤄보기로 하고)

오늘은 AppEngine 환경에서 env 파일을 어떻게 사용하는지에 대해 알아보도록 하겠습니다.

 

0. 먼저 React에서 CRA란?

 

현재 프로젝트의 프론트앤드는 CRA(Create-React-App)를 통해서 설계가 되어있습니다.

CRA는 리액트로 웹 애플리케이션을 만들기 위한 환경을 제공해주고 CRA 하나의 명령어만으로 리액트 개발환경을 쉽게 구축할 수 있다는 장점이 있죠. (자세한 내용은 여기 페이지에서 확인 할 수 있습니다.)

 

CRA에는 바벨, 웹팩과 같이 리액트 애플리케이션 실행에 필요한 다양한 패키지가 포함되어 있고 테스트 시스템, ES6+ 문법등 필수적인 개발 환경도 구축해줍니다. 기존 기능을 개선하거나 새로운 기능을 추가했을 때에도 패키지 버전만 올리면 되기 때문에 아주 편리한 보일러 플레이트라고 할 수 있죠.

 

자 이제 본격적으로 AppEngine에서 배포할 때의 env파일 사용법을 알아보겠습니다.

 

1. AppEngine 환경에 배포

 

AppEngine에서는 cloudbuild.yaml라는 파일을 통해 배포를 하게 됩니다. 프론트엔드 배포를 위한 cloudbuild.yaml의 예시를 한번 보겠습니다.

 

steps:
  # Get Secret Token for Private Packages

  - name: "gcr.io/cloud-builders/yarn:node-14.17.1"
    dir: "frontend"
    args: ["install", "--non-interactive", "--frozen-lockfile"]

  - name: "gcr.io/cloud-builders/yarn:node-14.17.1"
    dir: "frontend"
    args: ["run", "create-env"]
    env:
      - "REACT_APP_ENV=${_REACT_APP_ENV}"
      - "REACT_APP_SERVER_ENVIRONMENT=${_REACT_APP_SERVER_ENVIRONMENT}"
      - "SENTRY_BACK_DEV=${_SENTRY_BACK_DEV}"
      - "SENTRY_BACK_PROD=${_SENTRY_BACK_PROD}"
      - "SENTRY_FRONT_DEV=${_SENTRY_FRONT_DEV}"
      - "SENTRY_FRONT_PROD=${_SENTRY_FRONT_PROD}"
      
   - name: "gcr.io/cloud-builders/yarn:node-14.17.1"
    dir: "frontend"
    args: ["build"]

 

두 번째 name필드를 보겠습니다.

(여기서 name필드는 일반적인 도구를 실행하는 컨테이너 이미지인 클라우드 빌더를 지정하기 위한 필드입니다. 빌드 단계에서 빌더를 사용하여 작업을 실행합니다. dir은 말 그대로 작업 디렉토리를 의미하고 args는 인수 목록을 가져오고 name 필드로 참조되는 빌더에 전달합니다. 빌더에 전달된 인수는 명령어를 실행하는 데에 사용하게 되죠. 간단하게 이야기하자면 `args에 있는 명령어가 차례대로 실행이 된다`라고 생각하시면 편리합니다.)

 

run create-app

 

위 명령어를 통해 env 필드에 있는 key=value 형식의 데이터들이 .env 파일로 들어가게 되는데요.

 

1. frontend 폴더에

2. REACT_APP_ENV 변수에 _REACT_APP_ENV의 값을 넣고

3. REACT_APP_SERVER_ENVIRONMENT에 _REACT_APP_SERVER_ENVIRONMENT값을 넣어줘 라는 의미입니다.

 

그럼 이제 run create-app은 뭔가를 실행하라는 거 같긴한데... 뭘 실행하는거야? 라는 의문이 드실 텐데요.

create-app은 package.json에 scripts 부분에 작성해놓은 스크립트입니다. 아래를 보시죠.

"create-env": "printenv | grep -e APP_ENV -e SERVER_ENVIRONMENT > .env"

 

create-env를 실행하면 오른쪽 명령어들을 실행해줘.라는 의미이고, AppEngine 배포 시에 콘솔에 작성해놓은 env들을 가져와서 frontend 디렉토리안의 .env 파일에 담아두게 되는 것이죠.

 

그러면 위 과정들을 통해 env파일이 생성되고 바로 사용이 가능할까요? 아닙니다. 

 

프론트엔드 배포를 위한 cloudbuild.yaml 파일 마지막 필드를 보면 아래와 같습니다.

   - name: "gcr.io/cloud-builders/yarn:node-14.17.1"
    dir: "frontend"
    args: ["build"]

 

즉, react-app을 실행할 때, start를 하지 않고 build를 하게 세팅이 되어있기 때문이죠.

 

여기서 사용하는 것이 오늘의 게시물 부제인 env-cmd입니다.

 

2. env-cmd란? 

 

env-cmd 라이브러리를 사용하는 이유는 위의 문제를 해결하기 위함인데요. 환경변수를 build시에 분기 또는 주입할 수 있는 방법입니다. 

 

env-cmd 라이브러리는 명령줄에 환경 변수를 모두 나열해서 build시 파일에 환경 변수를 넣을 수 있게 해 줍니다. 따라서 env-cmd로 지정한 .env 파일의 모든 환경 변수는 cmd 명령줄에서 사용되고, CRA가 사용하는 모든 .env 파일보다 우선시하기 때문에 build시에 분기할 수 있게 되는 것이죠.

 

3. env-cmd 사용방법

 

그렇다면 env-cmd 사용법을 알아보겠습니다.

 

yarn add env-cmd

yarn 패키지 매니저로 env-cmd를 추가해주고, 아래와 같이 package.json 파일 build 스크립트를 아래와 같이 수정해주면 됩니다.

 

"build": "env-cmd -f .env build",

 

이제 이렇게 수정을 해주면 build로 AppEngine에 앱을 배포한 후에 process.env. {변수명}을 통해 마음껏 환경변수 .env를 사용할 수 있게 됩니다.

 

4. 치명적인 실수

 

이번에 process.env를 사용하기 위해서 작업을 하던 도중 아주 기초적인 실수 때문에 삽질을 좀 오래 했었는데요.

 

cloudbuild.yaml 내의 빌드 순서 때문이었습니다.

 

  - name: "gcr.io/cloud-builders/yarn:node-14.17.1"
    dir: "frontend"
    args: ["install", "--non-interactive", "--frozen-lockfile"]

  - name: "gcr.io/cloud-builders/yarn:node-14.17.1"
    dir: "frontend"
    args: ["run", "create-env"]
    env:
      - "REACT_APP_ENV=${_REACT_APP_ENV}"
      - "REACT_APP_SERVER_ENVIRONMENT=${_REACT_APP_SERVER_ENVIRONMENT}"

  - name: "gcr.io/cloud-builders/yarn:node-14.17.1"
    dir: "frontend"
    args: ["build"]

 

위 name태그 순서에서 맨 아래에 있는 build 하는 명령어와 두 번째 .env를 가져와서 넣어주는 명령어의 순서를 바꾸어서 배포하는 아주 기본적이지만 치명적인 실수를 하는 바람에 삽질을 오래 했었습니다..

 

 

5. 정리

 

이번 게시물에서는 프로젝트를 진행하던 도중 새롭게 알게 된 env-cmd를 통해 AppEngine 환경에서 build 시,. env 환경변수를 사용하기 위해. env에 데이터를 넣는 법을 알아보았습니다. 

 

다음 시간에는 좋은 Error handling이란 무엇일까? 에 대해서 고민하는 글을 작성해보려고 합니다.

 

감사합니다.

반응형