최근 기업 Poc를 진행하면서 RAG 기반 질의응답 서비스를 로컬 개발 환경에서 테스트한 뒤, Ubuntu 서버 위에 Docker로 배포해 실제로 서비스화했다.
이번 글에서는 그 과정인
📦 Streamlit + Milvus 기반 RAG 앱을
💻 Ubuntu 서버에 Docker Compose로 배포하는 과정을
처음부터 끝까지 정리했다.
본문 예시는 아래 두 파일을 기준으로 진행한다.
- docker-compose.yml
- Dockerfile
⚙️ 1. 서버 준비하기
✅ (1) 서버 선택
먼저 RAG 서비스를 올릴 서버를 준비한다.
| 클라우드 | AWS EC2, GCP VM, Naver Cloud | GPU 지원 필요 시 GPU 인스턴스 |
| 온프레미스 | 사내 서버, 연구실 서버 | SSH 접속 가능해야 함 |
✅ (2) Ubuntu 설치
권장 버전은 아래와 같다. 이게 최신에 나온 것 중 안정적이다.
Ubuntu 20.04 LTS 또는 22.04 LTS
✅ (3) SSH 접속
터미널 또는 vscode로 서버에 접속한.
ssh 사용자이름@서버IP 예: ssh agilesoda@~~~.~~~.~~~.~~~
🐋 2. Docker 및 Compose 설치
📦 (1) 시스템 업데이트
sudo apt update && sudo apt upgrade -y
📦 (2) Docker 설치
sudo apt install -y ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io
docker --version
📦 (3) Docker Compose 설치
sudo apt install -y docker-compose-plugin
docker compose version
🗂️ 3. 프로젝트 폴더 구성
외부에서 코드 작성한 경우 scp 명령어로 서버에 프로젝트를 복사한다.
scp -r ./jeju_rag_app agilesoda@210.116.106.104:/home/agilesoda/test/
scp와 cp는 둘 다 파일을 복사하는 명령어이지만,
복사하는 대상의 위치(로컬 ↔ 원격) 에 따라 완전히 다르게 동작한다
📍cp vs scp
| 구분 | cp | scp |
| 의미 | local copy (로컬 복사) | secure copy (보안 원격 복사) |
| 사용 범위 | 같은 서버 내 디렉토리 간 복사 | 다른 서버 간 파일 복사 (SSH 기반) |
| 통신 방식 | 파일 시스템 직접 접근 | SSH(22번 포트)를 통해 네트워크로 복사 |
| 보안 | 단순 복사, 암호화 없음 | SSH 암호화 통신으로 안전 |
| 사용 예시 | 로컬에서 폴더 간 복사 | 내 PC → 서버 또는 서버 ↔ 서버 복사 |
| 명령 구조 | cp [옵션] 원본 대상 | scp [옵션] 원본 대상 |
| 인증 필요 | 없음 | SSH 계정 비밀번호 필요 |
📍 (1) cp — 같은 서버 내부에서 복사
cp ./rag/config.py ./backup/config_backup.py
➡️ 같은 머신 안에서만 파일을 복사함.
네트워크를 전혀 사용하지 않음.
📍 (2) scp — 다른 서버로 복사
내 로컬에서 서버로 파일 전송할 때
scp -r ./jeju_rag_app agilesoda@~~~.~~~.~~~.~~~:/home/agilesoda/test/
➡️ -r은 폴더 단위 복사 옵션.
SSH 프로토콜로 원격 서버(~~~.~~~.~~~.~~~)에 복사함.
📍 (3) 서버에서 내 로컬로 가져오기 (반대 방향)
scp -r agilesoda@~~~.~~~.~~~.~~~:/home/agilesoda/test/jeju_rag_app ./backup/
➡️ 원격 서버 → 로컬로 안전하게 다운로드.
🧱 4. Dockerfile 작성
FROM python:3.12.3
WORKDIR /app
COPY requirements.txt /app/
RUN pip3 install -r requirements.txt
# 코드 복사
COPY . /app/
# 로그 디렉토리 생성
RUN mkdir -p /app/logs
RUN chmod 755 /app/logs
EXPOSE 8501
CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
🧱 5. docker-compose.yml 작성
version: '3.8'
services:
jeju-rag-app:
build: .
ports:
- "8501:8501"
environment:
# Milvus 설정
- MILVUS_URI=http://~~~.~~~.~~~.~~~:~~~~~
- MILVUS_DB=default
- MILVUS_COLLECTION=jeju_chloe_test3_hybrid
# 임베딩 서비스
- EMBED_BASE_URL=http://~~~.~~~.~~~.~~~:~~~~/v1
- EMBED_API_KEY=~~~
- EMBED_MODEL=Snowflake-ARCTIC-Embed-L-v2.0-ko
# LLM 설정
- LLM_PROVIDER=openai
- OPENAI_API_KEY=${OPENAI_API_KEY:-sk-프로젝트키}
- OPENAI_MODEL=gpt-4o
# 검색 파라미터
- TOP_N=15
- PER_QUERY_LIMIT=15
- SEARCH_MODE=hybrid
# 로깅
- LOG_LEVEL=INFO
- LOG_FILE=logs/rag_system.log
- ENABLE_CONSOLE_LOG=true
- ENABLE_FILE_LOG=true
volumes:
- .:/app
- ./logs:/app/logs
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8501/healthz"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
🧱 6. 빌드 및 배포
docker-compose.yml과 Dockerfile이 있는 위치로 이동한다.
cd /home/agilesoda/test/jeju_rag_app # 이동
docker compose build # 이미지 빌드
docker compose up -d # 실행
docker compose build 서비스명 # 이미지 빌드
docker compose up -d 서비스명 # 실행
docker compose ps

🔓 7. 방화벽 설정
Ubuntu UFW 방화벽에서 포트 8501을 열어야 외부에서 접속할 수 있다.
sudo ufw allow 8501/tcp
sudo ufw reload
sudo ufw status
결과
8501/tcp ALLOW Anywhere
🌐 8. 접속 확인
브라우저에서 서버와 포트번호 주소로 접속한다
http://~~~.~~~.~~~.~~~:포트번호


Streamlit RAG 앱이 정상적으로 실행되면 배포 성공 !! 🎉
🔁 9. 배포된 후 코드 수정 하고싶을때
(1) 코드만 바뀌었을 때
volumes: .:/app 설정 덕분에 코드 변경 시 바로 반영된다.
따라서 down해주고 up하면 된다.
docker compose down
docker compose up -d
(2) requirements.txt 또는 Dockerfile이 변경된 경우
이미지부터 다시 빌드해야 한다.
docker compose stop jeju-rag-app
docker compose rm -f jeju-rag-app
docker compose build jeju-rag-app
docker compose up -d jeju-rag-app
10. Docker 배포 기본 명령어 모음
| docker ps | 실행 중 컨테이너 확인 -> 컨테이너명확인가능 |
| docker compose ps | compose 상태 확인 |
| docker logs -f 컨테이너명 | 실시간 로그 확인 |
| docker exec -it 컨테이너명 /bin/sh | 컨테이너 내부 진입 |
| docker compose down | 컨테이너 중지 및 삭제 |
| docker image prune -f | 사용하지 않는 이미지 정리 |
🌍 11. 8501 포트와 외부 접근 구조
[브라우저] → http://서버IP:8501
↓
[방화벽: TCP 8501 허용]
↓
[Docker Host: 8501 포트 수신]
↓
[컨테이너 내부: Streamlit 실행 중]
만약 클라우드 서버라면,
AWS, GCP, Naver Cloud 보안그룹에서 8501 포트를 Inbound 허용해야 한다.
마지막으로 배포 흐름을 정리해보자면 !!
1 Ubuntu 서버 준비 및 SSH 접속
2 Docker, Compose 설치
3 프로젝트 파일 구성
4 Dockerfile, docker-compose.yml 파일 작성
5 이미지 빌드 및 배포
6 방화벽 포트 오픈
7 브라우저 접속 테스트
'Development environment' 카테고리의 다른 글
| [Git] Git 커밋 메세지 규칙 + 커밋 수정하기 (0) | 2025.12.17 |
|---|---|
| [Git] 이미 Git에 올라간 파일 .gitignore 추가하기 (0) | 2025.11.24 |
| [Docker] Docker 기본 개념 및 명령어 정리 (0) | 2025.10.16 |
| [Git] Git 정리: 개념, 필수 명령어, 협업 흐름, 트러블슈팅 총정리 (1) | 2025.09.19 |
| [Poetry] poetry 개발 환경 셋팅하기 : 설치부터 가상환경 구축까지 (1) | 2025.08.22 |