Гайд по деплою web-приложений для новичков. Часть 1. Shared-хостинг
Привет, коллеги! 👋
В web-разработке процесс деплоя играет важную роль. Это ответственный момент (даже торжественный), когда все усилия, потраченные на написание и тестирование кода, воплощаются в “живое” приложение, доступное пользователям. Ведь для этого приложение и делается, чтобы им кто-то пользовался. Каждый разработчик, независимо от уровня и специализации, регулярно сталкивается с задачей деплоя. Это статья в основном рассчитана на новичков, которые учатся разворачивать приложения на сервере и хотят узнать различные варианты, сравнить их и выбрать подходящий.
Деплой - это не просто загрузка кода на сервер (хотя лет 20 назад деплоили приложения по FTP). Прогресс не стоит на месте, приложения стали сложнее и сейчас деплой - это сложный и многоступенчатый процесс, который обычно включает в себя подготовку окружения, установку зависимостей, миграцию базы данных, минимизацию и компиляцию ассетов, проверку работоспособности и, наконец, переключение трафика на новую версию приложения.
Важность этого процесса не может быть недооценена. От качества и эффективности деплоя зависит стабильность работы приложения, удовлетворенность пользователей и, в конечном итоге, успех всего проекта.
Особенно важным является настройка деплоя для проектов, которые часто обновляются, и требуют частого развёртывания на сервере.
В этой статье я собрал популярные варианты деплоя приложений, от самых простых, требующих значительной вовлеченности до сервисов по деплою приложений в "один клик" с нулевым временем простоя.
Ссылки на другие части статьи:
Так как я работаю с Laravel, то и для примера буду деплоить приложение на Laravel. Это будет demo проект-блог, сделанный для демонстрации возможностей админ-панели для проектов на Laravel - MoonShine. Количество кода, пакетов и размеры базы данных можно считать равными обычному проекту-блогу.
Также в рамках этой статьи будем использовать GitHub. Я в работе использую именно его, наверное потому что Laravel использует GitHub (шутка). Всем начинающим разработчикам настоятельно рекомендую использовать git и привыкать к современным инструментам и принципам работы в команде, где без системы контроля версий никак не обойтись.
Вариант деплоя с архивом
Этот вариант уже в архиве истории. Его добавил для того чтобы немного поднять настроение. Брали папочку, подключались по ftp на сервер (я использовал программку FileZilla), загружали архив на сервер и там его распаковывали. Для сайтов-визиток работало неплохо. Всё что сложнее уже могут возникнуть проблемы.
"Классический" деплой на shared-хостинге с использованием GitHub
Считаю что этот "классический" способ должен знать каждый начинающий разработчик, чтобы понимать, что происходит при развертывании приложения на сервере. Используется при этом недорогой shared-хостинг (рублей 200-300/месяц на Timeweb, Beget, Рег.ру и т.д.) без необходимости администрирования. Подойдет для начинающих разработчиков. Дешево и сердито. В этой статье я буду показывать как деплоить на хостинге от beget (можно любой другой).
Требования к хостингу
поддерживает версию PHP, которая соответствует вашему проекту (в моём случае 8.3 - настоятельно рекомендую своевременно обновлять свои проекты)
есть система управления базами данных MySQL
есть возможность подключения по SSH
установлена система контроля версий Git
Что еще понадобиться
домен связан с хостингом (DNS-серверы хостинга внесены в настройки домена), или есть тестовый домен для проверки работоспособности проекта
на рабочем месте установлена система контроля версий Git
есть аккаунт на GitHub
Проще говоря - на хостинге уже есть папка с сайтом и в браузере можно вбить домен и сайт будет открываться.
Кроме этого понадобятся знания основ php, git и devops. Ну раз вы занялись деплоем, то наверняка вы разбираетесь в основах.
Начинаем.
Настройка git репозиториев
Переходим на GitHub, создаем новый репозиторий и напишем название - пусть будет CutCodeDeploy
- очень красиво. Дополнительно сделаем репозиторий приватным (устанавливаем переключатель в Private
). Условия приближенные к реальным - обычно, если мы делаем проект на заказ, то заказчику нужна конфиденциальность, для этого и служат приватные репозитории.
Нажимаем кнопку "Create repository"
. Репозиторий создан и GitHub предлагает нам пошаговую инструкцию - Quick setup. Давайте по ней и работать, чтобы ничего не забыть.
Приступаем.
Инициализируем новый локальный Git репозиторий на компьютере при помощи команды git init
.
По этой команде создается пустой репозиторий в директории, откуда была вызвана. То есть сначала переходим в ту папку, в которой хотите организовать локальный репозиторий:
cd "путь_к_папке_с_вашим_проектом"
git init
Эта команда создала папку .git
внутри папки с вашим проектом.
Хорошее начало. Осталось совсем немного.
Чтобы Git понимал какие файлы в проекте изменились, нужно добавить их в индекс.
git add -A
Эта команда добавляет содержимое текущего каталога в индекс. И теперь git будет отслеживать изменения в репозитории и какие из файлов мы добавим в следующий коммит.
Коммит в Git - это как сохранение в игре. Когда вы делаете коммит, вы фактически сохраняете текущее состояние вашего проекта. Это позволяет вам в любой момент вернуться к этому состоянию, если что-то пойдет не так в будущем. Важно отметить, что при первом коммите Git добавляет весь проект. В последующих коммитах Git будет добавлять только те файлы, которые были изменены после последнего коммита.
Пора сделать первый commit проекта (с комментарием "исходный проект") в созданный репозиторий:
git commit -m "исходный проект"
и настраиваем ветку главной:
git branch -M master
Представьте, что у вас есть версия проекта (игра, прогресс в которой вы хотите сохранить) на вашем компьютере (это ваша приставка), и вы хотите загрузить его на GitHub, чтобы другие могли им воспользоваться или чтобы вы могли работать над ним с другого компьютера.
Но прежде чем вы сможете загрузить свой проект туда, вы должны "связать" ваш локальный репозиторий на компьютере с удаленным репозиторием на GitHub. Так как у нас репозиторий приватный, то нужно настроить безопасное соединение между компьютером и GitHub через SSH.
Создание SSH ключей на локальном компьютере:
Откройте терминал и выполните команду для создания нового SSH ключа:
ssh-keygen
Добавьте SSH ключ в агент ssh:
eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_rsa
Копирование публичного ключа:
cat ~/.ssh/id_rsa.pub
Добавление публичного ключа на GitHub:
Перейдите в "Settings" > "SSH and GPG keys".
Нажмите "New SSH key" и вставьте ваш публичный ключ, а затем нажмите "Add SSH key".
Пора связать репозитории! Укажем удаленный репозиторий на GitHub с помощью команды:
git remote add origin https://github.com/"имя_пользователя"/"имя_репозитория".git
Замените имя_пользователя
и имя_репозитория
на ваше имя пользователя на GitHub и имя вашего репозитория соответственно.
В нашем случае, мы хотим связать наш локальный репозиторий с репозиторием CutCodeDeploy
на GitHub. Поэтому наша команда будет выглядеть так:
git remote add origin https://github.com/CutCodes/CutCodeDeploy.git
Теперь, когда ваш локальный репозиторий связан с удаленным репозиторием на GitHub, вы можете запушить (или отправить) свой проект на GitHub. Это можно сделать с помощью команды git push origin master
:
Если вы планируете часто обновлять свой проект, вам, возможно, не захочется каждый раз писать длинную команду git push origin master
. Вместо этого, вы можете сделать команду короче, просто git push
. В конце концов, хороший разработчик - это ленивый разработчик!
Чтобы сделать это, вы можете установить ветку master
вашего репозитория как ветку по умолчанию для команды git push
. Это можно сделать с помощью следующей команды:
git push -u origin master
Отлично. Проект на GitHub! И теперь, когда вы вводите git push
, Git автоматически пушит ваши изменения в ветку master
вашего удаленного репозитория на GitHub. Это делает процесс обновления вашего проекта на GitHub намного быстрее и проще!
Клонируем проект на хостинг из GitHub
Следующая задача - необходимо загрузить проект с GitHub на сервер. Так как мы создали приватный репозиторий на GitHub, нам нужно предоставить нашему серверу доступ к этому репозиторию.
Чтобы это сделать, мы должны установить безопасное соединение между нашим сервером и репозиторием на GitHub.
Для начала, переходим на нашем сервере в консоль. Затем мы создаем новую пару ключей SSH - это приватный и публичный ключи. Эти ключи нужны для установки безопасного соединения.
SSH-ключи создаются командой ssh-keygen
. Ключи обычно хранятся на сервере в каталоге ~/home/"имя_пользователя"/.ssh/"имя_файла"
.
Когда мы запускаем ssh-keygen
, мы указываем имя файла, в котором будут сохранены ключи. Также вы можете изменить место хранения ключей и добавить пароль для дополнительной защиты.
После того как ключи сгенерированы, в консоли сразу же указывается путь до них:
Приватный ключ:
~/home/"имя_пользователя"/.ssh/"имя_файла"
Публичный ключ:
~/home/"имя_пользователя"/.ssh/"имя_файла".pub
Теперь нам нужно добавить публичный ключ на GitHub. Копируем путь к публичному ключу, и при помощью команды cat
смотрим его содержимое:
cat ~.ssh/"имя_файла".pub
Копируем содержимое публичного ключа и переходим в настройки нашего репозитория на GitHub (это раздел "Settings"). Затем мы выбираем раздел "Deploy Keys".
В этом разделе мы добавляем новый ключ деплоя. Мы даем ему название (например, "CutCodeDeploy.beget.tech") и вставляем наш скопированный ключ в соответствующее поле.
После этого мы подтверждаем добавление ключа, нажав на кнопку "Add key".
Важное примечание.
На GitHub еcть опция в виде чекбокса, которая позволяет разрешить запись в репозиторий. Если этот чекбокс не выбран, то по настроенному SSH-соединению можно будет только считывать содержимое репозитория, но не вносить в него изменения.
Обычно для задач деплоя (развертывания проекта) дают доступ только на чтение, так как обычно нам просто нужно забирать обновления из репозитория, а не вносить в него изменения.
Это важно помнить при настройке SSH-соединения с GitHub.
Теперь, когда ключ от сервера для развертывания приватного репозитория добавлен, мы можем настроить взаимодействие между репозиториями на GitHub и сервером.
На GitHub, в нашем репозитории, мы выбираем раздел "Code", затем переходим на вкладку "ssh" и копируем адрес репозитория.
Заходим на сервер, переходим в директорию проекта и в консоли выполняем необходимую команду.
git clone git@"скопированный_адрес_репозитория"
Команда git clone
выполняет несколько действий: она инициализирует репозиторий Git в текущей директории, добавляет удаленный репозиторий (известный как "origin"
) с GitHub, и затем клонирует содержимое этого репозитория в текущую директорию.
После выполнения этих шагов, мы должны убедиться, что файлы из удаленного репозитория успешно скопировались. Это можно проверить, посмотрев содержимое директории в консоли или файловом менеджере.
Настроим git pull
update
При клонировании репозитория с помощью Git, ссылка на исходный репозиторий автоматически устанавливается как origin
. Это означает, что Git знает, откуда получать данные при выполнении git pull
.
Когда вы хотите забрать обновления с GitHub, вам просто нужно написать git pull
, и Git автоматически заберет обновления из ветки master
репозитория origin
, как почтальон, который знает, где ваш почтовый ящик.
Настройка символических ссылок
Точка входа в веб-приложении - это файл, который обрабатывает все запросы к вашему веб-сайту и перенаправляет их в ваше приложение. Обычно на shared-хостингах это файл index.php
или index.html
, который находится в корневом каталоге веб-приложения.
У нас приложение на Laravel. В Laravel точка входа обычно находится в каталоге public
. Это сделано для обеспечения безопасности, так как только файлы в каталоге public
доступны для прямого доступа, а все остальное - под замком. Круто придумано.
update
Получается, что точка входа index.php
в корневой папке веб-сервера на хостинге не совпадает с дефолтной точкой входа приложения на Laravel, и самый простой способ это исправить - это сделать символическую ссылку (мы используем недорогой shared-хостинг, где полного доступа к системе и конфигурационным файлам нет).
Итак, точка входа в приложение Laravel - это файл public/index.php
, и нам нужно, чтобы все запросы по умолчанию направлялись на public/index.php
. Простое решение этой задачи - создать символическую ссылку. Это как создать ярлык на рабочем столе, который ведет к нужной программе.
Если в корне проекта уже есть файл index.php
или index.html
, то сначала удалим его. А теперь давайте создадим символическую ссылку. Перейдем в корневой каталог вашего проекта Laravel и выполним нужную команду
ln -s public public_html
Это означает, что теперь у вас есть новый путь public_html
, который ведет прямо в ваш каталог public
.
Обновляем зависимости
Composer - это мощный инструмент для управления зависимостями в PHP. Он позволяет вам объявлять библиотеки, которые ваш проект использует, и он управляет (устанавливает/обновляет) их за вас. Это как ваш личный помощник, который следит за тем, чтобы все ваши библиотеки были в порядке.
Установка зависимостей Composer при деплое - это важный шаг, который гарантирует, что все необходимые библиотеки и пакеты, необходимые для работы вашего приложения, установлены и настроены правильно на сервере перед запуском вашего приложения. Это как проверка перед стартом, чтобы убедиться, что все готово к запуску.
Composer будет устанавливать все зависимости, указанные в файле composer.json
вашего проекта. Это как список покупок для вашего приложения, по которому Composer будет следовать.
На некоторых хостингах Composer может быть не установлен по умолчанию. Но обычно у хостинг-провайдеров есть подробные инструкции о том, как установить Composer на их серверах.
Что делать если на хостинге нет Composer?
Если Composer не установлен на сервере, вы всегда можете установить его локально в ваш проект и после этого обновить проект на сервере. Если Composer есть, то пропускаем эту главу - тык.
Сначала мы загружаем установочный файл Composer с помощью команды:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
Затем мы устанавливаем Composer с помощью команды:
php composer-setup.php
После завершения установки мы можем удалить установочный файл, он нам больше не понадобится:
php -r "unlink('composer-setup.php');" mv composer.phar /usr/bin/composer
Теперь в вашем проекте есть файл composer.phar
, и его можно использовать для управления зависимостями внутри вашего проекта.
Чтобы Composer появился на сервере, обновим проект, выполнив commit
и push
в репозиторий на GitHub:
Затем выполним pull
на сервере. И вуаля, Composer теперь у вас в проекте! Но помните, он доступен только внутри проекта и запускать его нужно командой composer.phar
.
Продолжаем работу с Composer
На некоторых хостингах, включая хостинг beget, требуется явно указывать версию PHP для Composer. Это связано с тем, что версия PHP в консоли может отличаться от версии, заданной в контрольной панели для сайта. Это как если бы у вас было два разных языка, один для общения с друзьями, и другой - для работы. И Composer должен знать, на каком языке ему говорить.
Вы можете узнать текущую версию PHP для консоли с помощью команды php -v
. Спросим у PHP: "Сколько тебе лет?".
Если на сервере установлено несколько версий PHP, то в команде нужно указывать конкретную версию PHP. В моём случае это php8.3.
Команда php8.3 composer install
обновит зависимости в вашем проекте. Однако, эта команда будет работать только в том случае, если php8.3 и composer доступны в вашем PATH
. Это означает, что оболочка может найти их, когда вы вводите эти команды.
Если php8.3 или composer не найдены, вам придется указать полный путь до этих программ. Например, если composer находится в /usr/local/bin/composer
, вы должны использовать этот полный путь в команде.
Алиас php8.3 обычно создается при установке этой версии PHP. Это делается для удобства, чтобы можно было легко переключаться между разными версиями PHP.
Выполним:
php8.3 composer install
По этой команде все необходимые нашему приложению пакеты Composer скачает и установит, вот такой он молодец.
Пару слов о composer.lock
В проектах, которые используют Composer, есть важный служебный файл под названием composer.lock
. Этот файл выполняет несколько ключевых функций:
Фиксация версий зависимостей: когда вы впервые устанавливаете зависимости с помощью команды composer install
, Composer смотрит на файл composer.json
вашего проекта, чтобы узнать, какие пакеты ему нужны, и скачивает их. Затем Composer записывает точные версии установленных пакетов в composer.lock
. Это означает, что если вы или кто-то другой запустите composer install
в будущем, Composer будет использовать версии из composer.lock
, а не искать новые версии. Это гарантирует, что все, кто работает над проектом, используют одни и те же версии пакетов, что уменьшает вероятность проблем совместимости.
Безопасность: файл composer.lock
также содержит хеши каждого пакета. Это позволяет Composer проверить, что пакеты не были изменены или повреждены с момента их установки.
Ускорение установки: файл composer.lock
содержит точные версии и источники каждого пакета, поэтому Composer быстрее устанавливает пакеты, не тратя время на их поиск.
Важно помнить, что
composer.lock
должен быть включен в ваш репозиторий кода, чтобы все, кто работает над проектом, могли использовать одни и те же версии пакетов. Если вы хотите обновить версии пакетов, вы можете использоватьcomposer update
, который обновитcomposer.lock
.
Создаём базу данных для приложения
Создание базы данных для приложения - это простой процесс. Все, что вам нужно, это найти раздел "Базы данных" в панели управления вашего хостинга.
Затем вы создаете отдельную базу данных для вашего проекта, а также пользователя, который будет иметь доступ к этой базе данных. Обычно имя базы данных совпадает с именем пользователя, это как двойное подтверждение вашей личности.
После создания пользователя, вы добавляете ему доступ к базе данных. Это как дать ключи от вашего дома доверенному лицу.
И последний шаг - запишите имя базы данных, пароль к ней и имя пользователя. Это важная информация, которую нужно хранить в безопасном месте.
Настраиваем .env
Файл .env
очень важен для работы проекта на Laravel. Этот файл содержит различные настройки окружения, такие как данные для подключения к базе данных, ключи API и другую конфиденциальную информацию, которая также зависит от окружения. .env
на продакшене один, у вас локально свой, у коллег по команде другой. Именно поэтому файл .env
не присутствует в git-репозитоиях.
Создадим файл .env
из шаблона (.env.example
) командой:
cp .env.example .env
Вот он появился:
Еще один способ просмотреть содержимое текущей директории - это использовать команду ls -la
. Эта команда отображает все файлы и папки в текущей директории, включая скрытые файлы (те, что начинаются с точки). Выполняем:
ls -la
В консоли вы увидите список всех файлов и папок в текущей директории.
Итак, файл .env
создан, редактируем его! Первым делом займемся APP_KEY
. Это ключ безопасности, который очень важен для Laravel, он используется для шифрования данных пользователя, таких как сессии, куки и пароли, а также для защиты от CSRF атак. Без этого ключа ваше приложение Laravel не сможет правильно функционировать.
Надо быть аккуратными при работе с
APP_KEY
, ведь если заново сгенерировать ключ на уже рабочем проекте, то все ранее зашифрованные данные (например, пароли пользователей) станут недоступными!
Ключ генерируется командой:
php8.3 artisan key:generate
Теперь в файле .env
появился новый ключ безопасности в строке APP_KEY
.
Кроме этого в .env надо установить еще несколько параметров:
APP_ENV=production
указываем что режим работы приложения - продакшенAPP_URL="домен приложения"
DB_DATABASE="имя БД"
DB_USERNAME="имя пользователя БД"
DB_PASSWORD="пароль от БД"
Миграции
Миграции в Laravel - это очень удобный способ управления структурой вашей базы данных. Команда php8.3 artisan migrate
запускает все ваши миграции, что, по сути, “накатывает” изменения на вашу базу данных. А при первом вызове создает структуру базы данных с нуля.
Поскольку вы указали APP_ENV=production
в файле .env
, Laravel выдает предупреждение перед запуском миграций. Это сделано для того, чтобы предотвратить случайные изменения в вашей продакшен-базе данных. Это двойная проверка перед тем, как вы вносите какие-либо изменения.
Рестарт очередей и компиляция ассетов
Рестарт очередей - это важный шаг, если ваше приложение использует очереди задач Laravel. Когда вы обновляете свое приложение, вам нужно убедиться, что все ваши очереди воркеров перезапускаются. Если в проекте джобы изменились, а вы забудете перезапустить очереди, то изменения не применятся и крутиться в воркерах будут старые джобы.
Рестарт очередей выполняется с помощью команды:
php artisan queue:restart
Компиляция ассетов - это процесс, в котором Laravel собирает и оптимизирует ваши CSS и JavaScript файлы. "Ассеты сбилдились" ("ассеты собраны", стили и скрипты скомпилированы) в отношении Laravel обычно означает, что ваши статические файлы, такие как CSS, JavaScript и изображения, были обработаны и оптимизированы.
Это делается с помощью инструмента под названием Laravel Mix или Vite. Для компиляции ассетов необходим NPM (Node Package Manager) - менеджер пакетов для JavaScript. Ассеты билдятся с помощью команды:
npm run build
Некоторые shared хостинги поддерживают Node.js и npm, но не все. Важно проверить у вашего провайдера хостинга - есть ли на нем npm.
Что делать есть shared-хостинг не поддерживает npm?
Мы можем скомпилировать стили в локальном проекте и через GitHub отправить на сервер. Вот как это сделать:
Скомпилируйте ваши стили. Используйте команду
npm run build
.Убедитесь, что папки с css и js добавлены в индекс, при необходимости добавьте. Используйте команду
git add public/css
илиgit add public/js
(или обе команды, если вы храните стили в обоих местах) для добавления скомпилированных файлов в локальный репозиторий Git.Сделайте коммит.
Запушьте изменения на GitHub.
Склонируйте изменения с GitHub на сервер.
Перед следующим коммитом не забудьте сбилдить ассеты!
Компиляция ассетов и рестарт очередей - это два важных шага, которые легко забыть при развертывании приложения Laravel.
Проверяем работу
Всё готово для проверки работы. Обновляем страницу и видим наше приложение на Laravel.
Всё настроено. Как теперь обновлять проект?
1. Отправляем изменения в удалённый репозиторий на GitHub.
1.1. Создаём коммит в локальном репозитории:
commit "описание коммита"
1.2. Отправляем изменения в GitHub:
git push
1.3. Проверяем что репозиторий на GitHub обновлён.
2. Теперь заберем изменения из GitHub-репозитория на сервер.
2.1. Переходим в командную строку на сервере. И выполняем:
git pull
2.2. Устанавливаем зависимости, если вдруг какие-то пакеты новые подключали:
php8.3 composer install
2.3. Накатываем миграции, собираем ассеты и делаем рестарт очередей:
php8.3 artisan migrate
npm run prod
php artisan queue:restart
Выводы
Вот так мы практически с нуля настроили деплой проекта на сервер. Примерно это займет около 30 минут. Каждый дальнейший деплой - 3-5 минут. Не очень радостные перспективы для проектов, на которых необходимо часто обновлять код на продакшене. Также не стоит забывать про человеческий фактор, много рутинной работы - можно забыть выполнить какой-то шаг - не обновить зависимости, забыть про миграции, компиляцию ассетов или рестарт очередей. Легко пропустить какую-то команду, а любая оплошность приведет к ошибке при деплое, и нужно будет тратить время на поиск причины.
В следующих частях статьи мы будем наращивать сложность материала - рассмотрим более сложный вариант деплоя - на выделенном сервере, а также посмотрим как можно автоматизировать деплой. Подписывайтесь на мой блог, чтобы не пропустить!
Ссылки на другие части статьи:
Данил Щуцкий, автор проекта CutCode.