版本一切。 是的, 所有内容 :基础架构,配置,应用程序代码和您的数据库。 如果这样做,您将拥有一个单一的真理来源,使您能够将软件系统以及创建软件所需的一切视为一个整体 。 凡是对所有版本都进行了版本化的团队,并不会一直试图找出哪个版本的应用程序代码与哪个数据库一起使用以及哪个版本的软件应用程序与哪种环境一起使用。 组成软件系统的源文件不在共享服务器上,不在笔记本电脑的文件夹中隐藏或嵌入在非版本数据库中。
如果您对所有版本进行版本控制,则任何授权的团队成员都应该能够在任何时间点重新创建软件系统的任何版本-应用程序代码,配置,基础结构和数据。 您应该能够仅使用提交给版本控制存储库(例如Subversion,Git,CVS或Rational ClearCase)的非二进制工件(不修改的库除外)来创建整个软件系统。一些示例)。
以我的经验,对所有内容进行版本控制的想法很容易理解,但是我很少看到它完全适用。 当然,您将看到应用程序代码的版本控制,一些配置以及数据。 一些团队使用依赖项存储库和工具(例如Nexus)来管理他们在开发软件时使用的库。 其他团队使用共享驱动器和版本控制系统的组合。 但是,很少看到公司对所有配置,所有它们的从属组件(例如,来自软件包存储库,例如yum
, apt-get
和rpm
)进行版本控制,以及创建数据库和数据库所需的所有脚本的版本。组成数据库的数据。
要确定是否你的版本应有尽有,简单的问题要问的是,“我可以重新创建完整的软件系统的特定版本 -基础设施,数据,软件和配置-通过运行一个命令 ,从获取特定版本我版本控制系统?” 如果不能,那么您就不会对所有内容进行版本控制。
对所有内容进行版本控制的关键前提是所有源工件必须采用脚本形式 。 这适用于基础架构,数据,配置和应用程序代码。 唯一的例外是您使用但从未修改过的库和软件包(例如JAR文件和RPM软件包)。 在对所有源工件进行脚本化之后,您可以轻松地对其进行版本控制。
在本文中,您将学习如何在代码中描述每种类型的软件工件以及使用它们的有效方法。 本文中的一些代码清单是如何将每个组件定义为执行和版本控制脚本的示例。 它们并不是要显示如何编写和运行每种类型的脚本。 此Agile DevOps系列和People for Automation系列中的其他文章为本文中描述的组件提供了更详细的示例。
申请代码
应用程序代码可能是必须进行版本控制的软件系统中最明显的部分。 清单1中的代码是一个简单的Java类(称为UserServiceImpl
),该类从对象中调用方法以获取一些数据:
清单1. Java应用程序代码
...
public Collection findAllStates() {
UserDao userData = new UserDaoImpl();
Collection states = userData.findAllStates(UserDao.ALL_STATES);
return states;
}
...
图1说明了将新的应用程序代码源文件( 清单1中的UserServiceImpl.java)提交给托管在GitHub上的Git版本控制存储库:
图1.用于将新的源代码文件提交和推送到Git存储库的命令

创建软件应用程序所需的所有应用程序代码都应提交给版本控制存储库。 您将对任何其他源文件使用相同的过程-基础结构代码,数据或配置。
基础设施
因为您可以像处理应用程序源文件一样将基础结构定义为代码(请参阅“ 敏捷DevOps:基础结构自动化 ”),所以可以在版本控制系统中对基础结构进行版本控制。 这些脚本可能具有清单 , 模块和食谱之类的名称 ,但是它们都是基于文本的脚本,可以执行以创建环境。
如果最佳实践是用代码定义基础架构,人们通常会做什么? 它是“艺术品”的混合包,其中每次都手动配置环境,或者是手动步骤和运行自动化脚本的混合。 这些方法中的每一种都会导致瓶颈,因为每次都需要工程师来执行这些步骤。 为了解决这个问题,有些人会在一组书面说明中认真描述每个步骤。 问题在于指令可能不正确或缺少某些步骤,或者操作人员可能无法正确执行这些步骤。 唯一的解决方案是用可以通过单个命令执行的代码全面描述您的基础架构。
例如,清单2中的Puppet清单描述了用代码安装PostgreSQL数据库服务器的步骤。 可以从命令行或通过持续集成(CI)服务器执行此代码。
清单2.描述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地址,域名。 和机器映像-可以动态获取,没有任何配置是硬编码的。 您可能无法使所有配置动态化,但是在使用云时,可以大大减少通常大多数软件交付系统都无法使用的硬编码配置的数量。
数据
关系数据库的结构可以在数据定义语言(DDL)脚本中定义。 这包括数据库,表,过程等的创建-除数据外的所有内容。 您可以使用数据操作语言(DML)脚本定义数据,包括插入,更新和删除语句。
清单5中所示的部分DDL脚本执行创建数据库的步骤:
清单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脚本的一部分。 Liquibase是一种用于数据库更改管理的开源域特定语言(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>
...
一些供应商提供了所谓的“部署自动化工具”。 有点用词不当:这些工具可能会编排部署,而不是自动化。 它们可以帮助您描述部署的步骤和顺序,但是实际的部署是通过一系列脚本和/或手动过程完成的。 您很少找到支持部署工件和工作流版本控制的工具。 尽管这些工具中的几种提供了内部版本控制,但是当您寻找软件系统的单个修订版时,这几乎没有用,除非您始终使用该工具-并且它仍将部署和其他源工件的版本控制隔离开来。 即使您使用的是这些供应商工具之一,也不必采用这种方式。 另一种方法是在诸如Capistrano之类的部署自动化DSL中描述您的整个部署。 这样,您可以对部署进行版本控制。 您应该能够使用一个命令来运行整个部署。 自动化部署应与自动化测试相结合。 编排工具执行部署脚本。
Capistrano是用于描述多个平台中的部署的DSL。 使用Capistrano,您可以定义任务,例如停止服务器,复制文件以及为跨多个节点和环境角色的部署应用工作流。 清单8显示了Capistrano脚本的一部分:
清单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显示了对Jenkins服务器和作业配置进行版本控制的示例:
清单9.用于对Jenkins服务器配置更改进行版本控制的简单bash
脚本
#!/bin/bash -v
# Change into your jenkins home.
cd /usr/share/tomcat6/.jenkins
# Add any new conf files, jobs, users, and content.
git add *.xml jobs/*/config.xml plugins/*.hpi .gitignore
# Ignore things we don't care about
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
# Remove anything from git that no longer exists in jenkins.
git status --porcelain | grep '^ D ' | awk '{print $2;}' | xargs -r git rm
# And finally, commit and push
git commit -m 'Automated commit of jenkins configuration' -a
git push
就像在软件系统的任何其他部分一样,您可以在版本控制存储库中对此脚本进行版本控制。
版本本
在本文中,您了解到,当开发人员和运营团队合作创建能够在任何时间点发布软件的持续交付平台时,所有内容都可以被版本化。 您已经看到,在对所有基础结构,数据和应用程序资源进行版本控制后,您还可以对构成系统的组件进行版本控制,这些系统将为软件系统执行软件交付。 在为用户开发的软件系统的每个资源以及将这些软件系统提供给用户时使用的内部系统的脚本都编写好之后 ,就可以对所有内容进行版本控制。
在下一篇文章中,您将学习动态配置管理:一种消除对配置使用静态特定于环境的属性的方法。
翻译自: https://www.ibm.com/developerworks/opensource/library/a-devops6/index.html