diff --git a/REMOTE_SETUP.md b/REMOTE_SETUP.md new file mode 100644 index 0000000..82258d9 --- /dev/null +++ b/REMOTE_SETUP.md @@ -0,0 +1,232 @@ +# 원격 워커 설치 및 실행 가이드 + +이 가이드는 별도의 서버/컴퓨터에서 워커를 실행하여 메인서버와 연결하는 방법을 설명합니다. + +## 1. 메인서버 설정 (이미 완료) + +### Redis 포트 열기 +```bash +# 메인서버에서 실행 +sudo ufw allow 6379/tcp +``` + +### Docker Redis 외부 접속 확인 +```bash +docker ps | grep redis +# 출력: 0.0.0.0:6379->6379/tcp 확인 +``` + +## 2. 원격지 서버 설정 + +### 2.1 저장소 클론 +```bash +git clone https://github.com/your-repo/worker-system.git +cd worker-system +``` + +### 2.2 Python 가상환경 생성 +```bash +# Python 3.8+ 필요 +python3 -m venv . +source bin/activate + +# 또는 기존 가상환경이 있다면 +source bin/activate +``` + +### 2.3 패키지 설치 +```bash +# 기본 패키지 설치 +pip install -r requirements.txt + +# 누락된 패키지가 있다면 개별 설치 +pip install simple-lama-inpainting translatepy celery redis +``` + +### 2.4 GPU 환경 설정 (선택사항) +```bash +# CUDA 사용 가능한 경우 +pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 + +# 또는 시스템에 맞는 PyTorch 설치 +``` + +## 3. 워커 실행 + +### 3.1 메인서버 IP 확인 +메인서버의 실제 IP 주소를 확인하세요: +- 내부 네트워크: `192.168.x.x`, `10.x.x.x` 등 +- 외부 네트워크: 공인 IP 주소 + +### 3.2 네트워크 연결 테스트 +```bash +# Redis 서버 연결 테스트 +redis-cli -h 메인서버IP -p 6379 ping +# 응답: PONG + +# 또는 telnet으로 테스트 +telnet 메인서버IP 6379 +``` + +### 3.3 워커 시작 + +#### 방법 1: 자동 스크립트 사용 (권장) +```bash +# 메인서버 IP를 실제 IP로 변경 +MAIN_SERVER_IP=192.168.1.100 ./start_worker.sh + +# 동시 처리 수 조정 +MAIN_SERVER_IP=192.168.1.100 CONCURRENCY=4 ./start_worker.sh + +# 원격 모드로 명시적 실행 +MAIN_SERVER_IP=192.168.1.100 WORKER_MODE=remote ./start_worker.sh +``` + +#### 방법 2: 직접 실행 +```bash +# 가상환경 활성화 +source bin/activate + +# 워커 실행 +python worker.py \ + --redis-url redis://메인서버IP:6379/0 \ + --main-server 메인서버IP \ + --worker-name worker-원격서버명 \ + --concurrency 2 +``` + +#### 방법 3: Docker 실행 +```bash +# docker-compose.yml의 Redis URL 수정 후 +MAIN_SERVER_IP=192.168.1.100 WORKER_MODE=docker ./start_worker.sh +``` + +## 4. 워커 상태 확인 + +### 4.1 메인서버에서 확인 +```bash +# 메인서버에서 실행 +python test_worker_client.py --test-type status + +# 출력 예시: +# 활성 워커: +# celery@메인서버: 0개 작업 실행 중 +# worker-원격서버@hostname: 0개 작업 실행 중 +``` + +### 4.2 Flower 대시보드 확인 +메인서버에서 Flower가 실행 중이라면: +``` +http://메인서버IP:5555 +``` + +## 5. 설정 예시 + +### 환경별 설정 예시 + +#### 같은 네트워크 내 서버 +```bash +# 메인서버: 192.168.1.100 +# 워커서버: 192.168.1.200 + +MAIN_SERVER_IP=192.168.1.100 \ +WORKER_NAME=worker-gpu-server \ +CONCURRENCY=4 \ +./start_worker.sh +``` + +#### 클라우드 환경 +```bash +# 메인서버: 퍼블릭 IP 또는 도메인 +MAIN_SERVER_IP=your-server.com \ +WORKER_NAME=worker-cloud-gpu \ +CONCURRENCY=2 \ +./start_worker.sh +``` + +#### 다중 워커 실행 +```bash +# 서버1 +MAIN_SERVER_IP=192.168.1.100 WORKER_NAME=worker-gpu1 ./start_worker.sh & + +# 서버2 +MAIN_SERVER_IP=192.168.1.100 WORKER_NAME=worker-gpu2 ./start_worker.sh & +``` + +## 6. 문제 해결 + +### 6.1 연결 실패 +```bash +# Redis 연결 확인 +redis-cli -h 메인서버IP -p 6379 ping + +# 방화벽 확인 (메인서버) +sudo ufw status | grep 6379 + +# 네트워크 연결 확인 +ping 메인서버IP +``` + +### 6.2 워커가 등록되지 않음 +```bash +# 워커 로그 확인 +tail -f worker.log + +# Redis 연결 상태 확인 +python -c " +import redis +r = redis.Redis(host='메인서버IP', port=6379, db=0) +print(r.ping()) +" +``` + +### 6.3 패키지 오류 +```bash +# 가상환경 재생성 +rm -rf bin lib include pyvenv.cfg +python3 -m venv . +source bin/activate +pip install -r requirements.txt +``` + +### 6.4 GPU 메모리 부족 +```bash +# 동시 처리 수 줄이기 +CONCURRENCY=1 ./start_worker.sh + +# GPU 메모리 모니터링 +nvidia-smi +``` + +## 7. 보안 고려사항 + +### 7.1 Redis 보안 +- 프로덕션 환경에서는 Redis에 비밀번호 설정 권장 +- 방화벽에서 특정 IP만 허용하도록 설정 + +### 7.2 네트워크 보안 +```bash +# 특정 IP만 허용 (메인서버에서 설정) +sudo ufw allow from 워커서버IP to any port 6379 +sudo ufw delete allow 6379/tcp +``` + +## 8. 성능 최적화 + +### 8.1 동시 처리 수 조정 +- **CPU 기반**: CPU 코어 수 +- **GPU 기반**: GPU 메모리에 따라 1-2개 +- **메모리 제한**: 이미지 크기 × 동시 처리 수 고려 + +### 8.2 네트워크 최적화 +- 메인서버와 워커 간 네트워크 지연 최소화 +- 가능한 같은 데이터센터/네트워크 사용 + +### 8.3 모니터링 +```bash +# 시스템 리소스 모니터링 +htop +nvidia-smi # GPU 사용 시 +``` + +이제 원격지에서 `git clone` 후 메인서버 IP만 설정하면 워커를 쉽게 실행할 수 있습니다! 🚀 \ No newline at end of file diff --git a/modules/iopaint_models/torch2trt b/modules/iopaint_models/torch2trt new file mode 160000 index 0000000..4e820ae --- /dev/null +++ b/modules/iopaint_models/torch2trt @@ -0,0 +1 @@ +Subproject commit 4e820ae31b4e35d59685935223b05b2e11d47b03 diff --git a/start_worker.sh b/start_worker.sh index 649e180..2dcfdb0 100755 --- a/start_worker.sh +++ b/start_worker.sh @@ -3,20 +3,31 @@ # 워커 자동 시작 스크립트 echo "=== 이미지 처리 워커 시작 ===" -# 기본 설정 -REDIS_URL=${REDIS_URL:-"redis://localhost:6379/0"} -MAIN_SERVER=${MAIN_SERVER:-"localhost"} +# 기본 설정 (원격 실행용) +# 메인서버 IP를 실제 IP로 변경하세요 +MAIN_SERVER_IP=${MAIN_SERVER_IP:-"localhost"} # 원격지에서는 메인서버의 실제 IP 설정 필요 +REDIS_URL=${REDIS_URL:-"redis://${MAIN_SERVER_IP}:6379/0"} +MAIN_SERVER=${MAIN_SERVER:-"$MAIN_SERVER_IP"} CONCURRENCY=${CONCURRENCY:-"2"} -WORKER_MODE=${WORKER_MODE:-"docker"} -#WORKER_NAME=${WORKER_NAME:-"worker-$(hostname)-$$"} -WORKER_NAME=${WORKER_NAME:-"worker-AGX-$$"} +WORKER_MODE=${WORKER_MODE:-"local"} +WORKER_NAME=${WORKER_NAME:-"worker-$(hostname)-$$"} +echo "메인서버 IP: $MAIN_SERVER_IP" echo "Redis URL: $REDIS_URL" echo "메인 서버: $MAIN_SERVER" echo "동시 처리 수: $CONCURRENCY" echo "실행 모드: $WORKER_MODE" echo "워커 이름: $WORKER_NAME" +# 원격 실행인지 확인 +if [ "$MAIN_SERVER_IP" = "localhost" ]; then + echo "" + echo "⚠️ 경고: 원격지에서 실행하는 경우 메인서버 IP를 설정하세요!" + echo "사용법: MAIN_SERVER_IP=메인서버IP ./start_worker.sh" + echo "예시: MAIN_SERVER_IP=192.168.1.100 ./start_worker.sh" + echo "" +fi + case $WORKER_MODE in "docker") echo "Docker 모드로 워커 시작..." @@ -29,21 +40,55 @@ case $WORKER_MODE in "local") echo "로컬 모드로 워커 시작..." + # 가상환경 활성화 확인 + if [[ "$VIRTUAL_ENV" != "" ]]; then + echo "가상환경 활성화됨: $VIRTUAL_ENV" + else + echo "가상환경을 활성화하세요: source bin/activate" + if [ -f "bin/activate" ]; then + echo "자동으로 가상환경 활성화 중..." + source bin/activate + else + echo "❌ 가상환경을 찾을 수 없습니다. 먼저 설정하세요." + exit 1 + fi + fi + python worker.py --concurrency $CONCURRENCY --redis-url $REDIS_URL --main-server $MAIN_SERVER --worker-name $WORKER_NAME ;; "remote") echo "원격 모드로 워커 시작..." + # 원격 모드는 local과 동일하지만 기본 설정이 원격용 + if [[ "$VIRTUAL_ENV" != "" ]]; then + echo "가상환경 활성화됨: $VIRTUAL_ENV" + else + if [ -f "bin/activate" ]; then + echo "자동으로 가상환경 활성화 중..." + source bin/activate + else + echo "❌ 가상환경을 찾을 수 없습니다." + exit 1 + fi + fi + python worker.py --concurrency $CONCURRENCY --redis-url $REDIS_URL --main-server $MAIN_SERVER --worker-name $WORKER_NAME ;; *) echo "사용법: WORKER_MODE=docker|local|remote ./start_worker.sh" + echo "" echo "환경 변수:" - echo " REDIS_URL: Redis 서버 주소 (기본값: redis://localhost:6379/0)" - echo " MAIN_SERVER: 메인 서버 주소 (기본값: localhost)" + echo " MAIN_SERVER_IP: 메인서버 IP 주소 (필수 - 원격 실행시)" + echo " REDIS_URL: Redis 서버 URL" + echo " MAIN_SERVER: 메인 서버 주소" echo " CONCURRENCY: 동시 처리 수 (기본값: 2)" - echo " WORKER_NAME: 워커 식별명 (기본값: worker-hostname-pid)" + echo " WORKER_NAME: 워커 식별명" + echo "" + echo "원격 실행 예시:" + echo " MAIN_SERVER_IP=192.168.1.100 WORKER_MODE=remote ./start_worker.sh" + echo " MAIN_SERVER_IP=10.0.0.50 CONCURRENCY=4 ./start_worker.sh" + echo "" exit 1 ;; esac \ No newline at end of file diff --git a/test_remote_connection.py b/test_remote_connection.py new file mode 100755 index 0000000..c308f77 --- /dev/null +++ b/test_remote_connection.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 +""" +원격 연결 테스트 스크립트 +원격지에서 메인서버 Redis 연결 상태를 확인합니다. +""" + +import sys +import argparse +import redis +from celery import Celery + +def test_redis_connection(host, port=6379): + """Redis 서버 연결 테스트""" + print(f"=== Redis 연결 테스트 ===") + print(f"서버: {host}:{port}") + + try: + r = redis.Redis(host=host, port=port, db=0, socket_timeout=5) + pong = r.ping() + print(f"✅ Redis 연결 성공: {pong}") + + # Redis 정보 확인 + info = r.info() + print(f"Redis 버전: {info.get('redis_version')}") + print(f"연결된 클라이언트: {info.get('connected_clients')}") + return True + + except Exception as e: + print(f"❌ Redis 연결 실패: {e}") + return False + +def test_celery_connection(redis_url): + """Celery 연결 및 워커 상태 테스트""" + print(f"\n=== Celery 연결 테스트 ===") + print(f"Redis URL: {redis_url}") + + try: + celery_app = Celery('test_client', broker=redis_url, backend=redis_url) + + # 워커 상태 확인 + inspect = celery_app.control.inspect() + + # 활성 워커 목록 + active_workers = inspect.active() + if active_workers: + print("✅ 활성 워커:") + for worker_name, tasks in active_workers.items(): + print(f" - {worker_name}: {len(tasks)}개 작업 실행 중") + else: + print("⚠️ 활성 워커가 없습니다") + + # 등록된 작업 목록 + registered_tasks = inspect.registered() + if registered_tasks: + print("\n📋 등록된 작업:") + for worker_name, tasks in registered_tasks.items(): + print(f" {worker_name}:") + for task in tasks: + if 'worker.' in task or 'app.' in task: + print(f" - {task}") + + return True + + except Exception as e: + print(f"❌ Celery 연결 실패: {e}") + return False + +def test_network_connectivity(host): + """네트워크 연결 테스트""" + print(f"\n=== 네트워크 연결 테스트 ===") + + import subprocess + try: + # ping 테스트 + result = subprocess.run(['ping', '-c', '3', host], + capture_output=True, text=True, timeout=10) + if result.returncode == 0: + print(f"✅ {host} ping 성공") + return True + else: + print(f"❌ {host} ping 실패") + return False + except Exception as e: + print(f"❌ 네트워크 테스트 오류: {e}") + return False + +def test_port_connectivity(host, port=6379): + """포트 연결 테스트""" + print(f"\n=== 포트 연결 테스트 ===") + + import socket + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(5) + result = sock.connect_ex((host, port)) + sock.close() + + if result == 0: + print(f"✅ {host}:{port} 포트 연결 성공") + return True + else: + print(f"❌ {host}:{port} 포트 연결 실패") + return False + except Exception as e: + print(f"❌ 포트 테스트 오류: {e}") + return False + +def main(): + parser = argparse.ArgumentParser(description="원격 메인서버 연결 테스트") + parser.add_argument('--host', required=True, help='메인서버 IP 주소') + parser.add_argument('--port', type=int, default=6379, help='Redis 포트 (기본: 6379)') + parser.add_argument('--skip-ping', action='store_true', help='ping 테스트 건너뛰기') + + args = parser.parse_args() + + print("🔍 원격 메인서버 연결 테스트 시작") + print(f"대상 서버: {args.host}:{args.port}") + print("=" * 50) + + success_count = 0 + total_tests = 4 + + # 1. 네트워크 연결 테스트 + if not args.skip_ping: + if test_network_connectivity(args.host): + success_count += 1 + else: + print("⏭️ ping 테스트 건너뜀") + total_tests -= 1 + + # 2. 포트 연결 테스트 + if test_port_connectivity(args.host, args.port): + success_count += 1 + + # 3. Redis 연결 테스트 + if test_redis_connection(args.host, args.port): + success_count += 1 + + # 4. Celery 연결 테스트 + redis_url = f"redis://{args.host}:{args.port}/0" + if test_celery_connection(redis_url): + success_count += 1 + + # 결과 요약 + print("\n" + "=" * 50) + print(f"📊 테스트 결과: {success_count}/{total_tests} 성공") + + if success_count == total_tests: + print("🎉 모든 테스트 통과! 워커를 시작할 수 있습니다.") + print(f"\n🚀 워커 시작 명령:") + print(f"MAIN_SERVER_IP={args.host} ./start_worker.sh") + return 0 + else: + print("❌ 일부 테스트 실패. 네트워크 및 방화벽 설정을 확인하세요.") + print(f"\n🛠️ 문제 해결:") + print(f"1. 메인서버 방화벽: sudo ufw allow {args.port}/tcp") + print(f"2. Redis 설정 확인: docker ps | grep redis") + print(f"3. 네트워크 연결 확인: ping {args.host}") + return 1 + +if __name__ == "__main__": + sys.exit(main()) \ No newline at end of file