ai-review/vector/build.sh
2025-06-15 13:52:26 +00:00

338 lines
11 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# build.sh - Poetry 기반 Vector DB API Service Image 빌드 스크립트
set -e
# 변수 설정
IMAGE_NAME="vector-api"
IMAGE_TAG="${1:-latest}"
ACR_NAME="${2:-acrdigitalgarage03}"
RESOURCE_GROUP="${3:-rg-digitalgarage-03}"
BASE_IMAGE_TAG="${4:-latest}"
# ACR URL 자동 구성
if [ -n "${ACR_NAME}" ]; then
REGISTRY="${ACR_NAME}.azurecr.io"
FULL_IMAGE_NAME="${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}"
BASE_IMAGE="${REGISTRY}/vector-api-base:${BASE_IMAGE_TAG}"
else
FULL_IMAGE_NAME="${IMAGE_NAME}:${IMAGE_TAG}"
BASE_IMAGE="vector-api-base:${BASE_IMAGE_TAG}"
fi
# 고정된 파일 경로
DOCKERFILE_PATH="deployment/container/Dockerfile"
BUILD_CONTEXT="."
# 색상 설정
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() { echo -e "${CYAN} $1${NC}"; }
log_success() { echo -e "${GREEN}$1${NC}"; }
log_warning() { echo -e "${YELLOW}⚠️ $1${NC}"; }
log_error() { echo -e "${RED}$1${NC}"; }
echo "========================================================"
echo "🚀 Poetry 기반 Vector DB API Service Image 빌드"
echo "========================================================"
echo "Service 이미지명: ${FULL_IMAGE_NAME}"
echo "Base 이미지: ${BASE_IMAGE}"
if [ -n "${ACR_NAME}" ]; then
echo "ACR 이름: ${ACR_NAME}"
echo "리소스 그룹: ${RESOURCE_GROUP}"
fi
echo "빌드 시작: $(date)"
echo ""
# 시작 시간 기록
BUILD_START=$(date +%s)
# 사용법 표시 함수
show_usage() {
echo "사용법:"
echo " $0 [IMAGE_TAG] [ACR_NAME] [RESOURCE_GROUP] [BASE_IMAGE_TAG]"
echo ""
echo "파라미터:"
echo " IMAGE_TAG : Service 이미지 태그 (기본값: latest)"
echo " ACR_NAME : Azure Container Registry 이름"
echo " RESOURCE_GROUP: Azure 리소스 그룹"
echo " BASE_IMAGE_TAG: Base 이미지 태그 (기본값: latest)"
echo ""
echo "예시:"
echo " $0 v1.0.0 # 로컬 빌드만"
echo " $0 v1.0.0 acrdigitalgarage01 rg-digitalgarage-03 # ACR 빌드 + 푸시"
echo " $0 v1.0.0 acrdigitalgarage01 rg-digitalgarage-03 v2.0.0 # 특정 Base Image 사용"
echo ""
echo "전제조건:"
echo " Poetry 기반 Base Image가 먼저 빌드되어 있어야 합니다:"
echo " ./build-base.sh ${BASE_IMAGE_TAG} [ACR_NAME] [RESOURCE_GROUP]"
echo ""
echo "💡 장점:"
echo " - 빠른 빌드: 앱 코드만 복사 (30초~2분)"
echo " - Poetry 환경: 의존성 관리 최적화"
echo " - 캐시 활용: Base Image 재사용으로 효율성 극대화"
}
# ACR 로그인 함수
acr_login() {
local acr_name="$1"
local resource_group="$2"
log_info "Azure Container Registry 로그인 중..."
if ! command -v az &> /dev/null; then
log_error "Azure CLI (az)가 설치되지 않았습니다."
exit 1
fi
if ! command -v jq &> /dev/null; then
log_error "jq가 설치되지 않았습니다."
exit 1
fi
if ! az account show &> /dev/null; then
log_error "Azure에 로그인되지 않았습니다."
echo "로그인 명령: az login"
exit 1
fi
local credential_json
credential_json=$(az acr credential show --name "${acr_name}" --resource-group "${resource_group}" 2>/dev/null)
if [ $? -ne 0 ]; then
log_error "ACR credential 조회 실패"
exit 1
fi
local username
local password
username=$(echo "${credential_json}" | jq -r '.username')
password=$(echo "${credential_json}" | jq -r '.passwords[0].value')
if [ -z "${username}" ] || [ -z "${password}" ] || [ "${username}" == "null" ] || [ "${password}" == "null" ]; then
log_error "ACR credential 파싱 실패"
exit 1
fi
echo "${password}" | docker login "${REGISTRY}" -u "${username}" --password-stdin
if [ $? -eq 0 ]; then
log_success "ACR 로그인 성공!"
return 0
else
log_error "ACR 로그인 실패"
exit 1
fi
}
# 파라미터 검증
if [ "$1" == "--help" ] || [ "$1" == "-h" ]; then
show_usage
exit 0
fi
if [ -n "${ACR_NAME}" ] && [ -z "${RESOURCE_GROUP}" ]; then
log_error "ACR_NAME이 제공된 경우 RESOURCE_GROUP도 필요합니다."
echo ""
show_usage
exit 1
fi
# 필수 파일 확인
log_info "필수 파일 확인 중..."
if [ ! -f "app/main.py" ]; then
log_error "app/main.py 파일을 찾을 수 없습니다."
exit 1
fi
if [ ! -f "${DOCKERFILE_PATH}" ]; then
log_error "${DOCKERFILE_PATH} 파일을 찾을 수 없습니다."
exit 1
fi
log_success "모든 필수 파일이 확인되었습니다."
echo "📄 Service Dockerfile: ${DOCKERFILE_PATH}"
echo "📄 메인 애플리케이션: app/main.py"
echo "🏗️ 빌드 컨텍스트: ${BUILD_CONTEXT}"
# Base Image 존재 확인
echo ""
log_info "Poetry 기반 Base Image 확인 중..."
if docker image inspect "${BASE_IMAGE}" >/dev/null 2>&1; then
log_success "Base Image 확인됨: ${BASE_IMAGE}"
# Base Image에서 Poetry 환경 확인
log_info "Base Image Poetry 환경 검증 중..."
if docker run --rm "${BASE_IMAGE}" poetry --version >/dev/null 2>&1; then
POETRY_VERSION=$(docker run --rm "${BASE_IMAGE}" poetry --version 2>/dev/null)
log_success "Poetry 환경 확인됨: ${POETRY_VERSION}"
else
log_warning "Base Image에서 Poetry를 찾을 수 없습니다"
fi
# Base Image 크기 확인
BASE_SIZE=$(docker images "${BASE_IMAGE}" --format "{{.Size}}")
echo "📊 Base Image 크기: ${BASE_SIZE}"
else
log_error "Base Image를 찾을 수 없습니다: ${BASE_IMAGE}"
echo ""
echo "📋 해결 방법:"
echo " Base Image를 먼저 빌드하세요:"
if [ -n "${ACR_NAME}" ]; then
echo " ./build-base.sh ${BASE_IMAGE_TAG} ${ACR_NAME} ${RESOURCE_GROUP}"
else
echo " ./build-base.sh ${BASE_IMAGE_TAG}"
fi
echo ""
echo " 또는 ACR에서 Base Image를 풀하세요:"
if [ -n "${ACR_NAME}" ]; then
echo " docker pull ${BASE_IMAGE}"
fi
exit 1
fi
# ACR 로그인 수행
if [ -n "${ACR_NAME}" ] && [ -n "${RESOURCE_GROUP}" ]; then
echo ""
acr_login "${ACR_NAME}" "${RESOURCE_GROUP}"
echo ""
fi
# Docker 빌드
log_info "Poetry 기반 Service Image 빌드 시작..."
echo " - 예상 빌드 시간: 30초~2분 (앱 코드만 복사)"
echo " - Base Image 재사용으로 빠른 빌드"
echo " - Poetry 환경 상속"
echo ""
echo "🔨 빌드 명령어:"
echo "docker build --build-arg BASE_IMAGE=\"${BASE_IMAGE}\" -t \"${FULL_IMAGE_NAME}\" -f \"${DOCKERFILE_PATH}\" \"${BUILD_CONTEXT}\""
echo ""
docker build --build-arg BASE_IMAGE="${BASE_IMAGE}" -t "${FULL_IMAGE_NAME}" -f "${DOCKERFILE_PATH}" "${BUILD_CONTEXT}"
if [ $? -eq 0 ]; then
# 빌드 종료 시간 계산
BUILD_END=$(date +%s)
BUILD_TIME=$((BUILD_END - BUILD_START))
BUILD_MINUTES=$((BUILD_TIME / 60))
BUILD_SECONDS=$((BUILD_TIME % 60))
log_success "Service Image 빌드 완료!"
echo ""
echo "⏱️ 총 빌드 시간: ${BUILD_MINUTES}${BUILD_SECONDS}"
# 이미지 정보 표시
echo ""
log_info "Service Image 정보:"
docker images "${FULL_IMAGE_NAME}" --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}"
# 🧪 빌드된 이미지 검증
log_info "Service Image 검증 중..."
echo "🔍 Poetry 환경 및 앱 코드 확인:"
docker run --rm "${FULL_IMAGE_NAME}" sh -c "
echo '✅ Poetry 버전:' && poetry --version &&
echo '✅ Python 버전:' && poetry run python --version &&
echo '✅ 설치된 패키지 수:' && poetry show | wc -l &&
echo '✅ 앱 코드 확인:' && ls -la /app/app/ 2>/dev/null | head -5
" 2>/dev/null || log_warning "일부 검증에 실패했습니다."
# latest 태그 추가 생성
if [ "${IMAGE_TAG}" != "latest" ] && [ -n "${REGISTRY}" ]; then
echo ""
log_info "latest 태그 생성 중..."
docker tag "${FULL_IMAGE_NAME}" "${REGISTRY}/${IMAGE_NAME}:latest"
log_success "latest 태그 생성 완료: ${REGISTRY}/${IMAGE_NAME}:latest"
fi
# ACR 푸시
if [ -n "${ACR_NAME}" ]; then
echo ""
log_info "ACR에 Service Image 푸시 중..."
echo "📤 푸시 중: ${FULL_IMAGE_NAME}"
docker push "${FULL_IMAGE_NAME}"
if [ $? -eq 0 ]; then
log_success "Service Image 푸시 성공"
if [ "${IMAGE_TAG}" != "latest" ]; then
echo "📤 푸시 중: ${REGISTRY}/${IMAGE_NAME}:latest"
docker push "${REGISTRY}/${IMAGE_NAME}:latest"
if [ $? -eq 0 ]; then
log_success "latest 태그 푸시 성공"
fi
fi
else
log_error "Service Image 푸시 실패"
exit 1
fi
fi
echo ""
log_success "🎉 Poetry 기반 Service Image 빌드 완료!"
echo ""
echo "📋 완료된 작업:"
echo " ✅ Service Image 빌드: ${FULL_IMAGE_NAME}"
echo " ✅ Base Image 활용: ${BASE_IMAGE}"
if [ "${IMAGE_TAG}" != "latest" ] && [ -n "${REGISTRY}" ]; then
echo " ✅ latest 태그: ${REGISTRY}/${IMAGE_NAME}:latest"
fi
if [ -n "${ACR_NAME}" ]; then
echo " ✅ ACR 푸시 완료"
fi
echo " ✅ Poetry 환경 상속"
echo ""
echo "🧪 테스트 명령어:"
echo " # 로컬 실행 테스트"
echo " docker run --rm -p 8000:8000 ${FULL_IMAGE_NAME}"
echo ""
echo " # Poetry 환경 확인"
echo " docker run --rm ${FULL_IMAGE_NAME} poetry show"
echo ""
echo " # 앱 헬스체크"
echo " docker run --rm ${FULL_IMAGE_NAME} poetry run python -c \"import app.main; print('✅ 앱 로드 성공')\""
echo ""
echo "📝 다음 단계:"
echo " 1. 로컬 테스트:"
echo " docker run --rm -p 8000:8000 ${FULL_IMAGE_NAME}"
echo ""
echo " 2. Kubernetes 배포:"
echo " kubectl apply -f deployment/manifests/"
echo ""
echo " 3. 스케일링:"
echo " kubectl scale deployment vector-api --replicas=3"
echo ""
echo "💡 성능 최적화:"
echo " ✅ 빠른 빌드: Base Image 재사용으로 빌드 시간 95% 단축"
echo " ✅ 효율적 캐시: Poetry 환경은 Base Image에서 관리"
echo " ✅ 작은 이미지: 앱 코드만 포함하여 배포 이미지 최소화"
echo " ✅ 개발 친화적: Poetry로 일관된 의존성 관리"
else
log_error "Service Image 빌드 실패!"
echo ""
echo "🔍 문제 해결:"
echo " 1. Base Image 확인: docker images | grep vector-api-base"
echo " 2. Dockerfile 확인: cat ${DOCKERFILE_PATH}"
echo " 3. 앱 코드 확인: ls -la app/"
echo " 4. 빌드 로그 확인: 위의 에러 메시지 참조"
exit 1
fi
echo ""
echo "🏁 Service Image 빌드 프로세스 완료 - $(date)"