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

假设我有应用程序服务器,数据库服务器和一些dns-round-robin负载平衡器。 所有这些function都是使用Packer创build的,使用Terraform进行部署pipe理。 当实例被破坏并重新创build时,如何更改数据库服务器的映像而不损坏其数据?

我能想到的最简单的事情就是closures写入,快照数据库,然后将快照还原到新服务器。 但是依靠这样的手动摆弄感觉真的是错误的,并且为了简单的升级而放弃服务也是不对的。 有一个更清洁,更好的方法,对吧?

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

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

通过正确的工具,故障转移系统和升级path,将其扩展到有状态的服务是绝对有可能的,但是对于简单的系统来说,这些通常是过度的(就像你所描述的那样)。

使用这些工具时要牢记的一点是,你不必“全身而退”。 Packer和Terraform的devise非常独特,只能在你想要的地方工作。 他们不会故意在所有的系统上执行一个模式。

实际上,解决这个问题的最好方法是在Packer之外维护你的数据库服务器(build立初始映像,是的!但是不一定像无状态的web服务器那样升级它们)或者把状态外包给某个人其他。 值得注意的选项包括Heroku Postgres或AWS RDS。

为了整理它 – 是的,这是可能的,但是对于我们现有的工具来说,可能更麻烦,那么它在小规模或者简单的架构上是值得的。

Packer和Terraform在同样的基础设施的其他方面仍然是一个巨大的利益 – 例如,Terraform可以以非常简单的方式为您的DigitalOcean应用程序服务器提供一个Heroku数据库。 Packer可以处理升级和释放应用程序服务器映像,同样适用于开发。

我认为Terraform现在具有这里所需的function。 基本模式是分别定义数据卷并将其附加到实例,以便在实例被销毁并创build新实例(例如,由Packer构build的新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来尝试)

最后一步是确保实例在启动时加载卷。 在aws_instance资源的user_data中可以通过以下方式实现:

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

为了上面的工作,你需要通过创build一个文件系统来准备卷,但是这只需要一次:

 mkfs -t ext4 /dev/xvdh 

更多细节可在Terraform问题#2740中find 。