首页 > 解决方案 > terraform destroy 无法删除 postgresql 数据库

问题描述

我的Terraform脚本愉快地创建了一个具有三个数据库的Postgresql实例和一个具有三个部署的Kubernetes集群。它工作得很好。当我运行破坏时,它几乎可以工作,但是在删除其中一个数据库实例时失败

Error: Error reading Database: googleapi: Error 400: Invalid request: Failed to delete database "xyz". Detail: pq: database "xyz" is being accessed by other users. (Please use psql client to delete database that is not owned by "cloudsqlsuperuser")
., invalid

Terraform已经报告说使用该数据库的 k8 pod 已被销毁(实际上所有 pod 都已被销毁),并且没有其他任何东西可以访问该数据库。再次尝试运行 destroy 成功删除了数据库,这表明这里不需要括号中的建议。

我怀疑 pod 的挂起时间比Terraform预期的要长,并且它很快报告了 pod 的破坏。我当然有一些标志来防止吊舱关闭得太快。但是我还没有找到一种方法来延迟或重试Terraform对数据库的销毁处理。

有没有办法做到这一点?

这是创建我的数据库的Terraform,当然,也会破坏它们。

resource "random_id" "db_name_suffix" {
  byte_length = 4
}

data "http" "myip" {
  url = "http://ipv4.icanhazip.com"
}

data "null_data_source" "my_ip_allowed" {
  inputs = {
    name  = "tf"
    value = chomp(data.http.myip.body)
  }
}

resource "google_sql_database_instance" "master" {
  name             = "${var.environment}-sql-${random_id.db_name_suffix.hex}"
  database_version = "POSTGRES_11"
  region           = var.region

  settings {
    tier             = "db-custom-1-3840"
    disk_autoresize  = "true"
    disk_size        = "10"
    disk_type        = "PD_SSD"
    replication_type = "SYNCHRONOUS"
    pricing_plan     = "PER_USE"
    ip_configuration {
      ipv4_enabled    = "true"
      private_network = "projects/${var.project}/global/networks/default"
      require_ssl     = "false"
      authorized_networks {
        name = "creatorIP"
        value = chomp(data.http.myip.body)
      }
    }
  }

  # Generate the DDL scripts that will be used when the databases are created.
  # and change the postgres password  
  provisioner "local-exec" {
    command = "chmod +x ddlsetup.sh && ./ddlsetup.sh ${google_sql_database_instance.master.name} ${var.dbpassword}"
  }
}

resource "google_sql_database" "xyz" {
  name      = "xyz"
  instance  = google_sql_database_instance.master.name
  charset   = "UTF8"
  collation = "en_US.UTF8"
  provisioner "local-exec" {
    command = "psql -h ${google_sql_database_instance.master.public_ip_address} -p 5432 -U postgres -d xyz -f \"/tmp/xyz-postgres.sql\""
    environment = {
      PGPASSWORD = var.dbpassword
    }
  }
}

resource "google_sql_database" "abc" {
  name      = "abc"
  instance  = google_sql_database_instance.master.name
  charset   = "UTF8"
  collation = "en_US.UTF8"

  provisioner "local-exec" {
    command = "psql -h ${google_sql_database_instance.master.public_ip_address} -p 5432 -U postgres -d abc -f \"/tmp/abc-postgres.sql\""
    environment = {
      PGPASSWORD = var.dbpassword
    }
  }
}

resource "google_sql_database" "jkl" {
  name      = "jkl"
  instance  = google_sql_database_instance.master.name
  charset   = "UTF8"
  collation = "en_US.UTF8"
}

output "database_public_ip_address" {
  value = google_sql_database_instance.master.public_ip_address
}

标签: postgresqlterraform

解决方案


我会使用图表来查看执行计划的可视化表示。

terraform graph -type=plan-destroy

输出将采用 DOT 格式,您可以使用GraphViz生成图表并通过以下方式转换为图像dot

terraform graph -type=plan-destroy | dot -Tsvg > graph.svg

在知道这是问题后,我会向您的资源添加依赖项。

# New resource for the S3 bucket our application will use.
resource "aws_s3_bucket" "example" {
  # NOTE: S3 bucket names must be unique across _all_ AWS accounts, so
  # this name must be changed before applying this example to avoid naming
  # conflicts.
  bucket = "terraform-getting-started-guide"
  acl    = "private"
}

# Change the aws_instance we declared earlier to now include "depends_on"
resource "aws_instance" "example" {
  ami           = "ami-2757f631"
  instance_type = "t2.micro"

  # Tells Terraform that this EC2 instance must be created only after the
  # S3 bucket has been created.
  depends_on = [aws_s3_bucket.example]
}

推荐阅读