服务器管理模式与软件工程实践解析
未配置区域的问题
在使用持续同步时,要清楚服务器的大部分配置并非由每次运行时应用的配置定义所管理。服务器的配置主要来源于创建服务器时使用的模板,如AMI、操作系统安装盘等。一旦服务器启动并运行,这些配置就基本处于未管理状态。
这通常不会产生问题,因为未为服务器的特定部分编写配置定义,可能意味着我们对服务器模板中的内容感到满意,无需进行更改。然而,这些未管理区域可能导致配置漂移。如果有人需要更改服务器未管理部分的配置,可能会选择手动修改,而不是编写配置定义。这样一来,特定更改就无法以确保在需要时始终生效的方式被记录下来,还可能导致“雪花服务器”的出现,即某些应用仅在被修改过的服务器上运行,却无人记得原因。
未管理区域不可避免的原因
解决这一问题的一个明显方法是确保配置定义能够覆盖系统的所有方面。但就当前的配置工具而言,这并不现实,主要有两个障碍:
- 服务器上需要管理的内容过多,当前工具难以有效处理。以Linux服务器为例,即使使用精简的服务器镜像,也会有大量文件。例如,使用“CentOS - 6.6 - x86_64 - minimal.iso”构建的CentOS 6.6虚拟机,运行
find /etc -type f | wc -l
命令显示有712个配置文件;CoreOS版本607.0.0的虚拟机则只有58个。对根文件夹(如/bin、/etc、/lib等)进行类似查找,CentOS虚拟机有38,496个文件,CoreOS虚拟机有4,891个。可见,即使是JEOS服务器能大幅减少需管理的文件数量,但仍有不少。
- 当前工具无法阻止向系统中添加不需要的内容。即使对服务器上的所有内容进行声明,仍需编写定义来排除不需要的内容,这几乎是一个无限的集合。采用白名单方法删除未明确声明的内容也不可行,因为系统中有许多临时文件和数据文件对服务器正常运行至关重要,但无法提前预测,而当前的服务器配置工具不支持对这些文件的保护。
不可变服务器的模式与实践
- 基本概念 :不可变服务器从模板创建后,其配置文件、系统包和软件在运行实例中不会被修改。任何更改都通过创建新的服务器实例来实现。为避免配置漂移,使用不可变服务器的团队通常会遵循“凤凰模式”,缩短服务器的使用寿命。
- 服务器模板管理 :使用不可变服务器需要更成熟的服务器模板管理,以便快速频繁地构建新模板。
- 服务器镜像作为制品 :采用不可变服务器的一个关键驱动因素是强大的测试。服务器模板创建并测试后,生产服务器上出现未经测试的更改和变化的可能性较小。运行时状态和数据会改变,但系统库、配置文件等服务器配置不会像持续同步那样在运行时更新或修改。服务器模板的变更管理管道有助于确保模板质量。
- 简化配置管理工具 :许多采用不可变模型的团队发现,在准备服务器模板时可以简化配置服务器的工具。像Ansible、Chef、Puppet等工具设计为持续运行,增加了设计和使用的复杂性。而针对服务器模板进行的配置可以对服务器的初始状态做出假设,团队通常使用一系列简单的shell脚本来配置服务器模板,减少了工具和维护开销。
不可变服务器的流程
graph LR
A[现有服务器] --> B[修改模板定义文件]
B --> C[打包新的服务器模板镜像]
C --> D[构建新服务器]
D --> E[替换现有服务器]
当需要进行更改时,先修改模板定义文件,然后用其打包新的服务器模板镜像,再用该镜像构建新服务器以替换现有服务器。理想情况下,替换运行中的服务器的过程不会中断服务器提供的服务。
创建时配置
早期不可变服务器的实践是将所有内容都放入服务器模板,但对于某些类型的更改,构建新模板所需的时间会导致周转时间过长。现在出现的一种做法是将几乎所有内容放入服务器模板,但在服务器创建时进行一些操作。
-
设置配置选项
:大多数动态基础设施平台允许在创建服务器时传递参数,如cloud - init等工具可用于设置选项,这有助于为特定服务器实例传递配置。
-
软件供应
:许多团队以这种方式供应微服务。他们创建一个配置为运行通用微服务应用的服务器模板,在服务器启动时,传递应用工件的URL,通过cloud - init脚本下载并运行该工件。
团队微服务应用标准示例
某团队采用标准化应用部署模式,制定了以下标准:
| 项目 | 详情 |
| ---- | ---- |
| 应用打包 | 应用打包为.tar.gz文件,根目录包含特定文件:
- 名为SERVICEID - VERSION.jar的jar文件,VERSION符合正则表达式(\d+).(\d+).(d+)
- 名为SERVICEID - config.yml的配置文件
- 名为SERVICEID - setup.sh的shell脚本 |
| 部署过程 | 服务器供应脚本从环境变量SERVICE_ARTEFACT_URI传递的URI下载工件,将其内容提取到/app/SERVICEID目录,该目录由名为SERVICEID的用户账户拥有,并在同一目录下创建名为SERVICEID - env.yml的文件,包含特定于环境的配置信息。供应脚本还运行SERVICEID - setup.sh脚本进行初始化,最后创建并启用服务启动脚本/etc/init.d/SERVICENAME,通过“java -jar /app/SERVICEID/SERVICEID - VERSION.jar server”命令启动应用。 |
这种做法仍遵循不可变服务器模式,缩短了微服务更改的周转时间,但可能会削弱“纯”不可变模型的测试优势,因为在创建服务器时安装微服务或进行其他更改可能在不同服务器上表现略有不同,从而导致意外行为。不过,在许多涉及频繁更改的情况下,这种权衡是可行的。
事务性服务器更新
事务性服务器更新是一种有潜力的方法,它使用支持将服务器上的所有包作为原子事务更新到定义版本集的包管理工具。如果任何更新失败,整个更新集将回滚,确保服务器的配置(至少就系统包而言)不会处于未经测试的状态。服务器要么更新到全新且完全测试过的状态,要么恢复到之前可能已测试过的现有状态。这种方法与不可变服务器和容器有很多相似之处。
配置定义管理实践
- 保持配置定义最小化 :代码(包括配置定义)存在开销,团队编写、维护、测试等代码的时间会随着代码量的增加而增长,且这种开销呈指数级增长。因此,团队应尽量减少代码库的规模,避免不必要的代码编写。基础设施团队应仅为真正需要显式、持续配置的区域编写和维护配置定义,可从小处着手,根据需要逐步添加和删减定义。
- 组织定义 :配置定义容易变得复杂混乱,基础设施团队掌握服务器配置工具的基础知识后,应学习利用工具的模块化和重用功能,保持单个模块或定义文件小而简单、易于理解,同时整体组织要清晰,便于相关人员查找和理解。
- 使用测试驱动开发(TDD)推动良好设计 :TDD的主要价值在于推动编写干净、可维护的代码设计。对于配置定义,要确保每个模块都有一组单元测试,能够独立测试该模块。通过严格编写和维护测试,可以发现模块是否变得过大或复杂,以及是否与依赖项耦合过紧。
服务器管理模式与软件工程实践解析(下半部分)
软件工程实践在基础设施中的应用
在将基础设施视为软件系统的背景下,软件工程的一些基本实践可以应用到基础设施管理中,这些实践有助于提高代码和系统的质量,确保能够快速且安全地进行变更。
版本控制
版本控制是管理基础设施代码的基础。它允许团队记录代码的变更历史,方便追溯问题、回滚到之前的版本,以及多人协作开发。通过版本控制系统(如Git),可以对服务器配置定义、脚本等文件进行管理。团队成员可以在不同的分支上进行开发,完成后将代码合并到主分支。例如,当需要对服务器配置进行更改时,可以创建一个新的分支进行修改和测试,测试通过后再合并到主分支,确保主分支上的代码始终是稳定的。
持续集成(CI)
持续集成是指频繁地将代码集成到共享的主干中,并自动进行构建和测试。在基础设施管理中,CI可以确保每次对配置定义或脚本的更改都能及时进行验证。当代码被推送到版本控制系统时,CI服务器会自动触发构建过程,运行一系列的测试(如单元测试、集成测试等)。如果测试失败,开发人员可以及时发现问题并进行修复。这样可以避免在部署到生产环境时才发现配置错误,提高开发效率和系统的稳定性。
代码质量管理
代码质量不仅仅关乎代码的正确性,还包括代码的可读性、可维护性和可扩展性。为了确保代码质量,可以采取以下措施:
-
代码审查
:团队成员之间进行代码审查,检查代码是否符合编码规范、是否存在潜在的问题等。通过代码审查,可以发现并纠正一些不易察觉的错误,同时也有助于团队成员之间的知识共享和技能提升。
-
静态代码分析
:使用静态代码分析工具(如Pylint、ESLint等)对代码进行检查,发现代码中的潜在问题,如语法错误、代码风格问题、安全漏洞等。这些工具可以在代码编写阶段就发现问题,避免问题在后续阶段被放大。
-
自动化测试
:编写自动化测试用例,对代码进行全面的测试。自动化测试可以确保代码在不同的环境下都能正常工作,并且在代码发生变更时能够快速验证代码的正确性。
测试驱动开发(TDD)在基础设施中的应用
测试驱动开发(TDD)是一种软件开发方法,它强调在编写代码之前先编写测试用例。在基础设施管理中,TDD同样具有重要的价值。
graph LR
A[编写测试用例] --> B[编写代码使测试通过]
B --> C[重构代码]
C --> A[编写新的测试用例]
- 编写测试用例 :在编写配置定义或脚本之前,先编写相应的单元测试用例。这些测试用例描述了代码应该具备的功能和行为。例如,如果要编写一个用于配置服务器防火墙规则的脚本,可以编写测试用例来验证防火墙规则是否正确设置。
- 编写代码使测试通过 :根据测试用例编写代码,使测试用例能够通过。在这个过程中,只需要编写满足测试用例的最少代码,避免过度设计。
- 重构代码 :在测试用例通过后,对代码进行重构,提高代码的可读性和可维护性。重构过程中要确保测试用例仍然能够通过,以保证代码的正确性。
- 编写新的测试用例 :随着需求的变化或功能的扩展,编写新的测试用例,重复上述过程,不断完善代码。
变更管理管道
变更管理管道用于自动化基础设施的测试、集成和部署过程。它可以确保对基础设施的更改经过严格的测试和验证,然后才部署到生产环境。一个典型的变更管理管道包括以下阶段:
| 阶段 | 描述 |
| ---- | ---- |
| 代码提交 | 开发人员将代码提交到版本控制系统。 |
| 静态代码分析 | CI服务器对提交的代码进行静态代码分析,检查代码质量。 |
| 单元测试 | 运行单元测试用例,验证代码的基本功能。 |
| 集成测试 | 将不同的组件集成在一起进行测试,确保它们能够协同工作。 |
| 预生产环境测试 | 将更改部署到预生产环境进行测试,模拟生产环境的实际情况。 |
| 生产环境部署 | 如果所有测试都通过,将更改部署到生产环境。 |
通过变更管理管道,可以实现对基础设施变更的自动化管理,减少人为错误,提高系统的可靠性和稳定性。
工程师的工作流程
使用上述软件工程实践管理基础设施时,工程师的工作流程通常如下:
1.
需求分析
:明确需要对基础设施进行的更改或优化。例如,需要添加新的服务器、更新配置等。
2.
代码编写
:根据需求编写配置定义、脚本等代码。在编写代码过程中,遵循编码规范和设计原则。
3.
测试编写
:编写相应的测试用例,确保代码的正确性。可以使用单元测试、集成测试等不同类型的测试。
4.
持续集成
:将代码提交到版本控制系统,触发CI流程,进行静态代码分析和测试。
5.
问题修复
:如果测试失败,分析问题原因并修复代码,再次提交进行测试。
6.
变更管理管道
:代码通过测试后,进入变更管理管道,依次经过集成测试、预生产环境测试等阶段。
7.
生产环境部署
:如果所有阶段都通过,将更改部署到生产环境。
8.
监控和维护
:部署后对系统进行监控,及时发现并处理可能出现的问题,对基础设施进行维护和优化。
通过遵循这样的工作流程,工程师能够更加高效、安全地管理基础设施,确保系统的稳定性和可靠性。
总之,将软件工程实践应用到基础设施管理中,可以提高基础设施的质量和可维护性,使团队能够更加高效地进行服务器的配置、更新和管理,适应不断变化的业务需求。
超级会员免费看
8万+

被折叠的 条评论
为什么被折叠?



