17、DevOps 开发者的基础设施与测试实践

DevOps实践:Puppet与Jenkins的基础设施管理

DevOps 开发者的基础设施与测试实践

1. Puppet 迁移难题

将现有的手工搭建的基础设施迁移到由 Puppet 管理是一个漫长而乏味的过程,就像在飞行中重建喷气发动机,同时还要保持稳定的高度,难度极大。

2. Jenkins 中的 Puppet 实践

从一开始,Jenkins 的 Puppet 工作就与 Vagrant 紧密结合。Vagrant 能与 Puppet 完美集成,用户可以轻松启动基于 Linux 的虚拟机,并使用 Puppet 进行配置。下面详细介绍不同方面:
- Puppet 的运行方式 :Puppet 有两种运行方式,即客户端 - 服务器架构和“独立模式”,前者更为常见。客户端 - 服务器模式有诸多优点,如能立即推送更改、从所有节点收集信息,但 Jenkins 采用的是独立模式。Jenkins 希望消除额外的服务依赖,在多地点部署时,客户端 - 服务器模式要么会在一个地点引入单点故障,要么需要在每个地点部署 Puppet 主节点。而且,由于 Vagrant 通过独立模式与 Puppet 集成,Jenkins 可以在本地以与生产环境更一致的方式测试其清单。
- 权衡取舍 :放弃客户端 - 服务器模式意味着 Jenkins 必须自行复制一些功能。例如,由于 Jenkins 无法向机器推送更新,它有一个用于从 Git 自动更新每台机器的模块,代码如下:

class autoupdate {
    include autoupdate::setup
    Class["autoupdate::setup"] -> Class["autoupdate"]

    cron {
        "pull puppet updates" :
            command     => "(cd /root/infra-puppet && sh run.sh)",
            user        => root,
            minute      => 15,
            ensure      => present;

        # Might as well clean these up at some point
        "clean up old puppet logs" :
            command     => "rm -f /root/infra-puppet/puppet.*.log",
            user        => root,
            hour        => 4,
            minute      => 30,
            weekday     => '*',
            ensure      => present;
    } 
}

class autoupdate::setup {
    exec {
        "setup_git_repo" :
            cwd     => "/root",
            creates => "/root/infra-puppet",
            command => "git clone git://github.com/jenkinsci/infra-puppet.git",
            require => Package["git-core"],
            # In the case of a new machine, we probably already have this
            unless  => "test -d /root/infra-puppet/.git",
            path    => ["/usr/bin", "/usr/local/bin"],
    }
}

同时,Jenkins 无法利用 Puppet 模块依赖管理的一些最新进展,因此采用 Git 子模块来管理对其他可重用模块的依赖,例如:
- puppetlabs - stdlib:许多 Puppet Labs 模块的常见依赖。
- puppetlabs - firewall:用于管理 iptables 规则。
- puppetlabs - ntp:用于自动设置 NTP、cron 等。
- puppet - sshd:用于管理 sshd_configs 并保持守护进程运行。
- puppet - concat:用于管理或连接不支持 conf.d/ 样式目录的服务配置。
- puppet - postgres:用于设置 PostgreSQL 权限、数据库等。

使用 puppet - module - tool ,Puppet 可以在 Puppet Forge(http://forge.puppetlabs.com)上创建、安装和搜索模块。大多数 Puppet 模块发布到 Puppet Forge,但它们的源代码通常托管在 GitHub 上,便于作为子模块添加,例如:

> cd project - root
> git submodule add git://github.com/puppetlabs/puppetlabs-firewall.git modules/firewall
> git commit -m "Add the firewall module to manage iptables"

添加到项目树后,在特定机器上使用它很简单,如下所示:

firewall {
   '000 accept all icmp requests' :
       proto  => 'icmp',
       action => 'accept';

   '001 accept inbound ssh requests' :
       proto  => 'tcp',
       port   => 22,
       action => 'accept';

   # etc, etc
}

子模块方法有利有弊。一方面,添加子模块有一定的版本锁定功能;但另一方面,如果子模块更新过于频繁或不断迭代,会在主项目中产生大量提交来更新子模块引用。不过,无论采用哪种方式,重用 Puppet Forge 中的现有模块都是一个不错的选择,可以快速启动项目。
- 真相来源 :与客户端 - 服务器模型相比,这种独立设置的另一个主要区别是 Puppet 管理的机器的“真相来源”。在传统的客户端 - 服务器架构中,Puppet 主节点是主导;而在 Jenkins 设置中,GitHub 是唯一的真相来源。这意味着仓库中“master”分支的状态就是机器的状态(误差在 15 分钟左右)。此外,这种方法的另一个好处是 Jenkins 可以通过 GitHub 拉取请求轻松接受对基础设施的贡献,无需核心团队授予硬件访问权限。

3. 使用 Vagrant 进行测试

Jenkins 从 Puppet 设置中获得的灵活性很大程度上得益于 Puppet 和 Vagrant 的结合。以搭建 BIND9 名称服务器为例,Jenkins 的操作流程如下:
1. 创建分支并设置文件夹:

> git checkout -b build - a - nameserver - quick
> mkdir -p modules/bind/manifests modules/bind/files
> vim modules/bind/manifests/init.pp
  1. 定义基本资源:大约 10 分钟后,定义了构成简单 BIND9 名称服务器的基本资源,代码如下:
# Skip the class declaration for now
package {
    'bind' :
        ensure => present, # Ensure the package is installed on Ubuntu
        name   => 'bind9';
}
service {
    "bind" :
        ensure  => running, # Ensure we have it up and running on boot
        require => Package['bind'],
        name    => 'bind9';
}
# Open up our firewall (provided by puppetlabs-firewall) to allow
# both TCP and UDP-based DNS traffic
firewall {
   "900 accept tcp DNS queries" :
       proto  => "tcp",
       port   => 53,
       action => "accept";
   "901 accept udp DNS queries" :
       proto  => "udp",
       port   => 53,
       action => "accept";
}
  1. 测试与迭代:使用 Vagrant 时,可能会进入一个不断测试迭代的循环:
> vagrant up # also provisions when the VM is online
> vagrant ssh # Log into our VM
# Check to make sure that everything looks right, oh wait, no it doesn't,
# why are you doing that BIND? Why! Argh! You're so stupid! Don't act like
# that or I'll shut you down, that's it!
> vagrant destroy # I'll show BIND who's boss!
> vim init.pp # Okay, where'd we go wrong.
  1. 完成与提交:大约在 35 分钟时,Jenkins 使名称服务器正常运行,并进行最终检查,然后提交代码到 GitHub:
> git commit modules/bind -m "Long and descriptive commit message should go here"
> git push origin

15 分钟内,相应的机器上线,成为一个经过充分测试、代码审查、可重现且功能齐全的名称服务器。

4. 总结与展望

Jenkins 的目标不是构建一个教科书式的基础设施,而是构建一个能正常工作并持续运行的基础设施,以便专注于构建出色的 CI 服务器。借助 Puppet 和 Vagrant,很多事情无需过多干预就能正常运行,使 Jenkins 能够以较小的投入拥有庞大的基础设施。

未来,Puppet 可以与 Augeas(http://augeas.net)结合使用,无需使用模板即可更改现有文件。如果开始在多个主机上使用 Puppet,可以考虑 Puppet Dashboard 来监控所有 Puppet 管理节点的状态,也可以关注 PuppetDB 来管理、存储和检索平台生成的数据。此外,Puppet Forge 上有许多社区创建的现有 Puppet 模块可供使用。还有一些相关书籍,如《Pro Puppet》和《Puppet 2.7 Cookbook》,可以提供更多关于 Puppet 的知识。

除了 Puppet 和 Vagrant,还有其他配置管理框架,如 CFEngine 和 Chef。CFEngine 是最古老的开源工具,而 Puppet 和 Chef 近年来也获得了强大的社区支持。可以花时间研究这些工具,选择适合自己的。

下面是一个简单的 mermaid 流程图,展示了 Jenkins 搭建 BIND9 名称服务器的主要流程:

graph LR
    A[创建分支并设置文件夹] --> B[定义基本资源]
    B --> C[使用 Vagrant 测试与迭代]
    C --> D[完成并提交代码到 GitHub]
    D --> E[机器上线成为名称服务器]
5. 自动化测试与 DevOps

在 DevOps 中,自动化测试起着至关重要的作用。任何成功通过自动化检查的构建都有可能投入生产,这些检查可以验证新代码或更新代码是否破坏了现有功能,防止回归失败。然而,自动化测试不仅仅是在构建服务器上运行一组单元测试。如果要将产品自动投入生产,团队成员必须确信测试的质量,即测试是否真正反映了客户对产品的需求,以及测试是否能帮助开发人员开发解决方案。

6. 验收测试的重要性
  • 透明性 :验收测试具有透明性,产品所有者可以准确知道特定版本中交付了哪些功能,业务分析师可以看到故事的具体实现方式,运维团队可以了解将投入生产的功能。
  • 沟通媒介 :自动化验收测试注重沟通,它不仅是执行测试,还包括发布和传达测试结果。验收测试驱动开发(ATDD)是一种高级的测试驱动开发形式,通过与用户协作定义自动化验收标准来驱动和聚焦开发过程,确保每个人都清楚正在开发的功能。
7. Thucydides 工具

Thucydides 是一个开源库,旨在使编写和报告自动化验收和回归测试更加容易。它可以帮助组织和构建验收标准,将其与测试的用户故事或功能相关联,并在测试执行时生成详细的报告,包括总体测试结果的高级视图和应用程序实现功能的详细步骤文档。

8. 定义验收标准

ATDD 和自动化验收测试的关键概念之一是通过示例进行规范。以在线分类广告网站为例,需求通常以简单的用户故事表达:
- 作为买家,为了找到最佳交易,我希望查看特定类别中的所有可用广告。
- 作为买家,为了更快找到感兴趣的物品,我希望能够列出描述或标题中包含特定关键字的所有广告。
- 作为买家,为了找到能负担得起的物品,我希望能够按价格范围过滤特定类别中的广告。
- 作为买家,为了降低邮费,我希望能够只列出特定地区的广告。

通过这些具体的示例,可以更好地定义系统应该如何工作,而不是使用过于笼统的正式规范。

下面再给出一个表格,总结 Puppet 相关的一些工具和资源:
| 工具/资源 | 描述 | 链接 |
| — | — | — |
| Puppet Forge | 查找和共享 Puppet 模块的地方 | http://forge.puppetlabs.com |
| puppet - module - tool | 用于在 Puppet Forge 上创建、安装和搜索模块 | https://github.com/puppetlabs/puppet - module - tool |
| Puppet Dashboard | 用于监控 Puppet 管理节点状态的 Web 应用程序 | - |
| PuppetDB | Puppet 数据仓库,用于管理、存储和检索平台生成的数据 | docs.puppetlabs.com/puppetdb |
| Augeas | 可与 Puppet 结合使用,无需模板即可更改现有文件 | http://augeas.net |

DevOps 开发者的基础设施与测试实践

9. 验收测试的实施挑战与应对

在将手动测试活动委托给自动化测试套件时,测试人员可能会担心失去对测试过程的控制。理解验收测试作为一种有效的测试方式通常是一个困难的过程。开发者(包括测试人员)需要作为一个团队协作,将客户的需求转化为可执行的测试用例,通过后再将其转变为回归测试。

为了应对这些挑战,团队可以采取以下措施:
- 加强沟通与培训 :组织定期的会议,让团队成员分享对验收测试的理解和经验。同时,提供相关的培训课程,帮助成员掌握 Thucydides 等工具的使用方法。
- 逐步推进自动化 :不要一次性将所有手动测试都转换为自动化测试,可以先选择一些简单、稳定的功能进行试点,逐步扩大自动化测试的范围。
- 建立反馈机制 :鼓励团队成员及时反馈测试过程中遇到的问题,以便快速调整测试策略和用例。

10. Thucydides 测试示例

假设我们要为上述在线分类广告网站编写一个使用 Thucydides 的验收测试。以下是一个简单的示例代码:

import net.thucydides.core.annotations.Managed;
import net.thucydides.core.annotations.Steps;
import org.junit.Test;
import org.openqa.selenium.WebDriver;

public class ClassifiedAdsTest {

    @Managed
    WebDriver driver;

    @Steps
    ClassifiedAdsSteps steps;

    @Test
    public void should_display_all_ads_in_a_category() {
        steps.open_classified_ads_site();
        steps.select_category("Electronics");
        steps.verify_all_ads_are_displayed();
    }
}

在这个示例中:
- @Managed 注解用于管理 WebDriver 实例。
- @Steps 注解用于注入测试步骤类 ClassifiedAdsSteps
- should_display_all_ads_in_a_category 方法定义了一个测试用例,用于验证在选择特定类别后是否显示该类别下的所有广告。

以下是 ClassifiedAdsSteps 类的简单实现:

import net.thucydides.core.annotations.Step;

public class ClassifiedAdsSteps {

    @Step
    public void open_classified_ads_site() {
        // 打开在线分类广告网站的代码
    }

    @Step
    public void select_category(String category) {
        // 选择指定类别的代码
    }

    @Step
    public void verify_all_ads_are_displayed() {
        // 验证广告是否全部显示的代码
    }
}
11. 验收测试的报告与分析

Thucydides 在测试执行后会生成详细的报告,这些报告可以帮助团队更好地了解测试结果。报告通常包括以下内容:
- 总体测试结果 :显示测试用例的通过、失败和跳过情况。
- 详细步骤文档 :描述每个测试用例的执行步骤和结果。
- 功能覆盖率 :展示哪些功能被测试覆盖,哪些功能还需要进一步测试。

团队可以根据这些报告进行以下分析:
- 找出失败原因 :对于失败的测试用例,分析是代码问题、测试用例问题还是环境问题导致的。
- 评估测试覆盖率 :判断测试是否全面覆盖了系统的重要功能,如果覆盖率不足,需要补充相应的测试用例。
- 优化测试策略 :根据测试结果和分析,调整测试策略,提高测试效率和质量。

下面是一个简单的表格,总结 Thucydides 报告的主要内容:
| 报告内容 | 描述 |
| — | — |
| 总体测试结果 | 显示测试用例的通过、失败和跳过情况 |
| 详细步骤文档 | 描述每个测试用例的执行步骤和结果 |
| 功能覆盖率 | 展示哪些功能被测试覆盖,哪些功能还需要进一步测试 |

12. 不同配置管理框架对比

除了 Puppet,还有 CFEngine 和 Chef 等配置管理框架,它们各有特点。以下是一个简单的对比表格:
| 框架名称 | 历史 | 社区支持 | 特点 |
| — | — | — | — |
| CFEngine | 最古老的开源工具,始于 1993 年 | 有一定的用户基础 | 成熟稳定,适用于大规模基础设施管理 |
| Puppet | 2005 年发布 | 近年来获得强大社区支持 | 易于使用,有丰富的模块和工具,适合初学者 |
| Chef | 2009 年发布 | 社区活跃 | 灵活度高,支持多种编程语言,适合复杂场景 |

开发者可以根据项目的具体需求、团队的技术栈和经验等因素选择合适的配置管理框架。

13. 未来趋势与建议

随着 DevOps 的发展,配置管理和自动化测试将变得越来越重要。未来可能会出现更多集成化的工具和平台,简化 DevOps 流程。同时,人工智能和机器学习技术也可能会应用到自动化测试中,提高测试的准确性和效率。

对于开发者来说,不断学习和掌握新的工具和技术是必要的。可以关注行业动态,参加相关的技术会议和培训,与同行交流经验。在选择工具时,要充分考虑项目的实际情况和团队的能力,避免盲目跟风。

下面是一个 mermaid 流程图,展示了 DevOps 中配置管理和自动化测试的主要流程:

graph LR
    A[代码开发] --> B[配置管理]
    B --> C[自动化测试]
    C --> D{测试通过?}
    D -- 是 --> E[部署到生产环境]
    D -- 否 --> F[修复代码]
    F --> A

通过合理运用配置管理工具和自动化测试技术,开发者可以提高开发效率,保证软件质量,实现 DevOps 的目标。希望本文介绍的内容能为开发者在实践中提供一些帮助和启示。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值