Всем привет!
Недавно я провел опрос среди подписчиков моего Telegram-канала "Код на салфетке", спросив их о возникающих проблемах и ошибках при деплое. Ответов накопилось немало, и большинство из них касались применения Docker. Однако были и комментарии о том, как организовать проект и репозиторий.
В этой статье мы обсудим ключевые моменты, которые помогут вам правильно организовать git-репозиторий, подготовить Docker-файлы, а также сделать процесс деплоя более гладким. Кроме того, мы подробно рассмотрим механику деплоя на двух примерах: деплой приложения на облачную платформу Dockhost и классический деплой на VPS с помощью Docker Compose.
Важное примечание
Всё, что вы найдёте в этой статье, предназначено для новичков. Если вам кажется, что это — основы, то вы правы. Поэтому просьба не судить материал строго, если для вас некоторые моменты кажутся само собой разумеющимся.
Примеры, которые я приведу, будут основаны на IDE PyCharm и git-хостинге GitHub. Тем не менее, информация, представленная здесь, вполне применима к любой другой IDE, терминалу или git-хостингу, будь то на основе Gitea или любого другого аналогичного сервиса.
Подготовка git-репозитория
Git — это система управления версиями, которая позволяет вам создавать "снимки" изменений в проекте с помощью коммитов. Она даёт возможность создать ответвления и возвращаться к определённым "снимкам" (коммитам) в любой момент.
Git полезен всем разработчикам, как тем, кто работает в команде, так и тем, кто разрабатывает проект самостоятельно. Частые коммиты помогают избегать ситуации, когда вы написали большой объем кода и только потом поняли, что часть из него не работает.
Установка git
Windows: скачайте установщик с https://git-scm.com/ и используйте "Git Bash" для работы с командной строкой.
macOS: выполните команду
brew install git
или установите Xcode Command Line Tools с помощью командыxcode-select --install
.Linux: для установки выполните
sudo apt-get install git
(для Debian/Ubuntu) илиsudo yum install git
(для CentOS/RHEL).
После установки важно "представиться" git. Это делается с помощью двух команд в терминале:
git config --global user.name "Ваше Имя"
git config --global user.email "you@example.com"
Первая команда задаёт ваше имя, которое будет отображаться в коммитах, а вторая — ваш адрес электронной почты. Эти данные необходимы, чтобы git мог корректно отправлять изменения в удалённый репозиторий (например, на git-хостинги). Без них управление версиями не будет работать должным образом, и вы не сможете синхронизировать свои изменения с удалённой версией проекта.
Инициализация git
Чтобы начать работать с git, вам нужно его инициализировать в каталоге вашего проекта. Это делается очень просто — с помощью одной команды:
git init
После выполнения этой команды вы увидите сообщение:
Инициализирован пустой репозиторий Git в <путькдиректории_проекта>/.git
Это означает, что git создал в вашем проекте скрытую папку .git
, в которой будут храниться все необходимые данные и метаданные вашего репозитория.

Если вы откроете директорию проекта в файловом менеджере, то заметите, что папка .git
действительно присутствует. Однако учтите, что по умолчанию она скрыта. Чтобы увидеть её, вам нужно включить отображение скрытых файлов в настройках вашей операционной системы.

Удалённый git-репозиторий
Удалённый репозиторий можно охарактеризовать как обёртку для git с графическим интерфейсом. Обычно это веб-сервис, такой как GitHub, GitLab и другие. В удалённом репозитории вы можете управлять файлами, вносить изменения и создавать коммиты. Однако основная цель использования удалённых репозиториев не в этом.
Главные преимущества удалённых репозиториев заключаются в возможности сохранения прогресса удалённо, что можно рассматривать как своего рода бэкап. Кроме того, удалённые репозитории позволяют работать над проектом совместно с другими разработчиками, запускать процессы CI/CD и многое другое.
Создание репозитория на примере Github
Чтобы создать новый репозиторий на GitHub, перейдите на любую страницу сервиса. В правом верхнем углу нажмите на кнопку "+" и выберите "New repository":

На открывшейся странице вам нужно будет ввести данные:
Название репозитория.
Доступность репозитория: публичный или приватный.
Описание — это опциональное поле. Что касается README.md
, .gitignore
и license
, лучше оставить их невыбранными, о чём мы поговорим чуть позже.
В чём разница между публичным и приватным репозиторием?
Основное отличие заключается в доступности:
Приватный репозиторий доступен только вам и тем, кого вы добавите в соавторы (collaborators).
Публичный репозиторий доступен всем пользователям. Они могут скачать ваш проект и отправить Pull Request с изменениями или написать вам в issue о возникших проблемах.
Приватные репозитории чаще всего используются, когда разработчики не хотят публично демонстрировать свой код. Это может быть связано с коммерческими проектами или с тем, что вы только учитесь и не хотите, чтобы вас критиковали. Причин может быть множество. Публичные репозитории идеально подходят для тех случаев, когда вам нужно показать свой проект кому-то, например, на собеседовании, или если вы хотите, чтобы другие люди использовали вашу работу. Это называется Open Source.
После заполнения всех необходимых полей нажмите кнопку "Create repository":

Если вы не выбирали README.md
, .gitignore
или license
, на открывшейся странице появятся инструкции по созданию и подключению локального репозитория:

Подключение удалённого репозитория к локальному
Теперь, когда удалённый репозиторий создан, пришло время связать его с вашим локальным проектом. Для этого нужно выполнить две команды.
Прежде всего, изменим главную ветку на main
. Почему это важно? Раньше главной веткой был master
, но в последние годы стандарты изменились, и теперь большинство проектов используют main
. Не будем углубляться в причины этой смены, просто примем это как актуальную практику. В некоторых системах главной веткой по-прежнему может быть master
, и это не вызовет больших проблем, но лучше сразу настроить на main
.
Чтобы изменить название ветки, выполните команду:
git branch -M main
В выводе не будет никаких сообщений, но в терминале или IDE вы сможете увидеть, что ветка изменилась:

Следующей командой мы подключим удалённый репозиторий:
git remote add origin https://github.com/proDreams/tempProject.git
Здесь вместо https://github.com/proDreams/tempProject.git
вам нужно указать адрес вашего репозитория с окончанием .git
.
Обратите внимание, что вывод тоже не появится:

Теперь ваши локальный и удалённый репозитории связаны. Вы можете добавлять файлы, создавать ветки и отправлять изменения, но об этом мы поговорим позже, шаг за шагом.
Работа с git-репозиторием
Давайте рассмотрим основы работы с git. Мы не будем углубляться в сложные аспекты, а пройдёмся по базовым понятиям. Если вы хотите изучить тему более подробно, существует множество статей, видеоуроков, а также удобный онлайн-тренажёр по git — Learn Git Branching.
.gitignore
Прежде чем добавлять файлы в репозиторий, важно защитить его от включения "ненужных" файлов. К таким файлам относятся системные файлы, файлы от IDE (например, директории .idea
или .vscode
), файлы баз данных, файлы переменных окружения и всё остальное, что не относится напрямую к коду проекта.
Создайте в каталоге вашего проекта файл с именем .gitignore
:

Этот файл будет содержать список файлов, директорий и путей, которые не должны попадать в репозиторий.
Вот пример базового .gitignore
для Python:
# Python-generated files
__pycache__/
*.py[oc]
build/
wheels/
*.egg-info
# Project files
.venv
.idea/
.DS_Store
.env
.vscode/
Разбор значений файла .gitignore
pycache/
— эта директория служит для хранения кэшированных байт-кодов Python. Эти файлы не нужны в репозитории, так как их можно сгенерировать заново.*.py[oc]
— правило для игнорирования скомпилированных файлов Python, таких как.pyc
и.pyo
.build/
иwheels/
— эти директории обычно содержат скомпилированные файлы пакетов и не должны включаться в репозиторий, так как они могут быть воссозданы.*.egg-info
— файлы, создаваемые при установке пакетов, которые также не нужно хранить в репозитории..venv
— игнорирует директорию виртуального окружения..idea/
и.vscode/
— директории конфигурации для IDE, такие как PyCharm и Visual Studio Code. Они могут содержать настройки, специфичные для вашей локальной разработки, и не имеют смысла для других участников проекта..DS_Store
— система хранения метаданных в macOS. Этот файл обычно не нужен в проекте..env
— файл, содержащий переменные окружения, такие как ключи API, пароли и другие конфиденциальные данные.

Теперь, когда вы настроили файл .gitignore
, вы можете добавлять файлы в git и отправлять их в удалённый репозиторий, не беспокоясь о том, что что-то лишнее попадёт в него.
Добавление файлов для отслеживания
Этот раздел называется "Добавление файлов для отслеживания", а не просто "Добавление файлов в git-репозиторий", потому что после добавления файл начинает отслеживаться системой. Это значит, что любые изменения в файле будут маркироваться как "изменённые". Это очень удобно: вы сможете видеть визуальное отображение изменённых файлов и в любой момент использовать команду git diff
, чтобы сравнить прошлую версию файла с актуальной. Это поможет вам решить, нужно ли отправлять изменения в удалённый репозиторий сразу или отложить это на потом.
Чтобы добавить файл к отслеживанию, выполните команду:
git add <название_файла_или_диреткории>
Не обязательно добавлять файлы по одному. Вы можете перечислять их через пробел:

Если вы посмотрите на файловый менеджер, то заметите, что в предыдущих скриншотах файл .gitignore
был выделен красным цветом. В PyCharm это обозначает, что файл не добавлен в git. После добавления, файл стал зелёным, что означает, что он теперь отслеживается в git репозитории. Ещё одно выделение — синим цветом — предназначено для файлов, в которых произошли изменения. Мы ещё подробнее рассмотрим это в следующих разделах.
Помимо ручного добавления каждого файла, вы можете использовать команду, которая добавит все файлы в проекте сразу. Обратите внимание! Эта команда добавит все файлы, находящиеся в директории проекта, к отслеживанию. Убедитесь, что файл .gitignore
настроен корректно, чтобы избежать попадания ненужных файлов в репозиторий!
git add -A
Используя эту команду, вы сможете легко организовать ваш проект и убедиться, что только нужные файлы находятся под контролем версий.
Отправка в удалённый репозиторий
Отправка изменений в удалённый репозиторий является важным моментом в работе с git. Рекомендуется делать это регулярно: написали новую функцию или выполнили задачу — закоммитили и отправили изменения. Не стоит накапливать много изменений за один раз, поскольку это может отрицательно сказаться на вашей возможности отката.
Перед тем как отправлять изменения, необходимо сделать "снимок" (коммит). Для этого выполните команду:
git commit -m "Краткое описание коммита"
Оформление коммитов
Немаловажной частью работы с git является то, как вы оформляете комментарии коммитов. Хотя вы можете писать в комментариях всё, что хотите, лучше следовать хорошей практике — использовать стиль Conventional Commits.
Что же такое этот стиль? Это определённое соглашение о формате сообщений коммитов, которое помогает сделать их более понятными и структурированными. Главная цель — обеспечить лёгкую интерпретацию, когда к истории проекта обращаются другие разработчики или вы сами в будущем.
Примеры сообщений коммитов в стиле Conventional Commits:
feat: добавлена поддержка JSON
fix: исправлен прыгающий header
docs: обновлён README
style: приведён код к стандартам линтера
refactor: оптимизирована функция обработки
test: добавлены тесты для auth
chore: обновлены зависимости
В нашем случае команда для создания коммита будет выглядеть так:
git commit -m "chore: добавлен .gitignore"
Такой формат не только помогает вам поддерживать порядок в ваших коммитах, но и облегчает работу всей команды, делая историю изменений более читабельной и понятной.
После выполнения команды коммита будет отображён процесс и список добавленных файлов:

Обратите внимание, что файлы стали белыми. Это означает, что они отслеживаются, и в них не было изменений с момента последнего коммита.
Теперь возвращаемся к отправке изменений.
Чтобы отправить изменения в удалённый репозиторий, достаточно выполнить одну команду, но у неё есть "две стадии".
При первом коммите используйте следующую команду:
git push -u origin main
Эта команда синхронизирует ваш локальный репозиторий с удалённым и отправляет все изменения. Флаг -u
(или --set-upstream
) устанавливает связь между вашей локальной веткой main
и удалённой веткой main
. Это упрощает дальнейшие отправки.
После этого для отправки изменений достаточно будет выполнять следующую команду:
git push
При первом запросе вас попросят ввести логин и пароль от удалённого репозитория. Вместо пароля можно ввести Personal Access Token (PAT), который предоставляет доступ к вашему репозиторию без необходимости вводить пароль.

После ввода авторизационных данных произойдёт отправка изменений:

Теперь вы можете перейти на страницу удалённого репозитория и увидеть отправленные файлы:

Таким образом, вы успешно отправили изменения в удалённый репозиторий и можете продолжать работу над проектом, зная, что ваши изменения были сохранены.
Работа с ветками
Теперь, когда вы узнали, как отправлять изменения, следует отметить, что все они отправляются в одну единственную ветку — main
. Это может быть приемлемо для очень небольшого проекта, но даже в этом случае гораздо удобнее и безопаснее использовать несколько веток.
Что я имею в виду? Git позволяет создавать ответвления от текущей ветки. Проще говоря, вы написали основу проекта и закоммитили её в ветке main
. После этого решаете разработать новую функцию, для чего создаётся новая ветка, в которой вы пишете код, в то время как ветка main
остаётся неизменной. В процессе разработки вам может понадобиться внести изменения в основной код для коллеги, но вы всё ещё работаете над новой функцией. В этом случае вы просто делаете коммит, переключаетесь на ветку main
, создаёте новую ветку для исправлений и работаете над ней.
Это может показаться сложным, но на самом деле всё довольно просто!
Можно выделить три основных типа веток:
main
— это основная ветка, в которой хранится актуальная (и зачастую рабочая) версия проекта. Проще говоря, это её prod-версия.dev
илиdevelop
— ветка, в которую сливаются изменения из всех остальных веток. В этой ветке могут существовать ещё не полностью отлаженные компоненты, но она уже готова для тестирования на dev-сервере. После того как в этой ветке накапливается достаточно изменений, их тестируют и, когда всё готово, вливают вmain
.feature/*
— ветки, предназначенные для разработки нового функционала. Эти ветки могут называться как угодно:add_parser
,feature/add_parser
, или, например, как делаем мы,фамилия/задача
—ashikhmin/task_1
. Изменения из этих веток также вливаются вdev
.
Создание ветки
Чтобы создать новую ветку, используйте команду:
git branch <название_ветки>
А для переключения на неё:
git checkout <название_ветки>
Например, для создания ветки dev
и переключения на неё выполните:
git branch dev
git checkout dev
Обратите внимание на терминал: там изменилось название активной ветки:

Внесение изменений
Теперь давайте внесём изменения в файл test.py
:

Вы увидите, что файл стал подсвечиваться синим, а в редакторе появится маркировка новых строк.
Добавим файл в коммит и зафиксируем изменения:

Теперь отправим изменения в удалённый репозиторий:

После этого, если вы перейдёте в удалённый репозиторий, то увидите новую ветку:

Создание Pull Request
После того как изменения из новой ветки отправлены в удалённый репозиторий и их накопилось достаточно (предположим, что у нас сейчас так), необходимо перенести их из временной ветки в постоянную, в данном случае — в main
.
На странице удалённого репозитория, находясь во временной ветке, нажмите кнопку "Contribute", затем выберите "Open pull request":

На открывшейся странице выберите исходную ветку и ту, в которую нужно влить изменения. Введите название и описание, а также вы можете указать ответственного за проверку кода и другие параметры. После ввода нажмите "Create pull request":

На странице открытого Pull Request, если всё в порядке, нажмите "Merge pull request" для слияния:

Введите название нового коммита слияния, оставьте описание и нажмите "Confirm merge":

Теперь вернёмся в IDE и обновим изменения в ветке main
. Для этого в терминале переключитесь на ветку main
, выполнив команду:
git checkout main
Вы получите сообщение:
Переключились на ветку «main»
Эта ветка соответствует «origin/main».
Теперь нужно получить изменения с удалённого репозитория. Для этого выполните команду:
git pull
Вы увидите, что функция, написанная в другой ветке, теперь появилась здесь:

Таким образом, вы узнали, как работать с ветками, вносить изменения и сливать их обратно в основную ветку, что является важным навыком при работе с git.
Знакомимся с Docker
Docker — это платформа для контейнеризации приложений (не путать с виртуализацией!). Она создает изолированные пространства, называемые контейнерами, и использует ядро Linux из хостовой системы (а в случае Windows и macOS — Linux-ядро, запущенное в виртуальной машине).
На сегодняшний день Docker является де-факто стандартом в индустрии контейнеризации. Хотя существуют альтернативы, они чаще всего более нишевые или используются в корпоративных системах. О Docker можно говорить долго, но в этой статье мы постараемся познакомиться с основами.
Из чего состоит Docker?
Docker не является "одной большой машиной", а состоит из набора модулей и компонентов, каждый из которых выполняет свои функции.
Docker Engine
Docker Engine — это центральный сервис, который устанавливается на вашу машину (сервер или локальный компьютер) и отвечает за всю процедуру контейнеризации:
Docker Daemon (dockerd) Фоновый процесс, который слушает запросы (например, создать контейнер, запустить образ) и взаимодействует с ядром операционной системы для управления контейнерами.
Docker CLI (docker) Утилита командной строки, через которую вы отправляете команды движку, такие как
docker run
,docker build
,docker ps
и подобные.REST API Под капотом движок может принимать и обрабатывать HTTP-запросы, что позволяет интегрироваться с внешними инструментами и панелями управления.
Образы (Images)
Образ — это "шаблон" или "чертёж", по которому можно создать контейнер:
Он содержит всё необходимое: файлы операционной системы, библиотеки, приложение и настройки.
Слойность: каждый образ состоит из слоёв. Когда вы изменяете образ (например, устанавливаете новую библиотеку), создаётся дополнительный слой. Это экономит место и ускоряет процесс передачи.
Образы могут храниться локально или в удалённых реестрах (Docker Hub, GitHub Container Registry, частные реестры).
Контейнеры (Containers)
Контейнер — это "живая" изолированная среда, созданная на основе образа:
Создаётся с помощью команды
docker run
.Имеет свой файловый слой (read-write), располагающийся поверх слоёв образа (read-only).
Изолирован по процессам, сети и файловой системе от хоста и других контейнеров (но может взаимодействовать через настроенные сети).
Лёгковеснее, чем виртуальная машина, так как использует общее ядро хоста и быстро загружается.
Docker Compose
Docker Compose — это инструмент для описания и запуска многоконтейнерных приложений с помощью одного YAML-файла (docker-compose.yml
):
Позволяет определить несколько сервисов (например, базы данных, веб-сервер, очередь сообщений) и их взаимосвязи.
Сети (Networking)
Docker по умолчанию создаёт несколько сетей, но вы также можете определять свои собственные:
bridge (мостовая) — стандартная сеть для контейнеров на одном хосте.
host — контейнер использует сетевые интерфейсы хоста напрямую.
overlay — позволяет соединять контейнеры на разных хостах (обычно в Swarm или Kubernetes).
macvlan — каждому контейнеру присваивается свой MAC/IP в подсети хоста.
В Docker Compose можно явно задать сети, а в командах docker network
есть удобные инструменты для их управления.
Тома (Volumes)
Тома позволяют сохранять данные вне контейнера, чтобы они не исчезали при удалении:
Volume (управляется Docker и обычно хранится в
/var/lib/docker/volumes/...
).Bind mount (директория на хосте подключается к контейнеру).
tmpfs (хранение в оперативной памяти, предназначенное для очень быстрых, но временных данных).
Теперь у вас есть общее представление о том, что такое Docker и из чего он состоит.
.dockerignore
Файл .dockerignore
— это специальный файл, принцип работы которого схож с файлом .gitignore
. Он позволяет указать, какие файлы и директории не должны попадать в Docker образ при его создании. Это особенно важно, чтобы избежать включения лишних файлов, таких как настройки IDE, временные файлы и конфиденциальные данные.
Пример содержимого файла .dockerignore
:
.venv
.idea/
.DS_Store
.env
.vscode/
Каждая строка в этом файле указывает на файлы или директории, которые будут исключены из контекста сборки при создании образа. В приведённом примере:
.venv
— игнорирует папку виртуального окружения..idea/
— исключает настройки проекта для среды разработки JetBrains..DS_Store
— исключает системные файлы macOS, которые не нужны в образе..env
— игнорирует файлы с переменными окружения, которые могут содержать конфиденциальные данные..vscode/
— исключает настройки для Visual Studio Code.
Использование .dockerignore
позволяет уменьшить размер создаваемого образа и защитить потенциально чувствительные данные от случайного добавления в публичные репозитории. Это важный шаг в процессе контейнеризации, помогающий сделать ваши образы более чистыми и безопасными.

Dockerfile и создание образа
Как уже упоминалось, Docker-образ — это своего рода "чертёж" будущего контейнера. Он создаётся не сам по себе, а описывается в специальном файле Dockerfile
.
Синтаксис файла должен строго следовать структуре:
КОМАНДА ДЕЙСТВИЕ/ОБЪЕКТ_ВЫПОЛНЕНИЯ/АРГУМЕНТ
Каждая команда выполняется с новой строки.
Основные команды для создания Dockerfile:
FROM
— задаёт базовый образ, от которого вы строите свой. Пример:FROM python:3.13
.LABEL
— добавляет метаданные, такие как автор, версия, описание и т.д. Пример:LABEL version="1.0"
.WORKDIR
— устанавливает рабочую директорию внутри контейнера. Все последующие команды (COPY, RUN и т.д.) будут выполняться в этой директории. Пример:WORKDIR /code
.COPY
иADD
— копируют файлы из контекста сборки (вашей машины) в файловую систему контейнера.ADD
имеет дополнительные возможности, такие как автоматическая распаковка архивов и скачивание по URL, но из-за возможных побочных эффектов его менее рекомендуют использовать. Пример:COPY ./src /code/src
.RUN
— выполняет команду внутри контейнера во время сборки образа, например, для установки пакетов. Пример:RUN apt-get update && apt-get install make
.ENV
— устанавливает переменные окружения. Пример:ENV APP_ENV=production
.EXPOSE
— документирует, на каких портах контейнер ожидает подключений (не пробрасывает порты автоматически, а лишь сообщает о намерениях). Пример:EXPOSE 80
.USER
— указывает, от какого пользователя будут выполняться команды и запускаться контейнер. Пример:USER appuser
.VOLUME
— создаёт "точку монтирования" для томов, чтобы сохранять данные за пределами контейнера. Пример:VOLUME ["/data"]
.ARG
— объявляет переменные, которые можно передавать в процессе сборки (через--build-arg
). Пример:ARG BUILD_ENV=dev
.ENTRYPOINT
— определяет основную команду (или исполняемый файл), которая будет запускаться при старте контейнера. Пример:ENTRYPOINT ["python3", "
main.py
"]
.CMD
— задаёт аргументы по умолчанию дляENTRYPOINT
или, еслиENTRYPOINT
не указан, определяет команду/скрипт для запуска. Если обе команды используются вместе,CMD
передаёт аргументы вENTRYPOINT
. Пример:CMD ["--help"]
.
Как видно, команд достаточно много, но не пугайтесь. Обычно хватает 4–5 основных команд, в то время как остальные используются по мере необходимости и зависят от конкретного проекта.
Для создания образа нам необходимо создать файл Dockerfile
и прописать в нём основной набор команд. (Для демонстрации я переименовал test.py
в main.py
и написал в нём простейший пример бота.)
FROM python:3.13-slim
WORKDIR /code
COPY requirements.txt /code
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY . /code
CMD [ "python", "./main.py" ]
Давайте разберём, что здесь происходит:
FROM python:3.13-slim
— в качестве базового образа используетсяpython
, далее через:
указывается версия образа. Поскольку демонстрационный бот довольно простой, нет смысла скачивать полный образ Python, достаточно использоватьslim-версию
.WORKDIR /code
— устанавливает рабочую директориюcode
.COPY requirements.txt /code
— копирует файлrequirements.txt
в рабочую директорию.RUN pip install --upgrade pip && pip install -r requirements.txt
— обновляетpip
и устанавливает необходимые зависимости.COPY . /code
— копирует остальные файлы проекта внутрь образа. Обратите внимание: будет скопировано всё, что находится в директории! Убедитесь, что ваш.dockerignore
настроен корректно.CMD [ "python", "./
main.py
" ]
— команда для запуска бота.
Для создания образа локально (или на сервере) используется команда:
docker build -t <название_образа> .
Вместо <название_образа>
укажите название своего образа (не путайте его с названием контейнера! Они должны отличаться), а .
в конце указывает, что Dockerfile
для сборки находится в текущей директории.
В процессе сборки Docker начнёт по порядку выполнять указанные команды:

Немного про слои
Вы, вероятно, заметили, что в строках 3, 4 и 5 происходит копирование requirements.txt
, обновление pip
и установка зависимостей в одной команде, а затем копируются остальные файлы. Возможно, у вас возник вопрос: "Зачем так делать?"
Причина заключается в оптимизации.
Каждая выполняемая команда создает отдельный слой образа, и для более эффективной сборки они кэшируются. Если мы сначала копируем файл с зависимостями, то если он не изменился, последующий шаг установки зависимостей будет взят из кэша. Это значительно ускоряет процесс и экономит ресурсы.
Если бы мы сначала скопировали все файлы, а затем установили зависимости, то при каждом изменении файлов Docker считал бы, что и следующий слой с установкой зависимостей устарел. В этом случае процесс сборки занял бы больше времени.
Запуск отдельного контейнера
Чтобы запустить контейнер из ранее созданного образа, используется команда docker run
с набором аргументов.
Самый простой пример выглядит так:
docker run --name <название_контейнера> -d <название_образа>
Разберём команду по частям:
docker run
— основная команда для запуска контейнера.--name <название_контейнера>
— задаёт имя для вашего контейнера. Если не указать, Docker автоматически присвоит уникальное имя.-d
— запускает контейнер в фоновом режиме (detached mode). Это означает, что контейнер будет работать в фоновом режиме, и ваша командная строка не будет заблокирована.<название_образа>
— имя образа, на основе которого будет создан контейнер.
Есть и другие аргументы, такие как -v
для монтирования томов, --network
для настройки сетевых параметров или -p
для проброса портов, но мы обсудим их позже в разделе о Docker Compose.
После выполнения команды вы увидите только идентификатор контейнера:

Если обратиться к тестовому боту, то можете увидеть, что бот успешно функционирует:

Однако! Стоит отметить, что вручную образы и контейнеры обычно не запускают. Для создания образов чаще всего используют CI/CD процессы, а для более удобного и продвинутого запуска контейнеров — Docker Compose, о котором мы поговорим далее.
Чтобы остановить контейнер, используйте команду:
docker stop <имя_контейнера>
Если вам нужно удалить остановленный контейнер, воспользуйтесь командой:
docker rm <имя_контейнера>
Также можно использовать аргумент -f
(force), чтобы удалить запущенный контейнер принудительно.
Чтобы удалить образ, воспользуйтесь командой:
docker rmi <имя_образа>
Обратите внимание! Нельзя удалить образ, если хотя бы один контейнер его использует. Поэтому сначала необходимо удалить все связанные контейнеры, а уже потом удалить сам образ.
Docker Compose
Docker Compose — это более продвинутый и удобный способ запуска контейнеров. Его основное преимущество заключается в том, что вам не нужно составлять длинные команды для запуска контейнера с множеством параметров, а также не обязательно заранее создавать образ (за исключением случаев, когда он создаётся в CI/CD процессе и публикуется в частный реестр образов).
Конфигурация Docker Compose описывается в специальном файле docker-compose.yaml
, который следует синтаксису разметки YAML-файлов.
Структура Docker Compose файла
Первым элементом в файле идёт ключевое слово services:
— именно так называются контейнеры в Docker Compose, их также называют "сервисами". После этого перечисляются названия сервисов и их параметры:
services:
web:
...
db:
...
В Docker Compose можно определить как один, так и множество сервисов. Это позволяет запускать несколько контейнеров изолированно, но с общим виртуальным локальным сетевым окружением, что даёт возможность контейнерам обмениваться запросами по имени сервиса.
Основные параметры сервиса
Вот основные параметры, которые можно использовать для описания сервисов:
image
— использовать готовый образ из реестра (например, Docker Hub или частное хранилище Docker образов).-
build
— позволяет собрать собственный образ из локального Dockerfile:context
— задаёт контекст сборки.dockerfile
— определяет имя файла Dockerfile.
container_name
— задаёт понятное имя контейнера (в противном случае Docker генерирует его автоматически). Это аналог аргумента--name
при создании контейнера.-
restart
— политика перезапуска контейнера:no
— никогда не перезапускать.always
— всегда перезапускать.on-failure[:max-retries]
— перезапускать при сбое, с указанием максимального числа попыток.unless-stopped
— перезапускать, если контейнер не был остановлен явно.
ports
— массив строк"хостовый_порт:контейнерный_порт"
для доступа к приложению извне.environment
— переменные окружения, которые могут быть указаны в виде списка или объекта.-
volumes
— для сохранения данных вне контейнера:named volume
— управляется Docker, например:web_data:/var/www/html
.bind mount
— директория на хосте подключается к контейнеру, например:./логическая_папка/:/путь/контейнера
.
depends_on
— задаёт порядок запуска сервисов; например, сервисweb
не запустится, пока не запущенdb
. По умолчанию ожидает только запуска, но существует дополнительный параметрcondition
со значениемservice_healthy
, который ждёт, пока указанный сервис не станет "здоровым".command
— переопределяет команду запуска в образе.-
healthcheck
— позволяет Docker отслеживать состояние здоровья контейнера:test
— команда проверки (можно указать список).interval
— как часто проверять состояние.timeout
— время выполнения проверки.retries
— сколько неудачных проверок подряд считать знаком нездоровья.
-
logging
— настройки логирования:driver
— например,json-file
,syslog
илиfluentd
.options
— параметры ротации, формата и др.
Дополнительные ключи в Docker Compose
Помимо services:
, в файле могут использоваться и другие ключи:
volumes:
— если используются именованные тома, их обязательно нужно подключить здесь, иначе возникнет ошибка.networks:
— помогает подключить контейнеры к указанным сетям. По умолчанию создаётсяbridge-сеть
для определённого Docker Compose, но можно указать другую сеть, например, из другого Docker Compose.
Как видим, параметров тоже не мало, но и тут с опытом и насмотренностью будет проще ориентироваться.
Пример конфигурации Docker Compose
Напишем тестовый файл docker-compose.yaml
для бота:
services:
test-bot:
build: .
container_name: test-bot
environment:
- BOT_TOKEN=${BOT_TOKEN}
Этот простой файл описывает сервис под названием test-bot
, который будет строиться из текущей директории (.
) и наделён переменной окружения BOT_TOKEN
, значение которой можно передать через файл окружения или напрямую в терминале.
Примеры Docker Compose для разных сервисов
Пример для PostgreSQL:
services:
db:
image: postgres:16.8-alpine
container_name: pg_db
restart: always
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=${DB_NAME}
- PGDATA=/var/lib/postgresql/data/pgdata
volumes:
- pg_db:/var/lib/postgresql/data
healthcheck:
test: [ "CMD-SHELL", "sh -c 'pg_isready -U ${DB_USER} -d ${DB_NAME}'" ]
interval: 10s
timeout: 3s
retries: 3
volumes:
pg_db:
В этом примере описан сервис базы данных db
, использующий образ PostgreSQL, с настройками окружения для пользователя, пароля и имени базы данных. Также добавлен том для хранения данных.
Пример для Caddy:
services:
caddy:
image: caddy:latest
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./sites.d:/etc/caddy/sites.d
- caddy_data:/data
- caddy_config:/config
- taiga-static-data:/taiga-back/static
- taiga-media-data:/taiga-back/media
- ../pressanybutton/pressanybutton/blog/static:/pab_static
- ../pressanybutton/pressanybutton/media:/pab_media
volumes:
caddy_data:
caddy_config:
taiga-static-data:
external: true
taiga-media-data:
external: true
networks:
default:
name: caddy_net
В данном случае это конфигурация для веб-сервера Caddy, который настраивает проброс портов и монтирование томов для конфигурации, статических файлов и внешних ресурсов.
Деплой
Слово "деплой" может вызывать у кого-то страх, стресс или даже панику, но бояться деплоя не стоит. Это процесс, который может быть достаточно увлекательным и, с опытом, быстрым занятием. Более того, деплой прекрасно автоматизируется.
Существуют различные способы деплоя проекта, но в основном их можно свести к следующим двум:
Деплой на VPS-сервер (вручную, с использованием CI/CD, с помощью инструментов и т.д.).
Деплой в специализированных сервисах — Docker-хостинг, облачные сервисы хостинга приложений (например, Heroku) и другие.
Мы рассмотрим оба этих варианта, но пройдёмся по ним поверхностно. Если вы хотите узнать подробности о каком-либо из способов — не стесняйтесь оставлять комментарии!
Деплой на DockHost
Dockhost — это облачный хостинг, который предоставляет инфраструктуру для автоматического деплоя приложений на основе Docker. Он позволяет размещать свои сервисы в виде контейнеров, используя Dockerfile
из репозитория, и автоматически разворачивает приложение при каждом пуше в Git.
Ключевые особенности Dockhost:
Поддержка автоматического деплоя из Git (GitHub, GitLab и др.).
Удобное управление переменными окружения и томами.
Хранение данных вне контейнеров (например, через volumes).
Возможность отката на предыдущую версию образа при ошибке.
Ориентирован на разработчиков, знакомых с Docker и CI/CD.
Таким образом, Dockhost — это платформа PaaS (Platform as a Service), которая ориентирована на тех, кто хочет автоматизировать деплой Docker-приложений без необходимости ручной настройки VPS.
Создание проекта
После регистрации в сервисе и перехода в личный кабинет вы попадаете на страницу проектов. При регистрации вам начисляется 100 рублей, чего достаточно для тестирования и изучения платформы. Нажмите кнопку "Новый проект":

Откроется окно, в котором нужно указать название проекта. Дополнительно можно изменить адреса DNS и выставить часовой пояс. После этого нажмите "Создать":

Затем перейдите в созданный проект, попадая на панель управления:

Перейдите на страницу "Репозитории Git", где отображаются подключённые репозитории и информация о них. Нажмите "Добавить":

В открывшемся окне введите название репозитория, адрес и выберите ветку, из которой хотите получать данные. Также доступны дополнительные настройки, такие как ресурсы сервера и авторизация (если у вас приватный репозиторий). Введите данные и нажмите "Применить":

После подключения начнётся процесс сборки образа из Dockerfile и сохранения его в репозиторий образов DockHost. Нужно немного подождать окончания сборки:

После завершения сборки на экране появится галочка и дата последней сборки:

Перейдя в раздел "Контейнеры", вы увидите запущенный контейнер. Однако, в моём случае он остановился с ошибкой:

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

В открывшемся окне найдите пункт "Переменные окружения" и нажмите "Добавить переменную". В появившемся поле введите ключ и значение, затем нажмите "Применить":

После применения настроек контейнер автоматически перезапустится:

Теперь проверим, как работает бот:

Бот отвечает, значит, всё в порядке. Это довольно простой (хоть и с небольшими недостатками, связанными с переменными окружения, но я уже отправил свой отзыв в поддержку) способ деплоя для тех, кто не хочет разбираться с настройкой VPS.
Деплой на VPS
В отличие от предыдущего способа, деплой на VPS может быть сложнее, так как требует уверенных знаний работы с Linux-сервером и командной строки. Однако этот способ предоставляет гораздо больше свободы и контроля над средой развертывания.
Обратите внимание! У вас уже должен быть приобретён VPS, чтобы выполнить действия, описанные ниже, и вы должны уметь подключаться к серверу по SSH.
Установка Docker
Скорее всего, на вашем сервере ещё не установлен Docker (если вы его не устанавливали вручную). Для установки достаточно выполнить одну команду:
curl -fsSL https://get.docker.com -o install-docker.sh | sh
При выполнении этой команды скрипт автоматически скачает и установит Docker.
Клонирование репозитория с проектом
Теперь необходимо перенести файлы проекта на сервер. Поскольку мы уже разобрались, как использовать удалённый репозиторий, воспользуемся именно этим методом. Введите команду:
git clone <ссылка_на_ваш_репозиторий>
Например, в моём случае команда выглядит так:
git clone https://github.com/proDreams/tempProject.git
Теперь перейдите в директорию скачанного проекта:
cd <название_репозитория>
В моём случае это:
cd tempProject
Далее необходимо создать .env
файл с переменными окружения:
nano .env
Эта команда откроет новый файл в редакторе Nano. Файла ещё нет, но как только мы его сохраним, он будет создан. Вводите нужные значения:

Чтобы сохранить изменения, нажмите CTRL+S
, а для выхода из Nano — CTRL+X
.
Запуск Docker Compose
Последний шаг — запустите Docker Compose, выполнив следующую команду:
docker compose up -d
Начнётся процесс сборки образа и запуска контейнера:

Когда вы увидите зелёную надпись "Started", и управление терминалом вернётся к вам, это значит, что всё прошло успешно и сервис запустился:

Теперь проверим, как работает бот:

Если бот отвечает, значит, всё запустилось корректно!
Вы можете задаться вопросом: "Где же обещанная сложность? Вроде всё достаточно просто". Да, в данном случае задача была простой, поскольку мы работали с элементарным ботом. Однако, когда дело доходит до развертывания нескольких контейнеров, включая веб-сайт, базы данных и веб-сервер, ситуация значительно усложняется. Здесь потребуется пробрасывать порты, указывать хосты и тома, настраивать локальные конфигурации и так далее. Все это нельзя описать сразу — к этому приходится приходить, обучаясь на собственных ошибках и опыте.
Заключение
В этой статье мы детально рассмотрели, как организовать работоспособный процесс деплоя с использованием git и Docker. Мы обсудили важность системы контроля версий и её роль в разработке, а также познакомились с основами работы с Docker и его компонентами. Для новичков это может показаться сложным, но с практикой и опытом вы обретете уверенность в этих инструментах.
Docker дает возможность легко разворачивать приложения и управлять ими, а работа с git позволяет отслеживать изменения и упрощает совместную работу. Кроме того, мы обсудили различные методы деплоя, от автоматических решений, таких как DockHost, до более сложных, требующих настройки на VPS.
Не бойтесь экспериментировать с новыми подходами и инфраструктурой! Постепенно вы сможете создавать стабильные и масштабируемые приложения. Надеюсь, данный материал окажется полезным для вас и поможет избежать многих распространенных ошибок.
Подписывайтесь на наш Telegram‑канал «Код на салфетке», у нас много интересного как для новичков, так и профессионалов!
Комментарии (4)
meonsou
17.07.2025 10:00Жалко что не написали как gitops делается на vps. По факту это настолько просто что целый специальный хостинг без надобности. Достаточно вместо того чтобы делать
docker compose up
напрямую на сервере создать удалённый контекст:docker context create vps --docker "host=ssh://me@example.com" docker context use vps
И можно деплоить на vps из того же github workflow.
narraider
Все же скрины важнее и должны быть больше разрешением, а не на половину, потому что обязательно этот водяной знак на пол картинки
proDream Автор
На скриншот можно нажать и он откроется в полном размере.