Мысли О Развертывании Веб-Приложений На Тестовом Сервере



Предисловие Следующий текст является результатом практического опыта и самообразовательных порывов человека, не имеющего систематического образования ни в одной из областей, о которых он (то есть я) берусь рассуждать.

Поэтому заумные рассуждения здесь будут перемежаться банальностями.

Ударь меня за первое и проигнорируй второе.

Для некоторых они тоже могут стать откровением.

Я попытаюсь описать идеальные варианты настройки тестового веб-сервера, хотя понимаю, какой бардак они обычно создают. Я остановлюсь на ситуации, когда деплоить приходится часто, то есть на сервере есть проект в активной стадии разработки или несколько проектов на разных стадиях.

Проектами занимаются разные разработчики или команды, поэтому проекты необходимо изолировать друг от друга.

Но сервер внутренний, поэтому не нужна такая степень изоляции и автоматизации процессов администрирования, как на арендованных серверах.

Основное внимание я буду уделять использованию различных версий Python в качестве языка поддерживаемых веб-приложений.

Хотя многое, вероятно, будет справедливо и для других языков, например, Ruby или Perl. Программа на Python взаимодействует с веб-сервером по протоколу WSGI (читается как «виски»), описанному в ПЭП 3333 и предшествующий ему документ, ПЭП 333 .



Одноуровневая архитектура

Преимущество одноуровневого подхода — простота настройки и умеренное потребление памяти в ущерб гибкости и, в некоторых случаях, производительности.

Самый популярный веб-сервер, работающий в таких условиях, настоящий «швейцарский нож» современного Интернета — Apache HTTPd (часто это имя сокращают до «Apache»).

Я буду иметь в виду текущие версии Apache: 2.2 и 2.4. Для подключения WSGI-приложений к Apache напрямую, без участия серверов второго уровня, используется плагин (в терминологии Apache — модуль).

mod_wsgi .

WSGI — это расширенный вариант протокола, специфичный для Python. компьютерная графика .

Технически интерпретатор Python (точнее, CPython) встроен в mod_wsgi как внешняя библиотека: статически или динамически — это определяется при сборке модуля.

Понятно, что в mod_python одновременно может быть встроена только одна версия CPython, так же, как Apache может обращаться только к одному модулю mod_wsgi за одну установку.

Это приводит к ограничению: в одноуровневой архитектуре с mod_wsgi мы не можем использовать на сервере одновременно Python2 и Python3 .

Для нас важен выбор мультипроцессорного модуля.

Чтобы эффективно распределять нагрузку между различными вычислительными ядрами в многоядерных (многопроцессорных) конфигурациях компьютеров, веб-сервер должен иметь возможность одновременно обрабатывать несколько запросов, запуская несколько экземпляров веб-приложения.

Существует два типа многопроцессорных модулей, которые по-разному выполняют вышеуказанную функцию.



превилка

Упрощенное выполнение CGI-запроса веб-сервером в UNIX-подобной среде выглядит следующим образом: получив запрос, сервер порождает процесс CGI-приложения, передавая ему параметры запроса в переменных среды, а тело — в стандартный ввод. транслировать.

Самые первые оптимизации были вызваны тем, что порождение процесса занимает довольно много времени, что увеличивает время ответа на запрос.

Чтобы не тратить время на запуск CGI-программы (в нашем случае интерпретатора Python, встроенного в mod_wsgi), достаточно запустить ее заранее и держать в подвешенном состоянии, не закрывая входной поток, до тех пор, пока на сервер не поступит запрос.

Если сервер может одновременно выполнять несколько потоков кода, имеет смысл запустить несколько обработчиков CGI и обеспечить запуск новых по мере их завершения.

Количество (размер пула) работающих и ожидающих обработчиков можно настроить.

Обработав один запрос, процесс-обработчик может принять следующий.

Если запросов слишком мало, сервер уничтожит ненужные простаивающие процессы.

Сервер также убивает процессы в профилактических целях, после того как количество обработанных ими запросов достигнет определенного (тоже настраиваемого) предела.

Именно так работают модули mod_prefork И mod_itk .

Последний для нас наиболее интересен, поскольку он способен обслуживать каждый виртуальный хост от имени пользователя, указанного в настройках этого виртуального хоста.

Но об этом позже.



рабочий

Второй способ «списать» затраты на генерацию CGI-процесса и при этом снизить общую нагрузку на сервер — использовать один процесс для одновременный обслуживание нескольких запросов, иными словами — в многопоточном режиме.

Описанная стратегия реализуется модулями mpm_worker и mpm_event. Последний также освобождает основной поток обработки запросов от некоторых учетных действий и на данный момент имеет статус экспериментального.

Worker долгое время считался нестабильным и небезопасным — не сам по себе, а из-за того, что многие другие модули Apache не были адаптированы к многопоточности или имели ошибки в ее реализации.

Но со временем эти проблемы были решены, и теперь рабочие достаточно безопасны для использования на практике.

Надо сказать, что благодаря такой особенности CPython, как GIL, mod_wsgi довольно легко адаптировался к многопоточной работе, однако эта самая возможность не позволяет получить все преимущества многопоточности.

GIL гарантирует, что в рамках одного процесса все потоки кода Python будут выполняться последовательно, квант за тактом, что лишь создает иллюзию одновременного выполнения.

Но это касается не C-кода, запускающего (или запускаемого из) Python, а парсинга параметров запроса, сопоставления адреса обработчику WSGI и т. д. — все это делается в C-коде.

Соответственно, сайты, написанные на Python, по-прежнему имеют определенный прирост производительности от использования mpm_worker.

Двухуровневая архитектура

Двухуровневая архитектура предполагает совместное использование веб-серверов на разных уровнях: внешнем (интерфейсном) и внутреннем (внутреннем).

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

Кроме того, внешний сервер делает то, для чего в 1990 году был создан протокол HTTP: предоставляет клиенту статические файлы (активы).

Хотя в последнее время эту функцию в производственной среде часто переносят на CDN-сервисы.

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

Внутренний сервер обычно зависит от архитектуры и языка реализации приложения.

Приложения Python часто используют uWSGI , Зеленый Единорог или ваши собственные серверы на основе многопоточных сетевых инфраструктур, таких как Twisted или Tornado. Многие веб-фреймворки также включают в себя более или менее боеспособные веб-серверы.

Например, встроенный в Django веб сервер предназначен исключительно для отладки и в производстве должен быть заменен чем-то более серьезным.

Встроенный веб-сервер ЧерриПи , наоборот, оптимизирован под боевую нагрузку.



Особые требования к тестовому серверу (CI-серверу)



Проблема с правами доступа к файлу

Сетевая архитектура в системах POSIX предполагает, что только привилегированные пользователи имеют доступ к портам 1–1024. Это ограничение распространяется на порты 80 (HTTP) и 443 (HTTPS), поэтому родительский процесс веб-сервера (внешний, если мы говорим о двухуровневой архитектуре) всегда является корневым.

Но не рекомендуется давать CGI-скрипту слишком широкие права из соображений безопасности.

Поэтому при работе со скриптами и данными веб-сервер всегда понижает привилегии до уровня обычного пользователя.

Такой пользователь в Apache указывается переменными среды APACHE_RUN_USER и APACHE_RUN_GROUP. В Debian и производных дистрибутивах этот пользователь называется «www-data».

Для дальнейшего повышения безопасности системы пользователь www-data, как и другие пользователи сервиса, не имеет оболочки и не может войти в систему.

Если веб-приложение установлено на сервере один раз и в дальнейшем не будет изменено (за исключением разве что файлов, загружаемых пользователем), то логично будет зайти на сервер как пользователь с высокими привилегиями, развернуть файлы на соответствующий каталог (/var/www в Debian) и измените владельца этих файлов:

  
  
   

# chown -R www-data:www-data /var/www/

Понятно, что этот способ неудобен для сервера разработки и вызывает опасения из-за постоянного использования привилегированной учетной записи.

Вопрос об идеальных правах доступа к каталогам и данным веб-сервера с подробным ответом можно найти здесь.

Здесь .

Статья была указана как каноническая проблема на Serverfault, а это кое-что значит. Суть статьи сводится к следующему:

  • если за развертывание сайта отвечает один человек, то нужно сделать его пользователем-владельцем всех файлов и каталогов сайта, а группу владельцев сделать "www-data", а для каталогов установить коды доступа 750 (770 для каталогов, в которые пользователи сайта смогут загружать файлы) и 640 для файлов (660 для файлов, написанных сервером).

    umask в сценариях запуска должен быть установлен на 027,

  • если доступ к сайту должен иметь несколько человек, необходимо сделать владельцем пользователя root, группой владельцев будет группа, в которой будут все разработчики, а веб-сервер будет иметь доступ к этим файлам с помощью нижних трех биты,
  • или установить владельцем данных www-data, а группу владельцев — группу разработки, но тогда вам нужно будет менять ее владельца после создания каждого файла.

    В другом ответе упоминается возможность устанавливать биты suid и guid в каталогах, чтобы владельцем созданного объекта был не создатель, а владелец каталога, в котором объект был создан.

    Этот нестандартный способ использования этих битов был перенесен в Linux из *BSD, и я даже не уверен, работал ли бы он, если бы файлы создавались веб-сервером.

  • хотя в идеале команда разработчиков должна использовать инструменты автоматического развертывания ( Кукольный , Шеф-повар ) или среду CI ( Дженкинс ), чтобы свести ситуацию к одному ответственному пользователю, с той лишь разницей, что этим пользователем будет бот,
  • В результате делается вывод, что полной изоляции виртуальных хостов невозможно добиться одной лишь установкой прав доступа: уязвимость одного сайта позволит злоумышленнику как минимум прочитать код всех веб-приложений на этом сервере.

Что не упоминается в обсуждении, так это ошеломляющая сложность всех этих манипуляций с chmod и chown и, как следствие, высокая вероятность человеческих ошибок, приводящих к уязвимостям.

Все становится намного проще и безопаснее, если вы воспользуетесь функциями разделения привилегий Apache или перейдете на двухуровневую архитектуру.



Инструменты разделения привилегий Apache



мпм_итк

Модуль mpm_itk позволяет нам самым простым и естественным способом определить, под каким пользователем будет работать наше веб-приложение:

<VirtualHost *:80> <IfModule mpm_itk_module> AssignUserID johnd developers </IfModule> … </VirtualHost>



mod_suexec

Если по каким-то причинам мы вынуждены использовать другой мультипроцессорный модуль, то он придет нам на помощь.

mod_suexec .

Единственным его недостатком является то, что его относительно сложно настроить, но это только в том случае, если мы хотим установить его из исходного кода.

В раздачах все автоматизировано.

И использование mod_suexec снова сводится к одной директиве в конфигурации виртуального хоста:

<VirtualHost *:80> <IfModule mod_suexec.c> SuexecUserGroup johnd developers </IfModule> … </VirtualHost>



Двухуровневая архитектура на тестовом сервере

Часто для оптимизации производительности сервера используется двухуровневая архитектура.

Разработчиков больше волнует простота развертывания веб-приложения, чем скорость его работы.

Использование двухуровневой архитектуры на тестовом сервере также имеет определенные преимущества.

К преимуществам можно отнести то, что за установку и настройку внутреннего сервера отвечает разработчик; он также определяет ее оптимальные параметры и способ запуска.

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

Журналы хоста также находятся в полном распоряжении разработчика.

Веб-приложение может использовать версию Python, указанную virtualenv, независимо от других проектов.

Все, о чем должен позаботиться администратор сервера, — это статические каталоги и сокет UNIX или непривилегированный порт, через который будут общаться внешний и внутренний серверы.

Разработчик также несет ответственность за автоматический запуск сервера и обеспечение его бесперебойной работы.

Если первое легко решается командой «crontab -e», то второго можно добиться с помощью руководитель .



Перезагрузка веб-сервера

При использовании Apache в качестве единственного сервера стоит добавить директиву « MaxRequestsPerChild 1 С его помощью разработчику не потребуется перезагружать сервер.

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

Конечно, запрет вторичного использования обработчика запросов снизит производительность сервера, но в противном случае вам придется перезапускать сервер при каждом изменении кода.

Существует два способа перезагрузки Apache: специфичный для WSGI и общий.

  • Метод, специфичный для WSGI, заключается в обновлении даты редактирования сценария WSGI. Это можно сделать с помощью сенсорной команды.

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

    (В общем очень желательно настроить mod_wsgi для работы в режиме демона, хотя по умолчанию этот режим отключен.

    )

  • Общий метод — это команда «apachectl restart» или подобная, для которой требуются права root. Конечно, вы можете обойтись соответствующей настройкой sudo, но использование sudo само по себе более сложное и более опасно чем может показаться.

    Поэтому не рекомендуется использовать этот метод.

Если используется двухуровневая архитектура, то перезагрузить нужно только внутренний сервер.

Он запускается под тем же пользователем, что и тот, под которым производится развертывание, поэтому проблем с его перезагрузкой (или настройкой работы без необходимости перезагрузки) не возникает.

выводы

Двухуровневая архитектура веб-сервера оптимальна для тестового сервера, используемого несколькими разработчиками или группами разработчиков на одном предприятии.

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

В то же время простота разработки иногда может достигаться за счет снижения производительности.

Но даже если организация настолько ограничена в деньгах, что вынуждена размещать тестовые и производственные проекты на одном сервере, безопасность и достаточно хороший уровень производительности в этом случае вполне достижимы.

Теги: #развертывание #веб #Apache #linux #python #wsgi #развертывание #тестовый сервер #ci #разработка веб-сайтов #python

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.