首页 > 解决方案 > 您如何使用 Packer 和 Terraform 管理图像版本?

问题描述

我目前正在使用在配备 Ansible 的裸机节点上运行的 Kubernetes 集群。有计划迁移到云端,我正在阅读有关 Terraform 和 Packer 的信息,为此做准备。撇开数据迁移不谈,我们似乎有一条非常直接的迁移路径:

  1. 使用我们现有的 Ansible 脚本使用 Packer 构建映像
  2. 使用 Terraform 将构建的映像部署到云端
  3. 使用我们当前的工具部署我们的 Kubernetes 资源

这一切都很棒。我们现在拥有不可变的基础设施,使用最先进的工具。

我正在努力寻找的是如何对使用 Packer 构建的图像进行版本控制。在某个地方,我们将不得不升级这些图像中的一些软件。有时 Ansible 脚本会发生变化,但有时只是在映像中拥有最新的安全更新。无论哪种方式,Packer 都必须为我们构建一个新镜像,并且我们必须使用 Terraform 部署它。如果新图像最终造成麻烦,我们将不得不恢复到旧图像。

我可以想象如何通过在运行模板之前编辑模板然后编辑 terraform 配置以获取新版本来手动完成此操作,但这不适用于 CI/CD 管道。另一个问题是我们可能会在不同的地区和供应商之间移动。因此,图像的一个版本可能存在于一个区域中,但不存在于另一个区域中,理想情况下,如果图像不存在,则管道应该创建图像,如果已经存在,则使用现有的图像。这可能会导致不同区域或云中的图像不同,尤其是因为它们可能在不同的日期构建并应用了不同的安全更新。

所有这些都内置在 Docker 工作流程中,但是使用 Packer,要做什么远非显而易见。我还没有找到任何涵盖该主题的文档或教程。Packer 和 Terraform 中是否有任何内置的版本控制功能?如果图像丢失,Terraform 是否能够调用 Packer?有没有公​​认的最佳实践?

在执行 Terraform 之前,我可以想象通过使用来自云提供商的 API 来检查所需图像的存在并为任何丢失的图像调用 Packer 来自动执行此操作。这可行,但我不想为每个云提供商编写自定义集成,这听起来像是 Terraform 应该已经提供的东西。我以前没有使用过 Terraform,所以也许我只是不知道在哪里看,也许在 Terraform 中实现并不难,但是为什么没有任何教程告诉我如何使用呢?

标签: terraformpacker

解决方案


这在很大程度上取决于提供商,您没有指定您正在使用的云提供商,但 AWS 在这里提供了一个很好的示例用例。

Terraform 和 Packer 都有选择与过滤器匹配的最新 AMI 的方法。

Packer 的 AWS AMI 构建器使用source_ami_filter可用于选择最新图像作为您的图像的基础。amazon-ebs构建器文档中给出了一个示例:

{
  "source_ami_filter": {
    "filters": {
      "virtualization-type": "hvm",
      "name": "ubuntu/images/\*ubuntu-xenial-16.04-amd64-server-\*",
      "root-device-type": "ebs"
    },
    "owners": ["099720109477"],
    "most_recent": true
  }
}

这里的一个典型案例是始终使用最新的官方 Ubuntu 映像进行构建。如果您正在为不同的用例(例如 Kubernetes 工作节点与 etcd 节点)生成多个 AMI,那么您可以从那里构建,这样您就可以创建一个具有已知命名方案(例如ubuntu/20.04/base/{{isotime | clean_resource_name}})的黄金基础镜像,该镜像在每个 AMI 中都有您想要的一切您生成,然后其他 AMI 也可以使用source_ami_filter选择您已发布的最新基本 AMI。

Terraform 的 AWS 提供商拥有以相同方式工作的aws_ami数据源,可用于自动选择与过滤器匹配的最新 AMI,以便发布新 AMI 然后运行 ​​Terraform 将生成替换您的实例或启动配置/模板的计划即引用 AMI 数据源。

aws_instance资源文档中给出了一个示例:

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "web" {
  ami           = "${data.aws_ami.ubuntu.id}"
  instance_type = "t2.micro"

  tags = {
    Name = "HelloWorld"
  }
}

通常,您应该依靠此类机制来自动选择最近发布的 AMI 并使用它,而不是在代码中硬编码 AMI ID。


管理图像的生命周期超出了 Packer 本身的范围,它应该被用作更大系统的一部分。如果要回滚图像,则有两个可用选项:

  • 如果您的构建是可重现的,并且问题出在可重现的东西上,那么您可以使用旧代码构建和注册新图像,以便您的最新图像现在与 2 个图像之前的图像相同
  • 取消注册最新图像,以便您在搜索最新图像时重新开始拾取旧图像。这取决于云提供商,但使用 AWS 可以通过编程方式完成,例如通过aws ec2 deregister-image命令行

虽然 Packer 可以自动将图像复制到不同的区域(请参阅ami_regionsAWS)和不同的账户(用于ami_users与其他账户或后处理器共享创建的 AMI 以在不同账户中创建单独的副本),但它无法在没有您的情况下轻松地做有条件的事情对于您想要共享事物的每种方式组合具有不同的 Packer 配置文件,并且无法分离推出,因此您在发布到生产帐户之前发布到非生产帐户等。

如果您想在某些账户和区域(但不是全部)中推出 AMI,那么您需要将该逻辑放在更高的位置,例如 CI/CD 系统等编排机制。


推荐阅读