Практическая автоматизация: Принципы автоматизации развертывания приложений, часть 2

Еще несколько способов организации процесса развертывания одним нажатием на кнопку

Развертывание приложений Java™ часто представляет собой плохо организованный и подверженный ошибкам ручной процесс, задерживающий выпуск системы. Во второй части серии "Практическая автоматизация" эксперт по этим вопросам Пол Дюваль описывает несколько дополнительных принципов, играющих ключевую роль в организации надежного и согласованного процесса, позволяющего развертывать Java-приложения одним нажатием на кнопку.

Пол Дюваль, технический директор, Stelligent Incorporated

Paul DuvallПол Дюваль (Paul Duvall) является техническим директором компании Stelligent Incorporated – консалтинговой фирмы, которая помогает командам разработчиков оптимизировать гибкие методологии разработки программного обеспечения. Он также соавтор книги Continuous Integration: Improving Software Quality and Reducing Risk (Addison-Wesley, 2007 г.). Он принимал участие в создании книг UML 2 Toolkit (Wiley, 2003 г.) и No Fluff Just Stuff Anthology (Pragmatic Programmers, 2007 г.).



30.04.2010

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

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

Об этой серии

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

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

Рисунок 1. Принципы автоматизации развертывания
Deployment-automation patterns

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

Компилируйте один раз, разворачивайте многократно в разных средах

Название. Двоичная согласованность

Принцип. Один архив (WAR или EAR) используется при разворачивании приложения в различных целевых окружениях.

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

После многочисленных споров с коллегами на эту тему я твердо решил придерживаться точки зрения, которую можно сформулировать, как "компилируйте один раз для всех сред развертывания" (противоположным является подход "компилируйте систему под каждую среду развертывания"). Например, артефактом при развертывании Web-приложений на Java является файл Web-архива (WAR) или корпоративного архива (EAR). Этот файл должен помещаться в систему контроля версий и помечаться тегом один раз (например, DEV для среды разработки).

Принцип однократной компиляции и многократного развертывания иллюстрируется на рисунке 2, в соответствии с которым файл brewery.war создается на сервере сборки, а затем разворачивается в каждой из целевых сред.

Рисунок 2. Один Web-архив разворачивается в нескольких разных целевых средах
The same web archive is deployed to different target environments

Ant включает задачу checksum, реализованную на основе хэширующего алгоритма MD5 (Message-Digest 5), для проверки того, что архив со скомпилированным приложением, сформированный на сервере сборки, не изменяется при развертывании в каждой из целевых сред.

Существует мнение, что хотя при развертывании может использоваться один артефакт, конфигурация может отличаться для каждой среды. Другими словами, при автоматическом скриптовом развертывании многие автономные процессы могут изменять содержимое файлов, несмотря на то, что они помещаются в один и тот же архив. Это верно, но при этом не исключено, что вы впустую потратите много времени, пытаясь определить причину проблемы, которая, например, заключается в том, что приложение было скомпилировано под одной версией JDK в среде для испытаний, а запущено под другой в среде для оценки качества. Кроме того, риск проблем еще возрастет, если версии JAR-файлов в центральном репозитории сторонних библиотек (например, Ivy или Maven), которые используются в среде разработки, отличаются от тех, которые используются в среде для испытаний. Эти факторы все больше убеждают меня в том, что для гарантии бинарной согласованности необходимо компилировать и формировать архив с приложением один раз, и этот архив затем может быть развернут в разных средах.


Удешевление процесса развертывания при помощи одноразовых контейнеров

Название. Одноразовый контейнер

Принцип. Автоматизация установки и конфигурирования контейнеров базы данных и Web путем отделения этих этапов развертывания друг от друга.

Противоположный принцип. Ручная установка и конфигурирование контейнеров для каждой среды развертывания.

В одной из предыдущих статей серии Практическая автоматизация под заголовком Неудачные принципы непрерывной интеграции, часть 2 объяснялось каким образом очищение "грязного" окружения помогает избежать ложных (отрицательных или положительных) результатов сборки. Подход на основе использования одноразового контейнера позволяет избежать многих проблем, связанных с использованием постоянных контейнеров. Данный подход основывается на двух принципах: во-первых, следует полностью удалить все компоненты контейнера перед развертыванием, а во-вторых – разделить этапы установки и конфигурирования контейнера. Кому-то, в особенности системным инженерам, это может показаться радикальным решением, поскольку контейнеры, в основном, должны управляться отдельной командой специалистов, как это было ранее, когда разработчики вообще не должны были прикасаться к контейнерам. Тем не менее, принимая во внимание тяжело устраняемые проблемы, которые могут возникнуть в процессе развертывания, все члены команды должны в итоге сойтись на наиболее выигрышном решении.

Развертывание одним нажатием на кнопку

Мне часто приходилось слышать от разработчиков: "Да, у нас организовать процесс автоматического развертывания". При этом в ответ на простые вопросы, например: "Можете ли вы развернуть рабочее приложение путем ввода всего одной команды", – я, как правило, слышал нечто вроде: "Да, как только установлен и настроен Web-контейнер..." или: "Да, останется только создать и наполнить базу данных". Лично я считаю, что действительно автоматическое развертывание – это когда достаточно установить только платформу Java и Ant на чистую машину (кстати, даже это можно автоматизировать), а затем ввести всего одну команду для развертывания приложения. Если вы не можете это сделать, то ваш процесс нельзя назвать "развертыванием одним нажатием на кнопку" и как следствие могут возникать трудно разрешимые проблемы, обусловленные человеческим фактором.

В основе принципа одноразового контейнера, показанного на рисунке 3, лежит философия, заключающаяся в том, что все объекты и процедуры, необходимые для развертывания, должны находиться в репозитории (см. принцип "Репозиторий" в предыдущей статье), а не в чьей-то голове.

Рисунок 3. Удаление и установка контейнера в процессе развертывания
Removing and installing containers during deployment

Скрипт Ant, приведенный в листинге 1, загружает ZIP-архив с Tomcat из Интернета, удаляет все следы предыдущей попытки развертывания, а затем распаковывает, устанавливает и запускает Tomcat.

Листинг 1. Пример скрипта развертывания Ant, который удаляет, устанавливает, запускает и настраивает контейнер
<!-- Перед этим необходимо проверить, запущен ли Tomcat -->
...
<exec executable="sh" osfamily="unix" dir="${tomcat.home}/bin" spawn="true">
  <env key="NOPAUSE" value="true" />
  <arg line="shutdown.sh" />
</exec>
<delete dir="${tomcat.home}" />
<get src="${tomcat.binary.uri}/${tomcat.binary.file}" 
  dest="${download.dir}/${tomcat.binary.file}" usetimestamp="true"/>
<unzip dest="${target.dir}" src="${download.dir}/${tomcat.binary.file}" />
<exec osfamily="unix" executable="chmod" spawn="true">
  <arg value="+x" />
  <arg file="${tomcat.home}/bin/startup.sh" />
  <arg file="${tomcat.home}/bin/shutdown.sh" />
</exec>
<xmltask source="${appserver.server-xml.file}"
  dest="${appserver.server-xml.file}">
  <attr path="/Server/Service[@name='${s.name}']/Connector[${port='${c.port}']" 
    attr="proxyPort" 
	value="${appserver.external.port}"/>
    <attr path="/Server/Service[${name='${s.name}']/Connector[${port='${c.port}']" 
	attr="proxyName"
	value="${appserver.external.host}"/>
</xmltask>
<!-- Остальное конфигурирование контейнера -->
...
<echo message="Starting tomcat instance at ${tomcat.home} with startup.sh" />
<exec executable="sh" osfamily="unix" dir="${tomcat.home}/bin" spawn="true">
  <env key="NOPAUSE" value="true" />
  <arg line="startup.sh" />
</exec>

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


Выполнение команд в нескольких внешних средах

Название. Удаленное развертывание

Принцип. Использование центрального сервера или кластера для развертывания приложения в нескольких целевых средах

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

После того как были установлены Web-контейнер и сервер базы данных, запуск процесса развертывания на рабочем компьютере разработчика, как правило, достаточно тривиален. Тем не менее существует множество различий между средами разработки и эксплуатации приложения. Если в компании ведется несколько проектов и поддерживается несколько сред, в которых может быть развернуто приложение (например, для тестирования и симуляции), то часто бывает необходимо управлять процессом развертывания централизованно, т.е. с одного компьютера или кластера. Нередко разработчики используют сервер сборки для управления развертывания во всех средах. В первой части рассказывалось о принципе использования автономных процессов, в соответствии с которым применяются публичные и секретные ключи, благодаря которым не приходится вручную подключаться к каждому компьютеру. Принцип удаленного развертывания, показанный на рисунке 4, в свою очередь основан на принципах автономного выполнения, единственной команды и развертывания при помощи скриптов, благодаря которым весь процесс значительно упрощается.

Рисунок 4. Сервер управления сборкой и удаленное развертывание в нескольких средах
Build management server to multiple environments

Для развертывания приложения с центрального сервера сборки удаленным образом необходимо использовать механизмы безопасного копирования и удаленного выполнения команд. В данной статье иллюстрируются два таких механизма – безопасное копирование (Secure Copy – SCP) и безопасный командный интерпретатор (Secure Shell – SSH). В листинге 2 показано, как Web-архив, сгенерированный скриптами развертывания на центральном сервере сборки, затем копируется на удаленный компьютер.

Листинг 2. Безопасное копирование файла war с одного компьютера на другой
<target name="copy-tomcat-dist">
  <scp file="${basedir}/target/brewery.war" 
  trust="true" 
  keyfile="${basedir}/config/id_dsa"
  username="bobama"
  passphrase=""
  todir="pduvall:G0theD!stance@myhostname:/usr/local/jakarta-tomcat-5.5.20/webapps" />
</target>

После того как WAR-файл был безопасным образом скопирован в удаленную среду, можно использовать Ant-задачу SSHExec и удаленно выполнять команды SSH через безопасный канал Java (Java Secure Channel) с центрального сервера сборки. Также можно подключиться к удаленному компьютеру через ssh и выполнять все команды локально. Это позволит снизить трафик и сократить общее время развертывания.


Перевод базы данных в известное состояние

Название. Обновление базы данных

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

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

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

Рисунок 5. Автоматизированный процесс последовательного внесения изменений в базу данных
Automatically applying incremental database updates.

В ранней статье серии "Практическая автоматизация" под названием Автоматический перенос базы данных рассказывалось о необходимости автоматизации процесса внесения последовательных изменений в базу данных. Обновление базы данных является частью процесса скриптового развертывания, а значит, все скрипты должны храниться в центральном репозитории.

LiquiBase (см. раздел Ресурсы) является примером приложения для последовательного обновления базы данных. При этом одни и те же изменения вносятся в каждой среде при выполнении скриптов развертывания. В листинге 3 показан SQL-скрипт, который является частью набора изменений (changelog) LiquiBase. Подобные наборы изменений описываются в XML, а затем выполняются в процессе скриптового развертывания. Как правило, скрипты вызываются средствами, аналогичными Ant.

Листинг 3. Запуск произвольного скрипта SQL в составе набора изменений LiquiBase
<changeSet id="1" author="jbiden">
  <sqlFile path="insert-distributor-data.sql"/>
</changeSet>

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


Проверка успешности процедуры развертывания

Название. Тестирование развертывания

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

Противоположный принцип. Результат развертывания проверяется вручную путем запуска функциональных тестов, которые не проверяют конкретные аспекты процедуры развертывания.

На рисунке 6 показан пример запуска тестов перед процедурой развертывания и после нее.

Рисунок 6. Выполнение функциональных тестов приложения в процессе развертывания
Running functional deployment tests against application

В листинге 4 приведен пример использования Ant для выполнения тестов перед процедурой развертывания с целью проверки того, что используются корректные версии программ. В процессе скриптового развертывания скрипты могут проверять, не заняты ли нужные порты (поскольку в этом случае запуск Web-контейнера завершится неудачей), установлено ли соединение с базой данных, запущены ли все нужные контейнеры, а также выполнять другие внутренние тесты.

Листинг 4. Выполнение проверок перед процедурой развертывания для гарантии ее успешности
<condition property="ant.version.success">
  <antversion atleast="${ant.check.version}" />
</condition>
<antunit:assertPropertyEquals name="ant.version.success" value="true" />
<echo message="Ant version is correct." />
<echo message="Validating Java version..."/>
<condition property="java.major.version.correct">
  <equals arg1="${ant.java.version}" arg2="${java.check.version.major}" />
</condition>
<antunit:assertTrue message="Your Java SDK version must be 1.5+. \
  You must install correct version.">
  <isset property="java.major.version.correct"/>
</antunit:assertTrue>

В расширенный вариант тестов могут также входить проверки корректности функционирования приложения. Вы можете создавать автоматические функциональные тесты, специфичные для конкретного процесса развертывания, при помощи таких средств, как Selenium (для Web-приложений) или Abbot (для клиентских приложений). С их помощью можно проверять успешное внесение всех изменений при развертывании. Подобные тесты представляют собой минимальные проверки целостности системы (smoke tests): они тестируют только функциональность, которая изменилась в процессе развертывания. В таблице 1 приведен ряд способов использования Selenium и других средств для тестирования Web-приложения.

Таблица 1. Виды проверок при развертывании приложения
Название тестаОписание теста
База данныхАвтоматические функциональные тесты, добавляющие данные в БД и проверяющие их успешную вставку.
Простой протокол передачи почтовых сообщений (SMTP)Автоматические функциональные тесты, отправляющие почтовые сообщения из приложения.
Web-сервисТесты, использующие средства наподобие SoapAPI для отправки запроса Web-сервису и проверяющие его отклик.
Web-контейнер(ы)Проверка функционирования всех сервисов контейнера.
Легковесный протокол доступа к каталогам (LDAP)Аутентификация при помощи LDAP из приложения.
ЖурналированиеТесты, делающие записи в журнале событий через механизм, предоставляемый приложением.

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


Откат изменений, внесенных в результате развертывания

Название. Откат среды

Принцип. Автоматический откат всех изменений после неудачного развертывания. Эта операция должна производиться путем ввода единственной команды.

Противоположный принцип. Ручная отмена всех изменений в приложении и базе данных.

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

Рисунок 7. Схема отмены изменений, внесенных в процессе развертывания
Rolling back deployment changes

Вне зависимости от того, используете вы автоматизированную процедуру развертывания или нет, желательно иметь возможность откатить результаты в случае, если что-то пойдет не так. Возможны ситуации, в которых ошибочно внесенные изменения могут привести к выходу системы из строя, что может обойтись компании в миллионы долларов. Откат среды означает, что окружение вашего приложения должно быть возвращено к состоянию, в котором оно пребывало до попытки развертывания. Для этого необходимо иметь скрипт для отката каждого внесенного изменения. При этом при развертывании Web-приложения часто делается больше изменений, чем потом может понадобиться откатить. Одним из примеров процедуры отката среды может служить создание резервной копии текущего архива приложения (файла WAR) перед развертыванием, а также использование скриптов для отката изменений в базе данных. При этом также необходимо вернуть в исходное состояние конфигурацию Web-контейнера.

В листинге 5 демонстрируется пример оператора для отката изменений, сделанных каждым оператором LiquiBase. В частности, созданию новой таблицы brewery соответствует оператор dropTable для ее удаления.

Листинг 5. Пример указания процесса отката при описании изменений в базе данных
<changeSet id="rollback-database-changes" author="bobama">
  <createTable tableName="brewery">
    <column name="id" type="int"/>
  </createTable>
  <rollback>
    <dropTable tableName="brewery"/>
  </rollback>
</changeSet>

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


Защита информации от любопытных глаз

Название. Защита файлов

Принцип. Находящиеся в репозитории файлы должны быть доступны только для авторизованного персонала.

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

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

Рисунок 8. Использование защищенного репозитория системы контроля версий для хранения конфиденциальных файлов
Using a protected version control repository for sensitive files

В некоторых случаях не все члены команды должны иметь доступ к информации, относящейся к конкретной среде развертывания. Однако хранение такой информации отдельно от скриптов развертывания может нарушить их выполнение. При обсуждении автономных процессов упоминалось об использовании ключей SSH и безопасных каналов Java для копирования файлов и удаленного выполнения команд без вмешательства человека. При этом файлы свойств, использующиеся при внешнем конфигурировании, скорее всего, будут содержать данные, которые не должны быть доступны всем членам команды. Для того чтобы обеспечивать выполнение автономных процессов, обеспечивая конфиденциальность данных в файлах свойств, их следует хранить в защищенном репозитории.

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

Листинг 6. Защита репозитория Subversion с использованием Apache
<DirectoryMatch "^/.*/(\.svn)/">
  Order deny,allow
  Deny from all 
  Allow bobama,jbiden,hclinton
</DirectoryMatch>

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


Развертывание одним нажатием на кнопку

В моем арсенале есть еще несколько принципов автоматизации развертывания кроме тех 15, которые были перечислены в данной мини-серии. Однако эти 15 принципов оказываются применимы в 80% ситуаций, с которыми я когда-либо сталкивался. Каждый из них поможет вам организовать процесс автоматического развертывания вашего приложения в нескольких средах путем выполнения единственной команды (или нажатием на кнопку). Желаю, чтобы ваш опыт развертывания приложений был максимально безболезненным.

На этом все

Это была моя последняя статья из серии Практическая автоматизация. Разделять свой опыт с читателями на протяжении более чем двух лет было невероятно увлекательно. Моей целью при этом всегда было объяснение того, как и почему следует автоматизировать множество различных процессов при разработке программного обеспечения, чтобы вы могли уделять больше времени работе над интересной задачей, а не заниматься утомительной работой, чреватой ошибками. В этой серии я показал, как можно автоматизировать процесс рецензирования кода с целью дальнейшего рефакторинга, выполнения последовательного обновления базы данных, использования принципов и средств непрерывной интеграции, запуска тестов при каждом изменении, генерации графических инсталляторов, организации процесса развертывания одним нажатием на кнопку, генерации документации, управления зависимостями, использования систем контроля версий, а также различных скриптов и средств сборки. Надеюсь, что, читая мои статьи, вы получили не меньше удовольствия, чем я в процессе их написания.

Ресурсы

Научиться

Получить продукты и технологии

  • Ant: Загрузите Ant и организуйте надежный и предсказуемый процесс сборки ваших приложений. (EN)
  • JSch: Загрузите Java-библиотеку защищенных каналов, обеспечивающую безопасный обмен данными. (EN)
  • Selenium: Загрузите Selenium - средства для выполнения функционального тестирования аспектов, специфичных для процесса развертывания. (EN)
  • LiquiBase: Загрузите LiquiBase для автоматизации внесения изменений в базу данных. (EN)
  • Abbot: Загрузите Abbot - средство для выполнения функционального тестирования в процессе развертывания. (EN)

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java
ArticleID=486564
ArticleTitle=Практическая автоматизация: Принципы автоматизации развертывания приложений, часть 2
publish-date=04302010