Bitbucket Pipelines로 Google App Engine에 자동 배포 시 안전하게 환경변수 추가하기

modolee
CrocusEnergy
Published in
8 min readOct 20, 2020

Bitbucket Pipelines로 Google App Engine에 자동 배포 시 안전하게 환경변수를 추가하는 방법을 소개합니다.

개발/배포 환경

  • 서버 : Google App Engine
    - runtime : custom
    - env: flex
  • 소스 관리 : Bitbucket
  • CI/CD 툴 : Bitbucket Pipelines

문제점

  • 일반적으로 Google App Engine 설정 파일 (app.yaml)에 환경 변수를 추가하는 방법은 env_varibles 항목에 key:value 형태로 평문 그대로 저장하는 방식입니다.
  • app.yaml 파일에 API Key, Auth Token 등의 노출되면 안되는 정보들이 그대로 노출됩니다.
  • app.yaml 파일에 직접 저장하는 방식이 아니라, 배포 시에 동적으로 추가해 주는 방식이 필요합니다.
  • Bitbucket 또는 GCP에 환경변수를 저장하고 사용하는 방식 중 한가지를 선택해야 합니다.

해결 방법 탐색

  • 구글링을 통해서 다양하게 찾아 봤지만, 딱 알맞게 적용할 수 있는 방법은 찾지 못했습니다.
  • Google Datastore에 저장하고 소스에서 직접 API를 호출해서 가져오는 방법은 GCP에 너무 종속적인 코드가 되는 것 같아서 제외 했습니다.
  • 배포 시에 .env 파일을 만드는 방법은 App Engine이 standard 환경 일 때는 동작하지만 flex 환경일 때는 동작하지 않습니다.
  • App Engine 배포 전 bitbucket pipelines 스크립트 실행 부분에서 수동으로 환경변수를 app.yaml 파일에 추가해 주는 방법이 그나마 괜찮은 방법 같았습니다.

해결 방법

  1. Bitbucket에 환경변수를 저장
  2. 저장 된 환경변수 이름을 관리하는 파일을 프로젝트에 추가
  3. 저장 된 환경변수 이름을 불러와서 app.yaml 파일에 추가하는 스크립트 생성
  4. Bitbucket pipelines를 통해서 Google App Engine으로 배포하기 직전에 해당 스크립트 실행

Bitbucket에 환경변수 저장

  • 기존에 app.yaml 에 평문으로 저장되어 있던 환경변수를 모두 Bitbucket에 저장합니다.
  • Bitbucket의 Repository settings > PIPELINES > Deployments 페이지로 이동하여 환경변수를 추가합니다.
  • Secured 옵션을 선택하고 저장 한 값은 다시 확인이 불가능하니 반드시 별도로 저장하시기 바랍니다.

환경변수 목록 파일 추가

  • 프로젝트 루트에 .env.array 파일을 생성합니다.
  • 생성 된 파일에 배포 시 자동으로 추가 할 환경변수 이름을 한 줄에 하나씩 추가합니다.
TEST_ENV1
TEST_ENV2
TEST_ENV3

환경변수 추가 스크립트 추가

  • 프로젝트 루트에 add-env-to-gae-conf.sh 파일을 생성합니다.
  • 아래 스크립트 코드를 복사해 붙여 넣습니다.
#!/bin/bash# Set default file input/output name
FILE_INPUT_NAME=.env.array
FILE_OUTPUT_NAME=app.yaml
# Set file input/output name, when user add options
while getopts "i:o:" opt; do
case $opt in
i)
FILE_INPUT_NAME=$OPTARG ;;
o)
FILE_OUTPUT_NAME=$OPTARG ;;
*) echo "usage: $0 [-i] [-o]" >&2
exit 1 ;;
esac
done
# Read all environment variables that have to be copied from input file
declare env_array=()
while IFS= read -r line || [[ "$line" ]]; do
env_array+=("$line")
done < "${FILE_INPUT_NAME}"
# Print all environment variables to output file
if [ "${#env_array[@]}" -eq 0 ]; then
echo "There is no environment variables";
else
{ printf "\n\n"; printf "env_variables:"; printf "\n"; } >> "${FILE_OUTPUT_NAME}";
for i in "${env_array[@]}";
do
printf " %s\n" "${i}: ${!i}" >> "${FILE_OUTPUT_NAME}";
done
fi;
  • 스크립트 저장소 바로가기
  • 기본 입력 파일 (.env.array), 기본 출력 파일 (app.yaml) 이 설정되어 있고, -i, -o 옵션을 통해서 변경 가능합니다.
  • 입력 파일을 읽어서 해당 파일에 저장 된 환경변수 목록을 읽어 환경변수 이름: 값 형태로 출력 파일 가장 하단에 추가합니다.
  • env_variables 항목을 통째로 추가하는 것이기 때문에 기존에 env_variables 항목이 정의되어 있다면 삭제해야 정상적으로 동작합니다.
  • 실행되는 머신에 저장 된 환경변수를 app.yaml 파일에 유동적으로 추가해 줍니다.
  • app.yaml 파일 하단에 아래와 같이 추가 됩니다.
env_variables:
TEST_ENV1: test string 1
TEST_ENV2: test string 2
TEST_ENV3: test string 3

환경변수 추가 스크립트 확인

  • 로컬 머신에서 아래 명령을 실행하면 app.yaml 파일에 환경변수가 추가 되는 것을 확인할 수 있습니다.
export TEST_ENV1='test string 1'
export TEST_ENV2='test string 2'
export TEST_ENV3='test string 3'
bash add-env-to-gae-conf.sh

Bitbucket Pipelines 배포 설정에 환경변수 추가 스크립트 실행 추가

  • bitbucket-pipelines.yml 파일 중 Google App Engine 배포 단계의 스크립트에 환경변수 추가 스크립트를 실행합니다.
  • node:alpine 이미지를 기본으로 사용하여 bash를 별도로 설치해 줍니다.
  • 스크립트의 실행 권한을 주고, 스크립트를 실행한 후 정상적으로 추가 됐는지 확인하기 위해 출력합니다.
image: node:alpinerun-test: &run-test
step:
name: Run jest unit test
caches:
- node
script:
- yarn
- yarn test
deploy-dev: &deploy-dev
step:
name: Deploy Develop Branch to App Engine
deployment: gcp-dev
script:
- apk add bash
- chmod +x ./add-env-to-gae-conf.sh
- bash ./add-env-to-gae-conf.sh
- cat ./app.yaml
- pipe: atlassian/google-app-engine-deploy:0.7.3
variables:
KEY_FILE: $KEY_FILE
PROJECT: $PROJECT
STOP_PREVIOUS_VERSION: 'true'
DEBUG: 'true'
pipelines:
branches:
master:
- <<: *run-test
develop:
- <<: *run-test
- <<: *deploy-dev

코드에서 확인

  • 코드에서 확인하기 위해 process.env.TEST_ENV1, process.env.TEST_ENV2, process.env.TEST_ENV3 를 console.log에 찍거나 JSON 형태로 반환해 봅니다.
  • Bitbucket에 저장 한 값이 나온다면 정상적으로 동작하는 것입니다.

보완이 필요한 점

  • 위에서도 언급했지만, app.yaml 파일에 env_variables 항목이 이미 있는 경우에는 정상적으로 동작하지 않습니다.
  • 이미 존재하는 환경변수도 함께 사용할 수 있는 방식으로 보완하면 더 좋을 것 같습니다.

참고

--

--