我使用terraform配置运行docker-compose堆栈的GCE实例。docker-compose堆栈引用带有标签的图像,并且我希望能够docker-compose up
在标签更改时重新运行,以便可以运行该服务的新版本。当前,我在terraform文件中执行以下操作:
provisioner "file" {
source = "training-server/docker-compose.yml"
destination = "/home/curry/docker-compose.yml"
connection {
type = "ssh"
user = "curry"
host = google_compute_address.training-address.address
private_key = file(var.private_key_file)
}
}
provisioner "remote-exec" {
inline = [
"IMAGE_ID=${var.image_id} docker-compose -f /home/curry/docker-compose.yml up -d"
]
connection {
type = "ssh"
user = "root"
host = google_compute_address.training-address.address
private_key = file(var.private_key_file)
}
}
但这是有各种原因的错误:
image_id
更改不会被terraform视为配置更改,那么它将不会运行预配器我想要的是将我的应用程序堆栈视为一种资源,以便当其属性之一发生更改时。的image_id
,资源被重建,但VM实例本身是没有的。
我如何用terraform做到这一点?还是有另一种更好的方法?
Terraform有一个Docker提供程序,如果您想使用Terraform来管理您的容器堆栈,那可能是正确的工具。但是,使用它实质上需要将您的Compose文件转换为Terraform语法。
我更习惯于使用Terraform来管理基础结构的拆分–例如,设置EC2实例及其网络设置–但使用诸如Ansible,Chef或Salt Stack之类的另一种工具在其上实际运行软件。然后,要更新软件(Docker容器),您需要更新配置管理工具的设置,以说出所需的版本(Docker映像标签),然后重新运行该版本。
一种可能有用的技巧是使用null资源,只要图像ID发生更改,该资源便可以让您“重新配置资源”:
resource "null_resource" "docker_compose" {
triggers = {
image_id = "${var.image_id}"
}
provisioner "remote_exec" {
...
}
}
如果您想沿用所有Terraform路线,理论上您可以编写Terraform配置,例如
provider "docker" {
host = "ssh://root@${google_compute_address.training-address.address}"
# (where do its credentials come from?)
}
resource "docker_image" "myapp" {
name = "myapp:${var.image_id}"
}
resource "docker_container" "myapp" {
name = "myapp"
image = "${docker_image.myapp.latest}"
}
但是您必须将整个Docker Compose配置转换为这种语法,并进行设置,以便开发人员可以选择在本地运行它,并复制诸如default
网络的Compose功能,等等。我不认为这通常是在实践中完成的。
非常感谢null_resource技巧,这很有趣。我同意分开配置和配置可能会更好,但是我感到将这两个区域分开的界限越来越模糊。在这种情况下,配置实际上是使用一个参数进行的单个操作(当然,堆栈很简单),因此沿ansible / chef / puppet / XXX路线走似乎过头了。许多“配置”已在基础映像中完成。也许我应该在某个时候重新考虑我的方法。
在最新版本的terraform(v0.12.20)中,可以改写image_id = var.image_id,但这绝对可以解决问题!非常感谢@ david-maze。