継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

『AWS Copilot CLI』 v0.4.0 で追加された機能を整理する

タダです.

AWS Copilot CLI」がv0.4.0が9/22にリリースされました.この記事でv0.4.0のリリースノートを参照してどのような機能が追加されたかを整理しておきます.

リリースノート github.com

1. パイプラインの手動承認をサポート

pipeline.ymlrequires_approval: trueを追加することで CodePipeline 内での手動承認処理をサポートしました.CodePipeline 自体には手動承認機能はあったので Copilot がそれに対応した形ですね.

docs.aws.amazon.com

2. タスク ID によるサービスのログフィルタリングをサポート

copilot svc logs のパラメータに --tasks が追加され,次のように特定のタスク ID を指定すればログのフィルタリングができるようになりました.

copilot svc logs --tasks 709c7eae05f947f6861b150372ddc443,1de57fd63c6a4920ac416d02add891b9

3. AutoScaling に対応

これは待望の機能じゃないでしょうか,AutoScaling の対応がされました! Copilot のマニフェストファイルで次のように count 以降にて定義することでサービスにおいて実行させたいマシン数をスケールさせることが可能です.

count:
  range: 1-10  # Specify a range for how many tasks you'd like to run in your service.
  cpu_percentage: 70     # To scale on average CPU.
  memory_percentage: 80  # Or, to scale on average Memory.

4. svc status 実行時に AutoScaling のアラームを表示

copilot svc status 実行時に AutoScaling のアラームを表示するようになりました.

5. Git リポジトリに Dockerfile がない場合の補助機能

Git リポジトリ内に Dockerfile が特定できない場合にそのパスを要求する補助が追加されました.

6. ELB スティッキーセッションへの対応

マニフェストファイルで http セクション配下に stickiness: true を追加することでスティッキーセッションが有効化できるようになりました.これまで手動対応だったところがマニフェストファイルで管理できるようになりました.

まとめ

AWS Copilot CLI」のv0.3.0で追加された機能やアップデートを整理しました.今後もツールのリリースに追随していきどんなことができるのかを把握していきたいと思います.「AWS Copilot CLI」のことを気になっている人の参考になれば嬉しいです.

関連記事

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

【Athena の躓きシリーズ】Athena で MySQL の UNIXTIME を扱うクエリを変換した時にハマったこと

タダです.

業務で MySQL で扱っていたクエリをAthena で使えるように変換しながら利用者のサポートしていて UNIXTIME の扱いでハマったので Athena でどのように対応したかをメモとしてまとめておきます.

1, UNIXTIME を JST に変換して使いたいケースのクエリ

SQL で下記のように UNIXTIME を JST 変換してYYYY-MM-DD形式で扱うクエリがありました.このままでは,Athena では扱えないのでエラーがでてしまうので,これを Athena 用に変換して利用可能に対応しました.なお,hogetime は UNIXTIME 形式でレコードで登録されているデータになります.

SELECT 
~中略~
date_format(min(FROM_UNIXTIME(hogetime/1000 + 9 * 3600)), "%Y-%m-%d") hoge_date
~中略~

結論として下記の変換を行ってます.FROM_UNIXTIME の位置を外側に持っていき,min関数の変換後に UNIXTIME タイムスタンプ変換で MySQL と同様にクエリの結果を得られるようにしました.

SELECT 
~中略~
date_format(FROM_UNIXTIME(min(hogetime/1000 + 9 * 3600)), '%Y-%m-%d') as hoge_date
~中略~

2, 現在の日付から1ヶ月先の日付を計算するケースのクエリ

次は,1ヶ月先のレコードを WHERE 句で扱いたい場合に対処した時の話です.between 以降で直近1ヶ月間のデータを扱うのですが,MySQL ではクエリ内で変数をセットしたりできましたが,Athena では変数のセットがサポートされてないようでエラーが出たので,この仕様も含んで対応しました.なお,hogetime は UNIXTIME 形式でレコードで登録されているデータになります.

SELECT 
~中略~
WHERE                                                           
~中略~                                                        
    and hogetime between @start_day - (30 * @end_day) and  @start_day
~中略~

結果として次のクエリにしました.

SELECT 
~中略~
WHERE                                                           
~中略~                                                        
    and from_unixtime(hogetime/1000)  <= (current_timestamp - interval '28' day)
~中略~

まず,比較演算子の左部分は先の1の問題に対応するために使った形式で UNIXTIME のデータを扱うよう変更しました.次に,Presto で何日後や何ヶ月後の計算にintervalを使うことで実現できるのでcurrent_timestamp関数と合わせて使って timestamp 形式で比較できるように対応して期待したクエリ結果を得られるようになりました.

prestodb.io

まとめ

Athena で MySQL の UNIXTIME を扱うクエリを変換対応した時のハマったポイントを整理しました.ネットで検索して Athena の UNIXTIME を扱う情報が日本語で見当たらなかったので今回記事にしました.同じ事象に当たった方の参考情報になれば嬉しいです.

関連記事

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

【Athena の躓きシリーズ】Athena 専用ユーザーを払い出してクエリを叩けるまでにハマったこと

タダです.

業務でいろんな部署の人に Athena の実行ユーザーを提供して分析業務を行ってもらっているのですが,そのために IAM ポリシーと Athena 側での設定でハマったことをまとめておきます.

IAM ポリシーでハマったこと

分析業務は AthenaとS3, KMS で暗号化しているのでそのあたりを気をつけて IAM ポリシーを検証しました.なお,デフォルトユーザーには ReadOnlyAccess が権限が振られており,データは Aurora からエクスポートしたデータなので KMS が暗号化されています.

sadayoshi-tada.hatenablog.com

ベースポリシーを AmazonAthenaFullAccess を参考に使って検証した時に,primary ワークグループへのアクセス権限が不足しているメッセージが出力されました.調べていくとドキュメントにあるように特定のワークグループを指定する必要がありました.また,Aurora でエクスポートしたデータの暗号化しているのを復号化しなきゃいけなかったので KMS の権限も足す必要がありました.

AmazonAthenaFullAccess の IAM ポリシー

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "athena:*"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "glue:CreateDatabase",
                "glue:DeleteDatabase",
                "glue:GetDatabase",
                "glue:GetDatabases",
                "glue:UpdateDatabase",
                "glue:CreateTable",
                "glue:DeleteTable",
                "glue:BatchDeleteTable",
                "glue:UpdateTable",
                "glue:GetTable",
                "glue:GetTables",
                "glue:BatchCreatePartition",
                "glue:CreatePartition",
                "glue:DeletePartition",
                "glue:BatchDeletePartition",
                "glue:UpdatePartition",
                "glue:GetPartition",
                "glue:GetPartitions",
                "glue:BatchGetPartition"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads",
                "s3:ListMultipartUploadParts",
                "s3:AbortMultipartUpload",
                "s3:CreateBucket",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::aws-athena-query-results-*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::athena-examples*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation",
                "s3:ListAllMyBuckets"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "sns:ListTopics",
                "sns:GetTopicAttributes"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudwatch:PutMetricAlarm",
                "cloudwatch:DescribeAlarms",
                "cloudwatch:DeleteAlarms"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "lakeformation:GetDataAccess"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

ワークグループの指定と KMS の復号化に関する権限を足して,Athena 専用ユーザーのポリシーを次のように作り,クエリは叩けるようになりました.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "athena:List*",
        "athena:Get*"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "athena:StartQueryExecution",
        "athena:GetQueryResults",
        "athena:DeleteNamedQuery",
        "athena:GetNamedQuery",
        "athena:ListQueryExecutions",
        "athena:StopQueryExecution",
        "athena:GetQueryResultsStream",
        "athena:ListNamedQueries",
        "athena:CreateNamedQuery",
        "athena:GetQueryExecution",
        "athena:BatchGetNamedQuery",
        "athena:BatchGetQueryExecution",
        "athena:GetWorkGroup"
      ],
      "Resource": [
        "arn:aws:athena:ap-northeast-1:XXXXXXXXXXX:workgroup/primary" <= ワークグループの ARN
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetBucketLocation",
        "s3:GetObject",
        "s3:ListBucket",
        "s3:ListBucketMultipartUploads",
        "s3:ListMultipartUploadParts",
        "s3:AbortMultipartUpload",
        "s3:PutObject"
      ],
      "Resource": [
        "arn:aws:s3:::XXXX",  <= Athena のクエリをログ格納場所
        "arn:aws:s3:::XXXX/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::XXXX/*" <= Athena のクエリをかける場所
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket",
        "s3:GetBucketLocation",
        "s3:ListAllMyBuckets"
      ],
      "Resource": [
        "*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "kms:DescribeKey",
        "kms:GenerateDataKey",
        "kms:Decrypt"
      ],
      "Resource": [
        "arn:aws:kms:ap-northeast-1:XXXXXXXXXXX:key/XXXX" <= Aurora データエクスポート で使った KMSARN
      ]
    }
  ]
}

Athena の設定でハマったこと

IAM ポリシーが検証できたことで,Athena を叩けるぞと思って専用ユーザーを払い出して担当者にクエリを叩いてもらったら下記のエラーがでてきました.

Your query has the following error(s):
No output location provided. An output location is required either through the Workgroup result configuration setting or as an API input. (Service: AmazonAthena; Status Code: 400; Error Code: InvalidRequestException; Request ID: XXXX)

これは Athena をマネジメントコンソールで叩くために必要な設定としてクエリ結果の保存場所を指定できてなかったためのエラーでした.クエリの結果保存場所の指定は Athena コンソールを使用して、クライアント側の設定クエリ結果の場所を指定ワークグループを使用したクエリ結果の場所の指定 の2パターンが用意されているため,Athena の利用方法に合わせて設定をしていきます.利用するユーザーが少ないのであれば,コンソールから都度指定したり,多数のユーザーが特定のワークグループだけしか使わない場合はワークグループに設定してしまうのが良いのかと思います.

クエリを実行する前に、Amazon S3 でクエリ結果バケットの場所を指定するか、バケットが指定されており、設定がクライアント設定を上書きするワークグループを使用する必要があります。クエリ結果の場所が指定されていない場合、クエリはエラーで失敗します。

現在は、アカウントが以前に Athena を使用していないリージョンで Athena クエリを実行する前に、クエリ結果の場所を指定するか、クエリ結果の場所の設定を上書きするワークグループを使用する必要があります。Athena はデフォルトのクエリ結果の場所を作成しなくなりましたが、以前に作成したデフォルトの aws-athena-query-results-MyAcctID-MyRegion の場所は有効なままであり、引き続き使用できます。

docs.aws.amazon.com

まとめ

Athena でクエリを叩くまでにハマったことを2点まとめました.分析業務で Athena を利用するケースはあると思いますのでこの情報が何か参考になれば幸いです.

S3 に保存したデータを BigQuery に読み込ませるための方法を検証した

タダです.

最近業務で BigQuery を触り始めたのですが,メインのシステムが AWS 上にありデータが S3 に保存されています.BigQuery で分析するためには S3 にあるデータを GCP 側に持っていく必要があり,その方法を検証したので備忘録としてこの記事でまとめていきます.

S3 から BigQuery にデータを投入する選択肢

S3 のデータを BigQuery にデータを投入する方法はいくつかあります.検証したのが Cloud Storage と BigQuery Data Transfer Service だったのですが,それぞれの検証所感を整理します.

  • Cloud Storage からデータの読み込み
  • ローカルからデータの読み込み
  • Google Drive からデータの読み込み
  • BigQuery Data Transfer Service で S3 のデータを投入する

Cloud Storage と BigQuery Data Transfer Service を使ってみての所感

Cloud Storage

まず,Cloud Storage ですが,対象のファイルをアップロードしておき BigQuery のテーブルデータに読み込ませる形式です.ワンショットの読み込みであればこのサービスを使って読み込みで良いと思いますが,例えば日次で更新が必要な場合仕組み化しないと運用が辛くなってくる印象でした.その点は次の BigQuery Data Transfer Service が特化していると言えると思います.

関連ドキュメント

cloud.google.com

BigQuery Data Transfer Service

次に BigQuery Data Transfer Service は S3 から BigQuery へのデータ読み込みをスケジューリングが可能です.この方式を使う際には前提として S3 のデータを読み取る権限(AmazonS3ReadOnlyAccess など)を有する IAM ユーザーとそのアクセスキー,シークレットアクセスキーが必要です.また,S3 の URI が必要で オブジェクトでもバケットレベルでも正規表現*も指定できます.

この機能を使うことで定期的な BigQuery のテーブル更新も簡単になるのはメリットである一方画像にあるようにベータ版の機能であるようです.IAM ユーザーの管理対象が増えます.また,転送が失敗した時の通知もメール通知がサポートされていますが,転送状況を監視できるようにしたいとなった場合には転送の仕組みは AWS で作り,Cloud Storage 経由で BigQuery にデータを読み込ませる、カヤックさんの開発されている bqinが選択肢になりうるのかなと思います.

f:id:sadayoshi_tada:20200915052656p:plain

関連ドキュメント

cloud.google.com

まとめ

簡単ではありますが,S3 から BigQuery にデータを投入する方法で検証した機能と所感を整理しました.自分たちが運用しやすい形で選択肢を検討していければと思います.

Aurora MySQL のスナップショットから特定テーブルデータを S3 にエクスポートする

タダです.

前回の記事で Aurora MySQL 互換のデータを SELECT INTO OUTFILE S3 を発行して S3 にエクスポートする情報を整理しました.今回は下記のドキュメントに沿って Aurora のスナップショットから特定テーブルデータをApache Parquet 形式で圧縮して S3 にエクスポートする検証した結果をまとめます.

関連ドキュメント docs.aws.amazon.com

機能の概要

本機能の特徴として Apache Parquet 形式で S3 に出力することで Athena や Redshift などのサービスで直接分析を行うことができることに加え,エクスポートは DB への影響を与えないことがあります.エクスポート処理がバックグラウンドで行われるので稼働している DB インスタンスへの影響を与えないので,業務システムで使っている DB からデータを抜きたいけど,本番のワークロードに影響を与えないでってことになるとこの手法が活きます.

エクスポートプロセスはバックグラウンドで実行されるため、アクティブな DB インスタンスのパフォーマンスには影響しません。

また,CLIAPI もあるので定期的に分析データが閲覧したい場合自動スナップショット取得と組み合わせた自動化の検討もしていけると思います.

準備

さて,エクスポートの準備としてS3 バケットへの書き込みを Aurora サービスに許可するための IAM ロールを作成しておきます.IAM ポリシーとロール,エクスポートのサービス信頼関係を下記のように作っていきます.

IAM ポリシー

{
     "Version": "2012-10-17",
     "Statement": [
         {
             "Effect": "Allow",
             "Action": [
                 "s3:ListBucket",
                 "s3:GetBucketLocation"
             ],
             "Resource": [
                 "arn:aws:s3:::*"
             ]
         },
         {
             "Effect": "Allow",
             "Action": [
                 "s3:PutObject*",
                 "s3:GetObject*",
                 "s3:DeleteObject*"
             ],
             "Resource": [
                 "arn:aws:s3:::[バケット名]",
                 "arn:aws:s3:::[バケット名]/*"
             ]
         }
     ]
}

信頼関係ポリシー

{
     "Version": "2012-10-17",
     "Statement": [
       {
         "Effect": "Allow",
         "Principal": {
            "Service": "export.rds.amazonaws.com"
          },
         "Action": "sts:AssumeRole"
       }
     ] 
   }

スナップショットデータのエクスポート

スナップショットは手動または自動で取得しているものをベースにしてデータエクスポートを行います.エクスポートするデータはスナップショットにある全てのデータか,特定のスキーマまたはテーブル単位でエクスポートできます.今回は特定のテーブルデータを出力するパターンを検証していきます.

まず,エクスポートする対象スナップショットを選択して,Amazon S3 へのエクスポートを選択します.

f:id:sadayoshi_tada:20200910080903p:plain

エクスポートに関する設定をしていきます.エクスポートの一意識別子,エクスポートするテーブルの指定を行います.テーブルの指定はスキーマ名.テーブル名で複数指定する場合はカンマ区切りで記載します.今回は前回の記事同様にテストデータをエクスポートします.

f:id:sadayoshi_tada:20200910081126p:plain f:id:sadayoshi_tada:20200910081140p:plain

続いて,エクスポート先の S3 バケットプレフィックス,準備で作った IAM ロールの指定,暗号化で使用する カスタマー管理型の KMS キーを指定します.エクスポートのパスは指定のプレフィックス/エクスポート識別子/スキーマ名/スキーマ名.テーブル名といった構成で作成されます.ここまでの設定が整えば Amazon S3 へのエクスポートを開始します.

f:id:sadayoshi_tada:20200910081755p:plain f:id:sadayoshi_tada:20200910081816p:plain f:id:sadayoshi_tada:20200910081830p:plain

エクスポートはデータサイズによって完了までの時間が異なります.自分の検証では 1GB に満たないデータでしたが,エクスポートが完了したのが約40分ほどでした.そのため,大量のデータをエクスポートする場合は時間に余裕を見ておくと良いと思います.完了すると下記の画像のような状態になります.

f:id:sadayoshi_tada:20200910082436p:plain

パスを辿っていくと,Parquet 形式のファイルが GZIP で圧縮された出力されていることを確認できました.以上でスナップショットからの特定データテーブルエクスポートは完了です. f:id:sadayoshi_tada:20200910082516p:plain

SELECT INTO OUTFILE S3 との使い分けの検討

スナップショットのエクスポートとSELECT INTO OUTFILE S3をそれぞれ使ってみて個人的な使い分けを考えてみました.状況に応じて使い分けをしていければと思います.

  • スナップショットのエクスポートの使い時
    • DB への負荷を気にせずにエクスポートしたい場合
    • 分析するソースファイルが Apache Parquet 形式で事足りる場合
  • SELECT INTO OUTFILE S3の使い時
    • エクスポートするデータサイズからクエリ発行したとしても DB への負荷が低い想定の場合
    • 分析するソースファイルがテキストファイルでも事足りるし,適宜ファイル形式の変換処理も組み込める場合

まとめ

Aurora MySQL のスナップショットから特定テーブルデータを S3 にエクスポートする検証をおこなったのでその整理を行いました.本番ワークロードの DB からデータをエクスポートしたくて,かつスナップショットも存在する場合はこの手法を検討余地があるかと思います.

関連記事

sadayoshi-tada.hatenablog.com