Содержание


Agile DevOps ― гибкая разработка и эксплуатация ПО

Все под контролем версий

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

Comments

Серия контента:

Этот контент является частью # из серии # статей: Agile DevOps ― гибкая разработка и эксплуатация ПО

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Agile DevOps ― гибкая разработка и эксплуатация ПО

Следите за выходом новых статей этой серии.

Все должно быть версировано. Абсолютно все: инфраструктура, конфигурация, код приложений и сценарии баз данных. Если это сделать, то у вас будет единый источник истины, что позволит рассматривать систему программного обеспечения — и все, что нужно для создания ПО — как единое целое. Группам, которые держат все под контролем версий, не нужно постоянно выяснять, какая версия кода приложения работает с той или иной базой данных и в какой среде. Исходные файлы, составляющие систему ПО, не разбросаны по серверам, не спрятаны в папки на ноутбуках и не встроены в неверсированную базу данных.

Если все находится под контролем версий, любой уполномоченный член группы в любой момент времени в состоянии воссоздать любую версию системы ПО — будь то код приложения, конфигурация, инфраструктура или данные. Всю систему (за исключением библиотек, которые остаются неизменными) можно воссоздать с помощью одних только недвоичных артефактов, хранящихся в репозитории с управлением версиями (таком как Subversion, Git, CVS, Rational ClearCase и многие другие).

По моему опыту, идея версирования всего проста и понятна, но я редко видел, чтобы ее применяли в полном объеме. Конечно, можно найти примеры версирования кода приложений, некоторых конфигураций и, возможно, данных. Некоторые группы применяют репозитории и инструменты управления зависимостями (например, Nexus) для управления библиотеками, которые они используют при разработке программного обеспечения. Другие используют сочетание общих накопителей с системой управления версиями. Однако редко встретишь компании, которые версируют всю свою конфигурацию, все зависимые компоненты (например, из репозиториев пакетов, таких как yum, apt-get и rpm) и все сценарии, необходимые для создания базы данных, а также данные, составляющие эти базы.

Чтобы определить, версировано ли все, достаточно задать простой вопрос: «А можно ли воссоздать конкретную версию всей системы ПО ― с инфраструктурой, данными, программным обеспечением и конфигурацией ― одной командой, которая извлечет эту версию из системы управления версиями?» Если нет, значит версировано не все.

Главным условием версирования всего является то, что все исходные артефакты должны быть представлены в форме сценариев. Имеется в виду инфраструктура, данные, конфигурация и код приложений. Единственное исключение составляют библиотеки и пакеты — например, JAR-файлы и пакеты RPM, — которые используются, но никогда не изменяются. Когда для всех исходных артефактов написаны сценарии, их можно легко версировать.

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

Код приложений

Код приложений, вероятно, ― наиболее очевидная часть системы программного обеспечения, которая должна находиться под контролем версий. Код, приведенный в листинге 1, служит примером простого класса Java (UserServiceImpl), который для получения некоторых данных вызывает метод из объекта.

Листинг 1. Код Java-приложения
...
public Collection findAllStates() {
    UserDao userData = new UserDaoImpl();
    Collection states = userData.findAllStates(UserDao.ALL_STATES);
    return states;
}
...

Рисунок 1 иллюстрирует помещение нового файла исходного кода приложения UserServiceImpl.java, приведенного в листинге 1, в репозиторий с контролем версий Git, размещенный на GitHub.

Рисунок 1. Команды для помещения нового файла исходного кода в Git-репозиторий
Committing new application source file by (1) marking the file for addition with git add UserServiceImpl.java; (2) committing the code using a git command and comment: git commit -m 'added user service impl class'; (3) running the git push command to push the code to the master repository.
Committing new application source file by (1) marking the file for addition with git add UserServiceImpl.java; (2) committing the code using a git command and comment: git commit -m 'added user service impl class'; (3) running the git push command to push the code to the master repository.

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

Инфраструктура

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

Итак, наилучший подход состоит в определении инфраструктуры в виде кода. А что люди делают на самом деле? Как правило, они создают целый воз «произведений искусства» из рабочих сред, настроенных вручную для каждого случая, или смеси ручных шагов с запуском автоматизированных сценариев. Каждый из этих подходов создает узкие места, поскольку все эти шаги каждый раз должен выполнять инженер. Чтобы решить эту проблему, некоторые старательно описывают каждый такой шаг в наборе письменных инструкций. Беда в том, что инструкции могут быть некорректными, некоторые шаги могут оказаться пропущенными, или оператор, выполняющий эти шаги, может сделать это неправильно. Единственное надежное решение заключается в том, чтобы полностью описать инфраструктуру в коде, который выполняется одной командой.

Например, манифест Puppet, приведенный в листинге 2, содержит код шагов для установки сервера базы данных PostgreSQL. Этот код можно выполнить из командной строки или посредством сервера непрерывной интеграции (CI).

Листинг 2. Манифест Puppet, описывающий установку PostgreSQL
class postgresql {

  package { "postgresql8-server":
    ensure => installed,
  }

  exec { "initdb":
    unless => "[ -d /var/lib/postgresql/data ]",
    command => "service postgresql initdb",
    require => Package["postgresql8-server"]
  }
...

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

Конфигурация

Конфигурация определяет информацию, которая варьируется в разных средах. Примерами служат местоположения каталогов и файлов, имена хостов, IP-адреса и порты сервера, как показано в листинге 3. Сценарии используют эту конфигурацию при создании рабочей среды, запуске сборок и развертывании и выполнении тестов.

Листинг 3. Конфигурация, определенная в файле свойств
jboss.home=/usr/local/jboss
jboss.server.hostname=jenkins.example.com
jboss.server.port=8080
jboss.server.name=default

Код, приведенный в листинге 4, представляет собой Ruby-сценарий, который загружает элементы конфигурации в базу данных NoSQL.

Листинг 4. Запись элементов динамической конфигурации в базу данных NoSQL
AWS::SimpleDB.consistent_reads do
  domain = sdb.domains["stacks"]
  item = domain.items["#{opts[:itemname]}"]

  file.each_line do|line|
    key,value = line.split '='
    item.attributes.set(
      "#{key}" => "#{value}")
  end
end

Так как вся конфигурация, приведенная в листинге 4, ― IP-адреса, доменные имена и образы машин ― может быть получена динамически, ни одна ее часть не является жестко закодированной. Иногда невозможно сделать динамической всю конфигурацию, но при использовании облака можно резко уменьшить количество жестко закодированных конфигураций, которые часто становятся бичом систем поставки программного обеспечения.

Данные

Структуру реляционной базы данных можно определить в сценариях на языке Definition Language (DDL). Сюда относится создание базы данных, таблиц, процедур и т.п. — все, за исключением данных. Данные определяются в сценариях на языке Data Manipulation Language (DML) с использованием операторов insert, update и delete.

Фрагмент DDL-сценария, показанный в листинге 5, выполняет шаги по созданию базы данных.

Листинг 5. DDL для создания таблиц базы данных
CREATE SEQUENCE hibernate_sequence START WITH 1 INCREMENT BY 1 NO MINVALUE \
NO MAXVALUE CACHE 1;
ALTER TABLE public.hibernate_sequence OWNER TO cd_user;

CREATE TABLE note ( id bigint NOT NULL, version bigint NOT NULL, cd_id bigint NOT NULL, \
note character varying(10000) NOT NULL, note_date_time timestamp without time zone \
NOT NULL);
ALTER TABLE public.note OWNER TO cd_user;
...

В листинге 6 показана часть сценария, написанного на языке Liquibase на основе XML. Это предметно-ориентированный язык с открытым исходным кодом (DSL) для управления изменениями базы данных.

Листинг 6. LiquiBase-сценарий для изменения столбца в существующей базе данных
<changeSet id="9" author="jayne">
  <addColumn tableName="distributor">
    <column name="phonenumber" type="varchar(255)"/>
  </addColumn> 
</changeSet>
...

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

Сборка и развертывание

При сборке все исходные файлы компилируются и упаковываются в дистрибутив. В случае кода приложения этот дистрибутив часто представляет собой двоичные данные, такие как WAR-файлы. Сборка может выполняться и для сценариев инфраструктуры для создания рабочей среды. Эта среда ― виртуальный экземпляр или образ, определяющий экземпляр. Сборка может производить и базу данных из сценария базы данных. Для сборки используется конфигурация, определенная в файлах конфигурации или базах данных. В листинге 7 приведена часть Maven-сценария сборки, который определяет каталоги и конфигурацию сборки.

Листинг 7. Фрагмент листинга сценария сборки на языке Maven
...
<build>
  <finalName>embeddedTomcatSample</finalName>
  <plugins>
      <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>appassembler-maven-plugin</artifactId>
          <version>1.1.1</version>
          <configuration>
              <assembleDirectory>target</assembleDirectory>
              <programs>
                  <program>
                      <mainClass>launch.Main</mainClass>
                      <name>webapp</name>
                  </program>
              </programs>
          </configuration>
          <executions>
              <execution>
                  <phase>package</phase>
                  <goals>
                      <goal>assemble</goal>
                  </goals>
              </execution>
          </executions>
      </plugin>
  </plugins>
</build>
...

Несколько поставщиков предлагает так называемые «инструменты автоматизации развертывания». Это не совсем точно: эти инструменты, скорее, организуют развертывание, а не автоматизируют его. Они помогают описать шаги и порядок развертывания, но фактически оно выполняется посредством серии сценариев и/или ручных процессов. Трудно найти инструменты, поддерживающие управление версиями артефактов и процесса развертывания. Несколько таких инструментов обеспечивают внутреннее управление версиями, но для единой версии системы программного обеспечения от этого мало прока, если только не использовать этот инструмент всегда ― и все равно он разделяет управление версиями кода развертывания и других исходных артефактов. Этого не следует делать — даже при использовании одного из таких инструментов. Альтернативный подход — описать весь процесс развертывания на DSL-языке автоматизации развертывания, например, Capistrano. В этом случае процесс развертывания можно версировать. Весь процесс развертывания должен запускаться одной командой. Автоматизированное развертывание должно сочетаться с автоматизированными тестами. Инструмент организации выполняет сценарий развертывания.

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

Листинг 8. Фрагмент сценария развертывания на Capistrano
namespace :deploy do
  task :setup do
    run "sudo chown -R tomcat:tomcat #{deploy_to}"
    run "sudo service httpd stop"
    run "sudo service tomcat6 stop"
  end

...

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

Системы

Прогрессивные группы все больше склоняются к тому, что инфраструктуру, конфигурацию, данные и код приложений желательно версировать. Еще один компонент, который также можно версировать, — это внутренние системы, например, конфигурация, определяющая среду CI. Вопрос ставится так: "Что произойдет с системой ПО, если рабочая среда, используемая для создания компонентов системы поставки программного обеспечения, перестанет функционировать?" Когда среда системы программного обеспечения полностью описана сценариями, можно создать сценарий и для среды создания системы поставки ПО вместе с инструментами автоматизации инфраструктуры. Этот код инфраструктуры и изменения конфигурации CI ― такой как конфигурация задач CI ― версируется. В листинге 9 приведен пример версирования сервера Дженкинс и конфигурации задач.

Листинг 9. Простой bash-сценарий версирования изменений конфигурации сервера Дженкинс
#!/bin/bash -v

# Изменения в каталоге jenkins.
cd /usr/share/tomcat6/.jenkins

# Добавить все новые файлы конфигурации, задачи, учетные записи пользователей и контент.
git add *.xml jobs/*/config.xml plugins/*.hpi .gitignore

# Игнорировать то, что нас не интересует
cat > .gitignore <<EOF
log
*.log
*.tmp
*.old
*.bak
*.jar
.*
updates/
jobs/*/builds
jobs/*/last*
jobs/*/next*
jobs/*/*.csv
jobs/*/*.txt
jobs/*/*.log
jobs/*/workspace
EOF

# Удалить из git все, чего больше нет в jenkins.
git status --porcelain | grep '^ D ' | awk '{print $2;}' | xargs -r git rm

# И, наконец, зафиксировать и выполнить
git commit -m 'Automated commit of jenkins configuration' -a
git push

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

Версируйте это

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

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


Ресурсы для скачивания


Похожие темы


Комментарии

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, Open source
ArticleID=860307
ArticleTitle=Agile DevOps ― гибкая разработка и эксплуатация ПО: Все под контролем версий
publish-date=03042013