Привет, Хабр! В этой статье мы запустим Docker с Django на локальной машине. Этот материал ориентирован исключительно на локальную разработку — наш Django будет работать с SQLite без использования образов PostgreSQL. Уже в следующей статье мы соберем более сложное приложение. Все действия будем выполнять в Windows, так как большинство начинающих разработчиков используют именно эту операционную систему. Перед началом работы убедитесь, что у вас установлен и настроен Docker Desktop для Windows. В сети много руководств по его установке, поэтому думаю, что с этим не возникнет проблем. Мы будем использовать Django 5.2.6 и Docker Desktop 28.4.0. Весь проект доступен на GitHub. Если материал оказался полезным, буду благодарен за звёзды в репозитории. Первым делом создадим приложение, для которого будем собирать образ:

pip install django==5.2.6

django-admin startproject app

cd startproject/

python manage.py runserver

Перейдем по url - http://127.0.0.1:8000/

Мы создали приложение Django, теперь сделаем простое приложение в нем и выведем - hello habr:

python manage.py startapp test_app

Теперь добавим приложение и сделаем самую простой views на FBV.

# app/urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('test_app.urls')), # Добавляем наше test_app приложение
]
# app/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'test_app', # Наше приложение
]
# test_app/views.py

from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    return HttpResponse("<h1>hello habr!<h1>") # вывод на нашу HTML страницу.

Создаем urls.py в test_app/ и вставляем данный код:

# test_app/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

Теперь повторно запускаем проект и видим:

По итогу у вас должен получится вот такой проект:

Теперь к Docker'у. Но перед этим важно понять для чего он нужен. Если вы только начинаете свой путь в веб-разработке, закономерный вопрос: "Зачем усложнять себе жизнь Docker'ом, если Django и так отлично работает?". Давайте разберемся на практических примерах. По моему мнению если хочешь что-то объяснить, то покажи на понятном примере.

Представьте ситуацию: - Вы написали крутое приложение на Django 5.2.6 с Python 3.11 - Ваш друг хочет помочь с разработкой, но у него стоит Python 3.8 - При запуске возникают ошибки совместимости - Вы тратите день на настройку окружения вместо программирования

Почему Docker, а не встроенный venv? Хороший вопрос. В Python есть встроенный инструмент venv для виртуальных окружений. Зачем тогда нужен Docker? Давайте вернемся обратно к примерам.

venv это как отдельная комната в доме:
- У вас есть изоляция для Python-пакетов
- Можно иметь разные версии
Django для разных проектов - Не конфликтуют зависимости между проектами

На бумажке всё звучит очень хорошо. И будто Docker ваш и не нужен. Уже задумались и без него об этом в Python. Сделав такой прекрасный инструмент, как venv. Но не всё так просто, как кажется. Но не стоит кое что забывать. А как насчет версии Python? Системные библиотеки? Базы данных? Внешние сервисы (Redis, Celery)?

Если вы частенько любите обновлять Windows или пишите на нескольких устройствах. Вы встречались с этой проблемой и прекрасно понимаете всю эту боль. Клонируешь репозиторий на новое устройство и при запуске приложения видите, что библиотека не установлена, другая старой версии, у третей с четвертой несовместимость версий.

Надеюсь! Понимание у вас появилось для чего все компании просят Docker. И мы можем приступить к созданию первого Dockerfile. Расположение у него будет в корне.

Но перед заполнением первого Dockerfile. Выполним данную команду, которая собирает все библиотеки, которые установлены на вашем устройстве, окружение.

pip freeze > requirements.txt

# Мой пример requirements.txt
asgiref==3.9.1
Django==5.2.6
sqlparse==0.5.3
tzdata==2025.2

Теперь заполним Dockerfile:

# Dockerfile

# Берем готовую основу: Python 3.11 на упрощенной системе Linux
FROM python:3.11-slim-bookworm

# Говорим Python не создавать временные файлы (.pyc) - чтобы не захламлять контейнер
ENV PYTHONDONTWRITEBYTECODE 1

# Говорим Python сразу показывать все сообщения в консоли (без задержек)
ENV PYTHONUNBUFFERED 1

# Создаем папку /app внутри контейнера и переходим в нее
# Это как создать рабочую папку на новом компьютере
WORKDIR /app

# Копируем файл с зависимостями (список что нужно установить)
COPY requirements.txt .

# Устанавливаем все нужные библиотеки из requirements.txt
# Флаг --no-cache-dir говорит не сохранять временные файлы установки
RUN pip install --no-cache-dir -r requirements.txt

# Копируем ВСЕ файлы из нашей текущей папки в папку /app контейнера
COPY . .

# Сообщаем что наше приложение будет работать на порту 8000
EXPOSE 8000

# Самая главная команда - что запускать когда контейнер стартует
# Запускаем Django-сервер так, чтобы он был доступен снаружи
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

После этого выполним команды:

# Эта команда читает Dockerfile и создает образ
docker build -t django_docker .

# Стартуем!!!
docker run -p 8000:8000 django_docker

Мы запустили первое приложение с помощью Docker'a! Оно доступно по http://127.0.0.1:8000/
Теперь посмотрим в Docker Desktop:

IMAGES
IMAGES
CONTAINERS
CONTAINERS

Можете не пугаться, если увидите в containers другое имя. Docker сам их придумывает, если мы не указываем их явно. Проект запущен в Docker. Неужели это так просто? Было бы так, если современные приложения были такими маленькими и без всяких nginx, PostgreSQL, React. Для них нужны точно такие же Dockerfile. Но не в ручную же каждый запускать? Конечно это можно сделать, но будет ли такой подход удобный.

Судя приходит Docker Compose, который решает эту проблему. Если Dockerfile - это инструкция по сборке одного компьютера, то Docker Compose - это пульт управления целым компьютерным классом.

Создадим его в корне нашего проекта:

Теперь заполним содержимым данный файл:

services:
  # Создаем сервис с названием - backend
  backend:
    # Даем понятное имя контейнеру -  django_app
    container_name: django_app
    
    # Собираем образ из Dockerfile. Выше мы уже выполняли эту команду)
    build:
      context: .  # указываем путь где лежит этот Dockerfile. У меня в корне.
      dockerfile: Dockerfile  # Используем инструкции из файла Dockerfile
      # Иногда названия могут быть другие, например Dockerfile.prod - для продакшена
    
    # запускаем наш проект, как все собрали
    command: python manage.py runserver 0.0.0.0:8000
    
    # Синхронизируем папки: связываем текущую папку на компьютере с папкой /app в контейнере
    volumes:
      - .:/app  
    
    # Указываем рабочую папку внутри контейнера (где лежит наш код)
    working_dir: /app
    
    # Открываем порт 8000: связываем порт твоего компьютера с портом контейнера
    ports:
      - "8000:8000"  

А теперь стартуем!

docker-compose up --build

А что такое volumes? Представьте, что контейнер Docker - это отдельный компьютер, а volumes - это общая папка между вашим реальным компьютером и этим виртуальным. На практике без volumes. Мы копируем при старте папку, а в дальнейшем без обновления сборки - код не обновляется. Мы находимся в том же состояние кода, который был при сборки. Но благодаря такой технологии - мы обновляем проект в реальном времени. Все изменения кода - сразу обновляются.

Я надеюсь, что Docker не показался тебе чем-то ненужным или совершенно непонятным. Объяснить даже базовую работу с Docker в одной статье - очень сложно, поэтому в первой части мы разобрали простую конструкцию, но уже начали закладывать фундамент. Если тебе что-то непонятно - это нормально. Главное - не сдаваться и продолжать изучать. Не существует человека, который бы понимал всё сразу.

Все исходники проекта: Github

Комментарии (6)


  1. ky0
    06.10.2025 16:39

    Плохой Докерфайл - несколько слоёв будет пересоздаваться при каждом изменении кода. Сначала копируете requirements, устанавливаете их - и только потом COPY . ., тогда первые два останутся закэшированными, пока не решите что-то изменить в зависимостях.


    1. swcasimiro Автор
      06.10.2025 16:39

      @ky0, привет. Благодарю за критику, исправил. Писал от руки, если есть еще замечания, то буду рад выслушать.


  1. danilovmy
    06.10.2025 16:39

    а зачем нужны requirements.txt ?

    Можно же сразу в докер файл писать.


    1. swcasimiro Автор
      06.10.2025 16:39

      А зачем усложнять Dockerfile? А если библиотек будет под 20? Вместо лаконичной строчки, будет огромный ад из 20 библиотек. Ну если нравится такой подход, то окей. Ну я особого преимущества лично не вижу в твоем варианте. Да и для примера, как мне кажется в этой статье. Такой вариант был бы куда проще для восприятия.


      1. shqiptar
        06.10.2025 16:39

        пусть пишет. нам будет проще найти работу


  1. shqiptar
    06.10.2025 16:39

    Вы тратите день на настройку окружения вместо программирования

    чегооооооо??? установил новую версию питона в отдельную папку, в проекте сделал венв python -m venv .venv активировал .venv\scripts\activate. всё.

    объяснение докера в статье - не люблю такое выражение,но чувак - учи матчасть. смотри не скажи такое на собеседовании.

    pip freeze > requirements.txt

    uv? не, не слышал

    Мы будем использовать Django 5.2.6

    задачки на подумать.
    1) что будет если использовать django select2 для выборки и таблицы с 20-30 тыс записей? а про подавление некоторых исключений в классах я вообще молчу.
    2) сколько предложений о работе на джанге и колько на фастапи?