글 목록으로 돌아가기

Cloud

Django REST API 생성과 Container 배포 준비

Python 가상환경에서 Django Project와 REST API Application을 만들고 설정·URL·검증 절차를 Container 배포 전 단계까지 구성합니다

Dohyeon Kim
Dohyeon Kim 2026년 10월 1일 · 5분 읽기
Cloud AWS AutoEverSW

요약


ECS에 Application을 배포하기 전에 Local에서 재현 가능한 Django Project와 REST Endpoint를 준비합니다. Python 가상환경으로 의존성을 격리하고, Django Project와 Application의 역할을 분리하며, 환경 변수로 Host와 Secret을 주입할 수 있게 구성합니다. 이 글은 Container Image, ECR와 ECS 배포 전 단계인 Application 생성과 Local 검증까지 다룹니다.

1. Django Project와 Application


Django에서 Project와 Application은 역할이 다릅니다.

구분 역할 이 글의 이름
Project 전체 Site의 설정, Root URL, WSGI·ASGI Entry Point 관리 apiserver
Application 특정 Domain의 View, Model, URL과 Test 관리 api

하나의 Project는 여러 Application을 포함할 수 있습니다. apiserver Package 자체를 업무 기능 Application처럼 INSTALLED_APPS에 추가하지 않고 실제 기능을 담당하는 api Application을 생성합니다.

2. 작업 Directory와 가상환경 생성


Python 가상환경은 Project별 Package Version을 분리합니다. Python 3.10 이상을 확인합니다.

python3 --version

Project Directory를 만들고 이동합니다.

mkdir django-api
cd django-api

.venv Directory에 가상환경을 생성합니다.

python3 -m venv .venv

운영체제와 Shell에 맞는 명령으로 활성화합니다.

환경 명령
Linux·macOS Bash/Zsh source .venv/bin/activate
Windows PowerShell .venv\Scripts\Activate.ps1
Windows Command Prompt .venv\Scripts\activate.bat

활성화된 Python과 pip가 .venv를 가리키는지 확인합니다.

python -c 'import sys; print(sys.executable)'
python -m pip --version

3. Django와 Django REST Framework 설치


이 예제는 장기 지원 버전인 Django 5.2 계열을 사용합니다. pip 자체를 갱신한 뒤 Django와 Django REST Framework를 설치합니다.

python -m pip install --upgrade pip
python -m pip install "Django==5.2.*" djangorestframework

설치 Version을 확인합니다.

python -m django --version
python -m pip show djangorestframework

pip 대신 python -m pip를 사용하면 현재 활성화한 Python Interpreter와 Package 설치 위치를 일치시키기 쉽습니다.

4. Project와 Application 생성


현재 Directory에 manage.py와 apiserver Package를 생성합니다.

django-admin startproject apiserver .

REST Endpoint를 담당할 api Application을 생성합니다.

python manage.py startapp api

생성된 주요 구조는 다음과 같습니다.

django-api/
├── .venv/
├── api/
│   ├── migrations/
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── apiserver/
│   ├── settings.py
│   ├── urls.py
│   ├── asgi.py
│   └── wsgi.py
└── manage.py
File 역할
manage.py 개발 Server, Migration, Test와 점검 명령 실행
apiserver/settings.py Application, Database, Time Zone와 보안 설정
apiserver/urls.py Project의 Root URL Routing
apiserver/wsgi.py WSGI Server의 Application Entry Point
apiserver/asgi.py ASGI Server의 Application Entry Point
api/views.py HTTP 요청 처리와 Response 생성
api/urls.py api Application 내부 URL Routing

5. Project 설정


apiserver/settings.py에서 표준 Library의 os를 Import합니다.

import os
from pathlib import Path

배포 환경에서 Secret Key를 Source Code에 고정하지 않도록 환경 변수에서 읽습니다.

SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]

허용할 Host도 환경 변수로 주입합니다.

ALLOWED_HOSTS = [
    host.strip()
    for host in os.environ.get(
        "DJANGO_ALLOWED_HOSTS",
        "127.0.0.1,localhost",
    ).split(",")
    if host.strip()
]

ALLOWED_HOSTS = ["*"]는 모든 Host Header를 허용하므로 운영 기본값으로 사용하지 않습니다. ALB Domain, Service Domain과 Health Check 경로에 실제로 필요한 Host만 지정합니다.

INSTALLED_APPS에는 Django REST Framework와 생성한 Application을 등록합니다.

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "rest_framework",
    "api",
]

Time Zone을 설정합니다.

TIME_ZONE = "Asia/Seoul"
USE_TZ = True

USE_TZ = True이면 Django는 내부 DateTime을 UTC 기준으로 다루고 표시 단계에서 설정한 Time Zone으로 변환합니다.

6. Local 환경 변수 설정


Local Shell에서 개발용 값을 설정합니다. <LOCAL_DEVELOPMENT_SECRET>에는 실제 운영 Secret과 다른 충분히 긴 임의 값을 사용합니다.

export DJANGO_SECRET_KEY='<LOCAL_DEVELOPMENT_SECRET>'
export DJANGO_ALLOWED_HOSTS='127.0.0.1,localhost'

운영 환경에서는 ECS Task Definition의 평문 Environment Variable에 Secret을 직접 입력하지 않고 AWS Secrets Manager 또는 Systems Manager Parameter Store를 이용해 주입합니다. 실제 값과 .env File은 Git에 Commit하지 않습니다.

환경 변수 이름만 확인하고 값은 출력하지 않습니다.

test -n "$DJANGO_SECRET_KEY" && echo 'DJANGO_SECRET_KEY is set'

7. REST API View 작성


api/views.py에 GET 요청을 처리하는 View를 작성합니다.

from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response


@api_view(["GET"])
def index(request):
    data = {
        "result": "success",
        "data": [
            {"id": "user-001", "name": "Example User"},
            {"id": "user-002", "name": "Sample User"},
        ],
    }
    return Response(data, status=status.HTTP_200_OK)

@api_view(["GET"])는 허용할 HTTP Method를 제한하고 Django REST Framework가 Request와 Response를 처리하게 합니다. 다른 Method로 요청하면 405 Method Not Allowed가 반환됩니다.

8. Application URL 구성


api/urls.py를 새로 생성합니다.

from django.urls import path

from .views import index


app_name = "api"

urlpatterns = [
    path("", index, name="index"),
]

Project의 apiserver/urls.py에서 api URL을 포함합니다.

from django.contrib import admin
from django.urls import include, path


urlpatterns = [
    path("admin/", admin.site.urls),
    path("api/", include("api.urls")),
]

Routing 흐름은 다음과 같습니다.

GET /api/
  ↓ apiserver/urls.py
include("api.urls")
  ↓ api/urls.py
index View
  ↓
JSON Response

9. Database 초기화와 설정 점검


Django 기본 Application이 사용하는 Database Table을 생성합니다.

python manage.py migrate

Project 설정과 URL 구성을 점검합니다.

python manage.py check

Migration 상태를 확인합니다.

python manage.py showmigrations

기본 설정은 Local SQLite File을 사용합니다. Container를 교체하면 Container 내부의 SQLite File도 사라질 수 있으므로 운영 ECS 환경에서는 RDS 같은 외부 Database와 Network·Credential 구성을 별도로 준비합니다.

10. API Test 작성


api/tests.py에 Endpoint의 Status Code와 JSON 구조를 검증하는 Test를 작성합니다.

from django.test import TestCase
from django.urls import reverse


class IndexApiTest(TestCase):
    def test_index_returns_success(self):
        response = self.client.get(reverse("api:index"))

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json()["result"], "success")
        self.assertEqual(len(response.json()["data"]), 2)

Test를 실행합니다.

python manage.py test

Test가 통과해야 Build Pipeline이 다음 단계로 진행하도록 CI에 연결할 수 있습니다.

11. 개발 Server 실행과 검증


Django 개발 Server를 Local Loopback Address에서 실행합니다.

python manage.py runserver 127.0.0.1:8000

다른 Terminal에서 API를 호출합니다.

curl -i http://127.0.0.1:8000/api/

예상 Body는 다음과 같습니다.

{
  "result": "success",
  "data": [
    {
      "id": "user-001",
      "name": "Example User"
    },
    {
      "id": "user-002",
      "name": "Sample User"
    }
  ]
}

지원하지 않는 Method가 거부되는지도 확인합니다.

curl -i -X POST http://127.0.0.1:8000/api/

runserver는 개발용이며 Production Traffic을 처리하도록 설계되지 않았습니다. Container 배포에서는 Gunicorn 같은 Production WSGI Server 또는 요구 사항에 맞는 ASGI Server를 사용합니다.

12. 의존성 고정


현재 가상환경의 Package Version을 requirements.txt로 저장합니다.

python -m pip freeze > requirements.txt

생성된 File을 확인합니다.

sed -n '1,120p' requirements.txt

다른 환경에서 동일한 의존성을 설치할 때 사용합니다.

python -m pip install -r requirements.txt

pip freeze는 직접 설치하지 않은 하위 의존성도 모두 기록합니다. 운영 Project에서는 Dependabot 같은 도구로 취약점과 Update를 관리하고 변경 후 Test를 수행합니다.

13. Container 배포 전 점검


Application을 Image로 만들기 전에 다음 항목을 확인합니다.

점검 항목 확인 방법
설정 오류 python manage.py check
Unit Test python manage.py test
의존성 고정 requirements.txt 생성·재설치 확인
Secret 분리 실제 Secret이 Source와 Git History에 없는지 검사
Host 제한 운영 Domain과 Health Check Host만 허용
Database Container 외부 Database와 Migration 전략 준비
Static File collectstatic과 S3·CloudFront 사용 여부 결정
Process Server runserver 대신 Production WSGI·ASGI Server 선택
Health Check Container와 Load Balancer가 호출할 Endpoint 정의
Log Standard Output·Error로 출력해 중앙 수집 준비

현재 단계의 요청 흐름은 다음과 같습니다.

Local Client
  ↓ GET /api/
Django Development Server
  ↓ URL Resolver
DRF Function View
  ↓
JSON Response

후속 Container 배포에서는 Dockerfile → Image Build → ECR Push → ECS Task Definition → ECS Service 흐름으로 확장합니다. 이 글에는 아직 Dockerfile, ECR Repository와 ECS Resource를 생성하는 절차를 포함하지 않습니다.

최종 정리

  • Django Project는 전체 설정과 Root URL을 관리하고 Application은 실제 기능을 분리합니다.

  • SECRET_KEY와 허용 Host는 환경 변수로 주입하고 실제 값을 Repository에 저장하지 않습니다.

  • REST Endpoint는 Application URL을 Project URL에 포함해 연결합니다.

  • check, Test와 Local HTTP 호출을 통과한 Application을 다음 단계에서 Container Image로 만듭니다.

참고 자료


댓글