Сайты это не только код, но и инфраструктура для их запуска. В первую очередь, в неё входят сервера, на которых крутится код, база данных и различные вспомогательные системы. Иногда все это помещается на один сервер, в более сложных ситуациях количество серверов измеряется тысячами, а для обслуживания таких систем привлекаются целые команды инженеров (разного рода администраторов). Независимо от размера сайта, проблемы обслуживания инфраструктуры у всех очень похожие. Поговорим об одной конкретной – настройке сервера.
Существуют подходы, которые позволяют избежать прямого взаимодействия с инфраструктурой. В рамках статьи они не рассматриваются, но знать про них полезно. К ним относятся классические хостинги с предустановленным софтом, serverless, хостинги статических сайтов, PaaS решения и kubernetes (и его аналоги)
В подавляющем большинстве случаев сервера арендуются у хостинговых компаний, таких как DigitalOcean или AWS. Делается это за 5 минут нажатием буквально нескольких кнопок. Нас попросят выбрать характеристики сервера, операционную систему и датацентр, в котором он будет развернут. В результате мы получаем машину (виртуальную) с предустановленной операционной системой и ip-адресом для входа по ssh.
Новая машина содержит только основную операционную систему с небольшим набором предустановленных программ. Перед тем, как запустить на ней какой-то сервис, например, обычный сайт, понадобится установить дополнительные пакеты. Набор пакетов зависит от стека технологий, на котором он написан. Если сайт "завернут" в Docker, то настройка значительно упрощается и сводится к установке самого Docker. В остальных случаях придется потратить какое-то время на донастройку и конфигурирование. Помимо пакетов часто требуется настраивать саму систему, менять конфигурационные файлы, права на файлы и директории, создавать пользователей и так далее:
# Как это могло бы быть
# Сервер на Ubuntu
# Заходим на удаленную машину
ssh root@ipaddress
# Создание пользователя для деплоя
# Где-то здесь копируются ssh ключи
sudo adduser deploy
sudo apt install curl
# установка Node.js
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt install nodejs
# установка и настройка Nginx
sudo apt install nginx
vim /etc/nginx/default.conf
# Формирование структуры директорий для сервиса
mkdir -p /opt/hexlet/versions/
Процесс первоначальной настройки занимает часы и даже дни. Постоянно придётся что-то подкручивать, донастраивать и устанавливать. Цикл повторится снова, когда понадобится перейти на новые версии пакетов. Снова придется заходить на сервер, вспоминать, что и где настраивалось, и как мягко обновиться, ничего не сломав. В чём проблема ручной настройки?
Сервера могут умирать и делать это внезапно. Сколько времени уйдёт на "раскатку" нового сервера? Практически столько же времени, сколько было потрачено первый раз. Порядок действий и нужные настройки просто никто не вспомнит даже через неделю после настройки, что уже говорить, если прошли месяцы. Более того, вдруг тот, кто изначально это делал, уже не работает в компании или находится в отпуске. Что тогда? Придётся долго извиняться перед пользователями за длительный простой, и хорошо, если бизнес от этого пострадает не сильно.
Переустановка сервера необязательно связана с какими-то форс-мажорными обстоятельствами. В компаниях с хорошей инженерной культурой сервера меняются на регулярной основе. Как минимум это важно для безопасности. Операционные системы содержат уязвимости, которые закрываются новыми пакетами или версиями. Следить за этим довольно сложно, поэтому проще регулярно освежать инфраструктуру. С другой стороны, обновление сервера может легко сломать рабочее приложение и вызвать простой в работе. Единственный способ гарантировать беспрерывную работу во время обновления – поднимать рядом ещё один сервер и настраивать его. Затем сервис просто выкатывается на новый сервер, а старый выключается.
Хорошо бы было автоматизировать настройку сервера. Для этого существует несколько подходов, которые мы рассмотрим ниже.
В простейшем случае для этого достаточно обычного bash-скрипта, в который последовательно добавляются команды, которые ранее мы запускали руками. Затем всё сводится к копированию скрипта на сервер и запуску:
# Копирование на сервер с помощью scp
scp mybashscript.sh root@ipaddress:~/
# Заходим на сервер и запускаем скрипт
ssh root@ipaddress
sh ~/mybashscript.sh
Если перенести команды в bash-скрипт "как есть", без модификации, то, скорее всего, нам придётся постоянно следить за выводом и не забывать подтверждать установку пакетов, так как это поведение по умолчанию:
➜ ~ apt install golang
The following additional packages will be installed:
golang-1.13 golang-1.13-doc golang-1.13-go golang-1.13-race-detector-runtime golang-1.13-src golang-doc golang-go
Need to get 63.5 MB of archives.
After this operation, 329 MB of additional disk space will be used.
Do you want to continue? [Y/n] # Скрипт останавливается и ждёт ответа
Автоматическое "да" добавляется опцией -y
. У других команд свои опции для подавления взаимодействия с пользователем. Придётся их всё учесть.
apt install -y golang
Другая проблема серьёзнее. Связана она с понятием "идемпотентность". Что будет если выполнить команду создания директории два раза?
mkdir /hexlet
mkdir /hexlet # ?
Команда завершится с ошибкой, она не идемпотентна. То есть последовательные вызовы одной и той же команды приводят к разному результату. Идемпотентность для настройки сервера очень важна. Иначе повторный запуск скрипта настройки завершится с ошибкой. А повторные запуски нужны, например, в случае отладки самого скрипта, когда мы его только пишем и проверяем, как он работает. В случае с командой mkdir
идемпотентности добиться легко, достаточно добавить флаг -p
:
mkdir -p /hexlet
mkdir -p /hexlet # ошибки не будет
Но, к сожалению, не все команды поддерживают такую возможность. Для многих ситуаций, идемпотентность нужно обеспечивать самостоятельно, что резко усложнит скрипт. Из простого набора команд он превратится в реальный код с условными конструкциями. И в какой-то момент разбираться в нём станет крайне сложно. Через это проходили многие, особенно раньше, когда не было альтернативы.
Но дело не только в идемпотентности. Часть задач, которые легко делались руками, становятся сложными в автоматизации. Представьте, что для изменения конфигурации нужно поправить конкретную строчку внутри файла. Как это легко сделать с помощью bash? Никак. Придётся либо полностью заменять файл, копируя всё его содержимое в bash-скрипт (или рядом с ним), либо использовать что-то вроде sed
для точечной замены строки.
И последнее, но очень важное ограничение. Bash-скрипт нужно доставить на сервер самостоятельно. И если для одного сервера это ещё как-то можно автоматизировать, то для нескольких "раскатка" скрипта становится проблемой. Важно делать это параллельно, иначе настройка растягивается на часы даже в случае полной автоматизации. Добавьте сюда разные сервера со своими скриптами, которые отличаются от других.
На этом этапе bash-скрипты перестают помогать, нужно придумывать что-то ещё. Так стали появляться специализированные инструменты для конфигурирования серверов. Одними из первых были проекты Chef и Puppet. Сейчас же наибольшую популярность приобрел Ansible, который значительно проще в освоении и использовании.
Независимо от операционной системы, установка Ansible требует наличия командной оболочки, например, bash или zsh. В линуксах (Ubuntu и подобные) и MacOS терминал с оболочкой доступен по умолчанию. В Windows ситуация сложнее и зависит от версии операционной системы. В последних версиях Windows достаточно установить WSL2. Для более ранних версий воспользуйтесь нашим гайдом.
Ansible – консольная утилита написанная на языке Python. У нее достаточно подробная инструкция, с примерами установочных команд для большого числа операционных систем. Среди всех этих способов, есть один универсальный – установка Ansible как Python-пакета. Для этого нужно выполнить несколько команд в терминале:
Запустите терминал с Bash или любой другой оболочкой.
Выполните установку Python, если его еще нет в системе. Подробнее о том, как ставить Python тут
Установите Ansible
python3 -m pip install --user ansible
По умолчанию pip устанавливает пакеты в директорию ~/.local/bin. Её необходимо добавить в переменную PATH
Проверить успешность установки можно запуском Ansible:
ansible --version
ansible [core 2.12.2]
config file = None
configured module search path = ['/home/vagrant/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/vagrant/.local/lib/python3.8/site-packages/ansible
ansible collection location = /home/vagrant/.ansible/collections:/usr/share/ansible/collections
executable location = /home/vagrant/.local/bin/ansible
python version = 3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0]
jinja version = 2.10.1
libyaml = True
Экспериментировать с Ansible можно тремя разными способами:
Через указание выполнять все команды на локальной машине. Тогда все что делается, будет отрабатывать там же, где происходит Ansible. Этот способ неудобен тем, что через него не получится прочувствовать все возможности Ansible, плюс многое зависит от конкретной операционной системы
Второй способ – использовать Vagrant
Купить машину где-нибудь в облаках и работать с ней. Это самый надежный и полноценный способ поработать с Ansible. Сделать это можно практически бесплатно, зарегистрировавшись по реферальной ссылке в Digital Ocean. После регистрации на счет поступит достаточное количество денег, для покупки недорогой виртуальной машины. Если сервис для вас не доступен, закончился кредит, воспользуйтесь другими сервисами, например Linode или Yandex Cloud, если вы из РФ.
Работа с Ansible подразумевает хорошее знакомство с командной строкой и ssh. Всему этому можно научиться прямо на Хекслете:
ansible --version
ansible [core 2.11.2]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/tirion/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/tirion/.local/lib/python3.8/site-packages/ansible
ansible collection location = /home/tirion/.ansible/collections:/usr/share/ansible/collections
executable location = /home/tirion/.local/bin/ansible
python version = 3.8.10 (default, Jun 2 2021, 10:49:15) [GCC 9.4.0]
jinja version = 3.0.3
libyaml = True
Digital Ocean тарифицируется на основе запущенных серверов. Поэтому удаляйте сервера и создавайте их заново, если вы делаете перерыв между уроками, чтобы сэкономить кредит в Digital Ocean. Если сервис для вас не доступен, закончился кредит, воспользуйтесь другими сервисами, например Linode или Yandex Cloud, если вы из РФ.
Вам ответят команда поддержки Хекслета или другие студенты.
Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.
Загляните в раздел «Обсуждение»:
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.
Наши выпускники работают в компаниях:
Зарегистрируйтесь или войдите в свой аккаунт