Управление конфигурацией нескольких сред часто становится бичом систем поставки программного обеспечения. Большинство организаций управляет параметрами с помощью статических файлов параметров (local.properties, dev.properties, test.properties, stage.properties, prod.properties и т.п.) для различных сред. Я сам разработал множество таких систем поставки программного обеспечения и проповедовал этот подход в статье Практическая автоматизация: быстрое автоматизированное развертывание. Это один из самых простых подходов, которые я видел, — но когда нужно управлять системой поставки программного обеспечения с сотнями или даже тысячами отдельных параметров для множества приложений и сотен экземпляров, этот процесс не обеспечивает масштабирования и в конечном итоге становится неуправляемым. Большинство отказов происходит из-за ввода неправильного значения в любой из сотен различных файлов параметров такой системы программного обеспечения.
Однако положение не безнадежно. Эффективно используя автоматизацию, динамическую настройку и облачную инфраструктуру, можно значительно сократить потребность системы поставки программного обеспечения в статических параметрах при перемещении ПО между рабочими средами. Эта статья посвящена тому, как это сделать.
В таблице 1 перечислены некоторые типичные параметры, которыми управляют ИТ-группы в пределах организации.
Таблица 1. Типичные параметры системы поставки программного обеспечения
| Параметр | Описание |
|---|---|
| IP-адрес | Уникальное адресуемое местоположение узла |
| Конечная точка | Имя домена любого узла — балансировщика нагрузки, экземпляра и т.п. |
| Имя домена | Уникальное адресуемое имя, которое используют для доступа к приложению; интерфейсы с регистратором доменов и службой доменных имен |
| Имя базы данных | Имя базы данных, используемое приложением |
| Порт | Уникальные числа от 0 до 65535, используемые для внутреннего и внешнего доступа к узлам |
| Имена пользователей и пароли | Имена пользователей и пароли, используемые для прямого доступа к ресурсам |
| Каталоги и файлы | Каталоги и файлы операционной системы |
| Ключи SSH | Файлы ключей Secure Shell для доступа к защищенным ресурсам |
Это не исчерпывающий список, но он отражает наиболее часто используемые виды параметров настройки типичной системы ПО.
Традиционный подход к управлению параметрами
В большинстве организаций с отдельными группами разработки и эксплуатации ПО группа разработки (программисты, тестеры, аналитики и т.п.) часто:
- создает файлы (например, local.properties) для управления параметрами, связанными с рабочей станцией;
- изменяет параметры среды разработки в файле dev.properties и помещает его в хранилище с контролем версий. Так как динамические параметры (такие как IP-адреса) могут меняться, группе приходится постоянно модифицировать этот файл, когда происходят такие изменения;
- модифицирует файл test.properties с одними и теми же атрибутами параметров, но другими значениями для тестеров, потому что те, скорее всего, используют другие IP-адреса, файлы и каталоги.
Процесс управления конфигурацией для группы разработки обычно на этом не заканчивается, потому что, помимо среды разработки и тестирования, эта группа обычно управляет и другими ИТ-средами.
В традиционной организации группа разработки передает пакет программного обеспечения группе эксплуатации (администраторы баз данных, операторы, инженеры по выпуску и т.п.) для дальнейшего развертывания в рамках цикла поставки программного обеспечения. Эта группа:
- изменяет параметры для промежуточной среды в файле stage.properties и помещает его в репозиторий с контролем версий;
- изменяет аналогичные свойства производственной среды в файле prod.properties и передает его в репозиторий с контролем версий. Так как динамические параметры (такие как IP-адреса) могут меняться, группе приходится постоянно модифицировать эти файлы конфигурации, когда происходят такие изменения.
Я видел группы, которые практикуют иерархию параметров: локальные параметры, параметры среды (как правило, по крайней мере четыре файла параметров среды, но часто гораздо больше), параметры приложений, параметры подсистемы и параметры экземпляра (экземпляров). Для сотен экземпляров нужны сотни различных файлов параметров, что делает практически невозможным управление постоянно меняющимися IP-адресами, каталогами и другими параметрами. Это ведет к частым нарушениям работы среды и процесса развертывания, которые бывает чрезвычайно трудно устранить, потому что сложность управления изменениями — кто именно что и когда изменил? — затрудняет установление причины ошибки.
В хорошо продуманной системы программного обеспечения, в которой используется традиционный подход, все параметры, которые могут отличаться для разных сред, экстернализируются ― переносятся во внешние файлы параметров. Другими словами, никакие параметры, которые могут меняться, не должны быть жестко закодированы в коде приложения. Но чем больше параметров, тем больше вероятность ошибок развертывания. Эти ошибки дорого обходятся ― их трудно устранить, и они часто вызывают задержки в «конвейере сборки» при поставке программного обеспечения пользователям.
Простой пример файла параметров приведен в листинге 1.
Листинг 1. Конфигурация, определенная в файле параметров
jboss.home=/usr/local/jboss jboss.server.hostname=jenkins.example.com jboss.server.port=8080 jboss.server.name=default |
В нетривиальных системах подобный файл обычно содержит сотни параметров. И эти параметры обычно дублируются между средами разработки, тестирования, промежуточного хранения и производства — что ведет к необходимости управлять сотнями или тысячами параметров при передаче программного обеспечения в производство.
В листинге 2 показан фрагмент Java™-кода, который извлекает значения из файла параметров.
Листинг 2. Пример Java-кода для получения параметров
public PropertyReader(final String name, final ClassLoader loader) {
try {
InputStream is = loader.getResourceAsStream(convertName(name));
if (is != null) {
properties.load(is);
is.close();
} else {
throw new IOException("Couldn't find property file: "
+ convertName(name));
}
} catch (IOException problem) {
System.out.println("Property Reader: problem initializing");
}
}
|
Это наиболее распространенный подход, который группы обычно используют при управлении параметрами. Но современные системы поставки программного обеспечения способны работать с беспрецедентными масштабами. Благодаря товаризации оборудования, виртуализации и облачным вычислениям, при поставке систем программного обеспечения и управления ими можно запускать (и ликвидировать) сотни рабочих сред. Подход к управлению конфигурацией должен допускать соответствующее масштабирование. И он его допускает (опять же благодаря товаризации оборудования, виртуализации и облачным вычислениям).
Как работает динамическая настройка
Подход, который я проповедую в этой статье — это динамический процесс задания и извлечения параметров. При определении среды с использованием инструментов автоматизации инфраструктуры (см. Agile DevOps ― гибкая разработка и эксплуатация ПО: автоматизация инфраструктуры) элементы конфигурации — такие как имя базы данных и имена файлов и каталогов — можно задать в базе данных конфигурации. Это можно сделать в сценариях, так как вся инфраструктура с самого начала построена на сценариях, помещенных в репозиторий с контролем версий. Более того, в облачной или виртуальной инфраструктуре можно динамически устанавливать и извлекать элементы конфигурации, такие как IP-адреса и имена доменов, которые в традиционных инфраструктурах часто определены статически.
Код, приведенный в листинге 3, представляет собой Ruby-сценарий, который загружает элементы конфигурации в базу данных SimpleDB (NoSQL).
Листинг 3. Запись элементов динамической конфигурации в базу данных 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
|
Capistrano ― это основанный на Ruby предметно-ориентированный язык (DSL) для развертывания систем на базе сценариев. Код, приведенный в листинге 4, взят из Capistrano-сценария, который определяет имя пользователя и пароль базы данных по параметру, однажды заданному пользователем.
Листинг 4. Настройка имени пользователя и пароля на языке Capistrano
set :dataSourceUsername do item = sdb.domains["stacks"].items["wildtracks-config"] item.attributes['dataSourceUsername'].values[0].to_s.chomp end set :dataSourcePassword do item = sdb.domains["stacks"].items["wildtracks-config"] item.attributes['dataSourcePassword'].values[0].to_s.chomp end |
Обладая полным контролем над инфраструктурой посредством сценариев, имя пользователя и пароль базы данных можно генерировать автоматически и хранить в защищенной базе данных конфигурации.
Эта же конфигурация используется и в остальной части системы поставки программного обеспечения. Данные, занесенные в эту базу данных, динамически извлекаются в вышестоящие среды и используются в нижестоящих.
Код, приведенный в листинге 5, — это часть сценария JSON CloudFormation AWS, который динамически задает и привязывает внешний IP-адрес.
Листинг 5. Динамическая настройка IP-адреса в CloudFormation
"IPAddress" : {
"Type" : "AWS::EC2::EIP"
},
"IPAssociation" : {
"Type" : "AWS::EC2::EIPAssociation",
"Properties" : {
"InstanceId" : { "Ref" : "WebServer" },
"EIP" : { "Ref" : "IPAddress" }
}
},
|
Такой сценарий помещается в репозиторий с контролем версий наряду с соответствующими автоматизированными тестами.
Код JSON CloudFormation, приведенный в листинге 6, использует службу AWS Route 53 для динамического создания записи домена "А" приложения.
Листинг 6. Настройка домена в CloudFormation
"JenkinsDNS" : {
"Type" : "AWS::Route53::RecordSetGroup",
"Properties" : {
"HostedZoneName" : { "Fn::Join" : [ "", [ {"Ref" : "HostedZone"}, "." ]]},
"RecordSets" : [
{
"Name" : { "Fn::Join" : ["", [ { "Ref" : "ApplicationName" }, ".", \
{ "Ref" : "HostedZone" }, "." ]]},
"Type" : "A",
"TTL" : "900",
"ResourceRecords" : [ { "Ref" : "IPAddress" } ]
}]
}
},
|
Такой сценарий исключает необходимость ручной настройки этого элемента поставщиком службы доменных имен (DNS), как это делается обычно.
Код, приведенный в листинге 7, взят из сценария CloudFormation, определяющего параметр DatabaseName.
Листинг 7. Задание имени базы данных в CloudFormation
"Parameters": {
"DatabaseName": {
"Description" : "The name of the database",
"Type": "String"
}
}
|
Параметр DatabaseName передается в сценарий инфраструктуры (например, манифест Puppet), когда сценарий создает новую базу данных для приложения. Весь сценарий передается в репозиторий с контролем версий, и пишутся автоматизированные тесты, которые проверяют, что база данных доступна.
Код, приведенный в листинге 8, устанавливает внешние порты для среды (и приложения).
Листинг 8. Настройка доступа к порту в пределах группы безопасности в CloudFormation
"FrontendGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Enable SSH and access to Apache and Tomcat",
"SecurityGroupIngress" : [
{"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "0.0.0.0/0"},
{"IpProtocol" : "tcp", "FromPort" : "8080", "ToPort" : "8080",\
"CidrIp" : "0.0.0.0/0"},
{"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", \
"CidrIp" : "0.0.0.0/0"}
]
}
},
|
В этом примере портами с внешним доступом являются только порты 22 (для SSH-доступа), 8080 (для Apache Tomcat) и 80 (для Apache HTTP Server). Доступ можно ограничить еще больше — посредством нотации Classless Inter-Domain Routing (CIDR) — сетью или даже отдельными узлами (см. раздел Ресурсы).
В этой статье говорится о том, что конфигурация, которая в большинстве систем поставки программного обеспечения обычно бывает определена статически, может и должна определяться динамически, чтобы ее не нужно было изменять для каждой целевой среды. Это значительно уменьшит количество параметров конфигурации, необходимых для создания среды.
Следующая статья будет посвящена платформе с открытым исходным кодом для непрерывной поставки программного обеспечения в облаке. Читатель узнает об основных шагах по запуску этой платформы, способах использования конвейера поставки и способах выполнения заданий по инициализации среды и развертыванию систем.
Научиться
- Оригинал статьи: Agile DevOps: Dynamic configuration.
-
Continuous Delivery in the Cloud: Dynamic Configuration: (Brian Jakovich, Stelligent, октябрь 2012 г.): о динамической настройке параметров конфигурации конвейера поставки в облачной инфраструктуре.
-
Automation for the people: Speed deployment with automation (Paul Duvall, developerWorks, январь 2008 г.): об экстернализации параметров конфигурации систем.
-
AWS CloudFormation: о службе AWS для управления, инициализации и обновления ресурсов.
-
CIDR Notation: статья в Википедии о нотации CIDR.
Получить продукты и технологии
-
IBM Tivoli® Provisioning Manager: Tivoli Provisioning Manager позволяет создавать динамическую инфраструктуру, автоматизируя управление физическими серверами, виртуальными серверами, программным обеспечением, системами хранения данных и сетью.
-
IBM Tivoli System Automation for Multiplatforms: Tivoli System Automation for Multiplatforms обеспечивает высокую готовность и автоматизацию приложений и ИТ-услуг по всей организации.

Пол Дюваль (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 г.).