- 投稿日:2020-04-05T22:48:46+09:00
ローカル(Docker)でDynamoDBの環境構築
概要
- DynamoDBをローカル環境でテストするためのDockerを用いたDynamoDB localについて解説します
- AWS CLIの設定などはすでに済んでいる前提なので、もしまだの場合ドキュメントを見てください
- Dockerの基礎的な知識とDockerの設定などはすでに済んでいる前提なので、もしまだの場合ドキュメントを見てください
- 対象読者はサクッとDynamoDBをローカルで試してみたいと考えている方です
- この記事はdynamodb-localを参考にしています
DynamoDB localとは
DynamoDB localは開発者が自身の開発環境で動作しているDynamoDBのバージョンを用いて開発・テストできるように作成されダウンロードが可能にされたもの
DynamoDB localの利点
- DynamoDB localの新しいDockerイメージでは、全てのDynamoDB localの依存関係とそれに必要な構成要素を組み込んだDockerイメージを用いることで、DynamoDB localを素早く開始することができる
- DynamoDB localの新しいDockerイメージでは、コンテナ化されたビルドに継続的な統合テストの一部としてDynamoD localを含めることができる
- DynamoDB localを使うためにインターネット接続は不要で、DynamoDB localは既存のDynamoDB APIで呼び出すことが出来る
- DynamoDB localではプロビジョニングされたスループット、データストレージ、データ転送のコストがない
DynamoDB localのイメージをプル
$ docker pull amazon/dynamodb-local立ち上げ
ただ立ち上げるだけ
$ docker run -p 8000:8000 amazon/dynamodb-local
- ローカルの8000番ポートで立ち上げるだけ
Ctr+C
で止めることが出来る- 止めたあとは
$ docker rm #{CONTAINER_NAME}
で削除
$ docker ps -a
で起動&停止中のコンテナを確認できる- コンテナを消すとデータは消える
--rm
オプションをつけると、Ctr+C
で停止すると削除する必要なく自動で消える-d
オプションをつけるとバックグランドで実行してくれる
- この場合、停止するために
$ docker stop #{CONTAINER_NAME}
を実行する必要があるローカルにデータをマウント(ボリューム)して立ち上げ
$ docker run -p 8000:8000 -v #{LOCAL_DYRECTORY}:/home/dynamodblocal/data amazon/dynamodb-local -jar DynamoDBLocal.jar -dbPath /home/dynamodblocal/data
- #{LOCAL_DYRECTORY}にはdb情報を保存しておきたいディレクトリ名を指定
-d
オプションと--rm
オプションについては上記同様適宜--rm
オプションをつけなければ、停止(docker stop
)させておきさえすれば、いつでも呼び出し(docker start
)できる- #{LOCAL_DYRECTORY}ディレクトリに
#{ACCESS_KEY}_#{REGION}.db
ファイルが作成されたことを確認する- コンテナ名(#{CONTAINER_NAME})を命名したいときは
--name
オプションを利用して--name #{CONTAINER_NAME}
を追加
- こうしておけばいちいち
$ docker ps -a
でコンテナ名を調べなくても$ docker stop #{CONTAINER_NAME}
や$ docker start #{CONTAINER_NAME}
を実行できる確認
$ aws dynamodb list-tables --endpoint-url http://localhost:8000
- 上記コマンド(AWS CLI)で以下のようなテーブル情報が出てくれば接続ができている
{ "TableNames": [] }
- 投稿日:2020-04-05T22:36:52+09:00
Amazon API Gateway/ALBのバックエンドで動くLambda関数をJava(Eclipse+maven)で実装する
前提条件
初心者向け。Lambdaは知ってるけどWeb APIどうやって実装するんだろう、といったところから。
先に結論を書いておくと、Web APIなLambda関数をJavaで実装するのは非常に燃費が悪い感があるのでオススメできない。制約が無い限りは、node.jsとかpythonとかを使った方が断然楽だと思った。
※トラブルシューティングの面でも、Javaとその他のスクリプト言語では情報量が全然違うというか、その他のスクリプト言語ってたぶんJavaほどトラブらない気がする……一応、環境はWindows10+Eclipse+Mavenなので、環境構築からする場合はこの辺の過去記事を見つつセットアップすると導入が早い。
あと、JDKは8か11にしておく。Lambdaは2020年4月時点ではまだJDK13のランタイムに対応していないのである。
サンプルプロジェクトからJarファイルを作成する
Eclipseのメニューで、ファイル→新規→プロジェクトのダイアログで、AWS Lambda Java Projectを選択。
プロジェクト名やMaven configurationは適当に決めて、Lambda Function Handlerの入力タイプでCustomを選択して完了ボタンを押すと、Lambda関数のサンプルプロジェクトが作られる。
サンプルプロジェクトにはJUnitのテストコードの雛形も入っているので便利!Web APIを実装する場合はこのカスタムハンドラをいじっていくのが手っ取り早いっぽい。
ハンドラの詳細な紹介は以下。
【AWS公式】AWS Lambda における Java 関数ハンドラーの提供インターフェイスの使用
RequestHandlerのインプットとアウトプットを作り込んでいけば良い。↑のハンドラのサンプルをベースにコードを書いたらプロジェクトを右クリックして、
- Maven clean
- Maven install
する。分かりにくいのでキャプチャを貼っておくと、↓こんな感じ。
基本はこれでtargetフォルダ配下にjarファイルができてアップロードして動かせるはずなのだけど、この後の工程で
ClassNotFoundException
が出て上手くいかない場合は、以下を参考にしながらmaven-shade-pluginを使ったパッケージ作成を行う(キャプチャの「Mavenビルド...」のダイアログで、ゴールをpackage shade:shade
指定する)。【AWS公式】Java Lambda 関数を使用した「ClassNotFoundException」エラーのトラブルシューティング方法を教えてください。
【AWS公式】Eclipse を使用した .jar デプロイパッケージの作成AWS SAM Localは必要か?
SAM Localは、ローカル環境でLambda関数を実行したり、DynamoDBに接続したりできるもの。
今回くらいのお試しだと、SAM Localの起動時間のオーバーヘッドの方が大きいので素直にアップロードしてテスト入力してみる方が早いけど、単体試験で回帰テストやるつもりならあっても良いかも。それとてJUnitでも良い気はするけど……参考は↓ここ。
【Developers.IO】[新ツール]AWS SAMをローカル環境で実行できるSAM Localがベータリリース
でも罠があって、npmでインストールできるSAM Localはバージョンが古くて、Java11のランタイムに対応していない。Java11ランタイムで動かしたいのであれば、SAM CLIを使う。
Docker Toolboxでインストールしたsam.exeのパスと、↑の手順でインストールしたsam.cmdのパスが違うので、設定を変えておくのを忘れないように。先にインストールしたからか、自分の環境ではDocker Toolboxのパスが優先されてしまうようだ。
Eclipseのメニューのウィンドウ→設定でダイアログを開き、AWSツールキット→AWS SAM Localでパスを設定できる。前節に書いたClassNotFoundExceptionはここでも起きるので、出た場合は↑のmaven-shade-pluginを試してみる。
また、ローカルのDockerサーバに接続できないようなエラーが出る場合は、環境変数の設定が必要かもしれない。この辺を試しているときには色々なエラーが出ていて、何が効果があったのかが良く分からなくなってしまった。↓参考までに環境変数に関する説明。
【MAGELLAN Dev Center】Docker Toolbox の使い方
Lambda関数の作成
さて、ここまでくればあとは普通にLambda関数を作るだけ。
「一から作成」で、ランタイムをJava8か11か使っている方にして、適切なロール(S3とCloudWatchLogsにアクセスできるもの)を設定する。
↑で作成したMavenのパッケージであればzipする必要はないので、そのままS3にアップロードして、「Amazon S3からのファイルのアップロード」でJarファイルのURLを貼り付ける。
ハンドラは、サンプルそのままであるならcom.amazonaws.lambda.demo.LambdaFunctionHandler::handleRequest
を設定する。
[ファイルパス][ハンドラのクラスファイル名]::[ハンドラ]
な感じだ。適当にテストを流して、期待した結果が得られたならファーストステップはクリアだ!
Amazon API Gateway/ALBのバックエンドで動かす
で、ここからが問題。
どうやらAPI GatewayもALBも、定型のJSONをレスポンスしないと、Lambdaプロキシを通せなかったり、ALBのヘルスチェックでエラーになってしまう。
テストを通ったとしても、Web APIとしては実用できないのである。【AWS公式】API ゲートウェイの「不正な Lambda プロキシ応答」エラー、または 502 ステータスコードを解決するにはどうすればよいですか?
【AWS公式】ターゲットとしての Lambda 関数どちらにも書いてあるように、↓こんな感じのJSONである。
{ "isBase64Encoded": true|false, "statusCode": httpStatusCode, "headers": { "headerName": "headerValue", ... }, "body": "..." }しかもこれ、Lambda関数が良い感じにBodyだけ取り出しちゃったりするので、LambdaのテストやSAM Localじゃデバッグできない。API Gatewayの方は適当にPOJOのResponseオブジェクトを作ってみたら動いたが、ALBの方はよりstrictにチェックするらしく、皆目見当もつかない。
こんなのどうしたらええねん……と思って調べてみると、↓こんな記事が。
【cloudpack.media】JavaでLambda関数を書いてSAMでデプロイしてみた今回はこれを参考に動かしてみて、Amazon API Gateway/ALBのどちらでも動作することが確認できた。
さて、次回からは応用編。このアプリケーションでALB+LambdaのCI/CDパイプラインを作ってみよう。
その他
文字コードに関するwarningがうるさいときに
- 投稿日:2020-04-05T20:50:44+09:00
EC2について
EC2とは
インスタンス単位で任意のAZにインスタンスを立ち上げてサーバーとして利用できるサービス
特長
・柔軟性が高い(短時間で使いたいサーバーを立てることができる)
・世界中のリージョンから選択できる
・セキュリティグループでトラフィックの制御できる
・AMIを使うことで同じサーバーをいくつも起動できるインスタンス作成の流れ
- OSイメージの選択
- インスタンスタイプの選択
- ストレージの選択
- セキュリティグループの設定
- SSHキーペアの選択
OSイメージの選択
以下のOSから選択可能
・AMI(AWSが提供)
・Windows
・Mac
・Linux
・カスタムAMI(自作)※データはS3内に保存される
インスタンスタイプの選択
タイプの項目のt2,t3はファミリー(種類)と世代(バージョン)とを表しており、後半は大きさを表す。
下に行けば行くほどスペックが良いがその分値段も上がるので用途に適したタイプを選択することが大切また、インスタンスの細かい設定もできる。
インスタンスの詳細設定の項目で重要度が高いであろう設定項目は以下である。※VPCのについては別途記事書きます
・終了保護の有効化
→本番環境で誤ってインスタンスを終了させないため
・モニタリング
→CloudWatchのモニタリングを有効にすることによってインスタンスの状況を可視可できる・AMIの設定
頻繁に使用するコマンドまたは各インスタンスに共通のソフト(Apache等)を入れたい時に
AMIを設定することによってインスタンスを立ち上げた際に設定したコマンドを実行してくれる。
※別途記事作成予定ストレージの選択
ストレージの種類と容量を選択できる
種類には画像の3パターンある
・汎用SSD(gp2)
→小〜中規模のDB。仮想デスクトップ等・プロビジョンド IOPS SSD(io1)
→高いI/O性能を必要とするもの。大規模DB等・マグネティック(standard)
→旧世代ボリューム。基本は使用しないセキュリティグループの設定
初期表示ではSSH接続が許可されており、SSHでログインするにはキーペアが必要になる
また、特定の通信を許可したい場合はセキュリティグループに接続方法とIPアドレスの範囲を指定したルールを追加するSSHキーペアの選択
インスタンスの接続に必要になるキーペアを設定する
無くさないようにしっかり管理することが大切※インスタンスのログイン・SSHのBASHコマンド操作については別途記事作成予定
関連サービスリンク
・VPC
・データベース各種
・CloudWatch
・AutoScalling
・セキュリティグループなどなど
- 投稿日:2020-04-05T20:28:31+09:00
[Python] Headless Chrome を AWS Lambda で動かす
- serverless-chromeをダウンロードして解凍
- 以下の
chromium 64.0.3282.167
で動作確認した- https://github.com/adieuadieu/serverless-chrome/releases/tag/v1.0.0-37
chromedriverをダウンロードして解凍
- 以下の
chromedriver_linux64.zip
で動作確認した- https://chromedriver.storage.googleapis.com/index.html?path=2.37/
実行権限付与
chmod 777 <ダウンロードしたファイル>
chrome
フォルダにダウンロードしたファイルを入れて、zipに固めるLambdaレイヤーにzipをアップロード
Lambdaレイヤーにseleniumをアップロード
Lambda関数に上記2つのレイヤーを追加
以下のようなコードで実行できる
from selenium import webdriver from selenium.webdriver.chrome.options import Options def lambda_handler(event, context): options = Options() options.binary_location = '/opt/chrome/headless-chromium' options.add_argument('--headless') options.add_argument('--no-sandbox') options.add_argument('--single-process') options.add_argument('--disable-dev-shm-usage') browser = webdriver.Chrome('/opt/chrome/chromedriver', chrome_options=options) browser.get('https://www.google.com') title = browser.title browser.close() browser.quit() return {"title": title}参考
https://blog.ikedaosushi.com/entry/2018/12/22/231421
https://qiita.com/nabehide/items/754eb7b7e9fff9a1047d環境
macOS 10.15.4
Python 3.7.7
- 投稿日:2020-04-05T20:03:45+09:00
PycharmでAWS CLIのプロファイルを切り替える
概要
Pycharm + AWS Toolkitで開発をしている時に、別アカウントの環境(CLIでプロファイル設定済み)に切り替えたいことがありました。ソースに変更を加えずに環境を切り替えたかったのですが、環境変数を設定するやり方が楽だったので紹介します。
方法
Edit Configurations > Environment variables から設定します。
日本語化してる人は、「構成の編集 > 環境変数」です。
設定する環境変数は以下の2つです。それぞれに利用したいプロファイル名を設定します。
AWS_DEFAULT_PROFILE AWS_PROFILEこれで、ソースの実行時に環境変数で設定したプロファイルが利用されます。
余談
Pycharmの画面右下にプロファイルが表示されていますが、これをクリックして変更しただけだと切り替わらない?もよう...
これだけで切り替わるとさらに楽になるのですが...
- 投稿日:2020-04-05T19:09:36+09:00
ECRにdockerをプッシュする時に、credentialsのエラーが出たときの対処
AWS ECRにdockerをプッシュする時、テンプレートのコピペだと上手くいかないところがあったのでメモ。
環境
aws-cli/2.0.6
AWSのプロファイル設定済みエラー内容
テンプレートをそのままコピペすると以下のコマンドになります。
$ aws ecr get-login-password --region [region] | docker login --username AWS --password-stdin [account].dkr.ecr.[region].amazonaws.com/[repositry name]が、上記のコマンドを実行しても、以下のようなエラーが出てしまいます。
Unable to locate credentials. You can configure credentials by running "aws configure". Error: Cannot perform an interactive login from a non TTY device解決方法
AWSのcredentialは設定済みだったのですが、そのプロファイル名を自分で指定してあげる必要がありました。そのためには、コマンド前半の
--region [region]
を--profile [profile name]
に変更する必要がありました。$ aws ecr get-login-password --profile [profile name] | docker login --username AWS --password-stdin [account].dkr.ecr.[region].amazonaws.com/[repositry name]これで、リポジトリにプッシュできるようになりました。(
[profile name]
には、自分で設定しているプロファイル名を入れます)
- 投稿日:2020-04-05T19:05:50+09:00
[Python] pip3のパッケージを AWS Lambda 上でimportできるようにする
AWS Lambda レイヤーにパッケージ用のレイヤーを追加する。
パッケージを配置したフォルダを作成
pip3 install -t python/lib/python3.7/site-packages <パッケージ名>
python3.7
の箇所は適宜置き換える
python
フォルダをzipに固めるレイヤーにアップロード
パッケージを利用したい関数にレイヤーを追加する
import <パッケージ名>
で使えるようになる参考
https://blog.ikedaosushi.com/entry/2018/12/22/231421
環境
macOS 10.15.4
Python 3.7.7
- 投稿日:2020-04-05T18:41:59+09:00
コロナ患者数が都が確保してる病床数超えたから自宅療養する人が増えるだろうから一人で不安だしなんかあった時の為に助けを求めるボット作った。
- 投稿日:2020-04-05T17:54:59+09:00
Cloudtrailのログを、awsマネージドではないsparkのmetastoreに登録する方法
はじめに
awsマネージドなSpark/hive環境であれば、
com.amazon.emr.hive.serde.CloudTrailSerde
あたりを利用してmetastoreにテーブルを登録することができます。
https://docs.aws.amazon.com/ja_jp/athena/latest/ug/cloudtrail-logs.html
しかし、com.amazon.emr.hive.serde.CloudTrailSerde
はawsマネージドではないSpark/hiveでは利用できません。本記事では、databricksなどの awsマネージドではないSpark環境 において、cloudtrailのログをmetastoreに登録する方法を説明します。
注意
- region/year/month/dayのpartitionが利用可能なようにcreate tableしています。
- partitionは手動で追加する必要があります。手順参照。
- hive上では、本手順では動きません。
- とはいえ、ちょっとした変更で動くと思う
手順
tableの定義
以下のqueryで
CREATE TABLE
をします。{}
内は適宜書き換えてください。
{table_path}
は、一般的にs3a://{CloudTrail_bucket_name}/AWSLogs/{Account_ID}/CloudTrail/
の形式になります。列名/objectのkey名は大文字小文字を適切に指定しないと読み込まないので注意( 本日の落とし穴 )。
sparksqlCREATE TABLE {db}.{table} ( Records ARRAY< STRUCT< additionalEventData:STRING, awsRegion:STRING, errorCode:STRING, errorMessage:STRING, eventID:STRING, eventName:STRING, eventSource:STRING, eventTime:STRING, eventType:STRING, eventVersion:STRING, readOnly:STRING, recipientAccountId:STRING, requestID:STRING, requestParameters:STRUCT< acl:STRING, bucketName:STRING, clusterId:STRING, databaseName:STRING, durationSeconds:INT, encryption:STRING, encryptionContext:STRING, expression:STRING, filterSet:STRING, instancesSet:STRING, name:STRING, nextToken:STRING, partitionInput:STRING, partitionValueList:STRING, partitionValues:STRING, pattern:STRING, policy:STRING, resourcesSet:STRING, roleArn:STRING, roleSessionName:STRING, spotInstanceRequestIdSet:STRING, stateValue:STRING, tableName:STRING, tagSet:STRING, versioning:STRING, volumeSet:STRING >, resources:ARRAY< STRUCT< ARN:STRING, accountId:STRING, type:STRING > >, responseElements:STRUCT< _return:STRING, assumedRoleUser:STRUCT< arn:STRING, assumedRoleId:STRING, credentials:STRUCT< accessKeyId:STRING, expiration:STRING, sessionToken:STRING >, requestId:STRING, spotInstanceRequestSet:STRING > >, serviceEventDetails:STRING, sharedEventID:STRING, sourceIPAddress:STRING, userAgent:STRING, userIdentity:STRUCT< accessKeyId:STRING, accountId:STRING, arn:STRING, invokedBy:STRING, principalId:STRING, sessionContext:STRING, type:STRING, userName:STRING >, vpcEndpointId:STRING > >, region STRING, year STRING, month STRING, day STRING ) USING json PARTITIONED BY (region, year, month, day) LOCATION {table_path} ;viewの定義
logを直接覗くとわかるのですが、Cloudtrailのlogは以下のようなjsonになっています:
{"Records":[ {"eventVersion":"1.05",...}, {"eventVersion":"1.05",...}, ]}これは、Records内にすべての行と列が内包されており、扱いが面倒です。
そこで、この問題を解決するviewを予め定義しましょう。
以下のqueryでCREATE VIEW
をします。sparksqlCREATE OR REPLACE VIEW {db}.{view} AS SELECT Record.*, region, year, month, day FROM ( SELECT explode(Records) AS Record, region, year, month, day FROM {db}.{table} ) ;partitionの追加
ディレクトリ(prefix)が
{partition_key}={partiton_val}
の形式ではないため、MSCK REPAIR TABLE
を利用できません。
そのため、ALTER TABLE ADD PARTITION
を使用します。
{partition_path}
は、一般的にs3a://{CloudTrail_bucket_name}/AWSLogs/{Account_ID}/CloudTrail/{region}/{year}/{month}/{day}/
の形式になります。ALTER TABLE {db}.{table} ADD IF NOT EXISTS PARTITION (region={region}, year={year}, month={month}, day={day}) LOCATION {partition_path};
- 投稿日:2020-04-05T16:39:15+09:00
S3バケット別概算コスト算出ツールを作ってみた
はじめに
S3って安価なストレージなので、容量気にせずとりあえずなんでも格納して放置なんてことが多いですよね?
将来的に分析するかもってことでデータレイクに蓄積して結果使わないなんてことも多い。(my観測範囲)で、新型コロナウィルスの影響で先行き不安な状況なので、収束まではどうにか支出を抑えて凌ぎたい。。
という人も多いと考え、S3バケットごとに要否判断(&不要であれば削除)しやすいように、S3バケットごとに
使用量/概算コストを簡単に一覧表示するツールを作ったので、紹介します。ツール概要
一言で言えば、
全リージョン/全バケット別にオブジェクト数/使用バイト数/概算月額料金を出力するツール
です。(誰かが作ってそうなんですが探してもなかったので作りました)CloudWatchからバケットサイズなど取得できるようになってるので、それを実行すればawscliでも取得できる
のですが、リージョン指定しないといけないとか、メトリクス/ディメンションを指定するのがダルイので
そこらへんうまくやってくれるツールが欲しいなぁと思ったのがモチベーションです。
あと、請求コンソールだとバケット別の使用量はわからないので。補足(&免責事項)
- コスト算出について
- 実行時点の利用量を1ヶ月間継続した場合の概算請求額であり正確ではありません(ご利用は自己責任で)
- ストレージ保存量に対して課金される料金が対象であり、それ以外(リクエスト/転送量)のコストは含みません
- 概算請求額は東京リージョン料金(2020/04時点)で算出します
- 料金通貨は米ドル
- バージョニングについて
- 以前のバージョンのオブジェクトやそのサイズもカウントされます
- ツール結果と
aws s3 ls --recursive
等で得られるオブジェクト数は異なります要は
ざっくりでいいのでバケットごとにかかる料金を知りたい
って人がターゲットです実行方法
前提
- AWSクレデンシャル情報(~/.aws/credentials)が設置されていること
Go言語がインストールされている環境の場合
GO111MODULE=off go get -v github.com/miyaz/s3usage cd $(go env GOPATH)/src/github.com/miyaz/s3usage go run main.goそれ以外の環境
こちらから環境に応じたzipファイルをダウンロードし
展開後s3usage
というバイナリを実行しますオプション
- -p {プロファイル名}
- ~/.aws/credentials に記載されているプロファイル名
- 指定なし時(デフォルト)は
default
- -v
- ストレージタイプ毎の使用量/概算コストも表示したい場合に指定
実行例
おわりに
コロナに負けるな!
- 投稿日:2020-04-05T15:37:17+09:00
DevOps
AWS DevOps自分用攻略本作成中
スケーリング
Q:200以上のスレッド処理している際にパフォーマンス低下、対応策は?
A:各インスタンスにスクリプトを追加して、同時セッション数を検出、セッション数が5分で200を超えている場合は、インスタンスにAutoScalingグループの必要な容量を1つ増やす。
Q:コンプライアンス問題を自動的検出、修正する方法は?
A:コンプライアンス変更通知をSNSトピックに発行するCWatchEventルールを作成する。メッセージチャネルHTTPSエンドポイントをSNSトピックにサブスクライブする。非準拠のセキュリティ構成に対処するLambda関数を記述、SNSトピックにサブスクライブする。
Q:VPCで新しいAWSの機能をテストする場合の最短方法は?
A:開発リクエストに応じて、ステージングVPCでEC2を起動し、構成管理を使用してアプリをセットアップ。テストハーネスを実行してアプリの機能を確認して、SNSで開発チームに結果を通知。
Q:DynamoDBからLambdaでデータを読み取る、Lambdaはテストが成功したら開発者によってデプロイされる。
A:CodePipelineを使用してテストOKな後にパイプラインをトリガーするポストコミットフックを設定、CodeDeployを使用して、トラフィックの割合と間隔を指定するカナリアデプロイ構成を作成。
Q:Cforamtionスタックが削除された後にRDBのスナップショットが作成できるようにするには?
A:CFormationテンプレートの削除ポリシーを使用し、RDBのスナップショットが作成されるようにする。
Q:RDS MySQLに読み取り競合がある場合の最良アプローチは?
A:各AZで実行されているECacheインメモリーキャッシュをデプロイする。各AZにRDSリードレプリカを追加する。
Q:アプリログの長期保存が求められている、スタッフはすぐにログを表示させたい。現状はS3に1時間ごとにアーカイブされている、どのような方法で迅速に表示されるようにできる?
A:S3ライフサイクルポリシーを更新して、古いログをGlacier、サービスを使用もしくは作成してCWatchLogsエージェントを使用してアプリログをCWatchLogsにストリーミングする。
Q:OpsWorksでリモートリポジトリから新しいインスタンスごとにアプリとクックブックをデプロイしている。上司がQAで承認されていないコードで異なるアプリバージョンを提供しているインスタンスがあることに気づいた。なぜ?
A:チームの誰かがコードを別々のブランチにコミットし、OpsWorksが新しいインスタンスを起動した。
Q:AWSでカナリアテストをするためには?アプリはAutoScalingグループにデプロイする必要があり、ClassicLBを使う必要がある。
A:ブルーグリーン別にClassicLBとAutoScalingグループを作成し、Route53を使用し、CLBで加重Aレコードを作成する。
Q:サードパーティサプライとの注文を処理する単一EC2がある。注文はSQSキューから取得され、5minごとにバッチ処理、処理の遅延は1h以内というビジネス要件あり。週に3回アプリが失敗し、停止するので手動で再起動している。これの回復力を上げるためには?
A:AutoScaling起動設定を作成して、グループを最小値、最大値1の起動設定を使用する。
A:アプリを変更して、インスタンスIDのディメンションをもつかすたむCWatchメトリクスを送信する。メトリクスが10min間動作しない場合にCWatchアラームを作成し、EC2アクションを実行してインスタンスを終了する。
Q:
A:
Q:
A:
Q:
A:
Q:
A:
Q:
A:
- 投稿日:2020-04-05T15:25:36+09:00
DynamoDB queryパラメータまとめ
はじめに
今さらだがDynamoDBのクエリパラメータについてまとめる。
既に他の人が同じような記事を書いているかもしれないが、
AWSのドキュメントを読んでいて、
「分かりづらいから一覧でまとめてくれ!!」と思い
あくまで自分のためのメモとして残す。
他のDB操作パラメータについては必要が出てきたら追記するつもり。Query Parameters
TableName
- 文字通りテーブル名を指定する
KeyConditionExpression
- プライマリーキー(パーティションキー、ソートキー)、セカンダリーインデックスに対する条件式を記述する
- DynamoDB予約語でなければ、後述のExpressionAttributeNamesでプレースホルダーを指定しなくてもそのまま使える
- 例
ExpressionAttributeNames
- KeyConditionExpressionで使う属性名のプレースホルダーを定義する
- オブジェクト文字列で指定する
- #を接頭辞としてつけるのが必須
- 例
ExpressionAttributeValues
- KeyConditionExpressionで使う属性値のプレースホルダーを定義する
- オブジェクトで指定
- 接頭辞としてコロン:をつけるのが必須
- 例
FilterExpression
- テーブルからのクエリ実行後に、APIとしての戻り値をフィルタリングするための条件式を書く
- ExpressionAttributeNames, ExpressionAttributeValuesで定義したプレースホルダーを使って、KeyConditionExpressionと同様にして書ける
ProjectionExpression
その他
DynamoDB DocumentClient
- 投稿日:2020-04-05T15:07:37+09:00
AWS LambdaのCustom Runtimeを使い、Node.js v8などEoLとなったランタイムを動かす
はじめに
Node.js、バージョンアップの足がかなり早いですよね。
AWS Lambdaにおけるランタイムサポート期間も、これにあわせてハイテンポになっています。ちゃんとバージョンアップをしろというご意見は重々承知の上ではありますが、
Node.js v8.10でLambda Functionを使い続けざるを得ない場合に、カスタムランタイムを使ってEoLとなったランタイムを動かし延命処置を図ります。動作確認環境
- Arch Linux (2020.04.04)
- Docker 19.03.8-ce
- aws-cli 1.18.36
カスタムランタイムの使い方
カスタムランタイムの仕様については、公式ドキュメントが詳しいので割愛します。
カスタムランタイムを使用するには、デプロイパッケージあるいはLayerに、
node
実行ファイルと、ハンドラー関数を起動するためのbootstrap
実行ファイルを含める必要があります。
今回は既存のLambda Functionを使用することを想定していますので、関数のデプロイパッケージには手を加えずLambda Layerでランタイムを読み込ませます。Lambda Layerの作成には、以下のリポジトリを活用させていただきます。
https://github.com/lambci/node-custom-lambdaこちらのリポジトリにはNode v10、v12のファイルが含まれています。(2020/04/04現在)
今回はこのリポジトリをフォークし、v8.10用のファイルを追加することでLayerを作成します。
bootstrap
については、CとJavascriptで書かれたものがそれぞれv12.x/bootstrap.c
、v12.x/bootstrap.js
にあります。(v10.xも同様)
bootstrap.c
(をコンパイルしたbootstrap
)がまずAWS Lambdaによって起動され、これがbootstrap.js
スクリプトをカスタムランタイムのNodeで実行します。
bootstrap.js
は、AWS Lambda ランタイムインターフェイスから関数の呼び出しイベントの受け取り、デプロイパッケージのスクリプト実行、実行結果のPOSTを行います。上記リポジトリの
bootstrap.js
はNode v8.10でも問題なく動くので、
必要な変更点はLambda Layerに含めるnode
実行ファイルをv8.10のものに変更するだけとなります。カスタムランタイムの作成
前節で紹介したリポジトリをクローンするところからはじめます。
Dockerが必要となります。$ git clone https://github.com/lambci/node-custom-lambda.git $ cd node-custom-lambdav12.xのディレクトリを元に、v8.10のディレクトリを作成します。
$ cp -r v12.x v8.10 $ cd v8.10v12.xのLayerファイルを削除しておきます。
$ rm layer.zipこのプロジェクトでは、Docker上で
bootstrap.c
のビルドとNodeのダウンロードを行います。
config.sh
を編集し、Nodeのバージョンを指定します。config.sh< export NODE_VERSION=12.16.1 --- > export NODE_VERSION=8.10.0ビルドします。
$ ./build.sh
v8.10/layer.zip
ファイルが出来上がります。
これを解凍すると以下のようなファイルが入っています。layer ├── bin │ └── node ├── bootstrap └── bootstrap.jsNodeのバージョンを確認しておきます。
$ ./layer/bin/node -v v8.10.0テストが用意されていますので、実行してみます。
$ ./test.sh
以上でカスタムランタイムのLayerが完成しました。
カスタムランタイムのデプロイ
リポジトリには
publish.sh
が用意されていますが、このスクリプトは全てのリージョンにデプロイされてしまいます。
今回はap-northeast-1にのみデプロイできればよいので、AWS CLIを使って手動でLayerを作成します。まず、作成したレイヤーのファイル(
layer.zip
)を任意のS3にアップロードします。aws s3api put-object --bucket ${BUCKET_NAME} --key nodejs/8.10.0/layer.zip --body layer.zip --output json次に、Lambda Layerを作成します。
ここではCloudFormationで作成します。template.ymlAWSTemplateFormatVersion: 2010-09-09 Parameters: S3BucketName: Description: A S3 bucket name contains layer.zip Type: String Resources: Nodejs8Runtime: Type: AWS::Lambda::LayerVersion Properties: Content: S3Bucket: !Ref S3BucketName S3Key: nodejs/8.10.0/layer.zip Description: Layer for Node.js 8.10.0 Custom Runtime LayerName: custom-runtime-nodejs-8 Outputs: Nodejs8RuntimeLayerARN: Description: A lambda layer ARN of Node.js 8.10.0 Custom Runtime Value: !Ref Nodejs8Runtime Export: Name: !Sub ${AWS::StackName}-runtime-nodejs8Stackを作成。
aws cloudformation create-stack --stack-name dev-lambdalayers-nodejs \ --template-body file://template.yml \ --parameter ParameterKey=S3BucketName,ParameterValue=${S3_BUCKET_NAME}Layerができていることを確認します。
$ aws lambda list-layer-versions --layer-name custom-runtime-nodejs-8 { "LayerVersions": [ { "LayerVersionArn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:custom-runtime-nodejs-8:1", "Version": 1, "Description": "Layer for Node.js 8.10.0 Custom Runtime", "CreatedDate": "2020-04-04T16:59:31.629+0000" } ] }Lambda Functionの作成とテスト
上記で作成したカスタムランタイムをテストします。
Lambda FunctionはServerless Frameworkを使用して作ることにします。
provider.runtime
にprovided
を指定することでカスタムランタイムを使用できます。
Lambda Layerは、先程のCloudformation StackのOutputをインポートしてARNを指定します。serverless.ymlservice: test-lambda-function provider: name: aws runtime: provided stage: dev region: ap-northeast-1 functions: hello: handler: handler.hello layers: - 'Fn::ImportValue': dev-lambdalayers-nodejs-runtime-nodejs8関数のコードはシンプルに、実行しているNode.jsのバージョンを返すだけです。
handler.jsmodule.exports.hello = async event => { return process.version; };これを実行して、
v8.10.0
という文字列が帰ってきたら成功です。$ sls invoke -f hello "v8.10.0"注意点
- AWS公式のNode.jsランタイムには
aws-sdk
が含まれていますが、この方法で作成したカスタムランタイムにはいずれのnpmパッケージも含まれていません。おわりに
以上でNode v8を使用するLambda Functionの延命措置ができました。
同様の方法で、Node v6、v4も動かすことが可能です。しっかりバージョンアップしていくのがベストであることは言うまでもありませんが、
node-gypなどネイティブモジュールはバージョンアップで動かなくなることも多々ありますので、とりあえずの措置には使えるかと思います。また今回使用したコードはすべて以下リポジトリにアップしています。
https://github.com/uhey22e/node-custom-lambda
- 投稿日:2020-04-05T14:40:30+09:00
Amazon Route53 サポートされるDNSレコードタイプ
A(アドレスコード)
- A(Address)レコードは、IPv4でホスト名とIPアドレスの関連づけを定義するレコードです。「www」などのホスト名を入力し、VALUEにグローバルIPアドレスを入力することによって、ご利用いただくサーバーへの名前解決が行われます。
- MXレコード、CNAMEレコード、NSレコードを設定するには、あらかじめ各レコードのVALUEに入力するホスト(FQDN)をAレコードとして設定されていることが必要です。
AAAAレコード(IPv6アドレスコード)
- AAAAレコードは、IPv6でホスト名とIPアドレスの関連づけを定義するレコードです。
CNAMEレコード
- CNAMEレコードは正規ホスト名に対する別名を定義するレコードです。
- 特定のホスト名を別のドメイン名に転送する時などに利用します。
※正規ホスト名はAレコードが登録されている必要があります。
※特定のファイルやサブディレクトリを指定する事はできません。
※ホスト名なしのCNAMEレコードは登録することができません。例)ドメイン名:mugicha.comの場合
【設定可能】
ホスト名:www
VALUE:www.ryokucha.com と入力
⇒http://www.mugicha.com/にアクセスするとhttp://www.ryokucha.com/に転送されます。【設定不可】
ホスト名:空白
VALUE:www.ryokucha.com と入力
⇒http://mugicha.com/にアクセスしhttp://www.ryokucha.com/に転送される設定はできません。
※ホスト名を空白にて設定したい場合、IPアドレスをご確認のうえ、Aレコード設定をご利用ください。
- 投稿日:2020-04-05T13:01:09+09:00
AWS CDKを使えばTypeScriptでAWSインフラを定義できるらしい
AWS CDKなるものを使うとコードでインフラを実装できるらしいです。
やってみます。What Is the AWS CDK?
使い慣れたプログラミング言語でAWSリソースを定義できるもの。
サポート言語は
- TypeScript
- JavaScript
- Python
- Java
- C#/.NET
とのこと。CDKの利点
個人的な利点は
- プログラムなのでCFnと比べてレビューの敷居が下がる
- 動的なインフラ定義の幅が広がる(予想)やってみる
というわけで、やってみます。
環境
- VSCode
- 1.43.2
- node.js
- v12.11.0
- aws-cdk
- 1.31.0
- TypeScrippt
- 3.8.3
- aws-cli
- 1.18.31
環境構築参考:
AWS CDK Intro Workshop > 前提条件作りたい構成
良さげなサンプルソースがあったので参考にして以下のような構成になればいいなと思ってます。
aws-samples/aws-cdk-examples/ecs-service-with-advanced-alb-config準備
プロジェクトを作成します。
cdk init sample-app --language typescript
libディレクトリに構築に使用するファイルが作成されます。
主にこのファイルをいじいじしていくらしいです。
.tsimport * as sns from '@aws-cdk/aws-sns'; import * as subs from '@aws-cdk/aws-sns-subscriptions'; import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; export class ElbSampleStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); const queue = new sqs.Queue(this, 'ElbSampleQueue', { visibilityTimeout: cdk.Duration.seconds(300) }); const topic = new sns.Topic(this, 'ElbSampleTopic'); topic.addSubscription(new subs.SqsSubscription(queue)); } }TypeScriptなのでファイル監視をします。
npm run watchとりあえずきれいにします。
.tsimport * as cdk from '@aws-cdk/core'; export class ElbSampleStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); } }必要なcdkモジュールをインストールします。
npm i @aws-cdk/aws-elasticloadbalancingv2 npm i @aws-cdk/aws-ecs実装
.tsimport * as cdk from '@aws-cdk/core'; // 使うモジュール import * as elb from '@aws-cdk/aws-elasticloadbalancingv2'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; export class ElbSampleStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); // Create a cluster const vpc = new ec2.Vpc(this, 'cdk-sample-vpc', { maxAzs: 2 }); const cluster = new ecs.Cluster(this, 'cdk-sample-cluster', { vpc }); cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: ec2.InstanceType.of( ec2.InstanceClass.T2, ec2.InstanceSize.MICRO ) }); // Create Task Definition const taskDefinition = new ecs.Ec2TaskDefinition( this, 'cdk-sample-taskDef' ); const container = taskDefinition.addContainer('web', { image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), memoryLimitMiB: 256 }); container.addPortMappings({ containerPort: 80, hostPort: 8080, protocol: ecs.Protocol.TCP }); // Create Service const service = new ecs.Ec2Service(this, 'cdk-sample-service', { cluster, taskDefinition }); // Create ALB const lb = new elb.ApplicationLoadBalancer(this, 'cdk-sample-elb', { vpc, internetFacing: true }); const listener = lb.addListener('PublicListener', { port: 80, open: true }); // Attach ALB to ECS Service listener.addTargets('ECS', { port: 80, targets: [ service.loadBalancerTarget({ containerName: 'web', containerPort: 80 }) ], // include health check (default is none) healthCheck: { interval: cdk.Duration.seconds(60), path: '/health', timeout: cdk.Duration.seconds(5) } }); new cdk.CfnOutput(this, 'LoadBalancerDNS', { value: lb.loadBalancerDnsName }); } }デプロイ
CDKを元にCFnを作成します。
cdk synthデプロイに使用するS3バケットを作成します。
cdk bootstrapCloudFormationを使用してS3バケットが作成されるようです。
デプロイします。
cdk deploy
y
でデプロイが実施されるのでログを眺めながら待ちます。成功しました。
後処理
デプロイしたリソースもコマンドで消せるようなので消しておきましょう。
cdk destroy削除されたようです。
めでたし。
感想
AWS CDKが話題になっていたのでなんとなく試してみましたが、CFnに比べて学習コストが2段階くらい下がったような気がします。
ただ、ソース量を見れば分かる通り定義していないものもうまい具合に作成してくれるようなので、意図しないリソースが作成されないように注意しなければいけないと感じました。
参考
【コードでインフラ定義】CDKという異次元体験をさくっとやるのに便利なAWS公式Workshopの紹介 | Developers.IO
AWS Cloud Development Kit (AWS CDK) ワークショップ
aws-samples/aws-cdk-examples/ecs-service-with-advanced-alb-config
- 投稿日:2020-04-05T02:01:32+09:00
EC2 Instance Connectでブラウザベースの接続ができない時の対処
Instance Connectのブラウザベースの接続
普段は自分のPCからsshでEC2のinstanceにログインしていましたが、
Instance Connectのブラウザベース接続というものがあると知りました。
これを使うとインターネット環境があればどこでも自由にEC2のinstanceへログインできるそうです。そこで以下を参考にして、Instance Connectのブラウザベースで接続を試みました。
EC2 Instance Connect のセットアップローカルPCからはsshでC2にログインできるのに、
Instance Connectのブラウザベースでは接続が失敗しました。試行錯誤した結果、この場合の確認ポイントは以下の3点でした。
1.セキュリティグループのインバウンドの設定
対象のEC2インスタンスのセキュリティグループのインバウンドの設定に以下を追加する必要があります。
タイプ:ssh
プロトコル:TCP
ポート範囲:22
ソース:カスタム 3.112.23.0/29
2.IAM(ユーザ)の設定
consoleにloginするIAM(ユーザ)に、以下のポリシーをアタッチします。
設定項目と設定値
Region:ap-northeast-1
AWS accountID:000000000000
InstanceID:i-99999999999999999
Osuser:ubuntu(AmazonLinux2のデフォルトのユーザー名はec2-user、Ubuntuの場合はubuntu){ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "ec2-instance-connect:SendSSHPublicKey", "Resource": "arn:aws:ec2:ap-northeast-1:000000000000:instance/i-99999999999999999", "Condition": { "StringEquals": { "ec2:osuser": "ubuntu" } } }, { "Effect": "Allow", "Action": "ec2:DescribeInstances", "Resource": "*" } ] }3.instance側の設定
対象のinstanceにsshでログインして、以下を実行します。
sudo apt-get update
sudo apt-get install ec2-instance-connect
4つの新しいファイルが作成されていることを確認します。
$ ls /usr/share/ec2-instance-connect/ eic_curl_authorized_keys eic_harvest_hostkeys eic_parse_authorized_keys eic_run_authorized_keysこれでブラウザベースのInstance Connectができるはずです!!
これでも解決しない場合
なお、ここまでやっても接続できない場合、
以下のように許可の範囲を一時的に広げて確認してみましょう。
- セキュリティグループのインバウンドのIPの範囲を「0.0.0.0/0」まで広げてみる
- consoleにloginするuserのIAMにAmazonEC2FullAccessのポリシーをアタッチしてみる
EC2 Instance Connectはインターネットが繋がれば、どこからでもEC2のinstanceにログインできるため、事前に準備してログインできるようにしておくと何かあった時に役立つと思います。
参考
AWS IP Address Ranges
EC2 Instance Connect の特徴や注意点についてまとめてみる