최근 프로젝트에서 Gitea, AWS ECR, Jenkins, Docker-Compose, 그리고 AWS Elastic Beanstalk(EB)를 활용하여 CI/CD 파이프라인을 구성하는 작업을 진행했습니다. 이 포스팅에서는 CI/CD 환경 구축 과정과 함께 발생했던 문제 및 이를 해결한 과정을 기록하고자 합니다.


1. 프로젝트 개요

목표

Django 기반의 웹 애플리케이션과 이를 지원하는 서비스(Nginx, Redis, TensorFlow)를 Docker-Compose로 구성하고, AWS Elastic Beanstalk를 통해 배포 및 관리하며, CI/CD를 통해 코드 변경 사항이 자동으로 배포되도록 하는 환경 구축.

사용 기술 스택

  • Gitea: 코드 저장소 관리
  • AWS ECR: Docker 이미지를 저장
  • Jenkins: CI/CD 자동화
  • Docker-Compose: 컨테이너 오케스트레이션
  • AWS Elastic Beanstalk: 배포 및 운영 환경
  • Redis: 캐시 및 세션 관리
  • TensorFlow Serving: 모델 서빙
  • Nginx: Reverse Proxy와 정적 파일 제공

2. CI/CD 파이프라인 구축

2.1 Gitea 설정

Gitea를 프로젝트의 소스 코드 저장소로 사용했습니다. Gitea의 Webhook 기능을 통해 Jenkins와 통합하여 코드 변경 시 자동으로 빌드가 트리거되도록 설정했습니다.

Webhook 설정:

  1. Gitea에서 프로젝트 Repository 설정으로 이동
  2. Webhook 추가 → Jenkins URL 및 토큰 입력

 

2.2 AWS ECR 설정

AWS ECR을 Docker 이미지를 저장하는 레지스트리로 사용했습니다.

ECR 설정 과정:

  1. AWS 콘솔에서 ECR 리포지토리를 생성
  2. Jenkins의 빌드 스크립트에서 aws ecr get-login-password를 통해 ECR에 로그인
  3. Docker 이미지를 태그 및 푸시하도록 스크립트를 구성

 

2.3 Docker-Compose 구성

Docker-Compose를 사용해 다음 서비스를 정의:

  • uwsgi (Django): 주요 애플리케이션 서버
  • nginx: Reverse Proxy 및 정적 파일 서비스
  • redis: Django의 캐시 및 세션 백엔드
  • ml_models (TensorFlow Serving): 모델 서빙

Docker-Compose 파일 예시:

version: '3'
services:
  uwsgi:
    ## image: ECR 경로
    depends_on:
      - redis
      - ml_models

  nginx:
    ## image: ECR 경로
    ports:
      - 80:80
    depends_on:
      - uwsgi

  redis:
    image: redis
    container_name: redis_server
    ports:
      - 6379:6379

  ml_models:
    image: emacski/tensorflow-serving
    restart: always
    volumes:
      ## - 프로젝트의 model 경로
    command: "--model_config_file=/models/model_config.config --model_config_file_poll_wait_seconds=60"
    ports:
      - 8501:8501

 

2.4 Jenkins 설정

Jenkins는 Gitea에서 Webhook 이벤트를 받아 CI/CD를 수행합니다.

Job 구성:

  • Pipeline: 멀티 스테이지로 빌드, 테스트, 배포를 구성
  • 빌드 스크립트: 아래와 같은 Shell Script를 사용
#!/bin/bash
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
set -e  # Stop script on error

# AWS credentials setup
export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID_VAR
export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY_VAR
export AWS_DEFAULT_REGION=ap-northeast-2

# AWS ECR login
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com

# Docker image build
docker build -t my-app-dev .

# Docker image tagging
docker tag my-app-dev:latest 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/my-app-dev:latest

# Push Docker image to ECR
docker push 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/my-app-dev:latest

# Prepare deployment for Elastic Beanstalk
zip -r my-app-eb-deploy.zip docker-compose.yml Dockerfile nginx/ app_models/

# Upload the zip file to S3
aws s3 cp my-app-eb-deploy.zip s3://my-app-s3/my-app-eb-deploy.zip

# Create a new Elastic Beanstalk application version
aws elasticbeanstalk create-application-version \
    --application-name "my-app" \
    --version-label "build-${BUILD_NUMBER}" \
    --source-bundle S3Bucket="my-app-s3",S3Key="my-app-eb-deploy.zip"

# Update Elastic Beanstalk environment
aws elasticbeanstalk update-environment \
    --environment-name "My-app-test" \
    --version-label "build-${BUILD_NUMBER}"

3. 트러블슈팅 사례

문제 1: Jenkins에서 eb 명령어 실행 불가

원인: Jenkins 계정에 awsebcli가 설치되지 않음.
해결: Jenkins 사용자 환경에서 pip install awsebcli --user로 설치 후 PATH 환경 변수 수정.

문제 2: Elastic Beanstalk 업데이트 실패 (ascii codec 에러)

원인: 환경 변수나 출력에서 비ASCII 문자가 포함됨.
해결: LANG 및 LC_ALL을 en_US.UTF-8로 설정하여 UTF-8 환경 보장.

export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

 

+ Recent posts