10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Terraform+Amazon Athenaで快適なログ集計の準備をする

Last updated at Posted at 2021-03-27

はじめに

Amazon AthenaはS3に入ったログをSQLで抽出したり集計したりできる超便利機能。
でも、Terraformで一発で作ろうとするとちょっとクセがあるので、整理をしてみた。

Amazon Athenaに必要なリソース

Amazon Athenaに必要なリソースは以下の5つ。

  • ワークグループ
  • データベース
  • テーブル
  • データ
  • SQL

だ。データベースに登録するデータはS3に格納しておく必要がある。

ワークスペース+データベースの作成

これはそんなに難しいことはない。Terraformで普通に定義していこう。

################################################################################
# Athena                                                                       #
################################################################################
resource "aws_athena_workgroup" "example" {
  name = local.athena_workgroup_name

  configuration {
    enforce_workgroup_configuration    = true
    publish_cloudwatch_metrics_enabled = false
    result_configuration {
      output_location = "s3://${aws_s3_bucket.athena_output.id}/"
    }
  }

  force_destroy = true
}

resource "aws_athena_database" "example" {
  name   = local.athena_database_name
  bucket = aws_s3_bucket.athena_output.id

  force_destroy = true
}

resource "aws_s3_bucket" "athena_output" {
  bucket = local.s3_output_bucket_name
  acl    = "private"

  force_destroy = true
}

それぞれのリソースの属性を force_destroy = trueにしているのは、中身が入っていると terraform destroy でエラーが発生するため。壊す必要がない商用のリソース等であれば、付与する必要はない。

テーブルの作成

ここは少し曲者で、Terraform ではテーブルの作成をするSQLを実行することはできない。aws_athena_named_query というリソースはあるが、実行することはできないのと、初回しか実行しないテーブル作成のSQLを保存しておいてもなので、データベース作成時のみ発動する null_resource を活用しよう。

resource "null_resource" "initialize_db" {
  provisioner "local-exec" {
    command = <<-EOF
      aws athena start-query-execution \
        --work-group "${aws_athena_workgroup.example.id}" \
        --query-execution-context Database="${aws_athena_database.example.id}" \
        --query-string "${replace(replace(replace(data.template_file.create_example_table_sql.rendered, "`", "\\`"), "\"", "\\\""), "$", "\\$")}"
    EOF
  }
}

data "template_file" "create_example_table_sql" {
  template = file("../sql/01_create_table.sql")

  vars = {
    athena_database_name = aws_athena_database.example.id
    athena_table_name    = local.athena_table_name
    input_bucket_name    = aws_s3_bucket.athena_input.id
  }
}

resource "aws_s3_bucket" "athena_input" {
  bucket = local.s3_input_bucket_name
  acl    = "private"

  force_destroy = true
}
01_create_table.sql
CREATE EXTERNAL TABLE IF NOT EXISTS ${athena_database_name}.${athena_table_name} (
  `request` STRING,
  `remote_addr` STRING, 
  `time_local` STRING
)
PARTITIONED BY (
  `file_datehour` STRING 
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES (
  "serialization.format" = "1"
)
LOCATION 's3://${input_bucket_name}/${athena_table_name}/'
TBLPROPERTIES (
  'has_encrypted_data'='false',
  'projection.enabled'='true',
  'projection.file_datehour.type'='date',
  'projection.file_datehour.format'='yyyy/MM/dd/HH',
  'projection.file_datehour.range'='2021/02/27/00,NOW',
  'projection.file_datehour.interval'='1',
  'projection.file_datehour.interval.unit'='HOURS',
  'storage.location.template'='s3://${input_bucket_name}/${athena_table_name}/$${file_datehour}'
);

なお、Athena は大量のログを扱う際、スキャンに対して料金がかかるため、テーブルの設計が重要になる。
集計をする単位でパーティショニングしておくことで、ログが有効活用できるようになる。
今回は、FireLens で出力されたログを集計することを前提にしたテーブル構成にしてみた。
※FireLens については、こちらの過去記事を参照。

パーティショニングに関する記述が、SQL の TBLPROPERTIES に書かれた部分だ。file_datehour というキーを定義し、PARTITIONED BY で指定を行い、TBLPROPERTIES で詳細を指定するイメージだ。TBLPROPERTIES の射影の設定については、公式のドキュメントが参考になる。

さて、これでデータを投入すれば準備は完了だ。

SQLの実行

Athena のマネージメントコンソールでワークスペースを切り替え……

キャプチャ1.png

Query editor でSQLを実行!

キャプチャ2.png

やった!結果が得られた!
抽出結果は、local.s3_output_bucket_name で指定したS3バケットにもCSV形式で保存されている。

何度も実行するようなSQLであれば、aws_athena_named_query で保存しておこう。

resource "aws_athena_named_query" "between_term" {
  name      = "between term"
  workgroup = aws_athena_workgroup.example.id
  database  = aws_athena_database.example.name
  query     = "select * from ${aws_athena_database.example.name}.${local.athena_table_name} where file_datehour between '2021/02/27/11' and '2021/02/28/10';"
}

こうしておくと、コンソールから簡単に実行ができる。CLIはちょっと面倒だけど……。

キャプチャ3.png

これで、快適なS3ログ解析生活が送れるようになる!

10
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?