使用Terraform将AWS Athena配置为使用Glue目录作为数据库。

10
我不确定如何使用terraform将Athena连接到我的Glue目录数据库。
我使用{{...}}。
resource "aws_glue_catalog_database" "catalog_database" {
    name = "${var.glue_db_name}"
}

resource "aws_glue_crawler" "datalake_crawler" {
    database_name = "${var.glue_db_name}"
    name          = "${var.crawler_name}"
    role          = "${aws_iam_role.crawler_iam_role.name}"
    description   = "${var.crawler_description}"
    table_prefix  = "${var.table_prefix}"
    schedule      = "${var.schedule}" 

    s3_target {
      path = "s3://${var.data_bucket_name[0]}"
  }
    s3_target {
      path = "s3://${var.data_bucket_name[1]}"
  }
 }

为了创建一个Glue DB和爬虫来爬取s3存储桶(这里只有两个),但我不知道如何将Athena查询服务连接到Glue DB。在Athena的terraform文档中,似乎没有一种方法将Athena连接到Glue目录,而只能连接到S3存储桶。然而,显然Athena可以与Glue集成
我该如何使用我的Glue目录作为数据源,而不是S3存储桶,来terraform Athena数据库?

1
你运行了爬虫吗?它创建了 AWS Glue 表格吗?如果你没有使用 Terraform 定义指向各自 S3 位置的 aws_glue_catalog_table 资源,那么爬虫至少需要运行一次来创建这些表格。一旦它们被创建,你的 Glue 数据库和表格应该在 Athena 中可见,即使没有定义 Terraform 的 aws_athena_database 资源。 - Martin
我已经运行了爬虫。在Glue数据库中没有创建任何表。说实话,我甚至不知道是否给予了爬虫正确的角色/策略:我创建了一个包含我正在使用的代码的gist:https://gist.github.com/stevenranney/3f5545e1e736266807b1f337e0be58e0 - Steven
我建议在问题中也添加标签“terraform”(或“terraform-aws”)。 - Martin
2个回答

6

我们目前的基本设置是让 Glue 爬取一个 S3 存储桶并在 Glue 数据库中创建/更新一张表,然后可以在 Athena 中查询,如下所示:

爬虫角色和角色策略:

  • IAM 角色的 assume_role_policy 只需将 Glue 作为主体
  • IAM 角色策略允许 Glue、S3 和日志的操作
  • Glue 的操作和资源可能可以缩小到真正需要的范围
  • S3 的操作仅限于爬虫所需的操作
resource "aws_iam_role" "glue_crawler_role" {
  name = "analytics_glue_crawler_role"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "glue.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "glue_crawler_role_policy" {
  name = "analytics_glue_crawler_role_policy"
  role = "${aws_iam_role.glue_crawler_role.id}"
  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "glue:*",
      ],
      "Resource": [
        "*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetBucketLocation",
        "s3:ListBucket",
        "s3:GetBucketAcl",
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": [
        "arn:aws:s3:::analytics-product-data",
        "arn:aws:s3:::analytics-product-data/*",
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": [
        "arn:aws:logs:*:*:/aws-glue/*"
      ]
    }
  ]
}
EOF
}

S3 Bucket(简称S3存储桶)、Glue数据库和Crawler:

resource "aws_s3_bucket" "product_bucket" {
  bucket = "analytics-product-data"
  acl = "private"
}

resource "aws_glue_catalog_database" "analytics_db" {
  name = "inventory-analytics-db"
}

resource "aws_glue_crawler" "product_crawler" {
  database_name = "${aws_glue_catalog_database.analytics_db.name}"
  name = "analytics-product-crawler"
  role = "${aws_iam_role.glue_crawler_role.arn}"

  schedule = "cron(0 0 * * ? *)"

  configuration = "{\"Version\": 1.0, \"CrawlerOutput\": { \"Partitions\": { \"AddOrUpdateBehavior\": \"InheritFromTable\" }, \"Tables\": {\"AddOrUpdateBehavior\": \"MergeNewColumns\" } } }"

  schema_change_policy {
    delete_behavior = "DELETE_FROM_DATABASE"
  }

  s3_target {
    path = "s3://${aws_s3_bucket.product_bucket.bucket}/products"
  }
}

1
我发现Glue爬虫在发现分区方面非常有用。它可以合理地发现模式,但我发现我花了很多时间更改爬虫并纠正它们发现的模式,因此我倾向于仅在需要时使用它们一次来发现分区。 - Davos
1
感谢您的评论@Davos。那绝对是正确的。我们确实已经开始使用Terraform aws_glue_catalog_table资源来定义我们的模式。通过使用Athena查询,也可以在没有爬虫的情况下添加分区:ALTER TABLE <table> ADD IF NOT EXISTS PARTITON (<partition attribute/value pairs here>) LOCATION <S3 path here>; 对于一些简单的情况(每天一个分区),我们会在午夜前不久运行Lambda执行此类查询,为第二天添加一个新分区。 - Martin
我在其他地方读到过这样的建议,就是提前创建很多分区;Athena支持每个表20000个分区,你可以一次性创建100个。Lambda也是一个不错的选择。 - Davos
1
使用AWS Glue目录,每个表的最大分区数实际上是1000万,AWS帐户中所有Glue数据库中的所有表的最大分区数为2000万。 Athena目录的最大值曾经是20000。https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html#limits_glue - Martin
哦,感谢您纠正错误并提供文档参考。1000万似乎需要“真正的大数据”才能达到那种极端程度,而不是我经常看到的“额外中等大小”的数据。另一方面,Bigquery仅允许4000,这是不够的https://cloud.google.com/bigquery/quotas#partitioned_tables。 - Davos

0

我的 Terraform 代码有很多问题。首先:

  1. aws_athena_database 代码中的 S3 bucket 参数是指查询输出的存储桶,而不是表应该构建的数据所在的存储桶。
  2. 我已经设置了我的 aws_glue_crawler 写入到 Glue 数据库而不是 Athena 数据库。确实,正如 Martin 上面建议的那样,一旦正确设置,Athena 就能够看到 Glue 数据库中的表。
  3. 我的爬虫没有正确的策略附加。最初,爬虫角色唯一附加的策略是:

    resource "aws_iam_role_policy_attachment" "crawler_attach" {
        policy_arn = "arn:aws:iam::aws:policy/service-role/AWSGlueServiceRole"
        role = "${aws_iam_role.crawler_iam_role.name}"
    } 
    

    在设置了第二个策略并明确允许所有想要爬取的存储桶的所有 S3 访问权限,并将该策略附加到同一个爬虫角色后,爬虫成功运行并更新了表。

第二个政策:
resource "aws_iam_policy" "crawler_bucket_policy" {
    name = "crawler_bucket_policy"
    path = "/"
    description = "Gives crawler access to buckets"
    policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1553807998309",
      "Action": "*",
      "Effect": "Allow",
      "Resource": "*"
    },
    {
      "Sid": "Stmt1553808056033",
      "Action": "s3:*",
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::bucket0"
    },
    {
      "Sid": "Stmt1553808078743",
      "Action": "s3:*",
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::bucket1"
    },
    {
      "Sid": "Stmt1553808099644",
      "Action": "s3:*",
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::bucket2"
    },
    {
      "Sid": "Stmt1553808114975",
      "Action": "s3:*",
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::bucket3"
    },
    {
      "Sid": "Stmt1553808128211",
      "Action": "s3:*",
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::bucket4"
    }
  ]
}
EOF
}

我相信我可以避免在此策略中硬编码存储桶名称,但我还不知道如何做到这一点。


1
crawler_bucket_policy有一个声明,允许在资源“”上执行动作“”,这似乎非常开放,真的有必要吗?我们当前的设置(我将在下面列出)除了s3操作外,还允许在资源“*”上执行动作“glue:*”。 - Martin
我建议升级到Glue目录,它可以自动与Athena集成,而且Athena目录已被弃用。我同意@Martin的评论,关于wide open policy(广泛开放政策)并不安全。另外,“Resource”可以是一个bucket列表,这样你就可以避免在其中包含太多语句了。通常对于策略,数据源aws_iam_policy_document效果很好,因为它是HCL语法,然后你可以将其json输出作为aws_iam_role_policy资源中的policy属性。然后,很容易将bucket列表作为变量传递,而无需进行json编码和其他奇怪操作。 - Davos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接