환경변수 관리의 중요성
애플리케이션 배포 및 운영 과정에서 환경변수 관리는 중요한 역할을 한다. 환경변수는 민감한 정보(ex. 데이터베이스 비밀번호, API 키)를 관리하거나 환경별 설정(develop, stage, production)을 간편하게 적용하는 데 사용된다. 최근 인프라를 새로 구축하면서 환경변수 주입 방식을 변경했는데, 기존에는 Docker 이미지 빌드 시점에 환경변수를 주입했다면, 변경된 방식은 Pod 생성 시점에 환경변수를 주입하는 것으로 바꼈다. 이번 글에서는 두 가지 방식을 살펴보고 차이점을 비교해 보자.
먼저 현회사의 CI/CD 파이프라인 흐름에 대해 간단히 알아보면 다음과 같다.
코드 변경 ➔ 브랜치 머지 ➔ GitHub Actions 빌드/푸시 ➔ 이미지 태그 업데이트(Kustomization) ➔ ArgoCD 감지 ➔ kubectl apply ➔ Pod 재시작(배포)
Docker 이미지 빌드 시점에 환경변수 주입
- GitHub Actions 또는 CI/CD 워크플로우에서 Secret Manager로 환경변수 가져오기
- Docker 빌드 시점에 .env 파일 복사
워크플로우 예제
주석을 달아놨지만 한번더 간단히 말하자면 AWS 에서 시크릿을 가져와 .env로 만듦 > 도커 이미지 빌드 > ECR에 푸시 순이다.
# .github/workflows/deploy.yml
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
# AWS 자격 증명 설정
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
# AWS Secrets Manager에서 시크릿 가져오기 및 환경변수로 설정
- name: Get Secrets from AWS Secrets Manager and set as environment variable
run: |
SECRETS=$(aws secretsmanager get-secret-value \
--secret-id 가져올시크릿이름- \
--query SecretString --output text)
echo "SECRETS=$SECRETS" >> $GITHUB_ENV
# .env 파일 생성
- name: Create .env file
run: |
jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' <<< "$SECRETS" > .env
# Amazon ECR 로그인
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
# Docker Buildx 설정
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
# Docker 이미지 빌드, 태깅 및 ECR 푸시
- name: Build, tag, and push image to Amazon ECR
uses: docker/build-push-action@v2
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} # ECR 레지스트리 설정
with:
context: . # 현재 디렉토리 사용해 빌드 후 아래 태그로 이미지 푸시
push: true
tags: ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}
cache-to: type=gha,mode=max
Dockerfile 예제
위의 build 워크플로우에서 .env를 생성해놨기 때문에 도커 이미지 빌드 시에 .env를 COPY 할 수 있게된다. 이렇게 하면 이미지 빌드 시점에 환경변수를 주입할 수 있다.
# Dockerfile
FROM python:3.9
# 디렉토리 생성
WORKDIR /app
# 코드 및 환경변수 복사
COPY . /app
COPY .env .
RUN pip install -r requirements.txt
CMD ["python", "main.py"]
애플리케이션 실행에 필요한 모든 파일이 포함되어 이미지의 이식성이 높은 것이 장점이나 환경변수 값을 변경하려면 이미지를 매번 새로 빌드해야하는게 단점이다. 특히 코드 변경이 없지만 환경변수만 변경이 있을때 항상 이미지를 다시 빌드해야 하는게 번거롭기 때문에 새로운 인프라에서는 pod 생성 시점에 환경변수를 주입하는 방식으로 바꾸게 되었다.
Pod 생성 시점에 환경변수 주입
- 쿠버네티스에서 환경변수 관리를 위해 ConfigMap 생성
- Deyployment의 init container 시점에 환경변수를 주입
Deployment 예제
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
# Init Container 정의 (환경변수 다운로드)
initContainers:
- name: init-env-vars # Init 컨테이너 이름
image: amazon/aws-cli # AWS CLI 이미지 사용
command:
- sh
- '-c'
- |
echo "Fetching secrets from S3..."
aws s3 cp s3://my-config-bucket/my-env-file /env/my-env-file --debug
echo "Exporting environment variables..."
set -a
. /env/my-env-file
set +a
volumeMounts:
- mountPath: /env # 다운로드 경로 마운트
name: env-volume
containers:
- name: my-app-container
image: my-app:latest
# ConfigMap에서 환경변수 주입
envFrom:
- configMapRef:
name: my-config
ports:
- containerPort: 8080
이렇게 설정하면 환경변수 값을 변경해도 이미지를 다시 빌드할 필요없이 팟만 다시 띄우면 된다. 동적으로 환경변수 관리가 가능하므로 환경변수 변경이 잦은 경우 이용하면 도움이 될 것이다.
차이점 비교
Docker 빌드 시점 주입 | Pod 생성 시점 주입 | |
유연성 | 환경변수 변경 시 이미지 재빌드 필요 | 환경변수 변경 시 Pod 재시작으로 충분 |
보안성 | 이미지에 환경변수가 포함될 수 있음 | ConfigMap/Secret로 분리 관리 가능 |
구현 난이도 | 단순 (Dockerfile 수정) | 약간 복잡 (Kubernetes 리소스 필요) |
운영 편의성 | 정적 관리 | 동적 관리 가능 |
환경변수 주입 방식은 애플리케이션의 배포 및 운영 요구사항에 따라 달라질 수 있다. 두 방식의 차이를 알아봤으니 각 상황에 맞게 적용해 운영의 효율성을 높일 수 있다.
'개발 환경 및 운영' 카테고리의 다른 글
Amazon Aurora DB (0) | 2024.04.17 |
---|---|
EC2 인스턴스 복제부터 로드밸런서 설정 및 Route53 DNS 설정까지 (0) | 2024.02.21 |
Github Action with docker, k8s (0) | 2023.07.08 |