如何使用 terraform.io 更改有状态服务器的映像而不会造成停机或数据丢失?

如何使用 terraform.io 更改有状态服务器的映像而不会造成停机或数据丢失?

假设我有应用服务器、数据库服务器和一些 dns-round-robin 负载均衡器。所有这些都由使用以下工具创建的图像提供支持:打包机通过部署管理地形. 当实例被销毁并重新创建时,如何更改数据库服务器的映像而不删除其数据?

我能想到的最简单的方法是关闭写入,对数据库进行快照,然后将快照还原到新服务器。但依赖这样的手动操作感觉真的很不对,而且为了简单的升级而关闭服务也感觉不对。有一种更干净、更好的方法,对吧?

答案1

没有简单的回答这个问题。

使用围绕图像设计的架构(通常称为“不可变基础设施”)对于无状态服务(例如应用程序服务器)非常有效。

使用正确的工具、故障转移系统和升级路径绝对可以将其扩展到有状态服务,但对于简单的系统(如您所描述的)来说,这些通常是过度的。

使用这些工具时要记住的一件事是,您不必“全力以赴”。Packer 和 Terraform 的设计非常巧妙,只适合在您需要的地方工作。它们不会故意在您的所有系统中强制执行一种模式。

实际上,处理此问题的最佳方法是以不同的方式维护您的数据库服务器,在 Packer 之外(构建初始映像,是的!但不一定以与无状态 Web 服务器相同的方式升级它们)或将状态管理外包给其他人。值得注意的选项包括 Heroku Postgres 或 AWS RDS。

总而言之,是的,这是可能的,但是使用我们当前的工具,在小规模或简单架构下,它可能会带来更多的麻烦。

Packer 和 Terraform 仍可在同一基础设施的其他方面发挥巨大作用 - 例如,Terraform 可以非常直接地配置 Heroku 数据库供您的 DigitalOcean 应用服务器使用。Packer 可以处理升级和发布您的应用服务器映像,同样适用于开发。

答案2

我认为 Terraform 现在具备了这里所需的功能。基本模式是单独定义数据卷并将其附加到实例,这样当实例被销毁并创建新实例时(例如从 Packer 构建的新 AMI),现有卷可以附加到新实例。

因此,使用 Terraform 的详细步骤如下:

  • 定义aws_ebs_volume资源
  • 将这些附加到您的实例aws_volume_attachment(这里我使用了device_name = "/dev/xvdh"
  • 确保您的aws_ebs_volume资源包括生命周期规则prevent_destroy = true(所以他们会绝不被 terraform 删除)
  • 确保您的aws_volume_attachment资源包括skip_destroy = true(在升级时,terraform 无法在卷已安装时销毁这些,并且停止实例无论如何都会销毁附件,因此 terraform 无需尝试这样做)

最后一步是确保实例在启动时挂载卷。这可以通过在资源中执行以下操作来user_data实现aws_instance

#!/bin/bash
mkdir /data #create mount point
mount /dev/xvdh /data #mount it

为了使上述操作有效,您需要通过创建文件系统来准备卷,但这只需要一次:

mkfs -t ext4 /dev/xvdh

更多详细信息请参阅Terraform 问题 #2740

相关内容