Agile DevOps ― гибкая разработка и эксплуатация ПО: Все под контролем версий

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

Какие артефакты системы программного обеспечения должны находиться под контролем версий? В этой статье из цикла Agile DevOps эксперт по DevOps Пол Дюваль рекомендует группам DevOps версировать код приложений, инфраструктуру, конфигурацию, данные и даже внутренние артефакты систем, чтобы обрести способность быстро и часто поставлять программного обеспечение пользователям.

Пол Дюваль, технический директор, 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 г.).



04.03.2013

Об этом цикле статей

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

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

Если все находится под контролем версий, любой уполномоченный член группы в любой момент времени в состоянии воссоздать любую версию системы ПО — будь то код приложения, конфигурация, инфраструктура или данные. Всю систему (за исключением библиотек, которые остаются неизменными) можно воссоздать с помощью одних только недвоичных артефактов, хранящихся в репозитории с управлением версиями (таком как 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.

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


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

Так как инфраструктуру можно определить в виде кода, как и исходные файлы приложений (см. 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

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


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

Будьте в курсе

Раздел Agile transformation портала developerWorks содержит новости, обсуждения и учебные материалы, которые помогут вам и вашей организации строить фундамент на принципах гибкой разработки (EN).

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

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

Ресурсы

Научиться

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

  • IBM Tivoli Provisioning Manager: Tivoli Provisioning Manager позволяет создавать динамическую инфраструктуру, автоматизируя управление физическими серверами, виртуальными серверами, программным обеспечением, системами хранения данных и сетью.
  • IBM Tivoli System Automation for Multiplatforms: Tivoli System Automation for Multiplatforms обеспечивает высокую готовность и автоматизацию приложений и ИТ-услуг по всей организации.
  • Оцените продукты IBM наиболее подходящим для себя способом: загрузите ознакомительную версию, попробуйте поработать в Интернете, используйте продукт в облачной среде или проведите несколько часов в среде SOA Sandbox, чтобы научиться эффективно создавать сервис-ориентированную архитектуру.

Комментарии

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, Open source
ArticleID=860307
ArticleTitle=Agile DevOps ― гибкая разработка и эксплуатация ПО: Все под контролем версий
publish-date=03042013