애플리케이션 개발과 배포 과정에서 환경 변수(Environment Variables)는 중요한 역할을 합니다. 특히 로컬 개발 환경부터 Docker 컨테이너, 그리고 쿠버네티스(Kubernetes) 인프라 환경까지 다양한 환경에서 애플리케이션이 실행될 때, 환경 변수의 설정과 오버라이딩(overriding)은 애플리케이션의 동작에 직접적인 영향을 미칩니다. 이러한 환경 변수들이 어떻게 오버라이딩되는지 기본 배경과 사례 관련된 유사 주제들입니다.
환경 변수의 기본 개념
환경 변수는 운영 체제나 실행 환경에서 애플리케이션에 전달되는 동적인 값입니다. 이를 통해 애플리케이션의 동작을 환경에 따라 조정할 수 있습니다. 예를 들어, 데이터베이스 연결 정보나 API 키 등을 환경 변수로 설정하여 코드 수정 없이도 환경별로 다른 설정을 적용할 수 있습니다.
환경 변수를 사용하는 이유
- 환경별 설정 관리: 개발, 테스트, 운영 환경에서 다른 설정 적용
- 보안: 민감한 정보를 코드에 하드코딩하지 않고 외부에서 주입
- 유연성: 동일한 애플리케이션을 다양한 환경에서 쉽게 배포
로컬 개발 환경에서의 환경 변수 관리
로컬 개발 환경에서는 주로 애플리케이션의 설정 파일과 소스 코드 내에서 환경 변수를 관리합니다.
Spring Boot에서의 설정 파일
Spring Boot는 application.properties
또는 application.yaml
파일을 통해 설정을 관리합니다. 또한, 환경별 설정을 위해 프로파일(profile)을 사용할 수 있습니다.
# application.yaml
spring:
profiles:
active: local
---
# application-local.yaml
app:
version: "v1.0.0"
---
# application-dev.yaml
app:
version: "v2.0.0"
위 예시에서 spring.profiles.active
를 통해 현재 활성화된 프로파일을 local
로 지정했습니다. 따라서 application-local.yaml
의 설정이 적용됩니다.
소스 코드에서의 환경 변수 주입
Spring Framework에서는 @Value
어노테이션을 사용하여 설정 값을 주입받을 수 있습니다.
@Value("${app.version:v3.0.0}")
private String appVersion;
@GetMapping("/version")
public String getVersion() {
return appVersion;
}
${app.version}
: 설정 파일에서app.version
값을 가져옵니다.:v3.0.0
: 만약app.version
값이 없을 경우 기본값으로v3.0.0
을 사용합니다.
Docker 컨테이너에서의 환경 변수 설정
Docker를 사용하여 애플리케이션을 컨테이너화할 때, 환경 변수는 Dockerfile이나 docker run
명령어를 통해 설정할 수 있습니다.
Dockerfile에서의 환경 변수
# Dockerfile
FROM openjdk:11-jre
ENV APP_VERSION="v4.0.0"
ADD app.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
ENV APP_VERSION="v4.0.0"
: Docker 이미지 빌드 시 환경 변수를 설정합니다.- 컨테이너 내부에서
APP_VERSION
환경 변수를 사용할 수 있습니다.
컨테이너 실행 시 환경 변수 주입
docker run -e APP_VERSION="v5.0.0" my-app-image
-e
옵션을 사용하여 컨테이너 실행 시 환경 변수를 주입합니다.- 이 경우 Dockerfile에서 설정한
APP_VERSION
은 오버라이딩됩니다.
쿠버네티스에서의 환경 변수 관리
쿠버네티스는 컨테이너 오케스트레이션 플랫폼으로, 환경 변수 관리를 위한 다양한 방법을 제공합니다.
Pod에서의 환경 변수 설정
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-container
image: my-app-image
env:
- name: APP_VERSION
value: "v6.0.0"
env
필드를 사용하여 컨테이너에 환경 변수를 주입합니다.- 이 값은 컨테이너 이미지 내부의 설정을 오버라이딩합니다.
ConfigMap을 통한 환경 변수 관리
ConfigMap은 비밀이 아닌 설정 데이터를 저장하고 관리하기 위한 쿠버네티스 리소스입니다.
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_VERSION: "v7.0.0"
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-container
image: my-app-image
envFrom:
- configMapRef:
name: app-config
envFrom
을 사용하여 ConfigMap의 모든 키-값 쌍을 환경 변수로 주입합니다.
환경 변수의 우선순위
여러 곳에서 동일한 이름의 환경 변수가 설정된 경우, 어떤 값이 최종적으로 적용될까요? 일반적으로 아래와 같은 우선순위가 적용됩니다.
- 명령줄 인자: 애플리케이션 실행 시 직접 전달되는 인자
- 시스템 프로퍼티: JVM 옵션으로 전달되는 값 (
-Dkey=value
) - 컨테이너 실행 시 주입된 환경 변수
- 쿠버네티스 Pod의 env 필드로 설정된 환경 변수
- 쿠버네티스 ConfigMap 또는 Secret을 통한 환경 변수
- Docker 이미지 빌드 시 설정된 ENV 변수
- Spring Boot의 설정 파일 (application.yaml, application.properties)
- 어노테이션의 기본값:
@Value
어노테이션의 기본값 - 소스 코드의 하드코딩된 값
구체적인 사례를 통한 이해
사례 1: 로컬 환경에서의 실행
- 설정 파일:
application-local.yaml
에서app.version
은"v1.0.0"
으로 설정 - 소스 코드:
@Value("${app.version:v2.0.0}")
로 주입, 기본값은"v2.0.0"
- 하드코딩된 값:
private String appVersion = "v3.0.0";
결과: /version
API 호출 시 "v1.0.0"
반환
설명: 설정 파일의 값이 가장 우선 적용됩니다.
사례 2: Docker 컨테이너에서의 실행
- Dockerfile:
ENV APP_VERSION="v4.0.0"
- 컨테이너 실행 시 추가 설정 없음
결과: /version
API 호출 시 "v4.0.0"
반환
설명: Docker 이미지의 환경 변수가 설정 파일의 값을 오버라이딩합니다.
사례 3: 컨테이너 실행 시 환경 변수 주입
- Dockerfile:
ENV APP_VERSION="v4.0.0"
- 컨테이너 실행:
docker run -e APP_VERSION="v5.0.0" my-app-image
결과: /version
API 호출 시 "v5.0.0"
반환
설명: 컨테이너 실행 시 주입된 환경 변수가 Dockerfile의 값을 오버라이딩합니다.
사례 4: 쿠버네티스에서의 실행 (Pod의 env
사용)
- Pod 설정:
env
필드에서APP_VERSION="v6.0.0"
설정
결과: /version
API 호출 시 "v6.0.0"
반환
설명: 쿠버네티스 Pod의 env
설정이 컨테이너 내부의 설정을 오버라이딩합니다.
사례 5: 쿠버네티스에서의 실행 (ConfigMap 사용)
- ConfigMap:
APP_VERSION="v7.0.0"
- Pod 설정:
envFrom
으로 ConfigMap 주입
결과: /version
API 호출 시 "v7.0.0"
반환
설명: ConfigMap을 통한 환경 변수가 우선 적용됩니다.
ConfigMap과 Secret의 활용
ConfigMap
- 비밀이 아닌 설정 데이터를 저장하고 관리
- 여러 Pod에서 공유 가능
- 파일로 마운트하거나 환경 변수로 주입 가능
Secret
- 민감한 정보를 저장 (예: 패스워드, API 키)
- Base64로 인코딩되어 저장
- 사용 방식은 ConfigMap과 유사하지만, 보안에 더 신경 씀
Secret 생성 및 사용
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
username: bXl1c2Vy
password: cGFzc3dvcmQ=
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-container
image: my-app-image
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
Spring Boot 프로파일과 설정 파일 관리
프로파일(Profile) 사용
application-{profile}.yaml
형식으로 환경별 설정 관리spring.profiles.active
로 활성화할 프로파일 지정
# application.yaml
spring:
profiles:
active: dev
---
# application-dev.yaml
app:
version: "v1.0.0"
---
# application-prod.yaml
app:
version: "v2.0.0"
외부 설정 파일 사용
- 실행 시 외부 설정 파일을 로드하여 설정 적용
--spring.config.location
옵션 사용
java -jar app.jar --spring.config.location=/path/to/external-config.yaml
베스트 프랙티스
- 환경 변수 최소화: 필요한 값만 환경 변수로 주입
- 민감한 정보는 Secret 사용: 패스워드, API 키 등은 Secret으로 관리
- 환경 변수 이름 일관성 유지: 모든 환경에서 동일한 이름 사용
- 우선순위 명확히 이해: 환경 변수의 오버라이딩 우선순위를 숙지
- 프로파일 활용: 환경별 설정 파일을 통해 코드 수정 없이 설정 변경
환경 변수는 애플리케이션의 유연한 설정과 안전한 운영에 필수적인 요소입니다. 로컬 개발 환경부터 Docker, 쿠버네티스까지 다양한 환경에서 환경 변수가 어떻게 설정되고 오버라이딩되는지 정확히 이해하는 것은 개발자와 운영자 모두에게 중요합니다. 환경 변수 관리의 핵심은 우선순위의 이해와 일관성 유지입니다. 이를 통해 예측 가능한 애플리케이션 동작을 보장하고, 환경에 따라 필요한 설정을 유연하게 적용할 수 있습니다.
참고 자료
추가적인 학습을 위한 주제
- Helm을 사용한 쿠버네티스 설정 관리: 복잡한 설정을 템플릿화하여 효율적으로 관리
- 12-Factor App 방법론: 현대적인 애플리케이션 개발을 위한 지침서로, 설정 관리에 대한 권장 사항 포함
- Vault를 통한 비밀 관리: HashiCorp Vault 등을 사용하여 민감한 정보를 안전하게 저장하고 주입
서버리스(Serverless)란 무엇인가?
서버리스는 서버 관리에 대한 부담을 덜고 애플리케이션 개발에 집중할 수 있도록 돕는 클라우드 컴퓨팅 모델입니다. 서버가 존재하지 않는 것이 아니라, 클라우드 제공자(AWS, Azure, GCP 등)가 서버의 모든 관리를 처리하고, 사용자는 애플리케이션 코드 작성에만 집중합니다.
- 자동 확장: 부하에 따라 클라우드 제공자가 리소스를 자동으로 조정.
- 과금 모델: 실제 코드 실행 시간만큼만 비용 청구(Pay-as-you-go).
- 개발 간소화: 서버 관리 없이 코드 작성에만 집중.
- 이벤트 기반 실행: 특정 이벤트가 발생할 때 함수가 실행됨.
서버리스 환경에서 보안 이슈
서버리스는 보안에 대한 새로운 도전 과제를 제시합니다.
- 비밀 관리(Secrets Management)
- API 키, 데이터베이스 비밀번호, 토큰 등의 민감 정보 저장 및 접근 문제.
- 소스 코드나 환경 변수에 민감 정보를 하드코딩하면 정보 유출 위험 증가.
- 권한 관리(IAM)
- 잘못된 권한 설정으로 인해 함수가 불필요한 리소스에 접근 가능.
- 최소 권한 원칙(Minimum Privilege)이 중요.
- 종속성 취약점
- 외부 라이브러리에 포함된 보안 취약점.
- 함수 실행 시 종속성이 최신 상태인지 확인 필요.
- 이벤트 소스 보안
- 트리거 역할을 하는 이벤트 소스(S3, DynamoDB 등)가 악의적으로 변조될 가능성.
- 데이터 보호
- 전송 중 및 저장된 데이터 암호화 필요.
비밀 관리 이슈와 해결 방법
이슈: 비밀 정보의 부적절한 관리
- 잘못된 예시
service: name: hello-world provider: name: aws functions: helloWorld: handler: helloworld.get environment: API_KEY: "hardcoded-api-key"
- 민감 정보(API_KEY)가 설정 파일에 하드코딩.
- 파일이 유출되거나 잘못 공유될 경우 심각한 보안 사고 발생 가능.
해결 방법: 비밀 관리 도구 활용
1. AWS Parameter Store 및 Secrets Manager 활용
- AWS에서 제공하는 안전한 비밀 저장소.
- Parameter Store는 텍스트 기반의 값 저장, Secrets Manager는 비밀번호와 인증 정보 관리에 최적화.
AWS Secrets Manager 사용 예제
service:
name: hello-world
provider:
name: aws
functions:
helloWorld:
handler: helloworld.get
environment:
API_KEY: ${ssm:/prod/api-key~true}
${ssm:/prod/api-key~true}
는 Parameter Store에서 복호화된 값을 가져옴.
Python 코드 예제
import boto3
import os
def lambda_handler(event, context):
# AWS Secrets Manager 사용
ssm = boto3.client('ssm')
parameter = ssm.get_parameter(
Name='/prod/api-key',
WithDecryption=True
)
api_key = parameter['Parameter']['Value']
print(f"API Key: {api_key}")
2. HashiCorp Vault
- 오픈소스 비밀 관리 도구로, 민감 정보를 안전하게 저장하고 관리.
- 기능: 동적 비밀번호 생성, 세분화된 액세스 제어, 감사 로깅.
설치 및 실행
# Vault 설치
sudo apt-get update && sudo apt-get install -y vault
# Vault 서버 실행
vault server -dev
비밀 저장 및 읽기
# Vault 초기화 및 토큰 설정
vault operator init
vault operator unseal
export VAULT_TOKEN=<token>
# 비밀 저장
vault kv put secret/api_key value=my-secret-api-key
# 비밀 읽기
vault kv get secret/api_key
Python 연동 예제
import hvac
client = hvac.Client(url='http://127.0.0.1:8200', token='your-token')
secret = client.secrets.kv.v2.read_secret_version(path='api_key')
print(secret['data']['data']['value'])
3. Azure Key Vault
- Azure에서 제공하는 비밀 관리 도구.
az keyvault
CLI를 사용하여 비밀 저장 및 검색 가능.
비밀 저장 및 검색
# Key Vault 생성
az keyvault create --name MyKeyVault --resource-group MyResourceGroup --location eastus
# 비밀 추가
az keyvault secret set --vault-name MyKeyVault --name "API-Key" --value "my-secret-api-key"
# 비밀 검색
az keyvault secret show --vault-name MyKeyVault --name "API-Key"
모범 사례
- 비밀 동적 호출
- 비밀은 코드에서 직접 사용하는 대신 런타임에 호출하여 사용.
- 비밀 회전(Key Rotation)
- 민감 정보를 정기적으로 갱신하여 유출 시 피해를 최소화.
- 최소 권한 설정
- IAM 정책을 통해 함수가 필요한 비밀에만 접근 가능하도록 제한.
- 모니터링 및 감사
- 비밀 접근 로그를 기록하고 이상 징후를 분석.
비밀 관리의 효과
- 민감 정보 노출 감소: 비밀이 코드나 환경 변수에 저장되지 않아 유출 가능성 감소.
- 관리 용이성: 모든 비밀을 중앙화된 도구에서 관리.
- 보안 강화: 키 회전 및 감사 로그를 통해 비밀 관리의 보안성 향상.
- 규정 준수: GDPR, HIPAA와 같은 데이터 보호 규정 준수.
서버리스 환경에서 비밀 관리 이슈는 보안에 중대한 영향을 미칩니다. AWS Parameter Store, Secrets Manager, HashiCorp Vault와 같은 도구를 사용하여 민감 정보를 안전하게 관리하고, 권한 제한 및 회전을 통해 보안을 강화 방식은 비밀 관리의 복잡성을 줄이고 애플리케이션의 신뢰성을 높이는 데 필수적입니다.
댓글