iBetter Books
수정

환경별 설정 관리

같은 코드가 개발 노트북, 테스트 서버, 프로덕션 서버에서 실행됩니다. 세 환경의 데이터베이스 주소, API 키, 디버그 모드가 모두 다릅니다. 이 설정들을 코드에 하드코딩하면 실수로 프로덕션 DB를 날려먹는 사고가 일어납니다.

환경별 설정을 코드와 분리해서 관리하는 것이 핵심입니다.

환경 분리 전략

세 가지 환경을 분리해서 관리합니다.

환경 용도 특징
dev 로컬 개발 DEBUG=true, 로컬 DB, 더미 API 키
staging QA, 검증 프로덕션과 유사한 설정, 실제에 가까운 데이터
prod 실제 서비스 DEBUG=false, 실제 DB, 실제 API 키

.env 파일 예시

# 새 파일: .env.devAPP_ENV=developmentAPP_PORT=3000DEBUG=trueDB_HOST=localhostDB_PORT=5432DB_NAME=myapp_devDB_USER=postgresDB_PASSWORD=devpasswordREDIS_HOST=localhostREDIS_PORT=6379API_KEY=dev-fake-api-key-12345SMTP_HOST=mailhogSMTP_PORT=1025
# 새 파일: .env.stagingAPP_ENV=stagingAPP_PORT=3000DEBUG=falseDB_HOST=staging-db.internalDB_PORT=5432DB_NAME=myapp_stagingDB_USER=myappDB_PASSWORD=REPLACE_WITH_ACTUAL_PASSWORDREDIS_HOST=staging-redis.internalREDIS_PORT=6379API_KEY=REPLACE_WITH_STAGING_KEYSMTP_HOST=smtp.sendgrid.netSMTP_PORT=587
# 새 파일: .env.prodAPP_ENV=productionAPP_PORT=3000DEBUG=falseDB_HOST=prod-db.myapp.comDB_PORT=5432DB_NAME=myapp_prodDB_USER=myappDB_PASSWORD=REPLACE_WITH_PROD_PASSWORDREDIS_HOST=prod-redis.myapp.comREDIS_PORT=6379API_KEY=REPLACE_WITH_PROD_KEYSMTP_HOST=smtp.sendgrid.netSMTP_PORT=587

실제 비밀번호와 API 키는 REPLACE_WITH_... 플레이스홀더로 두고, 서버 배포 시 실제 값으로 교체합니다.

환경 변수 검증 스크립트

앱 실행 전에 필수 환경 변수가 모두 설정되어 있는지 확인합니다.

#!/bin/bash# 새 파일: scripts/validate_env.sh# validate_env.sh: 필수 환경 변수 존재 확인set -euo pipefailRED='\033[0;31m'GREEN='\033[0;32m'NC='\033[0m'# 필수 변수 목록REQUIRED_VARS=(    "APP_ENV"    "APP_PORT"    "DB_HOST"    "DB_PORT"    "DB_NAME"    "DB_USER"    "DB_PASSWORD"    "API_KEY")MISSING=0echo "환경 변수 검증 중..."echo ""for var in "${REQUIRED_VARS[@]}"; do    if [ -z "${!var:-}" ]; then        echo -e "${RED}  누락: $var${NC}"        MISSING=$((MISSING + 1))    else        # 값을 보여주되 민감한 변수는 마스킹        if [[ "$var" == *"PASSWORD"* ]] || [[ "$var" == *"KEY"* ]] || [[ "$var" == *"SECRET"* ]]; then            echo -e "${GREEN}  설정됨: $var = ****${NC}"        else            echo -e "${GREEN}  설정됨: $var = ${!var}${NC}"        fi    fidoneecho ""if [ $MISSING -gt 0 ]; then    echo -e "${RED}${MISSING}개 필수 환경 변수가 없습니다.${NC}"    exit 1fiecho -e "${GREEN}모든 필수 환경 변수가 설정되어 있습니다.${NC}"exit 0

envsubst로 설정 파일 생성

설정 파일 템플릿에 환경 변수 플레이스홀더를 쓰고, envsubst로 실제 값을 채웁니다. nginx, 데이터베이스 접속 설정 등에 유용합니다.

# 새 파일: config/nginx.conf.templateserver {    listen ${APP_PORT};    server_name ${SERVER_NAME};    location / {        proxy_pass http://localhost:${BACKEND_PORT};        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;    }    error_log /var/log/nginx/${APP_ENV}_error.log;    access_log /var/log/nginx/${APP_ENV}_access.log;}
# 환경 변수를 템플릿에 적용export APP_PORT=80export SERVER_NAME=myapp.comexport BACKEND_PORT=3000export APP_ENV=productionenvsubst < config/nginx.conf.template > /etc/nginx/conf.d/myapp.conf# 결과 확인cat /etc/nginx/conf.d/myapp.conf
server {
    listen 80;
    server_name myapp.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    error_log /var/log/nginx/production_error.log;
    access_log /var/log/nginx/production_access.log;
}

특정 변수만 치환하고 싶을 때는 변수 이름을 지정합니다.

# APP_PORT와 SERVER_NAME만 치환 (나머지 $변수는 그대로 유지)envsubst '${APP_PORT} ${SERVER_NAME}' < template.conf > output.conf

env_setup.sh: 통합 환경 설정 스크립트

#!/bin/bash# 새 파일: scripts/env_setup.sh# env_setup.sh: 환경 감지 → 설정 로드 → 검증set -euo pipefailGREEN='\033[0;32m'YELLOW='\033[1;33m'RED='\033[0;31m'CYAN='\033[0;36m'NC='\033[0m'PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"# ─── 환경 감지 ────────────────────────────────────────────────────────────────detect_environment() {    # 1. 명시적으로 지정된 경우    if [ -n "${APP_ENV:-}" ]; then        echo "$APP_ENV"        return    fi    # 2. CI 환경 감지 (GitHub Actions, GitLab CI 등)    if [ -n "${CI:-}" ]; then        echo "staging"        return    fi    # 3. Git 브랜치로 감지    local branch    branch=$(git -C "$PROJECT_ROOT" symbolic-ref --short HEAD 2>/dev/null || echo "unknown")    case "$branch" in        main|master)   echo "prod" ;;        develop)       echo "dev" ;;        staging)       echo "staging" ;;        *)             echo "dev" ;;    esac}ENV=$(detect_environment)ENV_FILE="$PROJECT_ROOT/.env.$ENV"echo -e "${CYAN}환경 설정을 시작합니다...${NC}"echo "  감지된 환경: $ENV"# ─── .env 파일 로드 ───────────────────────────────────────────────────────────if [ ! -f "$ENV_FILE" ]; then    echo -e "${YELLOW}  경고: $ENV_FILE 파일이 없습니다. .env 파일을 사용합니다.${NC}"    ENV_FILE="$PROJECT_ROOT/.env"fiif [ -f "$ENV_FILE" ]; then    # shellcheck disable=SC1090    set -a    source "$ENV_FILE"    set +a    echo -e "${GREEN}  설정 로드 완료: $ENV_FILE${NC}"else    echo -e "${RED}  오류: 설정 파일을 찾을 수 없습니다.${NC}"    exit 1fi# ─── 환경 변수 검증 ───────────────────────────────────────────────────────────bash "$PROJECT_ROOT/scripts/validate_env.sh"# ─── 설정 파일 생성 (템플릿 있을 때) ──────────────────────────────────────────if [ -f "$PROJECT_ROOT/config/nginx.conf.template" ]; then    envsubst < "$PROJECT_ROOT/config/nginx.conf.template" \        > "$PROJECT_ROOT/config/nginx.conf"    echo -e "${GREEN}  nginx 설정 파일 생성 완료${NC}"fiecho ""echo -e "${GREEN}환경 설정 완료 (환경: $ENV)${NC}"

시크릿 관리 주의사항

.env 파일에는 비밀번호, API 키 같은 민감 정보가 담깁니다. 반드시 .gitignore에 추가해야 합니다.

# .gitignore에 추가cat >> .gitignore << 'EOF'# 환경 변수 파일 (절대 커밋하지 말 것).env.env.*!.env.exampleEOF

.env.example 파일은 커밋합니다. 실제 값 없이 변수 이름과 설명만 담은 템플릿입니다.

# 새 파일: .env.example# 이 파일을 .env로 복사하고 실제 값을 입력하세요.# cp .env.example .envAPP_ENV=development          # development | staging | productionAPP_PORT=3000DB_HOST=localhostDB_PORT=5432DB_NAME=myapp_devDB_USER=postgresDB_PASSWORD=your_password_here   # ← 실제 비밀번호로 교체API_KEY=your_api_key_here        # ← 실제 API 키로 교체

프로덕션 시크릿은 AWS Secrets Manager, HashiCorp Vault, 또는 GitHub Actions Secrets에 저장하고 배포 시 주입하는 방식을 사용합니다. 비밀번호를 파일에 평문으로 저장하지 않는 것이 원칙입니다.