클라우드 솔루션은 중대형 프로젝트에 적합하지만 소규모 개인 프로젝트에는 너무 무겁습니다. 작은 것(몇 개의 API 엔드포인트 및 작은 저장소)을 시작하려는 경우 세 가지 옵션이 있습니다.
저는 보통 SQLite를 사용하여 작은 애플리케이션을 작성합니다. SQLite는 모든 프로그래밍 언어에서 작동하고 예를 들어 데이터를 분석하기 위해 로컬 시스템에 복사할 수 있는 편리한 작은 단일 파일 데이터베이스입니다. 그래서 서버리스 접근 방식, 배포 용이성, SQLite 사용 기능을 결합한 미들웨어 솔루션을 찾다가 Fly.io를 발견했습니다.
Fly.io에 계정이 없다면 계정을 만들어야 합니다. 또한 프로젝트를 관리하려면 flyctl이라는 CLI 도구가 필요합니다. Fly.io는 로컬 및 CI에서 모두 배포할 수 있습니다.
flyctl은 Dockerfile의 프로젝트 루트 폴더에서 배포를 수행합니다. 이는 동일한 Dockerfile을 다른 시스템에서 사용할 수 있기 때문에 좋습니다. Fly.io를 플레이하기 위해 데이터베이스에 상태를 저장하는 간단한 FastAPI 프로젝트(클릭 계산 기능이 있는 일반 URL 단축기)를 준비했습니다.
도커파일:
FROM python:3.13-alpine WORKDIR /app COPY ./requirements.txt . RUN pip install --no-cache-dir --upgrade -r requirements.txt COPY . /app ENV HOST=0.0.0.0 PORT=8080 EXPOSE ${PORT} CMD uvicorn main:app --host ${HOST} --port ${PORT}
main.py:
import asyncio import random import string from urllib.parse import urlparse import aiosqlite from fastapi import FastAPI, HTTPException, Request from fastapi.responses import RedirectResponse DB_PATH = "/data/app.db" app = FastAPI() async def get_db() -> aiosqlite.Connection: if db := getattr(get_db, "_db", None): if db.is_alive: return db db = await aiosqlite.connect(DB_PATH, loop=asyncio.get_event_loop()) db.row_factory = aiosqlite.Row qs = """ CREATE TABLE IF NOT EXISTS links ( created_at INTEGER DEFAULT (strftime('%s', 'now')), short_code TEXT PRIMARY KEY, full_url TEXT NOT NULL, clicks INTEGER DEFAULT 0 ) """ await db.execute(qs) await db.commit() setattr(get_db, "_db", db) return db def random_code(length=8) -> str: alphabet = string.ascii_letters + string.digits return "".join(random.choice(alphabet) for x in range(length)) def is_valid_url(url: str) -> bool: try: parts = urlparse(url) return all([parts.scheme, parts.netloc]) except ValueError: return False @app.post("/") async def shorten(url: str, req: Request): if not is_valid_url(url): raise HTTPException(status_code=400, detail="Invalid URL") host = req.headers.get("host") if host is None: raise HTTPException(status_code=500, detail="Missing host header") short_code = random_code() db = await get_db() qs = "INSERT INTO links (short_code, full_url) VALUES (?, ?)" await db.execute(qs, (short_code, url)) await db.commit() return f"https://{host}/{short_code}" @app.get("/") async def list_links(): db = await get_db() qs = "SELECT short_code, full_url, clicks FROM links ORDER BY created_at DESC" async with db.execute(qs) as cursor: return await cursor.fetchall() @app.get("/{short_code}") async def redirect(short_code: str): db = await get_db() qs = """ UPDATE links SET clicks = clicks + 1 WHERE short_code = ? RETURNING full_url """ async with db.execute(qs, (short_code,)) as cursor: if row := await cursor.fetchone(): return RedirectResponse(row["full_url"]) raise HTTPException(status_code=404)
requirements.txt:
aiosqlite fastapi uvicorn
코드를 배포하려면 먼저 Fly.io 프로젝트를 만들어야 합니다. 이는 웹 인터페이스나 flyctl을 사용하여 수행할 수 있습니다. 코드가 있는 루트 폴더에 CLU 도구를 사용하여 프로젝트를 생성하려면 flyctl launch를 실행해야 합니다. 이 명령은 원하는 하드웨어를 선택하고 fly.toml 파일을 생성합니다:
fly launch --build-only
나중에 이 파일의 매개변수를 변경하거나 웹 UI를 통해 프로젝트를 수정할 수 있습니다. 기본 fly.toml은 괜찮아 보이지만 SQLite에는 다음을 사용하여 생성할 수 있는 Storage가 필요합니다.
fly volumes create sqlite_data -s 1 -r ams
여기서 -s 1은 볼륨 크기를 1GB(기본값은 3GB)로 설정하고 -r은 볼륨이 생성될 영역입니다(Fly.io 프로젝트가 생성되는 동일한 영역 사용). 저장용량 크기는 나중에 언제든지 변경할 수 있습니다.
마지막으로 해야 할 일은 fly.toml에 마운트 섹션을 추가하는 것입니다. 그러면 애플리케이션에 볼륨이 연결됩니다.
FROM python:3.13-alpine WORKDIR /app COPY ./requirements.txt . RUN pip install --no-cache-dir --upgrade -r requirements.txt COPY . /app ENV HOST=0.0.0.0 PORT=8080 EXPOSE ${PORT} CMD uvicorn main:app --host ${HOST} --port ${PORT}
sqlite_data는 스토리지 이름, /data는 볼륨이 연결될 경로입니다. 이는 docker run --mount source=sqlite_data,target=/data 또는 해당 Docker Compose 섹션과 기본적으로 동일합니다.
SQLite는 두 개 이상의 앱에서 쓸 수 없으며 Fly.io는 기본적으로 앱에 대해 2개의 인스턴스를 생성하므로 다음과 같은 경우에 복제본 수를 하나로 지정할 수 있습니다.
import asyncio import random import string from urllib.parse import urlparse import aiosqlite from fastapi import FastAPI, HTTPException, Request from fastapi.responses import RedirectResponse DB_PATH = "/data/app.db" app = FastAPI() async def get_db() -> aiosqlite.Connection: if db := getattr(get_db, "_db", None): if db.is_alive: return db db = await aiosqlite.connect(DB_PATH, loop=asyncio.get_event_loop()) db.row_factory = aiosqlite.Row qs = """ CREATE TABLE IF NOT EXISTS links ( created_at INTEGER DEFAULT (strftime('%s', 'now')), short_code TEXT PRIMARY KEY, full_url TEXT NOT NULL, clicks INTEGER DEFAULT 0 ) """ await db.execute(qs) await db.commit() setattr(get_db, "_db", db) return db def random_code(length=8) -> str: alphabet = string.ascii_letters + string.digits return "".join(random.choice(alphabet) for x in range(length)) def is_valid_url(url: str) -> bool: try: parts = urlparse(url) return all([parts.scheme, parts.netloc]) except ValueError: return False @app.post("/") async def shorten(url: str, req: Request): if not is_valid_url(url): raise HTTPException(status_code=400, detail="Invalid URL") host = req.headers.get("host") if host is None: raise HTTPException(status_code=500, detail="Missing host header") short_code = random_code() db = await get_db() qs = "INSERT INTO links (short_code, full_url) VALUES (?, ?)" await db.execute(qs, (short_code, url)) await db.commit() return f"https://{host}/{short_code}" @app.get("/") async def list_links(): db = await get_db() qs = "SELECT short_code, full_url, clicks FROM links ORDER BY created_at DESC" async with db.execute(qs) as cursor: return await cursor.fetchall() @app.get("/{short_code}") async def redirect(short_code: str): db = await get_db() qs = """ UPDATE links SET clicks = clicks + 1 WHERE short_code = ? RETURNING full_url """ async with db.execute(qs, (short_code,)) as cursor: if row := await cursor.fetchone(): return RedirectResponse(row["full_url"]) raise HTTPException(status_code=404)
이제 모든 구성이 완료되었으며 다음 명령을 사용하여 앱을 배포할 수 있습니다.
aiosqlite fastapi uvicorn
앱이 성공적으로 부팅되고 공용 DNS 이름이 콘솔에 인쇄됩니다. 이제 URL을 단축기에 게시하여 확인할 수 있습니다.
fly launch --build-only
그런 다음 이 링크를 방문하면 https://example.com으로 리디렉션됩니다. 마지막으로 클릭수가 업데이트되었는지 확인할 수 있습니다.
fly volumes create sqlite_data -s 1 -r ams
배포 사이에 저장된 데이터베이스 상태를 확인하려면 fly 배포로 새 배포를 수행하고 링크 목록이 위와 동일하게 유지되는지 확인할 수 있습니다(링크 1개, 클릭 1개).
마이그레이션을 위해 외부 솔루션을 사용하는 경우 앱이 시작될 때 코드에서 실행하는 대신 마이그레이션을 실행하는 유일한 방법은 RUN 명령의 일부로 Dockerfile에 넣는 것입니다.
Fly SSH 콘솔을 사용하여 컴퓨터에 연결한 다음 /data 폴더에서 데이터베이스 파일과 상호 작용할 수 있습니다. 또한 다음을 사용하여 데이터베이스 파일을 로컬 컴퓨터에 복사할 수 있습니다.
[mounts] source = "sqlite_data" destination = "/data"
Fly.io는 애플리케이션 배포를 위한 간단하고 편리한 서비스입니다. 배포는 Docker 컨테이너에서 작동하며 추가 서비스에는 PSQL, Redis, S3와 같은 스토리지(Vercel과 다름)가 포함됩니다. 가장 저렴한 서비스 비용은 3달러(공유 CPU 1개/256MB)입니다. 트래픽이 거의 없는 경우에는 더 적을 수도 있습니다. 컨테이너는 몇 분 동안 활동이 없으면 종료되고 트래픽이 나타나면 자동으로 켜집니다.
단점은 예약된 작업을 위한 내장 솔루션이 없다는 점입니다. 대신 공식적인 솔루션은 crontab을 사용하여 별도의 서버를 설정하고 여기에서 작업을 실행하는 것입니다. 다소 소름끼칩니다.
위 내용은 Fly.io에서 SQLite를 사용하여 FastAPI 애플리케이션 배포의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!