用于应用开发的 CI/CD 与用于基础结构即代码的 CI/CD
Why CI/CD with Infrastructure as Code is different than CI/CD for Application Development 为什么具有基础结构即代码的 CI/CD 与用于应用程序开发的 CI/CD 不同
The rise of Infrastructure as Code has revolutionized the management of infrastructure and the way we provision and maintain platforms for application deployment. Rather than manually deploying infrastructure through a CLI or GUI, we can now treat our infrastructure in the same way we treat our applications. We can leverage common software development paradigms like source control repositories, modules and libraries, and automation pipelines. At the same time, we must bear in mind that application and infrastructure deployments are different, and not all practices typical of software development map neatly to infrastructure deployment. Infrastructure deployment and management has unique challenges and features that require an adjustment in code maintenance and automation. In this article, we’ll examine how to treat infrastructure as code like software and the implications that has on continuous integration and delivery.
基础设施即代码的兴起彻底改变了基础设施的管理以及我们为应用程序部署配置和维护平台的方式。我们现在不必通过 CLI 或 GUI 手动部署基础架构，而是可以像对待应用程序一样对待我们的基础架构。我们可以利用常见的软件开发范例，如源代码管理存储库、模块和库以及自动化管道。同时，我们必须记住，应用程序和基础架构部署是不同的，并非所有典型的软件开发实践都与基础架构部署完全对应。基础架构部署和管理具有独特的挑战和功能，需要在代码维护和自动化方面进行调整。在本文中，我们将研究如何将基础结构视为软件等代码，以及它对持续集成和交付的影响。
Infrastructure as Code is CODE 基础设施即代码就是代码
Even though code is right there in the name, it’s not uncommon for operations professionals to treat IaC like another script they have in their repertoire, stashed away in someone’s home directory and passed around through a series of emails and file shares across the organization. But to truly leverage the power of IaC, we need to treat it like a software development process. What does that entail? Let’s review some key features:
尽管_代码_就在名称中，但运营专业人员将 IaC 视为他们曲目中的另一个脚本，隐藏在某人的主目录中，并通过一系列电子邮件和文件共享在整个组织中传递的情况并不少见。但要真正利用 IaC 的强大功能，我们需要将其视为软件开发过程。这意味着什么？让我们回顾一些关键功能：
Source Control 源代码管理
Your infrastructure as code needs to be stored in a repository on a centralized version control system of some kind. At a minimum, this allows you to track changes to the code and roll back to a previous version if needed. It also unlocks a ton of other features, including the ability of other team members to contribute, share, and use your IaC on their own project. Your repository can serve as a module or library for consumption by other members of the organization, allowing you to develop a standardized approach for common deployment patterns.
基础结构即代码需要存储在某种集中式版本控制系统上的存储库中。这至少允许您跟踪对代码的更改，并在需要时回滚到以前的版本。它还解锁了大量其他功能，包括其他团队成员在自己的项目中贡献、共享和使用您的 IaC 的能力。您的存储库可以用作供组织其他成员使用的模块或库，从而允许您为常见部署模式开发标准化方法。
Scanning and Testing 扫描和测试
Having your infrastructure defined in code means that the code can be scanned and evaluated in many ways. It starts with simply checking the basic syntax of the code to ensure that the defined resources, methods, and variables are logically valid. For instance, you could easily scan to ensure that a property you reference for a virtual machine is actually valid. Beyond simple syntactic testing and logical validation, code can also be statically analyzed to ensure compliance with regulations, company standards, and security best practices. You can flag code that opens up port 22 to the world or makes a storage account public. It’s also possible to deploy your code in a testing environment and validate the functionality of your infrastructure against its intended purpose.
在代码中定义基础结构意味着可以通过多种方式扫描和评估代码。它从简单地检查代码的基本语法开始，以确保定义的资源、方法和变量在逻辑上有效。例如，您可以轻松扫描以确保为虚拟机引用的属性确实有效。除了简单的语法测试和逻辑验证之外，还可以对代码进行静态分析，以确保符合法规、公司标准和安全最佳实践。可以标记向外界开放端口 22 或将存储帐户设为公共的代码。还可以在测试环境中部署代码，并根据其预期目的验证基础结构的功能。
Automate testing and deployment 自动化测试和部署
Once your infrastructure as code is stored in source control, you can use the hooks provided by that source control to kick off workflows for continuous integration, delivery, and deployment. Each of those workflows can be defined in pipelines that are stored alongside the infrastructure code and maintained through the same source control process. Within pipelines for continuous integration or continuous delivery, you can incorporate the testing and validation detailed earlier, adding in logic that requires the code to pass these tests before it can be promoted to production.
Through that lens of source control, testing, and automation, we can examine the continuous integration and delivery processes and highlight how IaC differs from typical application development and deployment.
通过源代码控制、测试和自动化的视角，我们可以检查持续集成和交付过程，并强调 IaC 与典型应用程序开发和部署的不同之处。
Continuous Integration 持续集成
Continuous Integration refers to the process in software development of merging a working branch into the main branch. The general recommendation is to have short-lived feature branches, along with a single well-defined main branch. This concept maps well to infrastructure as code, especially if you plan to separate out your configuration data from your code. Changes made to the code should be reflected in all environments that use the code, whereas configuration data customizes the deployed infrastructure for a given environment. When you’re first getting started with infrastructure as code, you might be tempted to store your IaC in the same repository as your applications code, also known as a monorepo. This may work well initially, but becomes difficult to maintain as the application and infrastructure tend to change at different rates and require separate testing processes. The recommended practice is to maintain separate repositories for application and infrastructure code with loose coupling and dependency inversion.
持续集成是指软件开发中将工作分支合并到主分支的过程。一般建议具有生存期较短的功能分支，以及单个定义良好的主分支。此概念很好地映射到基础结构即代码，尤其是在计划将配置数据与代码分离时。对代码所做的更改应反映在使用代码的所有环境中，而配置数据则为给定环境自定义已部署的基础结构。首次开始使用基础结构即代码时，可能会想将 IaC 存储在与应用程序代码相同的存储库中，也称为 monorepo。这在最初可能工作得很好，但由于应用程序和基础结构往往以不同的速率变化，并且需要单独的测试过程，因此变得难以维护。建议的做法是使用松散耦合和依赖关系反转为为应用程序和基础结构代码维护单独的存储库。
Bearing this separation in mind, what does a typical CI process look like for infrastructure as code? The process starts when a commit is made to the repository at the local workstation level, before the change is pushed to the centralized repository. At this early stage, you are trying to empower the developer to write infrastructure code that is formatted properly, syntactically correct, and logically valid. In the case of Terraform, this can be accomplished by using a linter in the code editor, the
terraform fmt command, and the
terraform validate command. This is similar to the basic checks one would expect an application developer to run before they pushed a new feature branch.
牢记这种分离，基础结构即代码的典型 CI 过程是什么样的？该过程从在本地工作站级别对存储库进行提交时开始，然后将更改推送到集中式存储库。在这个早期阶段，您正在尝试使开发人员能够编写格式正确、语法正确且逻辑有效的基础结构代码。对于 Terraform，这可以通过在代码编辑器中使用 linter、'terraform fmt' 命令和 'terraform validate' 命令来实现。这类似于人们期望应用程序开发人员在推送新功能分支之前运行的基本检查。
Once a commit is pushed to the centralized repository, the continuous integration process kicks off in earnest, typically running similar validation as the develop - trust, but verify - and blocking a pull request from being opened until all checks have passed.
一旦提交被推送到集中式存储库，持续集成过程就会认真启动，通常运行与开发类似的验证 - 信任，但验证 - 并阻止打开拉取请求，直到所有检查都通过。
Depending on the language used for the infrastructure code, your developer may also wish to write some unit tests that validate the functions inside the IaC. Often this is unnecessary, as the unit testing is encapsulated by the infrastructure provider, but if you are using a CDK with a general purpose programming language, then unit tests are desirable to test any custom functions or methods.
根据用于基础结构代码的语言，开发人员可能还希望编写一些单元测试来验证 IaC 中的函数。通常这是不必要的，因为单元测试是由基础设施提供商封装的，但是如果您使用的是具有通用编程语言的CDK，则需要进行单元测试来测试任何自定义函数或方法。
Integrating the code into the main branch will involve more in-depth testing and validation, including scanning the code with static analysis tools to verify adherence to policies, organization standards, and security requirements. Some common tools for accomplishing this goal are Checkov, tfesec, and Open Policy Agent (OPA). Each tool compares the infrastructure code to policies defined by the vendor or organization, and returns the test results with a pass/fail metric.
将代码集成到主分支将涉及更深入的测试和验证，包括使用静态分析工具扫描代码，以验证是否符合策略、组织标准和安全要求。实现此目标的一些常用工具是 Checkov、tfesec 和开放策略代理 （OPA）。每个工具将基础结构代码与供应商或组织定义的策略进行比较，并返回带有通过/失败指标的测试结果。
When a feature branch is integrated (merged) into the main branch, the next step in a typical continuous integration process would be building a new version of the application based on the updated code. However, this is a key place where infrastructure as code differs. IaC is not compiled and does not produce a binary, zip, or other similar artifact. There is no build process per se. Instead, the most common next step is to move on to the continuous delivery process.
将功能分支集成（合并）到主分支中时，典型持续集成过程的下一步是基于更新的代码构建应用程序的新版本。但是，这是基础结构即代码不同的关键位置。IaC 不会编译，也不会生成二进制文件、zip 项目或其他类似项目。本身没有构建过程。相反，最常见的下一步是继续持续交付流程。
Continuous Delivery 持续交付
In the world of application development, the build artifacts from the CI pipeline are deployed to a testing environment and validated for functionality before being made available to the production and lower environments. The parallel in IaC would be the deployment of code to a testing environment to validate the desired functionality of the updated code using something like kitchen-terraform or terratest.
在应用程序开发领域，CI 管道中的生成项目将部署到测试环境并验证功能，然后再提供给生产和更低环境。IaC 中的并行是将代码部署到测试环境，以使用诸如 kitchen-terraform 或 terratest 之类的东西来验证更新代码的所需功能。
A key difference between application and infrastructure deployment, for testing or production, is how the new application or infrastructure code is delivered to the target environments. The deployment of infrastructure requires proper credentials to create resources on the target provider. For instance, deploying a test environment on Microsoft Azure requires the pipeline to have credentials in Azure AD and permissions to create resources in the testing subscription. Handling sensitive credentials properly is a challenge for any pipeline solution, and it’s one you’ll need to consider when automating your testing and deployment.
对于测试或生产，应用程序和基础结构部署之间的主要区别在于如何将新的应用程序或基础结构代码传递到目标环境。基础结构的部署需要适当的凭据才能在目标提供程序上创建资源。例如，在 Microsoft Azure 上部署测试环境要求管道具有 Azure AD 中的凭据以及在测试订阅中创建资源的权限。正确处理敏感凭据对于任何管道解决方案来说都是一项挑战，这是在自动化测试和部署时需要考虑的问题。
Once functional testing is completed, the next step in the delivery process is a dry-run against production and lower environments to examine the impact of the code changes. This is another major difference between application CD and infrastructure CD. With an application update, you can perform blue/green deployments or canary roll-outs, and monitor the performance and stability of your updated application. Infrastructure code doesn’t have a parallel. Instead, the most common procedure is to perform a dry-run against each environment to assess what changes will be made by the updated code.
功能测试完成后，交付流程的下一步是针对生产和较低环境进行试运行，以检查代码更改的影响。这是应用程序 CD 和基础结构 CD 之间的另一个主要区别。通过应用程序更新，您可以执行蓝/绿部署或金丝雀部署，并监控更新的应用程序的性能和稳定性。基础结构代码没有并行。相反，最常见的过程是针对每个环境执行试运行，以评估更新的代码将进行哪些更改。
The results of the dry-run can be analyzed programmatically to determine the next step in the pipeline:
- Automatically promote the changes to production 自动将更改提升到生产环境
- Require manual approval for promotion 需要手动批准才能升级
- Deny promotion due to policy violations 因违反政策而拒绝发布
There are many testing frameworks out there you can use to analyze the results of the dry-run, but Open Policy Agent is quickly becoming a standard because of its flexibility.
An examination of the dry-run results should include, but is not limited to: 对试运行结果的检查应包括但不限于：
- The number of alteration being made to existing resources 对现有资源进行的改动次数
- The number of deletions and creations 删除和创建的数量
- Estimated cost of updated deployment 更新部署的估计成本
The last bullet point is especially important to call out, since once again this is a major difference between application and infrastructure code updates. An update to your application is unlikely to have an immediate and obvious impact on the cost of operations. However, infrastructure code can blow out your cloud bill if you’re not paying attention. Pick the wrong virtual machine size or storage class, and you could have quite a surprise coming for you at the end of the month. Fortunately, you can integrate cost estimation with a tool like Infracost, and flag any deployment that exceeds a certain amount or is a certain percentage more expensive than the current deployment.
最后一个要点尤其重要，因为这再次是应用程序和基础结构代码更新之间的主要区别。对应用程序的更新不太可能对运营成本产生直接而明显的影响。但是，如果您不注意，基础架构代码可能会使您的云账单大增。选择错误的虚拟机大小或存储类，您可能会在月底遇到很大的惊喜。幸运的是，您可以将成本估算与 Infracost 等工具集成，并标记任何超过特定数量或比当前部署贵一定百分比的部署。
Updating your infrastructure using IaC and CI/CD pipelines isn’t the end of the journey. You’ll still need to integrate with the application deployment process and continually monitor your infrastructure for potential issues. But now you’ll actually have time to do that, since you’ve automated away the tedious and error-prone process of deployment and updates.
使用 IaC 和 CI/CD 管道更新基础结构并不是旅程的终点。您仍然需要与应用程序部署过程集成，并持续监视基础结构是否存在潜在的问题。但是现在您实际上有时间这样做，因为您已经自动化了繁琐且容易出错的部署和更新过程。
Treating your infrastructure definition as code and implementing CI/CD pipelines to assist with integration and deployment is going to make your life simpler, faster and easier to maintain. There should be a single source of truth for your environments, separating the code from the configuration. You should automate the testing of your infrastructure code during both CI and CD to enable consistent and compliant results. Your testing will be a combination of static analysis and functional testing for validity, security, compliance, and cost. Pulling all these elements together is akin to keeping your tools neatly in a toolbox. A toolbox with the correct layout for your working practices, that helps you to work the way you want to, at the speed you need.
将基础结构定义视为代码并实现 CI/CD 管道以帮助集成和部署，这将使您的生活更简单、更快速、更易于维护。您的环境应该有一个单一的事实来源，将代码与配置分开。应在 CI 和 CD 期间自动测试基础结构代码，以实现一致且合规的结果。测试将是静态分析和功能测试的组合，以实现有效性、安全性、合规性和成本。将所有这些元素组合在一起类似于将工具整齐地放在工具箱中。一个工具箱，为您的工作实践提供正确的布局，帮助您以所需的速度按照您想要的方式工作。
This article is translated from the original text for the purpose of learning: