理解程序配置
在本课中,我们将明确程序配置的定义,并区分代码与配置,这并不总是那么容易。
配置的基本思想是,用户应该能够在不修改代码的情况下选择程序的行为。我们将探讨配置的多个方面,包括命令行标志、环境变量、配置文件等。
代码、输入、配置以及配置即代码
大多数非平凡的程序都有输入,它们会处理这些输入。输入可能会变化,但程序通常以相同的方式处理输入。除非程序设计中引入了随机元素,否则在相同输入上运行相同的代码应产生相同的输出。许多程序还可以被配置为以不同方式运行,因此相同的输入会根据配置产生不同的输出。例如,echo 命令默认会打印一个换行符。如果你连续执行两个 echo 命令,它们的输出将显示在两行上。试试看:
1echo 'Hi, '; echo there
然而,我们可以通过指定 -n 命令行标志来配置 echo 以省略换行符,结果两个 echo 命令的输出将显示在同一行上:
1echo -n 'Hi, '; echo there
在这个例子中,第一个 echo 命令的输入是字符串 "Hi,",而配置是标志 -n。区分输入和配置并不总是简单明了。有时输入通过命令行标志提供,有时当存在多个命令行参数时,很难判断哪些是真正的配置,哪些是实际输入。
为了增加混淆,"配置即代码" 这一短语偶尔会被使用,与 "基础设施即代码" 和 "GitOps" 一起出现。为了澄清这一点,配置即代码指的是配置管理系统(如 Jenkins 或 Ansible),这些系统通常负责配置应用程序的运行时和部署环境(服务器、云环境),而不是应用程序本身。该术语指的是像管理代码一样,在源代码控制系统中存储和管理这些系统配置。
这种方法也可以应用于某些形式的程序配置,比如配置文件。然而,从程序的角度来看,其配置是如何存储和管理的无关紧要。
程序配置的多种形态
程序可以通过多种方式进行配置。每种方法都有其优缺点,在许多情况下,结合多种方法是明智的做法。
命令行标志
命令行标志在多次以不同选项启动命令行程序时非常方便。在之前的课程中,你已经看到过多个使用命令行标志配置 multi-git 以及其他程序的例子。
然而,当你希望以交互方式多次启动同一个程序并带有大量配置选项时,命令行标志就不太理想了。这需要你反复输入很长的命令行,既繁琐又容易出错。在这种情况下,使用环境变量通常更好。
环境变量
环境变量是另一种历史悠久的程序配置机制。如果程序读取环境变量,你只需设置一次环境变量,就可以多次调用程序而无需重复传递命令行参数。
例如,multi-git 读取两个环境变量 MG_ROOT 和 MG_REPOS。其理念是,我们希望多次运行 multi-git 来管理同一组位于同一根目录下的 git 仓库。如果我们每次运行 multi-git 都必须提供这些信息,那将非常繁琐。
然而,环境变量也有自身的缺点:
- 环境变量仅对当前环境有效,除非导出。
- 如果你的程序启动其他程序,你必须确保相应地设置它们的环境。
- 环境变量共享同一命名空间,因此必须小心命名以避免冲突。
- 环境变量始终是字符串,不携带任何类型信息。
- 环境变量不适合传递大型、分层的配置数据。
当环境变量无法满足需求时,配置文件便派上用场。
配置文件
配置文件是配置管理的主力。对于具有大量配置选项或分层配置的众多程序而言,它是首选的配置方式。配置文件有多种格式。
在早期的 Windows 时代,.ini 文件是主流,因为它们非常简单,但只支持单一层次的嵌套。随后 XML 出现,成为一种流行的配置文件格式,遗憾的是至今仍在 Android 等平台上使用。
Web 2.0 和 REST API 推动了 JSON 作为一种更受欢迎的替代方案。在 UNIX 系统中,简单的 key = value .conf 文件仍然非常常见。
如今,YAML 和 TOML 是流行的文件格式。
配置文件带来了查找位置和文件名的问题。每个程序可能有自己的约定,包括搜索路径、默认文件名等。当然,一种常见做法是通过命令行参数和/或环境变量指定配置文件。
在下一课中,我们将讨论更多主题,如远程配置、默认值以及合并多个配置源。