継続は力なり

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

AWS 構成図を PlantUML で描画できる『AWS-PlantUML』

タダです.

AWS 環境の構成図を書く機会で PowerPointCacoo 等のサービスを使うことがあると思います.作図もコードで制御する方法もないかと思い調べてみたら,「AWS-PlantUML」というツールがありました.今回はこのツールを使って作図する方法と所感を書いていきます.

github.com

AWS-PlantUML」とは

AWS-PlantUML」とは,PlantUML 形式で AWS 構成図を書くためのツールになります.PlantUML の実行環境は調べればたくさん出てきますが,僕は普段 Visual Studio Code(以下,vscode)を使うため vscode で使う環境をセットアップしました.

plantuml.com

github.com

qiita.com

AWS-PlantUML」を導入するか

vscode の環境ができたら「AWS-PlantUML」のセットアップを行います.2つの方法があります.1つ目は,インターネット接続をしたくない場合にcommon.pumlをダウンロードして!include ディレクトリパス/common.pumlpumlファイルで@startumlの後に定義する方法です.

@startuml

!include ディレクトリパス/common.puml

github.com

2つ目は,下記のように直接リポジトリの URL を指定する方法です.今回は2つ目の方法で設定して進みます.

@startuml

!includeurl https://raw.githubusercontent.com/milo-minderbinder/AWS-PlantUML/release/18-2-22/dist/common.puml

!includeurl AWSPUML/common.puml

AWS-PlantUML」の使い方

AWS アイコンの指定方法

それでは,実際に構成図を書いていきます.まず,AWS のサービスアイコンの指定方法は以下のように定義します.!includeurl AWSPUML/までは共通ですが,それ以下のパスはリポジトリ内のdistディレクトリパスで指定します.また,アイコンの指定方法はAWS_SERVICE_NAME_UPPERCASE(puml resource name, display name)のように行います.

!includeurl AWSPUML/ApplicationServices/AmazonAPIGateway/AmazonAPIGateway.puml
!includeurl AWSPUML/Compute/AWSLambda/LambdaFunction/LambdaFunction.puml
!includeurl AWSPUML/Database/AmazonDynamoDB/AmazonDynamoDB.puml
!includeurl AWSPUML/Database/AmazonDynamoDB/table/table.puml

USER(user)
CLIENT(browser)
JAVASCRIPT(js,SDK)

AWSCLOUD(aws) {

    AMAZONS3(s3) {
        BUCKET(site,www.insecurity.co)
        BUCKET(logs,logs.insecurity.co)
    }

    AMAZONAPIGATEWAY(api)

    AWSLAMBDA(lambda) {
        LAMBDAFUNCTION(addComments,addComments)
    }

    AMAZONDYNAMODB(dynamo) {
        TABLE(comments,Comments)
    }
}

参考

https://github.com/milo-minderbinder/AWS-PlantUML/blob/master/dist/ApplicationServices/AmazonAPIGateway/AmazonAPIGateway.puml

  • Lambda アイコンへのパス

https://github.com/milo-minderbinder/AWS-PlantUML/blob/master/dist/Compute/AWSLambda/AWSLambda.puml

  • DynamoDB アイコンへのパス

https://github.com/milo-minderbinder/AWS-PlantUML/blob/master/dist/Database/AmazonDynamoDB/AmazonDynamoDB.puml

サービス間のシーケンス図

サービス間のシーケンス図は下記のような指定で描画できます.例えば,以下の指定だと S3 バケット間の連携を記載できます.

AMAZONS3(s3) {
    BUCKET(site,www.insecurity.co)
    BUCKET(logs,logs.insecurity.co)
}
site .r.> logs : events

f:id:sadayoshi_tada:20191012160248p:plain

その他の記法

その他の記法は,PlantUML の文法を参考に記載できます.

qiita.com

作図コードのサンプル例

コードの参考例として下記のような定義で vscode 上でプレビューして状況を確認できます.

@startuml
!define AWSPUML https://raw.githubusercontent.com/milo-minderbinder/AWS-PlantUML/release/18-2-22/dist

!includeurl AWSPUML/common.puml
!includeurl AWSPUML/ApplicationServices/AmazonAPIGateway/AmazonAPIGateway.puml
!includeurl AWSPUML/Compute/AWSLambda/AWSLambda.puml
!includeurl AWSPUML/Compute/AWSLambda/LambdaFunction/LambdaFunction.puml
!includeurl AWSPUML/Database/AmazonDynamoDB/AmazonDynamoDB.puml
!includeurl AWSPUML/Database/AmazonDynamoDB/table/table.puml
!includeurl AWSPUML/General/AWScloud/AWScloud.puml
!includeurl AWSPUML/General/client/client.puml
!includeurl AWSPUML/General/user/user.puml
!includeurl AWSPUML/SDKs/JavaScript/JavaScript.puml
!includeurl AWSPUML/Storage/AmazonS3/AmazonS3.puml
!includeurl AWSPUML/Storage/AmazonS3/bucket/bucket.puml


skinparam componentArrowColor Black
skinparam componentBackgroundColor White
skinparam nodeBackgroundColor White
skinparam agentBackgroundColor White
skinparam artifactBackgroundColor White


USER(user)
CLIENT(browser)
JAVASCRIPT(js,SDK)

AWSCLOUD(aws) {

    AMAZONS3(s3) {
        BUCKET(site,www.insecurity.co)
        BUCKET(logs,logs.insecurity.co)
    }

    AMAZONAPIGATEWAY(api)

    AWSLAMBDA(lambda) {
        LAMBDAFUNCTION(addComments,addComments)
    }

    AMAZONDYNAMODB(dynamo) {
        TABLE(comments,Comments)
    }
}

user - browser

browser -d-> site :**1a**) get\nstatic\ncontent
site ~> logs :1a
site .u.> browser :**1b**
browser - js
js -r-> comments :**2a**) get\ncomments
comments ..> js :**2b**

js -r-> api :**3**) add\ncomment

api -d-> addComments :**4**

addComments -> comments :**5**

comments ..> js :**6**) new\ncomments
@enduml

プレビュー画面例 f:id:sadayoshi_tada:20191012155049p:plain

構成図をアウトプットする

作図したデータを HTML や PDF ファイルなどに出力する方法も見ておきます.プレビュー画面上で右クリックし,Open in Browserをクリックします.ブラウザで表示後,右クリックし別名で保存をクリックすれば HTML ファイルで保存でき,印刷をクリックして PDF 保存も可能です.

f:id:sadayoshi_tada:20191012155320p:plain

f:id:sadayoshi_tada:20191012155754p:plain

まとめ

PlantUML 形式で AWS 構成図を作図する「AWS-PlantUML」の紹介と,簡単な使い方を紹介しました.手動で細かく描画するよりコードでサービス間のシーケンス図を書けるのは普段の手間を考えると楽ですし,コードで管理できるのでバージョン管理もしていきやすいのではと思いました.AWS のアイコンの中にはまだ対応が追いついていないもの(EKSなど)もあるので,issue出してリクエスト出してよりよくしていくようお願いしていきたいですね!

AWS 謹製のデータ分析モジュール『AWS Data Wrangler』チュートリアルの紹介

タダです.

AWS 謹製の Python データ分析モジュールの「AWS Data Wrangler」がリリースされました.今回は普段 Python を使ってデータ分析の勉強をしているため,「AWS Data Wrangler」を公式ブログチュートリアルを参考に使ってみた所感を書いていきます.

aws.amazon.com

github.com

利用方法はドキュメントで確認していきましょう.

aws-data-wrangler.readthedocs.io

AWS Data Wrangler のメリット

AWS Data Wrangler」のメリットは下記の通りです.

  • AWS Data Wrangler」を利用することで, Athena や S3 の CSV データから Pandas を数行のコードで実現できる
  • PySpark から Redshift に連携できるため利用者は ETL(Extract/Transform/Load) に集中することが可能
    • AWS Data Wrangler」登場前は, ETL 処理にいくまでにサービスへの接続設定,各種コーディング必要だったが ETL 処理に集中していける

最大のメリットは, 利用者は ETL 処理に集中してコーディングを行える ことだと読み取れます.それでは実際に環境を作ってどれくらい簡単かをコーディングして確認していきます.

AWS Data Wrangler を使って ETL を行う

今回の環境は以下の画像の環境で,ブログで紹介された構成です.CSV を S3 に配置し,SageMaker から「AWS Data Wrangler」経由で Athena,S3 の CSVデータにアクセスした後,ETL 処理後の CSV データを S3 に出力するチュートリアルとなっています.

f:id:sadayoshi_tada:20191006114150p:plain 引用元: https://aws.amazon.com/jp/blogs/news/how-to-use-aws-data-wrangler/ シナリオの構成図より

1. S3 への CSV データをアップロード

まず,S3 へ CSV データをアップロードします.データは下記のGreen Taxi Trip Records(CSV) の1月データを使いました.

www1.nyc.gov

ローカルにダウンロードしたデータを S3 にアップロードします.

f:id:sadayoshi_tada:20191006115108p:plain

2. Athena でデータベースおよびテーブルを作成する

Athena でデータベースとテーブルを作成します.

# データベース作成
CREATE DATABASE greentripdata;

#テーブル作成
CREATE EXTERNAL TABLE green_tripdata(
  VendorID string, 
  lpep_pickup_datetime string,
  lpep_dropoff_datetime string,
  store_and_fwd_flag string,
  RatecodeID string,
  PULocationID string,
  DOLocationID string,
  passenger_count int,
  trip_distance double,
  fare_amount double,
  extra double,
  mta_max double,
  tip_amount double,
  tolls_amount double,
  ehail_fee string,
  improvement_surcharge double,
  total_amount double,
  payment_type string,
  trip_type string,
  congestion_surcharge double
  )
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' 
LOCATION 's3://S3バケット名/CSV データ格納ディレクトリ/'; 

そして,後続でも使うためテーブルのデータ数を確認しておきます.630919 件のデータがあることを確認しました.

select count(*) from green_tripdata

f:id:sadayoshi_tada:20191006115522p:plain

3. SageMaker から AWS Data Wrangler 経由で Athena,S3 の CSVデータにアクセスする

SageMaker ノートブックインスタンス起動時に設定する IAM ロールにAmazonS3FullAccessAmazonAthenaFullAccessを付与しておきます.起動後に,「AWS Data Wrangler」モジュールをインストールします.

!pip install awswrangler

Collecting awswrangler
  Downloading https://files.pythonhosted.org/packages/ce/ab/677e5f5aa33584a6bacc15b7eaabea31f5ad7eb4e850a3105f5b73ebc99e/awswrangler-0.0.8.tar.gz
Collecting pyarrow>=0.14.0 (from awswrangler)
  Downloading https://files.pythonhosted.org/packages/c9/ed/e9fda0abcf087e0288ce78f744dffbfc2ac8dfba6f242a8ab025d76bee27/pyarrow-0.15.0-cp36-cp36m-manylinux1_x86_64.whl (60.1MB)
    100% |████████████████████████████████| 60.1MB 815kB/s eta 0:00:01
Collecting pandas>=0.25.1 (from awswrangler)
  Downloading https://files.pythonhosted.org/packages/73/9b/52e228545d14f14bb2a1622e225f38463c8726645165e1cb7dde95bfe6d4/pandas-0.25.1-cp36-cp36m-manylinux1_x86_64.whl (10.5MB)
    100% |████████████████████████████████| 10.5MB 7.8MB/s eta 0:00:01
Requirement already satisfied: botocore>=1.12.239 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from awswrangler) (1.12.239)
Requirement already satisfied: boto3>=1.9.239 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from awswrangler) (1.9.239)
Collecting s3fs>=0.3.4 (from awswrangler)
  Downloading https://files.pythonhosted.org/packages/01/5c/5899c874ac3a00c4b99be983eae22c8a3800c3d5fc3d22f6f1e5058aacf2/s3fs-0.3.4-py3-none-any.whl
Collecting tenacity>=5.1.1 (from awswrangler)
  Downloading https://files.pythonhosted.org/packages/1e/a1/be8c8610f4620c56790965ba2b564dd76d13cbcd7c2ff8f6053ce63027fb/tenacity-5.1.1-py2.py3-none-any.whl
Collecting pg8000>=1.13.2 (from awswrangler)
  Downloading https://files.pythonhosted.org/packages/16/32/ae895597e43bc968e0e3e63860e9932b851115457face0d06d7f451b71fc/pg8000-1.13.2-py3-none-any.whl
Requirement already satisfied: numpy>=1.14 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from pyarrow>=0.14.0->awswrangler) (1.14.3)
Requirement already satisfied: six>=1.0.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from pyarrow>=0.14.0->awswrangler) (1.11.0)
Requirement already satisfied: pytz>=2017.2 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from pandas>=0.25.1->awswrangler) (2018.4)
Requirement already satisfied: python-dateutil>=2.6.1 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from pandas>=0.25.1->awswrangler) (2.7.3)
Requirement already satisfied: urllib3<1.26,>=1.20; python_version >= "3.4" in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from botocore>=1.12.239->awswrangler) (1.23)
Requirement already satisfied: docutils<0.16,>=0.10 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from botocore>=1.12.239->awswrangler) (0.14)
Requirement already satisfied: jmespath<1.0.0,>=0.7.1 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from botocore>=1.12.239->awswrangler) (0.9.4)
Requirement already satisfied: s3transfer<0.3.0,>=0.2.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from boto3>=1.9.239->awswrangler) (0.2.1)
Collecting fsspec>=0.2.2 (from s3fs>=0.3.4->awswrangler)
  Downloading https://files.pythonhosted.org/packages/95/2c/31fce3889ce89ec13e47201c71a0cb6d2ff6e5c7b5fed066fe0ac5c5e22b/fsspec-0.5.1-py3-none-any.whl (56kB)
    100% |████████████████████████████████| 61kB 30.3MB/s ta 0:00:01
Collecting scramp==1.1.0 (from pg8000>=1.13.2->awswrangler)
  Downloading https://files.pythonhosted.org/packages/bb/ef/6bdba6756ba7ccb81187833504ebba0511af750a2d9beaa04e4b56c3974f/scramp-1.1.0-py3-none-any.whl
Building wheels for collected packages: awswrangler
  Running setup.py bdist_wheel for awswrangler ... done
  Stored in directory: /home/ec2-user/.cache/pip/wheels/d9/81/7d/f4e8f56f0d44f17a571fcbe5b90a4ceb6001d6debdf8951be9
Successfully built awswrangler
Installing collected packages: pyarrow, pandas, fsspec, s3fs, tenacity, scramp, pg8000, awswrangler
  Found existing installation: pandas 0.24.2
    Uninstalling pandas-0.24.2:
      Successfully uninstalled pandas-0.24.2
  Found existing installation: s3fs 0.1.5
    Uninstalling s3fs-0.1.5:
      Successfully uninstalled s3fs-0.1.5
Successfully installed awswrangler-0.0.8 fsspec-0.5.1 pandas-0.25.1 pg8000-1.13.2 pyarrow-0.15.0 s3fs-0.3.4 scramp-1.1.0 tenacity-5.1.1
You are using pip version 10.0.1, however version 19.2.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

AWS Data Wrangler」経由で Athena,S3 の CSVデータにアクセスしてデータの件数を確認してみます.2. Athena でデータベースおよびテーブルを作成するで確認したのと同じ630919件であることを確認できました.

import pandas as pd
import awswrangler

session = awswrangler.Session()
df = session.pandas.read_sql_athena(
    sql="select * from green_tripdata",
    database="greentripdata"
)

print(df)

【output】
       vendorid  lpep_pickup_datetime  lpep_dropoff_datetime  \
0       VendorID  lpep_pickup_datetime  lpep_dropoff_datetime   
1              2   2018-12-21 15:17:29    2018-12-21 15:18:57   
2              2   2019-01-01 00:10:16    2019-01-01 00:16:32   
3              2   2019-01-01 00:27:11    2019-01-01 00:31:38   
4              2   2019-01-01 00:46:20    2019-01-01 01:04:54   
...          ...                   ...                    ...   
630914         2   2019-01-31 23:08:27    2019-01-31 23:22:59   
630915         2   2019-01-31 23:21:26    2019-01-31 23:23:05   
630916         2   2019-01-31 23:30:05    2019-01-31 23:36:14   
630917         2   2019-01-31 23:59:58    2019-02-01 00:04:18   
630918         2   2019-01-31 23:18:22    2019-01-31 23:26:06   

        store_and_fwd_flag  ratecodeid  pulocationid  dolocationid  \
0       store_and_fwd_flag  RatecodeID  PULocationID  DOLocationID   
1                        N           1           264           264   
2                        N           1            97            49   
3                        N           1            49           189   
4                        N           1           189            17   
...                    ...         ...           ...           ...   
630914                   N           1           255           226   
630915                   N           1            75           151   
630916                   N           1            75           238   
630917                   N           1            74            74   
630918                   N           1            75           262   

        passenger_count  trip_distance  fare_amount  extra  mta_max  \
0                   NaN            NaN          NaN    NaN      NaN   
1                     5           0.00          3.0    0.5      0.5   
2                     2           0.86          6.0    0.5      0.5   
3                     2           0.66          4.5    0.5      0.5   
4                     2           2.68         13.5    0.5      0.5   
...                 ...            ...          ...    ...      ...   
630914                1           3.33         13.0    0.5      0.5   
630915                1           0.72          4.0    0.5      0.5   
630916                1           1.75          7.0    0.5      0.5   
630917                1           0.57          5.0    0.5      0.5   
630918                1           2.11          8.5    0.5      0.5   

        tip_amount  tolls_amount  ehail_fee  improvement_surcharge  \
0              NaN           NaN  ehail_fee                    NaN   
1             0.00           0.0        NaN                    0.3   
2             0.00           0.0        NaN                    0.3   
3             0.00           0.0        NaN                    0.3   
4             2.96           0.0        NaN                    0.3   
...            ...           ...        ...                    ...   
630914        2.14           0.0        NaN                    0.3   
630915        1.06           0.0        NaN                    0.3   
630916        0.00           0.0        NaN                    0.3   
630917        1.00           0.0        NaN                    0.3   
630918        1.96           0.0        NaN                    0.3   

        total_amount  payment_type  trip_type  congestion_surcharge  
0                NaN  payment_type  trip_type                   NaN  
1               4.30             2          1                   NaN  
2               7.30             2          1                   NaN  
3               5.80             1          1                   NaN  
4              19.71             1          1                   NaN  
...              ...           ...        ...                   ...  
630914         18.39             1          1                   0.0  
630915          6.36             1          1                   0.0  
630916          8.30             1          1                   0.0  
630917          7.30             1          1                   0.0  
630918         11.76             1          1                   0.0  

[630919 rows x 20 columns]

4. ETL 処理の実行

それでは ETL 処理の実行をしていきます.まず,trip_distanceカラムのデータが0の部分を分析対象外として行の削除処理を行います.削除する行は10721行であることを確認できます.

# trip_distanceが0の値を抽出
rows_drop = df.index[df["trip_distance"] == 0.00]
# trip_distanceが0の値の件数を確認
print(df.loc[rows_drop].count())

【output】
vendorid                 10721
lpep_pickup_datetime     10721
lpep_dropoff_datetime    10721
store_and_fwd_flag       10721
ratecodeid               10721
pulocationid             10721
dolocationid             10721
passenger_count          10721
trip_distance            10721
fare_amount              10721
extra                    10721
mta_max                  10721
tip_amount               10721
tolls_amount             10721
ehail_fee                    0
improvement_surcharge    10721
total_amount             10721
payment_type             10721
trip_type                10721
congestion_surcharge      1228
dtype: int64

trip_distanceカラムの0のデータ部分を削除していきます.総データ数が630919から10721行を削除するので,620198件のデータ削除処理しました.

# trip_distanceが0の値を削除
df_drop = df.drop(rows_drop)
print(df_drop)

【output】
        vendorid  lpep_pickup_datetime  lpep_dropoff_datetime  \
0       VendorID  lpep_pickup_datetime  lpep_dropoff_datetime   
2              2   2019-01-01 00:10:16    2019-01-01 00:16:32   
3              2   2019-01-01 00:27:11    2019-01-01 00:31:38   
4              2   2019-01-01 00:46:20    2019-01-01 01:04:54   
5              2   2019-01-01 00:19:06    2019-01-01 00:39:43   
...          ...                   ...                    ...   
630914         2   2019-01-31 23:08:27    2019-01-31 23:22:59   
630915         2   2019-01-31 23:21:26    2019-01-31 23:23:05   
630916         2   2019-01-31 23:30:05    2019-01-31 23:36:14   
630917         2   2019-01-31 23:59:58    2019-02-01 00:04:18   
630918         2   2019-01-31 23:18:22    2019-01-31 23:26:06   

        store_and_fwd_flag  ratecodeid  pulocationid  dolocationid  \
0       store_and_fwd_flag  RatecodeID  PULocationID  DOLocationID   
2                        N           1            97            49   
3                        N           1            49           189   
4                        N           1           189            17   
5                        N           1            82           258   
...                    ...         ...           ...           ...   
630914                   N           1           255           226   
630915                   N           1            75           151   
630916                   N           1            75           238   
630917                   N           1            74            74   
630918                   N           1            75           262   

        passenger_count  trip_distance  fare_amount  extra  mta_max  \
0                   NaN            NaN          NaN    NaN      NaN   
2                     2           0.86          6.0    0.5      0.5   
3                     2           0.66          4.5    0.5      0.5   
4                     2           2.68         13.5    0.5      0.5   
5                     1           4.53         18.0    0.5      0.5   
...                 ...            ...          ...    ...      ...   
630914                1           3.33         13.0    0.5      0.5   
630915                1           0.72          4.0    0.5      0.5   
630916                1           1.75          7.0    0.5      0.5   
630917                1           0.57          5.0    0.5      0.5   
630918                1           2.11          8.5    0.5      0.5   

        tip_amount  tolls_amount  ehail_fee  improvement_surcharge  \
0              NaN           NaN  ehail_fee                    NaN   
2             0.00           0.0        NaN                    0.3   
3             0.00           0.0        NaN                    0.3   
4             2.96           0.0        NaN                    0.3   
5             0.00           0.0        NaN                    0.3   
...            ...           ...        ...                    ...   
630914        2.14           0.0        NaN                    0.3   
630915        1.06           0.0        NaN                    0.3   
630916        0.00           0.0        NaN                    0.3   
630917        1.00           0.0        NaN                    0.3   
630918        1.96           0.0        NaN                    0.3   

        total_amount  payment_type  trip_type  congestion_surcharge  
0                NaN  payment_type  trip_type                   NaN  
2               7.30             2          1                   NaN  
3               5.80             1          1                   NaN  
4              19.71             1          1                   NaN  
5              19.30             2          1                   NaN  
...              ...           ...        ...                   ...  
630914         18.39             1          1                   0.0  
630915          6.36             1          1                   0.0  
630916          8.30             1          1                   0.0  
630917          7.30             1          1                   0.0  
630918         11.76             1          1                   0.0  

[620198 rows x 20 columns]

# trip_distanceが0の値の件数を確認
df_lens = df_drop.count()
print(df_lens)

【output】
vendorid                 620198
lpep_pickup_datetime     620198
lpep_dropoff_datetime    620198
store_and_fwd_flag       620198
ratecodeid               620198
pulocationid             620198
dolocationid             620198
passenger_count          620197
trip_distance            620197
fare_amount              620197
extra                    620197
mta_max                  620197
tip_amount               620197
tolls_amount             620197
ehail_fee                     1
improvement_surcharge    620197
total_amount             620197
payment_type             620198
trip_type                620198
congestion_surcharge      83310
dtype: int64

不要データを削除したものに対してデータ内のカラムの置き換えを行います.payment_typeという項目に対してデータの置き換えを行います.データの置き換えしたことで一部のみの表示ですがCredit cardに置き換わっていることを確認しました.

df_replace = df_drop.replace(
    {'payment_type': 
        {
            '1': 'Credit card', 
            '2': 'Cash', 
            '3': 'No charge', 
            '4': 'Dispute', 
            '5': 'Unknown', 
            '6': 'Voided trip'
        }
    }
)

print(df_replace['payment_type'])

【output】
0         payment_type
2                 Cash
3          Credit card
4          Credit card
5                 Cash
              ...     
630914     Credit card
630915     Credit card
630916     Credit card
630917     Credit card
630918     Credit card
Name: payment_type, Length: 620198, dtype: object

5. ETL 後のデータを別の CSV ファイルにして S3 に出力する

ETL 後のデータを別の CSV ファイルにして S3 に出力します.replace_csvフォルダに CSV データを出力します.S3 に2件のデータが出力されていることを確認しました.

session.pandas.to_csv(
    dataframe=df_replace,
    path="s3://xxxx/replace_csv/",
    sep=",",
    database=None,
    table=None,
    partition_cols=None,
    preserve_index=True, 
    mode='append',
    procs_cpu_bound=None, 
    procs_io_bound=None
)

【output】
['s3://xxxx/replace_csv/c379726f1d6d4b1b939fd64c730f059d.csv',
 's3://xxxxreplace_csv/febc156980ec4a0ea23a640558a3a596.csv']

f:id:sadayoshi_tada:20191006122354p:plain

出力後のデータの件数が行削除後のデータ件数かも確認します.620198のデータ件数であることを確認できました.一緒ですね.

df2 = session.pandas.read_sql_athena(
    sql="select * from green_tripdata_replace",
    database="greentripdata"
)

print(df2)

【output】
      vendorid lpep_pickup_datetime  lpep_dropoff_datetime  \
0       "315602"                  "2"  "2019-01-16 17:12:12"   
1       "315603"                  "2"  "2019-01-16 17:05:29"   
2       "315604"                  "2"  "2019-01-16 17:30:44"   
3       "315605"                  "2"  "2019-01-16 17:09:35"   
4       "315606"                  "2"  "2019-01-16 17:37:14"   
...          ...                  ...                    ...   
620193  "315597"                  "2"  "2019-01-16 18:00:02"   
620194  "315598"                  "2"  "2019-01-16 17:08:57"   
620195  "315599"                  "2"  "2019-01-16 17:29:20"   
620196  "315600"                  "2"  "2019-01-16 17:24:21"   
620197  "315601"                  "2"  "2019-01-16 18:01:00"   

           store_and_fwd_flag ratecodeid pulocationid dolocationid  \
0       "2019-01-16 17:28:05"        "N"          "1"         "74"   
1       "2019-01-16 17:13:48"        "N"          "1"         "95"   
2       "2019-01-16 17:44:44"        "N"          "5"        "134"   
3       "2019-01-16 17:16:01"        "N"          "1"        "130"   
4       "2019-01-16 17:46:56"        "N"          "1"        "130"   
...                       ...        ...          ...          ...   
620193  "2019-01-16 18:15:39"        "N"          "1"        "182"   
620194  "2019-01-16 17:17:41"        "N"          "1"         "75"   
620195  "2019-01-16 17:33:48"        "N"          "1"         "75"   
620196  "2019-01-16 17:56:35"        "N"          "1"         "97"   
620197  "2019-01-16 18:43:47"        "N"          "1"         "97"   

        passenger_count  trip_distance  fare_amount  extra  mta_max  \
0                   NaN            NaN          NaN    NaN      NaN   
1                   NaN            NaN          NaN    NaN      NaN   
2                   NaN            NaN          NaN    NaN      NaN   
3                   NaN            NaN          NaN    NaN      NaN   
4                   NaN            NaN          NaN    NaN      NaN   
...                 ...            ...          ...    ...      ...   
620193              NaN            NaN          NaN    NaN      NaN   
620194              NaN            NaN          NaN    NaN      NaN   
620195              NaN            NaN          NaN    NaN      NaN   
620196              NaN            NaN          NaN    NaN      NaN   
620197              NaN            NaN          NaN    NaN      NaN   

        tip_amount  tolls_amount ehail_fee  improvement_surcharge  \
0              NaN           NaN     "0.0"                    NaN   
1              NaN           NaN     "0.0"                    NaN   
2              NaN           NaN     "0.0"                    NaN   
3              NaN           NaN     "0.0"                    NaN   
4              NaN           NaN     "0.0"                    NaN   
...            ...           ...       ...                    ...   
620193         NaN           NaN     "0.0"                    NaN   
620194         NaN           NaN     "0.0"                    NaN   
620195         NaN           NaN     "0.0"                    NaN   
620196         NaN           NaN     "0.0"                    NaN   
620197         NaN           NaN     "0.0"                    NaN   

        total_amount payment_type      trip_type  congestion_surcharge  
0                NaN      "16.62"  "Credit card"                   NaN  
1                NaN        "9.8"         "Cash"                   NaN  
2                NaN      "18.02"  "Credit card"                   NaN  
3                NaN       "9.36"  "Credit card"                   NaN  
4                NaN      "11.16"  "Credit card"                   NaN  
...              ...          ...            ...                   ...  
620193           NaN       "15.3"  "Credit card"                   NaN  
620194           NaN        "9.8"         "Cash"                   NaN  
620195           NaN       "8.76"  "Credit card"                   NaN  
620196           NaN       "23.3"  "Credit card"                   NaN  
620197           NaN       "34.8"         "Cash"                   NaN  

[620198 rows x 20 columns]

まとめ

リリースされた Python データ分析モジュールの「AWS Data Wrangler」のチュートリアルを行なってみました.Pandas で CSV を読み書きするときに JupyterNotebook の実行環境のローカルに配置して処理していましたが,S3 や Athena に接続設定などを書かずにローカルに ETL 処理対象があるかのようにデータを扱えた印象でした.本モジュールのメリットにあるように ETL 処理に集中していくことが可能なのかと感じます.AWS のデータ解析のエコシステムを作るときに登場してくる存在として今後のアップデートに注目していきたいですし,採用も検討していきたいですね!

GUI 頼りを卒業するための AWS CLI コマンド集

タダです.

みなさんは普段 AWS マネジメントコンソールをよく見ますか? GUI は直感的ですぐに状態確認もできて便利なのですが, GUI に頼っていると時間がない時や何度も見るページならすぐに確認できる術を知っておくと運用時にメリットが大きいはずです.

そこで, AWS CLI です.AWS CLI であればターミナルから AWS の情報を取得可能です.この記事では頻繁に使うコマンド,運用時に使って便利だと感じたコマンドを随時サービス別に整理して GUI に依存した対応を少なくしていくことを目的にしたいと考えています.

AWS CLI 共通のコマンド

コマンドのパラメーター例の生成

aws ec2 run-instances --generate-cli-skeleton

ただし,--generate-cli-skeleton--cli-input-json パラメータを使用できるものに限定されます.

docs.aws.amazon.com

EC2 のコマンド

AMI ID を取得する

# Linux
## Amazon Linux2
aws ssm get-parameters --names "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" --region ap-northeast-1 --query "Parameters[0].[Value]"
## Amazon Linux
aws ssm get-parameters --names "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" --region ap-northeast-1 --query "Parameters[0].[Value]"

## Ubuntu
aws ec2 describe-images --owners 099720109477 --filters 'Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-????????' 'Name=state,Values=available' --output json | jq -r '.Images | sort_by(.CreationDate) | last(.[]).ImageId'

## REHL
aws ec2 describe-images --owners 309956199498 --filters 'Name=name,Values=RHEL-8*' 'Name=state,Values=available' --output json | jq -r '.Images | sort_by(.CreationDate) | last(.[]).ImageId'

## SUSE
aws ec2 describe-images --owners amazon --filters 'Name=name,Values=suse-sles-15-v????????-hvm-ssd-x86_64' 'Name=state,Values=available' --output json | jq -r '.Images | sort_by(.CreationDate) | last(.[]).ImageId'

# Windows
aws ssm get-parameters-by-path --path "/aws/service/ami-windows-latest" --region ap-northeast-1 --query 'Parameters[0].[Value]

Linux AMI の検索 docs.aws.amazon.com

Windows AMIの検索 docs.aws.amazon.com

EC2 インスタンスの状態確認

以下のコマンド例は,特定の Availability Zone の EC2 のステータスを確認するコマンドです.

aws ec2 describe-instance-status --filters Name=availability-zone,Values=<Availability Zone 名> Name=instance-status.status,Values=<状態>

EBSの状態確認

aws ec2 describe-volumes --filters Name=availability-zone,Values=<Availability Zone 名>

Availability Zone の状態確認

aws ec2 describe-availability-zones

リージョン全取得してソートする

aws ec2 describe-regions | jq -r '.Regions[] | .RegionName' | sort)

RDS に関するコマンド

RDS インスタンスの状態確認

aws rds describe-db-instances --query 'DBInstances[?AvailabilityZone==`<Availability Zone 名>`].{Name:DBInstanceIdentifier,Status:DBInstanceStatus}'

ELB に関するコマンド

1時間毎のUnHealthyHostCountの平均数を出すためのコマンド

aws cloudwatch get-metric-statistics --namespace AWS/ApplicationELB \
--metric-name UnHealthyHostCount --statistics Average  --period 3600 \
--dimensions Name=LoadBalancer,Value=app/xxxx/xxxxxxxxx \
--start-time YYYY-MM-DDTHH:MM:SSZ --end-time YYYY-MM-DDTHH:MM:SSZ 

特定日におけるリクエストの総数を1時間毎に収集する

aws cloudwatch get-metric-statistics --namespace AWS/ApplicationELB \
--metric-name RequestCount --statistics Sum --period 3600 \
--dimensions Name=LoadBalancer,Value=app/xxxx/xxxxxxxx \
--start-time YYYY-MM-DDTHH:MM:SSZ --end-time YYYY-MM-DDTHH:MM:SSZ \
--query "sort_by(Datapoints,&Timestamp)[?Sum>\`0\`][Sum,Timestamp]" --output text

特定日における 5XX系のエラー総数を1時間毎に収集する

aws cloudwatch get-metric-statistics --namespace AWS/ApplicationELB \
--metric-name HTTPCode_ELB_5XX_Count --statistics Sum --period 3600 \
--dimensions Name=LoadBalancer,Value=app/xxxx/xxxxxxxx \
--start-time YYYY-MM-DDTHH:MM:SSZ --end-time YYYY-MM-DDTHH:MM:SSZ \
--query "sort_by(Datapoints,&Timestamp)[?Sum>\`0\`][Sum,Timestamp]" --output text

CloudWatch に関するコマンド

メトリクス情報を取得する

aws cloudwatch list-metrics --namespace <名前空間>

STS に関するコマンド

エラーメッセージのデコード

aws sts decode-authorization-message --encoded-message <エラー文>

AWS アカウント ID の取得

# デフォルト
aws sts get-caller-identity | jq -r '.Account'

# --profile をつけると profile 定義したアカウント ID を取れる
aws sts get-caller-identity --profile <profile名> | jq -r '.Account'

AssumeRole を使う

aws sts assume-role --role-arn <AssumeRole の ARN> --role-session-name <AssumeRole のセッション名>

まとめ

運用時に使っているコマンドをまとめました.新たに追加するコマンドがあれば追加していきます.AWS CLI コマンドに寄せることでシェルと組み合わせて自動化や GUI で確認しづらい情報も確認しやすくなると思います.GUI 依存をできるだけなくして効率的な運用を検討していきましょう

Mac で Matplotlib のグラフが描画できない問題の対処方法

タダです.

現在,ベータ版である Pyhon3 エンジニア検定データ分析試験を受験するために指定書籍で勉強を進めています.自前の Mac で環境構築し勉強中に Matplotlib のグラフが描画できない問題が起こり,その問題に対処したので対応内容をまとめます.

なお,環境は以下になります.Python の実行環境は venv の仮想環境で作っていました.

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.6
BuildVersion:   18G95
$ python -V
Python 3.6.8
$ cat requirements.txt
~中略~
matplotlib==2.2.2

問題の事象

Matplotlib の次のコードを作ったので実行してみたところエラーがでました.

import matplotlib.pyplot as plt

x = [1,2,3]
y = [2,4,9]

plt.plot(x,y)
plt.title('Test-Graph')
plt.show()

エラー文の内容が以下のようなものでした.Python as a framework on Mac OS X. Please either reinstall Python as a framework, or try one of the other backends. If you are using 1 import matplotlib.pyplot as plt と記載があるため,Matplotlib の backend に関する指定が怪しそうという推測をしました.

$ python dev-matplotlib.py
Traceback (most recent call last):
  File "dev-matplotlib.py", line 1, in <module>
    import matplotlib.pyplot as plt
  File "/xxxx/xxxx/pydataenv/lib/python3.6/site-packages/matplotlib/pyplot.py", line 115, in <module>
    _backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup()
  File "/xxxx/xxxx/pydataenv/lib/python3.6/site-packages/matplotlib/backends/__init__.py", line 62, in pylab_setup
  1 Provides a MATLAB-like plotting framework.
    [backend_name], 0)
  File "/xxxx/xxxx/pydataenv/lib/python3.6/site-packages/matplotlib/backends/backend_macosx.py", line 17, in <module>
    from matplotlib.backends import _macosx
RuntimeError: Python is not installed as a framework. The Mac OS X backend will not be able to function correctly if Python is not installed as a framework. See the Python documentation for more information on installing Python as a framework on Mac OS X. Please either reinstall Python as a framework, or try one of the other backends. If you are using   1 import matplotlib.pyplot as plt

変更前の設定の確認

Matplotlib の設定ファイルの場所を確認してみると,最初は仮想環境のsite-packagesディレクトリ配下に指定となっており,確認してみたところbackendの指定はmacosxとなっていました.ググると,site-packagesディレクトリ配下をいじるのはよくない対応という記述を見つけたため ~/.matplotlib/matplotlibrcを変更して対応します.

$ python -c "import matplotlib;print(matplotlib.matplotlib_fname())"
/xxxx/xxxx/pydataenv/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc
$ cat /xxxx/xxxx/pydataenv/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc | grep backend
~中略~
backend      : macosx

設定変更方法について

設定変更は簡単です. 以下のように対応してみて再度グラフを描画することができました.

$ echo "MacOSX" >  ~/.matplotlib/matplotlibrc
$ cat  ~/.matplotlib/matplotlibrc
backend : MacOSX

再描画 f:id:sadayoshi_tada:20190922000907p:plain

Matplotlib のbackend 設定

余談ですが, Matplotlib のbackend設定はいくつかオプションがあります.今回設定した MacOSX グラフを描画できなかったので最初は設定自体が誤りかと思ったのですが,設定ファイルの場所が変えることで動作することを確認できたので設定値として適切です.利用方法に合わせてbackendを設定していきましょう.

Select the backend used for rendering and GUI integration.
Parameters
----------
backend : str
    The backend to switch to.  This can either be one of the standard
    backend names, which are case-insensitive:
    - interactive backends:
      GTK3Agg, GTK3Cairo, MacOSX, nbAgg,
      Qt4Agg, Qt4Cairo, Qt5Agg, Qt5Cairo,
      TkAgg, TkCairo, WebAgg, WX, WXAgg, WXCairo
    - non-interactive backends:
      agg, cairo, pdf, pgf, ps, svg, template
    or a string of the form: ``module://my.module.name.

参考URL

matplotlib.org

[https://github.com/matplotlib/matplotlib/blob/98507c076c29fea1a70711f4dc7df32cdd7ec3c7/lib/matplotlib/init.py#L1207-L1241:embed:cite]

まとめ

Mac の Matplotlib のグラフ描画できない問題への対処方法をまとめました.同じ問題に遭遇した方の何か参考になれば幸いです!

IAM の棚卸しで活用すべき「認証情報レポート」の紹介

タダです.

アカウントの運用で IAM ユーザーのパスワードがポリシーに反して変更されてないか や MFA 有効化しなければならないのに有効化されないで放置されている等定期的に棚卸ししているかと思います.

今回はIAM ユーザーの棚卸しに役立つ, IAM の「認証情報レポート」という機能を紹介します.

AWSドキュメント

docs.aws.amazon.com

認証情報レポートとは

認証情報レポート」とは IAM ユーザーの各種認証情報 (パスワード,アクセスキー,MFA デバイスなど) の設定状況をレポートとして出力してくれる機能です.レポートは4時間ごとに1回生成されているので,最新のレポートでは過去4時間以内のレポートを利用者は入手可能です.

レポートの項目

認証情報レポート」の項目がどのようになっているかですが,次の項目があります.

カラム名 説明
user ユーザー名
arn IAMユーザーのARN
user_creation_time ユーザーが作成された日時 (ISO 8601 日付/時刻形式)
password_enabled ユーザーがパスワードを持っている場合TRUE
それ以外の場合はFALSE
AWS アカウントのルートユーザーはnot_supported
password_last_used ルートユーザーまたは IAM ユーザーのパスワードを使用して最後に AWS ウェブサイトにサインインした日時
password_last_changed ユーザーのパスワードが最後に設定された日時
ユーザーがパスワードを所有していない場合,N/A (該当なし)
ルートユーザーはnot_supported
password_next_rotation パスワードの更新を必要とするパスワードポリシーがある場合,新しいパスワードを設定するためのユーザーに求める日時
ルートユーザーはnot_supported
mfa_active MFA が有効な場合,TRUE
無効な場合,FALSE
access_key_1_active ユーザーがアクセスキーを所有しアクセスキーのステータスが Activeである場合TRUE
それ以外の場合はFALSE
access_key_1_last_rotated アクセスキーが作成または最後に変更された日時
アクセスキーを所有していない場合N/A
access_key_1_last_used_date AWS API リクエストにユーザーのアクセスキーが使用されたときの ISO 8601 日付/時刻形式の日付と時刻
access_key_1_last_used_region アクセスキーが使用されたリージョン
access_key_1_last_used_service アクセスキーを使用して最近アクセスされた AWS サービス
access_key_2_active ユーザーが 2 つ目のアクセスキーを所有し,その 2 つ目のキーのステータスがActiveである場合TRUE
それ以外の場合FALSE
access_key_2_last_rotated ユーザーの 2 つ目のアクセスキーが作成または最後に変更された日時
access_key_2_last_used_date AWS API リクエストにユーザーの 2 つ目のアクセスキーが直近に使用されたときの ISO 8601 日付/時刻形式の日付と時刻
access_key_2_last_used_region ユーザーの 2 つ目のアクセスキーが直近に使用されたリージョン
access_key_2_last_used_service ユーザーの 2 つ目のアクセスキーを使用して最近アクセスされた AWS サービス
cert_1_active ユーザーが X.509 署名証明書を所有しその証明書のステータスがActiveである場合TRUE
それ以外の場合FALSE
cert_1_last_rotated ユーザーの署名証明書が作成または最後に変更された日時
cert_2_active ユーザーが2つ目の X.509 署名証明書を所有しその証明書のステータスがActiveである場合TRUE
それ以外の場合FALSE
cert_2_last_rotated ユーザーの2つ目の署名証明書が作成または最後に変更された日時

AWSドキュメント

docs.aws.amazon.com

認証情報レポート生成方法

前提として以下の権限がレポートの生成に必要です.

  • 認証情報レポートを作成生成する : GenerateCredentialReport
  • レポートをダウンロードする : GetCredentialReport

AWS マネジメントコンソールから生成方法

マネジメントコンソールからの生成方法は以下の通りです.

1, IAMの画面より「認証情報レポート」 を選択します.

f:id:sadayoshi_tada:20190918231623p:plain

2, 「レポートをダウンロード」 を選択すると,「status_reports_YYYY-MM-DD THH-MM-DD+SS-SS(ISO 8601 日付/時刻形式).csv」ファイルがダウンロードされます.

f:id:sadayoshi_tada:20190918231659p:plain

まとめ

IAM の「認証情報レポート」の概要とレポートの項目,その生成方法をまとめました.IAM は AWS の権限管理の基盤となりますので,組織の運用方針に沿った管理ができているかを定期的に確認する材料として活かせるレポートです.運用で IAM ユーザーを棚卸する必要がある場合,「認証情報レポート」の利用を検討してみていかがでしょうか?

なお,レポートに関係するパスワードポリシーは IAM のメニューの「アカウント設定」より確認可能です.

AWS ドキュメント docs.aws.amazon.com