Notice
Recent Posts
250x250
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
관리 메뉴

일상 코딩

[윈도우 개발 환경 설정] 6편: Python & FastAPI 환경 구축 본문

Windows 개발환경 세팅

[윈도우 개발 환경 설정] 6편: Python & FastAPI 환경 구축

polarcompass 2026. 3. 31. 22:25
728x90

이제 모든 최신 정보를 확인했습니다. 6편을 작성합니다.


6편: Python & FastAPI 환경 구축

시리즈: 윈도우 네이티브 개발 환경 세팅부터 클라우드 배포까지 (6/14)

이전 편 전제: Go, Gin 프레임워크, Hello World API 서버 세팅 완료


들어가며

5편에서 Go + Gin으로 첫 번째 백엔드를 만들었다. 이번 편에서는 두 번째 백엔드를 Python + FastAPI로 구축한다. FastAPI는 타입 힌트 기반의 자동 문서화, 비동기(async) 지원, Pydantic 검증 등 현대적인 Python 웹 프레임워크의 장점을 모두 갖추고 있어 API 서버로 널리 쓰인다.

pyenv-win으로 Python 버전을 관리하고, venv로 프로젝트별 가상환경을 격리한 뒤, FastAPI + Uvicorn으로 Hello World API 서버를 띄우는 것까지가 이번 편의 목표다. 모든 작업은 PowerShell 7에서 진행하며, WSL은 사용하지 않는다.


1. 사전 준비: Windows App Execution Aliases 비활성화

Windows 10/11에는 python이나 python3 명령을 입력하면 Microsoft Store로 리다이렉트하는 내장 앱 별칭이 있다. 이것이 pyenv-win보다 우선순위가 높으면 pyenv로 설치한 Python이 인식되지 않는다. 반드시 먼저 비활성화해야 한다.

시작 메뉴에서 "앱 실행 별칭 관리"(Manage App Execution Aliases)를 검색해서 연다. 목록에서 "앱 설치 관리자 - python.exe""앱 설치 관리자 - python3.exe" 두 항목을 모두 끔(Off)으로 전환한다.

이 설정은 한 번만 하면 되며, 이후 pyenv-win이 정상적으로 Python 경로를 관리할 수 있게 된다.


2. pyenv-win으로 Python 설치

2-1. pyenv-win 설치

pyenv-win 공식 리포지토리에서 제공하는 PowerShell 설치 스크립트를 사용한다.

Invoke-WebRequest -UseBasicParsing `
  -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" `
  -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"

이 스크립트는 %USERPROFILE%\.pyenv 경로에 pyenv-win을 설치하고, 환경변수(PYENV, PYENV_HOME, PYENV_ROOT)와 PATH(bin, shims)를 자동으로 등록한다.

설치 후 터미널을 완전히 종료했다가 다시 연다. 새 터미널에서 확인한다.

pyenv --version
pyenv 3.1.1

버전 번호가 출력되면 성공이다.

Execution Policy 에러가 발생하면: Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned를 먼저 실행한다. (1편에서 이미 설정했다면 생략)

2-2. 설치 가능한 Python 버전 목록 확인

pyenv install -l

수백 개의 버전이 출력된다. 특정 버전만 필터링하려면:

pyenv install -l | findstr 3.13
3.13.0-win32
3.13.0
3.13.1-win32
3.13.1
...
3.13.12-win32
3.13.12

목록이 최신 버전을 포함하지 않는다면: pyenv update 명령으로 버전 데이터베이스를 갱신한다.

2-3. Python 설치

현재 Python 안정 버전은 3.13 계열이다. FastAPI 최신 버전(0.135.x)이 Python 3.10 이상을 요구하므로 3.13을 설치한다.

pyenv install 3.13.12

참고: 설치 중 Windows 인스톨러 위저드가 나타날 수 있다. 기본 옵션 그대로 진행하면 된다. 조용한 설치를 원하면 pyenv install 3.13.12 -q 플래그를 추가한다.

2-4. 글로벌 버전 설정

pyenv global 3.13.12

이 명령은 시스템 전체에서 기본으로 사용할 Python 버전을 지정한다. 확인한다.

pyenv version
3.13.12 (set by C:\Users\사용자이름\.pyenv\pyenv-win\.python-version)

Python과 pip도 확인한다.

python --version
pip --version
Python 3.13.12
pip 24.x.x from C:\Users\사용자이름\.pyenv\pyenv-win\versions\3.13.12\Lib\site-packages\pip (python 3.13)

python 명령이 여전히 Microsoft Store로 연결된다면: 1장의 App Execution Aliases 비활성화를 다시 확인한다. 또한 환경변수에서 pyenv의 shims 경로가 다른 Python 경로보다 위에(높은 우선순위) 있는지 확인한다.

2-5. pyenv 핵심 명령어 정리

pyenv-win에서 자주 쓰는 명령어를 정리하면 다음과 같다.

pyenv install -l은 설치 가능한 모든 버전을 나열한다. pyenv install <version>은 지정 버전을 설치하고, pyenv uninstall <version>은 제거한다. pyenv global <version>은 시스템 전체 기본 버전을 설정하고, pyenv local <version>은 현재 디렉토리에 .python-version 파일을 생성해서 해당 폴더에서만 특정 버전을 사용하게 한다. pyenv versions는 설치된 모든 버전을 보여주고, pyenv version은 현재 활성 버전을 보여준다. pyenv rehash는 shim을 재생성하며, pip로 패키지를 설치한 뒤 CLI 도구가 인식되지 않을 때 실행한다. pyenv update는 설치 가능한 버전 목록 데이터베이스를 갱신한다.


3. 가상환경(venv) 설정

Python 프로젝트마다 의존성 버전이 다르기 때문에 가상환경으로 격리하는 것이 필수다. Python 3.3부터 표준 라이브러리에 포함된 venv 모듈을 사용한다. 별도 설치가 필요 없다.

3-1. 프로젝트 디렉토리 생성

mkdir my-fastapi-app
cd my-fastapi-app

3-2. 가상환경 생성

python -m venv .venv

.venv는 가상환경 디렉토리 이름이다. 관례적으로 .venv 또는 venv를 사용한다. 점(.)으로 시작하면 숨김 디렉토리가 되어 프로젝트 파일 목록이 깔끔해진다.

3-3. 가상환경 활성화

.\.venv\Scripts\Activate.ps1

활성화되면 프롬프트 앞에 (.venv)가 붙는다.

(.venv) PS C:\Users\사용자이름\my-fastapi-app>

Activate.ps1 실행이 차단된다면: 이것도 Execution Policy 문제다. Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned를 실행한다.

활성화 상태에서 pythonpip가 가상환경 내부를 가리키는지 확인한다.

python -c "import sys; print(sys.executable)"
C:\Users\사용자이름\my-fastapi-app\.venv\Scripts\python.exe

경로에 .venv가 포함되어 있으면 정상이다.

3-4. 가상환경 비활성화

작업이 끝나면 deactivate 명령으로 빠져나올 수 있다.

deactivate

프롬프트에서 (.venv)가 사라진다. 다시 활성화하려면 .\.venv\Scripts\Activate.ps1을 실행한다.

중요: 이후 모든 pip install과 서버 실행은 가상환경이 활성화된 상태에서 수행한다.


4. FastAPI + Uvicorn 설치

4-1. 패키지 설치

가상환경이 활성화된 상태에서 설치한다.

pip install fastapi uvicorn[standard]

fastapi는 웹 프레임워크 본체이고, uvicorn[standard]는 ASGI 서버에 추가 의존성(uvloop, httptools 등)을 포함한 버전이다. 현재 FastAPI 최신 버전은 0.135.2, Uvicorn은 0.42.0이다.

설치 확인:

pip show fastapi
pip show uvicorn

각각 Name, Version, Location 정보가 출력되면 정상이다.

4-2. requirements.txt 생성

현재 가상환경에 설치된 모든 패키지를 파일로 기록한다. 다른 환경에서 동일한 의존성을 재현할 때 사용한다.

pip freeze > requirements.txt
cat requirements.txt
annotated-types==0.7.0
anyio==4.8.0
click==8.1.8
colorama==0.4.6
fastapi==0.135.2
h11==0.14.0
httptools==0.6.4
idna==3.10
pydantic==2.10.6
pydantic_core==2.27.2
sniffio==1.3.1
starlette==0.45.3
typing_extensions==4.12.2
uvicorn==0.42.0
...

나중에 이 파일로 의존성을 설치하려면 pip install -r requirements.txt를 실행하면 된다.


5. Hello World API 서버 작성

5-1. main.py 생성

프로젝트 루트에 main.py 파일을 만든다.

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello, FastAPI!"}


@app.get("/ping")
async def ping():
    return {"message": "pong"}


@app.get("/hello/{name}")
async def hello(name: str):
    return {"hello": name}

코드를 하나씩 짚어 보자.

FastAPI()로 애플리케이션 인스턴스를 생성한다. 이 객체가 라우트, 미들웨어, 이벤트 핸들러 등 모든 설정의 진입점이다.

@app.get("/")은 데코레이터로 GET 요청에 대한 경로를 등록한다. 함수 이름은 자유롭게 지정할 수 있고, 반환값은 자동으로 JSON 직렬화된다.

@app.get("/hello/{name}")에서 {name}은 경로 파라미터다. 함수 인자 name: str의 타입 힌트를 FastAPI가 읽어서 자동 검증과 문서화에 사용한다. 5편의 Gin 예제에서 :name으로 작성했던 것과 같은 역할이다.

async def를 사용한 이유는 FastAPI가 비동기 함수를 네이티브로 지원하기 때문이다. 동기 함수(def)로 작성해도 동작하지만, I/O 바운드 작업에서는 async가 성능상 유리하다.

5-2. 현재 프로젝트 구조

my-fastapi-app/
├── .venv/                ← 가상환경 (git에 포함하지 않음)
├── main.py
└── requirements.txt

6. 서버 실행 & 확인

6-1. 서버 실행

가상환경이 활성화된 상태에서 Uvicorn으로 서버를 시작한다.

uvicorn main:app --reload

main:app에서 main은 파일명(main.py), app은 FastAPI 인스턴스 변수명이다. --reload는 코드 변경 시 서버를 자동 재시작하는 개발 모드 옵션이다.

INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [xxxxx] using StatReload
INFO:     Started server process [xxxxx]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

6-2. API 테스트

새 PowerShell 탭을 열어서 요청을 보낸다.

curl http://localhost:8000/
{"message":"Hello, FastAPI!"}
curl http://localhost:8000/ping
{"message":"pong"}
curl http://localhost:8000/hello/pythonista
{"hello":"pythonista"}

6-3. 자동 생성 API 문서 확인

FastAPI의 킬러 기능 중 하나는 자동 API 문서 생성이다. 코드에 작성한 라우트와 타입 힌트를 기반으로 인터랙티브 문서가 자동으로 만들어진다.

브라우저에서 http://localhost:8000/docs를 열면 Swagger UI가 표시된다. 각 엔드포인트를 펼쳐서 "Try it out" 버튼으로 바로 요청을 보내볼 수 있다.

http://localhost:8000/redoc을 열면 ReDoc 스타일의 문서가 표시된다. 읽기 전용이지만 레이아웃이 더 깔끔하다.

별도의 설정이나 코드를 작성하지 않아도 이 문서가 자동 생성된다는 점이 FastAPI의 가장 큰 장점이다.

6-4. 서버 종료

서버가 실행 중인 터미널에서 Ctrl+C를 누르면 종료된다.


7. 포트 정리: Go 서버와 Python 서버

현재까지 두 개의 백엔드 서버를 세팅했다. 각각 다른 포트에서 동작한다.

Go + Gin 서버는 :8080, Python + FastAPI 서버는 :8000이다. 프론트엔드 Vite 개발 서버는 :5173이다.

나중에 클라우드 서버에 배포할 때 Caddy(11편)가 리버스 프록시로 이 포트들을 하나의 도메인 아래 묶어주게 된다. 예를 들어 /api/go/*:8080으로, /api/py/*:8000으로 라우팅하는 식이다. 지금은 로컬에서 각 서버가 서로 다른 포트에서 충돌 없이 동작하는 것만 확인하면 충분하다.


8. .gitignore 설정

Python 프로젝트에서 Git에 포함하면 안 되는 파일과 디렉토리를 .gitignore에 등록한다.

New-Item -Path ".gitignore" -ItemType File

.gitignore:

# Python
__pycache__/
*.py[cod]
*.pyo
*.egg-info/
dist/
build/

# 가상환경
.venv/

# IDE
.vscode/
.idea/

# 환경변수
.env

9. 최종 확인 체크리스트

# 1. pyenv & Python 확인
pyenv --version
python --version
pip --version

# 2. 프로젝트 이동 & 가상환경 활성화
cd my-fastapi-app
.\.venv\Scripts\Activate.ps1

# 3. FastAPI & Uvicorn 설치 확인
pip show fastapi
pip show uvicorn

# 4. 서버 실행
uvicorn main:app --reload
# → http://127.0.0.1:8000 에서 서버 시작

# 5. 새 터미널에서 API 테스트
curl http://localhost:8000/
# → {"message":"Hello, FastAPI!"}

curl http://localhost:8000/ping
# → {"message":"pong"}

curl http://localhost:8000/hello/pythonista
# → {"hello":"pythonista"}

# 6. 자동 API 문서 확인
# → 브라우저에서 http://localhost:8000/docs 열기 (Swagger UI)
# → 브라우저에서 http://localhost:8000/redoc 열기 (ReDoc)
확인 항목 기대 결과
pyenv --version pyenv 3.1.1
python --version Python 3.13.12
pip --version pip 24.x.x (가상환경 경로 포함)
pip show fastapi Version: 0.135.x
pip show uvicorn Version: 0.42.x
uvicorn main:app --reload http://127.0.0.1:8000에서 서버 시작
GET / {"message":"Hello, FastAPI!"}
GET /ping {"message":"pong"}
GET /hello/pythonista {"hello":"pythonista"}
http://localhost:8000/docs Swagger UI 표시

10. 원클릭 자동화 스크립트

아래 PowerShell 스크립트로 pyenv-win 설치 확인부터 Python 설치, 가상환경 생성, FastAPI 프로젝트 세팅까지 자동화할 수 있다.

10-1. 스크립트 파일 생성

아래 내용을 setup-fastapi.ps1로 저장한다.

<#
  setup-fastapi.ps1
  6편 자동화 스크립트: Python + FastAPI + Uvicorn 환경 구축
  실행: PowerShell 7에서 .\setup-fastapi.ps1
  인자: -ProjectName <이름>      (기본값: my-fastapi-app)
        -PythonVersion <버전>    (기본값: 3.13.12)
#>

param(
    [string]$ProjectName = "my-fastapi-app",
    [string]$PythonVersion = "3.13.12"
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

function Write-Step {
    param([string]$Message)
    Write-Host "`n========================================" -ForegroundColor Cyan
    Write-Host " $Message" -ForegroundColor Cyan
    Write-Host "========================================" -ForegroundColor Cyan
}

# ─────────────────────────────────────────────
# 1. pyenv-win 설치 확인
# ─────────────────────────────────────────────
Write-Step "1/8 pyenv-win 확인"

if (-not (Get-Command pyenv -ErrorAction SilentlyContinue)) {
    Write-Host "pyenv-win이 설치되어 있지 않습니다. 설치합니다..." -ForegroundColor Yellow
    Invoke-WebRequest -UseBasicParsing `
        -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" `
        -OutFile "./install-pyenv-win.ps1"
    & "./install-pyenv-win.ps1"
    Remove-Item "./install-pyenv-win.ps1" -ErrorAction SilentlyContinue

    # PATH 새로고침
    $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")

    if (-not (Get-Command pyenv -ErrorAction SilentlyContinue)) {
        Write-Host "pyenv-win 설치 후 터미널을 재시작해야 합니다. 스크립트를 종료합니다." -ForegroundColor Red
        exit 1
    }
}
Write-Host "pyenv version: $(pyenv --version)" -ForegroundColor Green

# ─────────────────────────────────────────────
# 2. 버전 목록 갱신
# ─────────────────────────────────────────────
Write-Step "2/8 pyenv 버전 목록 갱신"

pyenv update 2>&1 | Out-Null
Write-Host "버전 목록 갱신 완료" -ForegroundColor Green

# ─────────────────────────────────────────────
# 3. Python 설치
# ─────────────────────────────────────────────
Write-Step "3/8 Python $PythonVersion 설치"

$installedVersions = pyenv versions 2>&1 | Out-String
if ($installedVersions -match [regex]::Escape($PythonVersion)) {
    Write-Host "Python $PythonVersion 이미 설치되어 있습니다." -ForegroundColor Yellow
} else {
    Write-Host "Python $PythonVersion 설치 중... (시간이 걸릴 수 있습니다)" -ForegroundColor Yellow
    pyenv install $PythonVersion -q
}

pyenv global $PythonVersion
pyenv rehash

# PATH 새로고침 (shims 반영)
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")

Write-Host "python: $(python --version)" -ForegroundColor Green
Write-Host "pip:    $(pip --version)" -ForegroundColor Green

# ─────────────────────────────────────────────
# 4. 프로젝트 디렉토리 생성
# ─────────────────────────────────────────────
Write-Step "4/8 프로젝트 생성: $ProjectName"

if (Test-Path $ProjectName) {
    Write-Host "'$ProjectName' 폴더가 이미 존재합니다. 건너뜁니다." -ForegroundColor Yellow
} else {
    New-Item -ItemType Directory -Path $ProjectName | Out-Null
}

Set-Location $ProjectName

# ─────────────────────────────────────────────
# 5. 가상환경 생성 & 활성화
# ─────────────────────────────────────────────
Write-Step "5/8 가상환경 생성"

if (-not (Test-Path ".venv")) {
    python -m venv .venv
    Write-Host ".venv 생성 완료" -ForegroundColor Green
} else {
    Write-Host ".venv가 이미 존재합니다." -ForegroundColor Yellow
}

# 활성화
& ".\.venv\Scripts\Activate.ps1"
Write-Host "가상환경 활성화됨: $(python -c 'import sys; print(sys.executable)')" -ForegroundColor Green

# ─────────────────────────────────────────────
# 6. FastAPI + Uvicorn 설치
# ─────────────────────────────────────────────
Write-Step "6/8 FastAPI + Uvicorn 설치"

pip install --upgrade pip 2>&1 | Out-Null
pip install fastapi "uvicorn[standard]"

Write-Host "fastapi:  $(pip show fastapi | Select-String 'Version')" -ForegroundColor Green
Write-Host "uvicorn:  $(pip show uvicorn | Select-String 'Version')" -ForegroundColor Green

# requirements.txt 생성
pip freeze > requirements.txt
Write-Host "requirements.txt 생성 완료" -ForegroundColor Green

# ─────────────────────────────────────────────
# 7. 소스 파일 생성
# ─────────────────────────────────────────────
Write-Step "7/8 소스 파일 생성"

# main.py
$mainPy = @'
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello, FastAPI!"}


@app.get("/ping")
async def ping():
    return {"message": "pong"}


@app.get("/hello/{name}")
async def hello(name: str):
    return {"hello": name}
'@

Set-Content -Path "main.py" -Value $mainPy -Encoding UTF8
Write-Host "  main.py" -ForegroundColor Gray

# .gitignore
$gitignore = @'
# Python
__pycache__/
*.py[cod]
*.pyo
*.egg-info/
dist/
build/

# 가상환경
.venv/

# IDE
.vscode/
.idea/

# 환경변수
.env
'@

Set-Content -Path ".gitignore" -Value $gitignore -Encoding UTF8
Write-Host "  .gitignore" -ForegroundColor Gray

Write-Host "소스 파일 생성 완료" -ForegroundColor Green

# ─────────────────────────────────────────────
# 8. 빌드(import) 테스트
# ─────────────────────────────────────────────
Write-Step "8/8 FastAPI import 테스트"

$testResult = python -c "from fastapi import FastAPI; app = FastAPI(); print('FastAPI import OK')" 2>&1
if ($testResult -match "OK") {
    Write-Host $testResult -ForegroundColor Green
} else {
    Write-Host "FastAPI import 실패. 에러 로그를 확인하세요." -ForegroundColor Red
    Write-Host $testResult -ForegroundColor Red
    exit 1
}

# ─────────────────────────────────────────────
# 완료 메시지
# ─────────────────────────────────────────────
Write-Host "`n" -NoNewline
Write-Host "============================================" -ForegroundColor Green
Write-Host " Python + FastAPI 프로젝트 세팅 완료!" -ForegroundColor Green
Write-Host "============================================" -ForegroundColor Green
Write-Host ""
Write-Host "  프로젝트 경로:     $(Get-Location)" -ForegroundColor White
Write-Host "  Python 버전:       $(python --version)" -ForegroundColor White
Write-Host "  가상환경 활성화:   .\.venv\Scripts\Activate.ps1" -ForegroundColor White
Write-Host "  개발 서버 실행:    uvicorn main:app --reload" -ForegroundColor White
Write-Host "  API 문서:          http://localhost:8000/docs" -ForegroundColor White
Write-Host "  테스트 요청:       curl http://localhost:8000/ping" -ForegroundColor White
Write-Host ""
Write-Host "  현재 프로젝트 구조:" -ForegroundColor White
Write-Host "  $ProjectName/" -ForegroundColor Gray
Write-Host "  ├── .venv/" -ForegroundColor Gray
Write-Host "  ├── .gitignore" -ForegroundColor Gray
Write-Host "  ├── main.py" -ForegroundColor Gray
Write-Host "  └── requirements.txt" -ForegroundColor Gray
Write-Host ""

10-2. 스크립트 실행

# 기본값으로 생성
.\setup-fastapi.ps1

# 커스텀 프로젝트 이름과 Python 버전 지정
.\setup-fastapi.ps1 -ProjectName "my-api-server" -PythonVersion "3.13.12"

스크립트가 완료되면 8단계 모두 녹색 메시지로 결과가 출력된다. 가상환경이 활성화된 상태로 마무리되므로, 바로 uvicorn main:app --reload로 개발 서버를 시작할 수 있다.


다음 편 예고

7편: Docker Desktop 설치 & 기본 사용법에서는 Docker Desktop을 윈도우에 설치하고, 이미지·컨테이너·볼륨 등 Docker의 핵심 개념을 실습한다. 8편부터는 PostgreSQL, MinIO, n8n을 각각 Docker 컨테이너로 띄우게 되므로, 7편에서 Docker의 기본기를 확실히 다져 두는 것이 중요하다.

728x90