IaC(基础设施即代码)

基础设施即代码(IaC)是通过机器可读的文件来管理和配置所有基础设施资源的过程。这些文件通常是版本控制的,并像代码一样在Git中管理。在这种情况下,它通常被称为GitOps。 IaC可以是命令式的、声明式的,或两者的结合。命令式意味着文件是过程性的,例如脚本,而声明式则是通过描述所需状态的标记语言(如YAML或JSON)来实现的一种功能性方法。要充分发挥IaC的作用,您应以能够应用更改的方式来管理它,而不仅仅是进行资源的完全配置和去配置。这通常被称为持续配置自动化(CCA)。

工具

有许多可以用于IaC和CCA的工具。例如,您可以使用特定于云的工具,如Azure ARM、Bicep或AWS CloudFormation。然而,也有许多独立的工具,您可以用于本地基础设施。一些最受欢迎的工具如下所示:

IaC和多云部署

需要注意的是,一个支持多个云提供商的IaC工具并不意味着它可以将相同的资源部署到多个云中!这是一个常见的误解。您仍然需要编写特定于云的自动化脚本。但您可以使用相同的语法和工具。

这仅仅是冰山一角。市场上有许多工具。找到最佳组合的过程可能非常复杂,超出了本书的范围。如果您只采用单一云策略,最好从云本地工具开始。如果您有一个复杂的环境,包含多个云和本地资源,并且希望使用相同的工具进行管理,您必须投入大量的分析工作。

最佳实践

无论您使用什么工具,在实施 IaC 时,您应该考虑以下几点:

  • 将配置存储在 Git 中,并像管理代码一样管理它,使用受保护的分支、拉取请求和代码所有者。代码所有者是确保合规性的一种有效方式,尤其是当您将配置存储在接近应用代码的位置时。

  • 使用 GitHub Actions 执行部署。在编写和调试 IaC 时,可以交互式地发布资源。但一旦完成,您应该通过工作流实现完全自动化的发布。IaC 是代码,和应用代码一样,从开发者机器上进行部署存在不可重复的风险。

  • 秘密和密钥管理是 IaC 中最关键的部分。确保不要将它们保存在代码中,而是将其保存在安全的地方(如GitHub Secrets)。像 HashiCorp Vault 或 Azure KeyVault 这样的保管库可以在秘密泄露时轻松地进行密钥轮换。此外,它还将您的安全管理与资源的配置解耦。

  • 尽可能使用 OpenID Connect(OIDC)。这可以避免使用凭证访问云资源,而是使用短期有效的令牌,这些令牌也可以进行轮换(有关更多信息,请参阅 GitHub文档)。

本书中使用的是云本地工具。从这些工具过渡到 IaC 或 CCA 工具要比反过来过渡容易。

策略

关于如何以可管理、可扩展和合规的方式组织基础设施代码,有不同的策略。基本上,这取决于您的组织结构以及哪种方式最适合您。以下是几种常见的策略:

  • 集中式(Central):基础设施资源存储在中央仓库中,功能团队可以通过自服务方式(即触发工作流)从中进行资源配置。这种方法的优点是所有资源集中在一个地方,负责的团队能够对其进行严格控制。缺点是对于开发人员来说灵活性较差,且代码与基础设施之间的距离会影响工程师如何处理基础设施。

  • 分散式(Decentral):基础设施资源与代码一起存储。您可以使用模板(请参阅“工作流模板”部分)来帮助工程团队设置基础设施。此外,您可以使用 CODEOWNERS 和受保护的分支,要求共享的负责团队进行审批。这种方法非常灵活,但成本控制和治理较为困难。您可以在每次构建时部署或确保基础设施的正确状态,但这会导致构建时间变慢并浪费宝贵的构建分钟。在大多数情况下,最好通过单独的工作流按需部署资源。

  • 模板化(Templated):负责共享基础设施的团队提供固定模板,供功能团队使用。这些模板可以是 Actions,即具有预配置原生操作的复合操作,或完全自定义的 Docker 或 JavaScript 操作。另一个选择是使用可重用的工作流(请参阅“可重用工作流”部分)。无论是哪种方式,重用的工作流或操作的所有权都由中央团队保持。如果您限制企业中允许的操作数量,这种方法会很有效。

  • 混合式(Mixed):这是一种结合前面三种策略的方式。例如,测试和开发基础设施可以是分散的,而生产环境可以是模板化的。

无论您使用哪种策略,都要有意识地做出选择。这个解决方案将极大地影响您的团队如何协作以及基础设施如何在价值交付中发挥作用!

工作流模板

工作流模板是存储在组织的 .github 仓库中的 workflow-templates 文件夹中的工作流文件,并且与元数据文件和图标文件一起存储(见图 9.6):

image 2024 12 27 14 26 11 054
Figure 1. 图 9.6 – 组织的工作流模板

模板本身是一个普通的工作流文件。您可以使用 $default-branch 变量作为触发器,按默认分支进行过滤。

除了模板外,您还需要保存一个 .svg 格式的图标和一个属性文件。属性文件的格式如下:

{
  "name": "My Workflow Template",
  "description": "Description of template workflow",
  "iconName": "my-template",
  "categories": [
    "javascript"
  ],
  "filePatterns": [
    "package.json$",
    "^Dockerfile",
    ".*\\.md$"
  ]
}

在这里,namedescriptioniconName 值是必填项。请注意,iconName 的值不包括扩展名。在 categories 数组中,您可以指定该工作流模板适用的编程语言。filePatterns 也是如此:您可以为用户的仓库中的某些文件指定匹配模式。如果仓库中包含与某个模式匹配的文件,该模板将会更加显著地展示。

现在,如果组织的用户创建新的工作流,他们将会看到该组织的工作流模板(见图 9.7):

image 2024 12 27 14 26 37 914
Figure 2. 图 9.7 – 从模板创建工作流

模板已被复制,可以进行修改!这就是为什么工作流模板不适合模板化策略的原因。

要了解更多关于工作流模板的信息,请访问 [GitHub文档](https://docs.github.com/en/actions/learn-github-actions/creating-workflow-templates)。

可重用工作流

可重用工作流是可以被其他工作流调用的工作流。要使一个工作流成为可重用的,必须具有 workflow_call 触发器:

on:
  workflow_call:

您可以定义可以传递给工作流的输入。输入可以是布尔值、数字、字符串或密钥:

on:
  workflow_call:
  inputs:
    my_environment:
      description: 'The environment to deploy to.'
      default: 'Prod'
      required: true
      type: string
  secrets:
    my_token:
      description: 'The token to access the environment'
      required: true

在可重用工作流中,您可以使用 inputs 上下文 (${{ inputs.my_environment }}) 来访问输入,使用 secrets 上下文 (${{ secrets.my_token }}) 来访问密钥。

要使用可重用工作流,您必须按以下格式引用文件:

{owner}/{repo}/{path}/{filename}@{ref}

该工作流在一个作业中被调用,您可以在作业中指定输入和密钥,示例如下:

jobs:
  call-workflow-1:
    uses: org/repo/.github/workflows/reusable.yml@v1
    with:
      my_environment: development
    secrets:
      my_token: ${{ secrets.TOKEN }}

可重用工作流非常适合避免重复工作。结合语义版本控制和标签,这是向组织中的团队发布可重用工作流的绝佳方式。

要了解更多关于可重用工作流的信息,请访问 [GitHub文档](https://docs.github.com/en/actions/learn-github-actions/reusing-workflows)。