From b4283d5a59a5e87e349a784dd9cc34d9858800d2 Mon Sep 17 00:00:00 2001 From: youyeon11 Date: Thu, 28 Aug 2025 17:51:56 +0900 Subject: [PATCH 1/4] =?UTF-8?q?del:=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C?= =?UTF-8?q?=20=EB=B3=80=EC=88=98=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/core/config.py | 9 ++++----- app/schemas/job.py | 14 +++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/app/core/config.py b/app/core/config.py index e6db7c6..79a0078 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -2,14 +2,13 @@ import os class Settings(BaseSettings): - REDIS_URL: str = os.environ.get("REDIS_SERVER_URL", "redis://localhost:6379") + REDIS_URL: str = os.environ.get("REDIS_URL", "redis://localhost:6379") S3_REGION: str = os.environ.get("S3_REGION", "ap-northeast-2") - S3_ENDPOINT_URL: str | None = os.environ.get("S3_ENDPOINT_URL") BUCKET_NAME: str = os.environ.get("BUCKET_NAME") - STREAM_JOB: str = "image.jobs" - STREAM_RESULT: str = "image.results" - GROUP_NAME: str = "fastapi-workers" + STREAM_JOB: str = "image.jobs" # SpringBoot에서 job 발행 (FastAPI에서 listen) + STREAM_RESULT: str = "image.results" # FastAPI에서 결과 발행 (SpringBoot에서 listen) + GROUP_NAME: str = "fastapi-workers" # FastAPI Consumer group name CONSUMER_NAME: str = "consumer-1" diff --git a/app/schemas/job.py b/app/schemas/job.py index 6c71872..4313bc5 100644 --- a/app/schemas/job.py +++ b/app/schemas/job.py @@ -12,10 +12,10 @@ class JobResult(BaseModel): finished_at: str class ImageJob(BaseModel): - correlationId: str - presignedUrl: str - replyQueue: str - callbackUrl: str | None = None - contentType: str - createdAt: str - ttlSec: int + correlation_id: str = Field(alias="correlationId") + presigned_url: str = Field(alias="presignedUrl") + reply_queue: str = Field(alias="replyQueue") + callback_url: str | None = Field(alias="callbackUrl") + content_type: str = Field(alias="contentType") + created_at: str = Field(alias="createdAt") + ttl_sec: int = Field(alias="ttlSec") From 6366fe0aca56f37ee1f04a67405776b44da01c12 Mon Sep 17 00:00:00 2001 From: kite_U Date: Thu, 28 Aug 2025 22:39:46 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20=ED=99=98=EA=B2=BD=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/core/config.py | 14 +++++++++++--- app/core/lifespan.py | 3 --- app/main.py | 6 +++--- app/services/s3_service.py | 1 - app/worker/redis_client.py | 10 +--------- requirements.txt | 3 ++- 6 files changed, 17 insertions(+), 20 deletions(-) diff --git a/app/core/config.py b/app/core/config.py index 79a0078..5e336f3 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -1,10 +1,18 @@ from pydantic_settings import BaseSettings import os +from dotenv import load_dotenv + +load_dotenv() + +redis_url = os.getenv("REDIS_SERVER_URL") +bucket_name = os.getenv("BUCKET_NAME") +s3_region = os.getenv("S3_REGION") + class Settings(BaseSettings): - REDIS_URL: str = os.environ.get("REDIS_URL", "redis://localhost:6379") - S3_REGION: str = os.environ.get("S3_REGION", "ap-northeast-2") - BUCKET_NAME: str = os.environ.get("BUCKET_NAME") + REDIS_URL: str = redis_url + S3_REGION: str = bucket_name + BUCKET_NAME: str = s3_region STREAM_JOB: str = "image.jobs" # SpringBoot에서 job 발행 (FastAPI에서 listen) STREAM_RESULT: str = "image.results" # FastAPI에서 결과 발행 (SpringBoot에서 listen) diff --git a/app/core/lifespan.py b/app/core/lifespan.py index 73635a5..9bdc15f 100644 --- a/app/core/lifespan.py +++ b/app/core/lifespan.py @@ -25,9 +25,6 @@ async def lifespan(app: FastAPI): worker = JobWorker(redis_client) worker_task = asyncio.create_task(worker.run()) - app.state.redis_client = redis_client - app.state.worker_task = worker_task - try: yield finally: diff --git a/app/main.py b/app/main.py index 1c8c224..fa3dff5 100644 --- a/app/main.py +++ b/app/main.py @@ -3,9 +3,9 @@ from app.api.endpoints import predictions app = FastAPI( - title="DearBelly AI-Powered Pill Identification Service", - description="An AI service to identify pills from images, using a job queue for async processing.", - version="2.0.0", + title="DearBelly CV API", + description="DearBelly CV를 위한 Swagger 입니다.", + version="1.0.0", lifespan=lifespan ) diff --git a/app/services/s3_service.py b/app/services/s3_service.py index 44bb85d..b85d4fc 100644 --- a/app/services/s3_service.py +++ b/app/services/s3_service.py @@ -11,7 +11,6 @@ def __init__(self): self.client = boto3.client( "s3", region_name=settings.S3_REGION, - endpoint_url=settings.S3_ENDPOINT_URL, config=BotoConfig( retries={"max_attempts": 5, "mode": "standard"}, read_timeout=30, diff --git a/app/worker/redis_client.py b/app/worker/redis_client.py index cf9e793..8b7339b 100644 --- a/app/worker/redis_client.py +++ b/app/worker/redis_client.py @@ -1,17 +1,9 @@ import redis -from dotenv import load_dotenv -import os from pydantic import BaseModel, Field from typing import Any, Dict from app.core.config import settings -load_dotenv() - -redis_host = os.environ.get("REDIS_SERVER_HOST") - -redis_client = redis.Redis( - host=redis_host, port=6379, encoding="UTF-8", decode_responses=True -) +redis_client = redis.asyncio.from_url(settings.REDIS_URL, decode_responses=True) class PublishRequest(BaseModel): stream: str = Field(default=settings.JOB_STREAM, description="Redis Stream Job name") diff --git a/requirements.txt b/requirements.txt index 90373b8..5cf02b2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,5 @@ boto3 requests torch==2.8.0 torchvision==0.23.0 -Pillow==11.3.0 \ No newline at end of file +Pillow==11.3.0 +dotenv \ No newline at end of file From 8bad107c2f8f34dd71a47a44eda0b010da03b89b Mon Sep 17 00:00:00 2001 From: kite_U Date: Thu, 28 Aug 2025 22:54:54 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20Dockerfile=20=EC=9E=91=EC=84=B1=20(?= =?UTF-8?q?=20Nvidia=20cuda=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a8e773f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM nvidia/cuda:12.6.0-runtime-ubuntu24.04 + +WORKDIR /app + +RUN apt-get update && \ + apt-get install -y python3 python3-pip git && \ + ln -s /usr/bin/python3 /usr/bin/python && \ + pip install --upgrade pip && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +COPY . . + +RUN pip install --no-cache-dir -r app/requirements.txt + +EXPOSE 8000 + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file From 9cd9d0dc57830e6724aed7d8a00546bf6d1cdd34 Mon Sep 17 00:00:00 2001 From: kite_U Date: Thu, 28 Aug 2025 22:56:13 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20ECR=20=EC=97=85=EB=A1=9C=EB=93=9C?= =?UTF-8?q?=20=EB=B0=8F=20=EB=B0=B0=ED=8F=AC=20workflow=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/workflow.yml | 73 ++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 .github/workflows/workflow.yml diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 0000000..3ee7fae --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,73 @@ +name: workflow.yml +on: + push: + branches: [ main ] + +jobs: + + build: + name: Build Image + runs-on: ubuntu-24.04 + + steps: + - name: Check out code + uses: actions/checkout@v2 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} + aws-region: ap-northeast-2 + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Build, tag, and push image to Amazon ECR + run: | + docker build -t dearbelly-cv . + docker tag dearbelly-cv:latest ${{ secrets.ECR_URI }}/dearbelly-cv + docker push ${{ secrets.ECR_URI }}/dearbelly-cv:latest + + transfer: + runs-on: ubuntu-24.04 + needs: build + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + + deploy: + name: Deploy + runs-on: ubuntu-24.04 + needs: transfer + steps: + - name: SSH into EC2 server and Deploy + uses: appleboy/ssh-action@v1 + with: + host: ${{ secrets.REMOTE_HOST }} + username: ${{ secrets.REMOTE_USER }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + port: 22 + script: | + # 1. cd + mkdir -p ~/dearbelly + cd ~/dearbelly + + # 2. .env file + echo "${{ secrets.ENV }}" > .env + sudo chmod 600 .env + + # 3. aws login + aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin ${{ secrets.ECR_URI }} + + # 4. export env + export ECR_URI=${{ secrets.ECR_URI }} + + # 5. pull Image + docker pull ${{ secrets.ECR_URI }}/dearbelly-cv:latest + + # 6. docker start + # TODO : 스크립트 작성 + docker run -d --name app-blue -p 8000:8000 ${{ secrets.ECR_URI }}/dearbelly-cv:latest \ No newline at end of file