오늘은 실제 서비스 배포 완료와 트러블 슈팅 내용을 다뤄보겠습니다.
1. 외부 API (KAMIS) SSL 연결 에러 해결
실시간 시세 데이터를 가져오는 외부 API(KAMIS) 서버가 구형 보안 설정을 사용하여, 컨테이너 내부 통신 시
SSLV3_ALERT_HANDSHAKE_FAILURE 에러가 발생했습니다.
해결 방법:
- 코드 레벨에서 SSL 보안 수준을 낮추는 커스텀 어댑터를 적용하여 통신이 가능하도록 로직을 수정했습니다. (AI 코딩 어시스턴트 활용하여 해결)
2. 깃허브 푸시 및 EC2 서버 코드 반영
로컬에서 수정한 API 연동 코드를 깃허브에 푸시한 뒤, EC2 서버에서 풀(Pull)을 받아 변경 사항을 반영하고 컨테이너를 다시 빌드했습니다.
# 프로젝트 폴더로 이동
cd ~/Meat-A-Eye-Service
# 깃허브에서 최신 코드 가져오기
git pull origin main
# 기존 컨테이너 중지
docker compose down
# 변경된 코드로 백엔드 컨테이너 다시 빌드 및 실행
docker compose up --build -d
3. 스토리지 용량 부족 (EBS 볼륨 확장)
AI 모델 서버 컨테이너를 띄우기 위해 PyTorch 등 무거운 패키지를 설치하던 중, EC2 인스턴스의 기본 스토리지(8GB)가 가득 차서 No space left on device 에러와 함께 설치가 중단되었습니다.
해결 방법:
- AWS 콘솔에서 해당 EC2의 EBS 볼륨을 16GB로 확장한 후, 터미널에서 리눅스 파티션을 재조정하여 용량을 인식시켰습니다.
# 디스크 및 파티션 상태 확인
lsblk
# 디스크 파티션 크기 확장 (nvme0n1 디스크의 1번 파티션 기준)
sudo growpart /dev/nvme0n1 1
# 파일 시스템 크기 조정
sudo resize2fs /dev/nvme0n1p1
4. AI 서버 연결 및 트러블슈팅 완료
용량 확보 후 AI 서버를 구동하고 프론트엔드와 연결하는 과정에서 발생한 자잘한 이슈들을 일괄 조치하여 최종 연결을 완료했습니다.
- 라이브러리 설치: OpenCV 구동에 필요한 OS 의존성 문제(libGL.so.1) 해결.
- 가중치 파일 경로 매핑: 실제 업로드된 파일(epoch_010.pth)과 서버가 찾는 파일명(b2_imagenet_pork_50-v4.pth)이 달라 심볼릭 링크로 연결.
- 통신 IP 설정: .env 파일의 AI_SERVER_URL을 EC2 내부 IP로 수정.
- Nginx 라우팅 (403 에러): 컨테이너 내부에 SPA 라우팅을 위한 try_files 설정 강제 주입.
# 4-1. 시스템 라이브러리 설치
sudo apt update
sudo apt install libgl1 libglib2.0-0 -y
# 4-2. 가중치 파일 심볼릭 링크 연결 및 AI 서버 재시작
mv ~/Meat-A-Eye-Service/Meat_A_Eye-aimodels/ai-server/models/s/* ~/Meat-A-Eye-Service/Meat_A_Eye-aimodels/ai-server/models/
ln -s ~/Meat-A-Eye-Service/Meat_A_Eye-aimodels/ai-server/models/epoch_010.pth ~/Meat-A-Eye-Service/Meat_A_Eye-aimodels/ai-server/models/b2_imagenet_pork_50-v4.pth
pkill -f "python main.py"
cd ~/Meat-A-Eye-Service/Meat_A_Eye-aimodels/ai-server
source ../venv/bin/activate
nohup python main.py > ai_server.log 2>&1 &
# 4-3. IP 변경 적용 (.env 수정 후 컨테이너 재시작)
cd ~/Meat-A-Eye-Service
docker compose down
docker compose up --build -d
# 4-4. Nginx SPA 라우팅 설정 주입 및 리로드
docker exec meat-frontend-container sh -c "printf 'server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files \$uri \$uri/ /index.html;
}
}' > /etc/nginx/conf.d/default.conf"
docker exec meat-frontend-container nginx -s reload
5. 서버 고정 IP (탄력적 IP) 할당 및 적용
요금 절감을 위해 필요할 때만 인스턴스를 켜야 하지만, 인스턴스를 중지했다 켜면 퍼블릭 IP가 매번 변경되어 프론트엔드/백엔드 통신 주소를 다시 설정해야 하는 문제가 있습니다. 이를 방지하기 위해 IP를 고정했습니다.
- 진행 방법 (AWS 콘솔):
- AWS EC2 콘솔 왼쪽 메뉴에서 네트워크 및 보안 > 탄력적 IP(Elastic IPs) 클릭.
- 탄력적 IP 주소 할당 클릭 후 생성.
- 생성된 IP를 선택하고 작업 > 탄력적 IP 주소 연결 클릭.
- 현재 운영 중인 EC2 인스턴스를 선택하여 연결.
- 주의사항: 탄력적 IP는 연결된 EC2가 실행 중일 때는 무료지만, EC2가 중지되어 있을 때는 소액의 IP 유지 비용이 발생합니다.
6. 다음 할 일 (서버 및 DB 중지 - 비용 절감)
작업이 끝났으므로 불필요한 과금을 막기 위해 서버를 내립니다. 순서가 중요합니다. 애플리케이션(EC2)을 먼저 끄고 DB(RDS)를 꺼야 안전합니다.
6-1 EC2 인스턴스 중지:
- AWS EC2 콘솔 > 인스턴스 메뉴.
- 실행 중인 인스턴스 우클릭 > 인스턴스 상태 > 인스턴스 중지 클릭. (종료/Terminate를 누르면 삭제되니 주의)
6-2 RDS 데이터베이스 중지:
- AWS RDS 콘솔 > 데이터베이스 메뉴.
- 실행 중인 DB 식별자 선택 > 작업 > 일시 중지 클릭.
- 주의사항: RDS는 최대 7일까지만 중지 상태를 유지하며, 7일이 지나면 자동으로 다시 시작됩니다. 장기간 안 쓸 경우 스냅샷(백업)을 찍고 삭제하는 것이 좋습니다.
'3. 자습 & 메모(실전, 실습, 프로젝트) > 3-3 배포 실전 공부' 카테고리의 다른 글
| [배포] Meat-A-Eye 배포 마무리 정리 - AWS 서버 활용법 (마무리!) (0) | 2026.03.28 |
|---|---|
| [배포] 데이터베이스 연결, CORS, 외부 API 보안 연결 문제 (6) (0) | 2026.03.26 |
| [배포] AWS EC2 재가동 및 도커 배포 (4) (2) | 2026.03.24 |
| [Meat-A-Eye 배포] AWS EC2 서버 구축 및 AI 환경 세팅(3) (0) | 2026.03.13 |
| [배포] AWS RDS 활용 - MySQL DB 구축 및 초기화(2) (0) | 2026.03.11 |
