サーバーレスの入門に!自宅サーバーレス+自宅S3環境で作るサーバーレス・サムネイルサーバー!

サーバーレスのHelloWorld = サムネイルサーバー?

日本語で読めるサーバーレスの有名記事といえば,伊藤直也さんの一休の事例だと思います.
下記の記事では,Amazon Lambdaを使って,一休のサムネイルサーバーを構築した事例の紹介をしています.

伊藤直也氏が語る、サーバーレスアーキテクチャの性質を解剖する(前編)。QCon Tokyo 2016
伊藤直也氏が語る、サーバーレスアーキテクチャの性質を解剖する(中編)。QCon Tokyo 2016
伊藤直也氏が語る、サーバーレスアーキテクチャの性質を解剖する(後編)。QCon Tokyo 2016

スケールしやすい.安価にサービスできる.ということでサーバーレス・アーキテクチャは注目が集まっているようです.

そこで,今回,一休での事例をまねて,

1時間で作れる!かんたん自宅Serverless環境! ~はじめてのServerless Application入門~

で作った,Serverless環境のiron-functionsと,

コマンド1つで作れる!かんたん自宅Amazon S3互換環境!

で作った,S3互換環境を合わせて,サーバーレス・サムネイルサーバーを構築したいと思います.

サーバーレス・サムネイルサーバーのシークエンス

image.png

ざっくりとした概要の図です.
1. リクエストから「ファイル名」と「サイズ」を受け取る
2. minioのthumbsのバケットに該当のサイズのサムネイルがあるか?ない場合は3.へ.ある場合は7.へ.
3. minioのimagesのバケットからファイルをダウンロード
4. ダウンロードした画像ファイルをリサイズ
5. リサイズした画像をminioのthumbsのバケットへアップロード
6. リサイズした画像をレスポンスし,終了
7. minioのthumbsのバケットからサムネイルをダウンロード
8. ダウンロードした画像をレスポンスし,終了

API仕様書

(仕様書というほどではないですが・・・)

概要

png画像のサムネイルを提供する.

  • 指定できるサイズは画像の横のサイズのみ.
  • 縦横比は保持する.
  • png以外の画像フォーマットには非対応.
  • テストのため,エラーハンドリングは考慮しない

エントリポイント

/iron_thumbs/thumbs

URLパラメーター

変数 説明
filename imagesにアップロードされたファイル名(key)
size サムネイルの画像の横のサイズ

レスポンス

png画像データ

http://localhost:8000/iron_thumbs/thumbs?filename=test.jpg&size=30

minioのimagesバケットに入っているtest.pngを,画像の横のサイズが30pxになるように縮小し,バイナリデータとして出力する.

事前準備

今回,

  • iron-functions
  • minio

という2つのソフトウェアを使います.
手前みそですが,Seveless環境のiron-functionsは

1時間で作れる!かんたん自宅Serverless環境! ~はじめてのServerless Application入門~

の記事で紹介しています.
また,S3互換環境であるminioに関しては,

コマンド1つで作れる!かんたん自宅Amazon S3互換環境!

の記事で紹介しています.
今回,サムネイルサーバーを構築するにあたって,最低限必要なものとして,

  • docker
  • awscli
  • glide

の3種類です.glideは上記記事では,取り扱っていませんが,go言語でライブラリをインストールするためのパッケージとして今回必要です.
あとgolangの開発環境があるとよいですが,今回,動かすだけであれば必要ないと思います.(おそらく,glideのインストールと同時にgo言語の開発環境も入ると思います)

ソースコード

今回,コードが300行程度あったため,githubのほうに置きました.
https://github.com/kotauchisunsun/iron_thumbs.git

デプロイ

最初にMinio(S3互換サーバー)を前回と同じ設定で8080ポートでサービスします.

設定する変数
Access Key AKIAIOSFODNN7EXAMPLE
Secret Key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# minioを起動
$ sudo docker run --rm -p 8080:9000 -it 
    -e MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE
    -e MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
    minio/minio server /export

その次に,minioにバケットを作成します.

# minioへimagesバケットの作成
$ aws --endpoint-url http://192.168.0.6:8080 s3 mb s3://images
# minioへthumbsバケットの作成
$ aws --endpoint-url http://192.168.0.6:8080 s3 mb s3://thumbs

iron-functionsを8000ポートでサービスします.

# iron-functionsのサービス
$ sudo docker run --rm -it --name functions -v ${PWD}/data:/app/data 
                   -v /var/run/docker.sock:/var/run/docker.sock 
                   -p 8000:8080 iron/functions

サムネイルサーバーをサービスします.一応Dockerコンテナの流儀のようなものを意識して,各種サービスに必要なパラメーターは環境変数として渡しています.

# ソースコードをクローン
$ git clone https://github.com/kotauchisunsun/iron_thumbs.git
$ cd iron_thumbs
# パッケージの依存関係を解消
$ glide update
$ sudo fn build
$ fn apps create iron_thumbs 
    --config IMAGE_BUCKET=images
    --config THUMB_BUCKET=thumbs
    --config S3_ENDPOINT=http://192.168.0.6:8080
    --config S3_REGION=us-east-1
    --config S3_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE
    --config S3_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
$ fn routes create iron_thumbs /thumbs

今回,テストデータとして,いらすとやの画像を使います.それっぽい画像としてクラウドコンピューティングの画像を使います.
image.png

# 素材をダウンロード
$ wget "http://4.bp.blogspot.com/-dVbfTZcofUU/VGX8crT5GiI/AAAAAAAApG4/CB7GF5UmMqE/s400/computer_cloud_system.png"
# minioにファイルをアップロード
$ aws --endpoint-url http://192.168.0.6:8080 s3 cp computer_cloud_system.png s3://images/

実際にiron_thumbsに対してリクエストしてみます.

$ curl "http://localhost:8000/r/iron_thumbs/thumbs?filename=computer_cloud_system.png&size=180" > thumbs.png

これでサムネイルが出来ています!

ベンチマーク

「いらすとや」ベンチ

今回もベンチマークを取ってみました.

どのようなものを想定したかというと,「いらすとや」を自分で運用すると考えました.
image.png

「いらすとや」で画像を検索すると,検索にマッチした画像のサムネイル(赤枠の部分)が表示されます.この画像の横のサイズが約180pxになっています.(実際は少し違います)
このサムネイルをいかに速く作れるのか?をベンチマークしてみたいと思います.

使ったベンチマークソフトは以前も使ったApacheBench.設定は,

$ ab -n 1000 -c 10 "http://localhost:8000/r/iron_thumbs/thumbs?filename=computer_cloud_system.png&size=180"

こんな感じ.
今回,2種類のベンチマークをしました.

always_make_thumbs

これはリクエストごとに常にサムネイルを生成し,レスポンスします(ソースコードを改変してます.)

cached_thumbs

これはthumbsのバケットからサムネイルを取ってきて,レスポンスします.

サムネイルサーバーのシステム設計をする

色々なサムネイルサーバーの話がネットには転がっています.

pixivのサムネイル事情(pixiv)
料理を楽しくする画像配信システム(cookpad)

このように各社各社がしのぎを削ってるようです.
今回,このようなサムネイルサーバーの構成を考えてみました.

image.png

実運用されているサムネイルサーバーは,サムネイルの動的生成だけでなく,CDNが前に立つことがよくあるようです.
理由は主に2つあって,

  1. サムネイルサーバーの負荷軽減
  2. 高速なサムネイルの配布

です.サムネイル作成はCPUへの負荷が高く,サーバーが高負荷になりやすいです.では,サーバーを追加すればよいか?という話になるのですが,お金のないベンチャーはそういうことが出来ません.そのため,出来るだけCDNでサムネイルをキャッシュし,なおかつアクセスのある時は,サーバーレスで短時間動かすことで,安値でスケールしやすいシステムを作ることが出来ます.
実はこの辺の,サムネサーバーの要求要件が,かっちりサーバーレスのアーキテクチャにはまっているため,事例として,よく取りあげられてるのだろうなぁ.と思っています.

なのですが,

ぶっちゃけCDNとサムネサーバーとS3の面倒を見るのはめんどくさいです

キャッシュというのは,高速化には常套手段ではありますが,個人的には,バグを引き起こす原因の上位に来てます.(サーバーレスアーキテクチャだけど,すごくステートフルだし)
実際に,最近,メルカリではCDNの周りで個人流出事件を起こしてます(CDN切り替え作業における、Web版メルカリの個人情報流出の原因につきまして)
そのような理由で,個人的にはキャッシュは出来るだけ,使いたくない気持ちではあります.
しかし,今回考えたサムネサーバーの構成は,先ほどの図にあるように2段階にキャッシュを持っています.

  1. CDN
  2. サムネイル

CDNにサムネイルがなければ,サムネサーバーに問い合わせ,サムネサーバーがサムネイルを今までに作ったことがなかった場合,画像ファイルをダウンロードしてきて,サムネイルを作ります.

そのため,今回は,出来るだけキャッシュを少なくするために,「どこかのサーバーを省略できないかな?」というのが,このベンチの目的です.
そのため,

  • CDNを使わないバージョン=cached_thumbs
  • サムネを動的に作り続けるバージョン=always_make_thumbs

と考えて,ベンチを行ってみました.

結果・考察

項目 平均レスポンス時間[ms]
always_make_thumbs 8417.722
cached_thumbs 7542.938

一度サムネをS3(minio)にキャッシュする方が,1,000[ms]程度速く,7,500[ms]でサムネイルをサービスすることが出来ました

ただ50歩100歩で,普通にWebページを見ていて,7.5秒もサムネの表示に時間がかかってたら使い物にならない感じです.前に検証した,

Serverless環境は600倍以上遅い? ~GoとNode.jsとPythonでベンチマークとってみた!~

の通り,そもそもiron-functionsは遅いです.簡単なGoのサーバーレスのサービスでも6,500[ms]程度かかってました.そこから考えると,サムネ生成からレスポンスまで,8,500[ms]-6,500[ms]なので,2,000[ms],約2秒と考えられます.

あなたのサイトは2秒以内?表示速度がフォームコンバージョンに与える影響

によると,

47%のEコマースユーザーは2秒以内にページが読み込まれることを期待している

だそうです.そのため,サムネの表示に2秒程度かかっていては,やはり問題があります.そのため,前段のCDNのようなキャッシュ機構はまだまだ必要なようです.

ただ一方で

今の世の中だと2秒ぐらいでサムネイルを作れる

という見方もあります.
確かに,2秒というレスポンス時間は遅いです.これに実際にサーバーレスの起動の時間が入ると,もっと時間がかかる.Amazon Lambdaが早いといっても,レスポンスに3秒ぐらいかかるかもしれない.ただ

1人サムネイル生成を待てば,あとはCDNがキャッシュしてくれる.

という世界観だとどうでしょう.割と個人的にはありなんじゃないかなーと.1人が3秒ぐらいサムネイルの生成を待つけども,それ以外の人はCDNが高速にレスポンスしてくれる.
 今回,サムネイルサーバーを作ってみて,「結構めんどくさいなぁ.」とか「S3のバケット2つに依存するなぁ」とか,「これサムネイル側のキーの衝突とかちゃんとハンドリングするの面倒だなぁ」とか,「効率化するためにサムネをS3にキャッシュするのだるいなぁ」とか思いました.そういうことを考えると,コードをクリーンに保ちつつ,運用しやすいインフラを考えると,サーバーレス+CDNの構成で十分で,サムネイル自身をバケットに保持してキャッシュする必要はそうそうないんだなーと思いました.
確かに,

サーバレスにサムネイル画像を配信する試み

という記事の中で,

ユーザに投稿してもらった画像は、オリジナル画像としてS3に保存
オリジナル画像は配信しない (private)
サムネイル画像が要求されたらオリジナル画像から動的変換2 し、CDNで配信
サムネイル画像は保存しない
CDN にヒットしなかったらもう一度動的変換

サムネイル画像は保存しない.という方向性があって,へー.と思ってたんですが,これなら割と落としどころとしてはありなラインなんだなぁ.と検証してみて思いました.

感想

最近,後輩を指導してて,

私「この問題は,Aの可能性があります.ただ一方でBの問題も考えられ,Cの問題も考えられます.別の視点だとDの問題も考えられ・・・」
後輩「その原因のうち,どれを選んで,どれから調べればいいんですか?」
私「

という話をしました.
実際のところ,「問題のある箇所を特定するためにテストを行い」「問題を切り分け」「解決する」というのが一般的だと思います.しかし,全てが全てそういう風に出来るわけではないです.
そんな中で「えいや」と問題を割り切って,テストをしたときに,問題の原因が一発で分かる.みたいなところが「勘」と言ってる所以です.

今回,サムネイルサーバーを作ってみて,この「勘」と呼ばれる部分が働かずに苦労しました.私はGo言語に慣れていないのですが,慣れていると「普通は,はまらないところには,はまらない.」ということが出来ます.しかし,慣れていないと,「普通はこういう実装しないよな・・・」というやり方で実装してしまい,「普通は,はまらないところに,はまる」をしてしまい,問題解決にすごく時間を取られて,頭を悩ませたりしました.

あとiron-functions周りもそうでした.これは純粋にナレッジが少ない面もありますが,公式のドキュメントもなくて,厳しかったです.私はあまりDockerやDocker周りのお作法をあまり知らない面もあるので,その面で「勘」が働かず,毎度毎度厳しい感じになってました.

特に,glideによるライブラリのインストールとiron-functionsの連携部分が厳しく,GoとDockerとiron-functionsの3つの領域の重なった領域だったので,かなり時間がかかってしまいました.

そんなわけで日々組んでおかないといざ作るときになると厳しいなぁ.と思うことはよくあります.やはり日々精進が必要なのだなぁと感じた次第でした.

続きを読む

AWSCLIインストール手順

はじめに

AWSCLIを使う際にエラーがやたらに出て、詰まったのでメモ。

環境

  • Mac OS Sierra

AWS CLIのインストール


Pythonのパッケージ管理ツールを経由してawscliを入れるためPythonをインストールする。

$ brew install python

$ sudo easy_install pip

$ sudo pip install awscli

// 上記の方法で出来なかった方は以下
$ sudo pip install awscli --upgrade --ignore-installed six

AWS CLIの設定


// AWSの設定を行う
$ aws configure

上記コマンドを入力後、AWSのアクセスキーとシークレットキーを入力あとは省略してもOKです。

pemファイルの権限

sshで接続する際に、pemファイルの権限がないと怒られたので、同様の方は以下

$ chmod 600 hoge.pem

hoge.pemは任意で変更し、pemファイルまでのパスを記述すればOK

以上で完了です。

続きを読む

[JAWS-UG CLI] Amazon Kinesis Firehose re:入門 (6) 関連リソースの削除

この記事について

JAWS-UG CLI専門支部 #90 Kinesis Firehose 復習編で実施するハンズオン用の手順書です。

前提条件

必要な権限

作業にあたっては、以下の権限を有したIAMユーザもしくはIAMロールを利用してください。

  • 以下のサービスに対するフルコントロール権限

    • Kinesis Firehose
    • IAM
    • EC2
    • S3
    • CloudWatch Logs
    • STS
    • (Lambda)
      • データの変換を行う場合
    • (KMS)
      • データの暗号化を行う場合

0. 準備

0.1. リージョンを指定

オレゴンリージョンで実施します。(東京マダー?)

コマンド
export AWS_DEFAULT_REGION="us-west-2"

0.2. 資格情報を確認

コマンド
aws configure list

インスタンスプロファイルを設定したEC2インスタンスでアクセスキーを設定せずに実行した場合、以下のようになります。

結果
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************QSAA         iam-role
secret_key     ****************c1xY         iam-role
    region                us-west-2              env    AWS_DEFAULT_REGION

0.3. バージョン確認

コマンド
aws --version
結果
aws-cli/1.11.129 Python/2.7.12 Linux/4.9.38-16.33.amzn1.x86_64 botocore/1.5.92

0.4. バージョンアップ(必要に応じて)

コマンド
sudo pip install -U awscli

0.5. 変数の確認

コマンド
cat << ETX

    CF_STACK_NAME: ${CF_STACK_NAME}

ETX

1. Stackの削除

1.1. Stackの削除

Stack名の確認

コマンド
cat << ETX

    CF_STACK_NAME: ${CF_STACK_NAME}

ETX
結果

    CF_STACK_NAME: firehose-jawsug-cli

Stackの確認

コマンド
aws cloudformation describe-stacks 
    --stack-name ${CF_STACK_NAME}
結果
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:us-west-2:XXXXXXXXXXXX:stack/firehose-jawsug-cli/5d4aac10-7aba-11e7-bd3e-50a686be738e",
            "Description": "JAWS-UG CLI Kinesis Firehose Hands-on",
            "Parameters": [
                {
                    "ParameterValue": "XXXXXXXXXXXX_firehose_jawsug_cli",
                    "ParameterKey": "KeyPairName"
                },
                {
                    "ParameterValue": "10.0.0.0/16",
                    "ParameterKey": "VPCNetworkAddress"
                },
                {
                    "ParameterValue": "10.0.0.0/24",
                    "ParameterKey": "PublicSubnetAddr"
                }
            ],
            "Tags": [],
            "Outputs": [
                {
                    "OutputKey": "PublicIP",
                    "OutputValue": "34.209.250.207"
                },
                {
                    "OutputKey": "IAMRoleARN",
                    "OutputValue": "arn:aws:iam::XXXXXXXXXXXX:role/service-role-firehose"
                },
                {
                    "OutputKey": "S3BucketName",
                    "OutputValue": "firehose-jawsug-cli-s3bucket-1qtuo76w7zanq"
                }
            ],
            "CreationTime": "2017-08-06T15:17:30.587Z",
            "Capabilities": [
                "CAPABILITY_NAMED_IAM"
            ],
            "StackName": "firehose-jawsug-cli",
            "NotificationARNs": [],
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false
        }
    ]
}

Stackの削除

コマンド
aws cloudformation delete-stack 
    --stack-name ${CF_STACK_NAME}

Stackの削除を待機

コマンド
aws cloudformation wait stack-delete-complete 
    --stack-name ${CF_STACK_NAME}

【注意】スタックを完全に削除できない場合があります。原因を解消し再試行してください。

想定される原因として、以下の様なものが考えられます。

  • S3バケットにデータが残っている
  • IAMロールにCloudFormation以外の手段でポリシーをアタッチしている

Stackの確認

コマンド
aws cloudformation describe-stacks 
    --stack-name ${CF_STACK_NAME}
結果
An error occurred (ValidationError) when calling the DescribeStacks operation: Stack with id firehose-jawsug-cli does not exist

以上

続きを読む

[JAWS-UG CLI] Amazon Kinesis Firehose re:入門 (5) Delivery Streamの削除

この記事について

JAWS-UG CLI専門支部 #90 Kinesis Firehose 復習編で実施するハンズオン用の手順書です。

前提条件

必要な権限

作業にあたっては、以下の権限を有したIAMユーザもしくはIAMロールを利用してください。

  • 以下のサービスに対するフルコントロール権限

    • Kinesis Firehose
    • IAM
    • EC2
    • S3
    • CloudWatch Logs
    • STS
    • (Lambda)
      • データの変換を行う場合
    • (KMS)
      • データの暗号化を行う場合

0. 準備

0.1. リージョンを指定

オレゴンリージョンで実施します。(東京マダー?)

コマンド
export AWS_DEFAULT_REGION="us-west-2"

0.2. 資格情報を確認

コマンド
aws configure list

インスタンスプロファイルを設定したEC2インスタンスでアクセスキーを設定せずに実行した場合、以下のようになります。

結果
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************QSAA         iam-role
secret_key     ****************c1xY         iam-role
    region                us-west-2              env    AWS_DEFAULT_REGION

0.3. バージョン確認

コマンド
aws --version
結果
aws-cli/1.11.129 Python/2.7.12 Linux/4.9.38-16.33.amzn1.x86_64 botocore/1.5.92

0.4. バージョンアップ(必要に応じて)

コマンド
sudo pip install -U awscli

0.5. 変数の確認

コマンド
cat << ETX

    DELIVERY_STREAM_NAME: ${DELIVERY_STREAM_NAME}

ETX

1. Delivery Streamの削除

1.1. Delivery Streamの削除

Delivery Stream名の確認

コマンド
cat << ETX

    DELIVERY_STREAM_NAME: ${DELIVERY_STREAM_NAME}

ETX
結果

    DELIVERY_STREAM_NAME: jawsug-cli-stream

Delivery Streamの確認

コマンド
aws firehose describe-delivery-stream 
    --delivery-stream-name ${DELIVERY_STREAM_NAME}
結果
{
    "DeliveryStreamDescription": {
        "HasMoreDestinations": false,
        "LastUpdateTimestamp": 1502033993.512,
        "VersionId": "2",
        "CreateTimestamp": 1502033075.665,
        "DeliveryStreamARN": "arn:aws:firehose:us-west-2:XXXXXXXXXXXX:deliverystream/jawsug-cli-stream",
        "DeliveryStreamStatus": "ACTIVE",
        "DeliveryStreamName": "jawsug-cli-stream",
        "Destinations": [
            {
                "DestinationId": "destinationId-000000000001",
                "ExtendedS3DestinationDescription": {
                    "RoleARN": "arn:aws:iam::XXXXXXXXXXXX:role/service-role-firehose",
                    "Prefix": "",
                    "BufferingHints": {
                        "IntervalInSeconds": 60,
                        "SizeInMBs": 1
                    },
                    "EncryptionConfiguration": {
                        "NoEncryptionConfig": "NoEncryption"
                    },
                    "CompressionFormat": "UNCOMPRESSED",
                    "S3BackupMode": "Disabled",
                    "CloudWatchLoggingOptions": {
                        "Enabled": true,
                        "LogStreamName": "S3Delivery",
                        "LogGroupName": "/aws/kinesisfirehose/jawsug-cli-stream"
                    },
                    "BucketARN": "arn:aws:s3:::firehose-jawsug-cli-s3bucket-1qtuo76w7zanq",
                    "ProcessingConfiguration": {
                        "Enabled": true,
                        "Processors": [
                            {
                                "Type": "Lambda",
                                "Parameters": [
                                    {
                                        "ParameterName": "NumberOfRetries",
                                        "ParameterValue": "3"
                                    },
                                    {
                                        "ParameterName": "LambdaArn",
                                        "ParameterValue": "arn:aws:lambda:us-west-2:XXXXXXXXXXXX:function:test-func-apache2json:$LATEST"
                                    }
                                ]
                            }
                        ]
                    }
                },
                "S3DestinationDescription": {
                    "RoleARN": "arn:aws:iam::XXXXXXXXXXXX:role/service-role-firehose",
                    "Prefix": "",
                    "BufferingHints": {
                        "IntervalInSeconds": 60,
                        "SizeInMBs": 1
                    },
                    "EncryptionConfiguration": {
                        "NoEncryptionConfig": "NoEncryption"
                    },
                    "CompressionFormat": "UNCOMPRESSED",
                    "CloudWatchLoggingOptions": {
                        "Enabled": true,
                        "LogStreamName": "S3Delivery",
                        "LogGroupName": "/aws/kinesisfirehose/jawsug-cli-stream"
                    },
                    "BucketARN": "arn:aws:s3:::firehose-jawsug-cli-s3bucket-1qtuo76w7zanq"
                }
            }
        ]
    }
}

Delivery Streamの削除

コマンド
aws firehose delete-delivery-stream 
    --delivery-stream-name ${DELIVERY_STREAM_NAME}

Delivery Streamの確認

完全に削除が完了するまで、数分かかります。しばらくお待ち下さい。

コマンド
aws firehose describe-delivery-stream 
    --delivery-stream-name ${DELIVERY_STREAM_NAME}
結果
An error occurred (ResourceNotFoundException) when calling the DescribeDeliveryStream operation: Firehose jawsug-cli-stream under account XXXXXXXXXXXX not found.

以上

続きを読む

[JAWS-UG CLI] Amazon Kinesis Firehose re:入門 (4) Kinesis Agentによるレコードの登録

この記事について

JAWS-UG CLI専門支部 #90 Kinesis Firehose 復習編で実施するハンズオン用の手順書です。

前提条件

必要な権限

作業にあたっては、以下の権限を有したIAMユーザもしくはIAMロールを利用してください。

  • 以下のサービスに対するフルコントロール権限

    • Kinesis Firehose
    • IAM
    • EC2
    • S3
    • CloudWatch Logs
    • STS
    • (Lambda)
      • データの変換を行う場合
    • (KMS)
      • データの暗号化を行う場合

0. 準備

0.1. リージョンを指定

オレゴンリージョンで実施します。(東京マダー?)

コマンド
export AWS_DEFAULT_REGION="us-west-2"

0.2. 資格情報を確認

コマンド
aws configure list

インスタンスプロファイルを設定したEC2インスタンスでアクセスキーを設定せずに実行した場合、以下のようになります。

結果
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************QSAA         iam-role
secret_key     ****************c1xY         iam-role
    region                us-west-2              env    AWS_DEFAULT_REGION

0.3. バージョン確認

コマンド
aws --version
結果
aws-cli/1.11.129 Python/2.7.12 Linux/4.9.38-16.33.amzn1.x86_64 botocore/1.5.92

0.4. バージョンアップ(必要に応じて)

コマンド
sudo pip install -U awscli

0.5. 変数の確認

コマンド
cat << ETX

    KEY_MATERIAL_FILE_NAME: ${KEY_MATERIAL_FILE_NAME}
    PUBLIC_IP_ADDRESS: ${PUBLIC_IP_ADDRESS}
    DELIVERY_STREAM_NAME: ${DELIVERY_STREAM_NAME}
    BUCKET_NAME: ${BUCKET_NAME}

ETX

1. ログイン

1.1. SSHで接続

初回接続時、yesを選択

コマンド
ssh -l ec2-user -i ~/.ssh/${KEY_MATERIAL_FILE_NAME} ${PUBLIC_IP_ADDRESS}

2. Kinesis Agentの設定

2.1. 設定ファイルの生成

設定ファイル名の指定

コマンド
AGENT_SETTING_FILE_NAME="agent.json"

デリバリーストリーム名の指定

コマンド
DELIVERY_STREAM_NAME="jawsug-cli-stream"

変数の確認

コマンド
cat << ETX

   AGENT_SETTING_FILE_NAME: ${AGENT_SETTING_FILE_NAME}
   DELIVERY_STREAM_NAME: ${DELIVERY_STREAM_NAME}

ETX
結果

   AGENT_SETTING_FILE_NAME: agent.json
   DELIVERY_STREAM_NAME: jawsug-cli-stream

設定ファイルの生成

コマンド
cat << EOF > ${AGENT_SETTING_FILE_NAME}
{
  "cloudwatch.emitMetrics": true,
  "cloudwatch.endpoint": "https://monitoring.us-west-2.amazonaws.com",
  "firehose.endpoint": "https://firehose.us-west-2.amazonaws.com",
  "flows": [
    {
      "filePattern": "/var/log/httpd/access_log",
      "deliveryStream": "${DELIVERY_STREAM_NAME}",
      "initialPosition": "START_OF_FILE"
    }
  ]
}
EOF

cat ${AGENT_SETTING_FILE_NAME}

JSONファイルの検証

コマンド
jsonlint -q ${AGENT_SETTING_FILE_NAME}

2.2. 設定ファイルの配置

既存ファイルの退避

コマンド
sudo cp /etc/aws-kinesis/agent.json /etc/aws-kinesis/agent.json.org

生成したファイルの配置

コマンド
sudo cp agent.json /etc/aws-kinesis/agent.json

権限の付与

Kinesis-Agentの実行ユーザである「aws-kinesis-agent-user」に対して、
データソースの読み取りおよび実行権限が必要です。

Writing to Amazon Kinesis Firehose Using Amazon Kinesis Agent

コマンド
sudo chmod 755 /var/log/httpd
sudo chmod 644 /var/log/httpd/*

サービスの再起動

コマンド
sudo service aws-kinesis-agent restart

ログオフ

コマンド
exit

3. 動作確認

3.1. Web Serverにアクセス

てきとうにアクセスしてみてください。

そして、1分ほど待ちます。。。

3.2. S3バケット上のファイルを確認

S3バケット上のファイルを確認

コマンド
aws s3 ls --recursive ${BUCKET_NAME}

S3 Bucket上のファイルをダウンロード

コマンド
mkdir data03
cd data03
コマンド
aws s3 sync s3://${BUCKET_NAME} .
結果
download: s3://jawsug-cli-firehose-************/2016/12/19/07/jawsug-cli-stream-1-2016-12-19-07-54-56-47a385b8-4075-44ec-bf15-4f6143b03ddb to 2016/12/19/07/jawsug-cli-stream-1-2016-12-19-07-54-56-47a385b8-4075-44ec-bf15-4f6143b03ddb

S3 Bucket上のファイルを閲覧

コマンド
cat (任意のファイル名)
結果
222.150.28.224 - - [03/Dec/2016:08:05:20 +0000] "GET / HTTP/1.1" 403 3839 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
222.150.28.224 - - [03/Dec/2016:08:05:21 +0000] "GET / HTTP/1.1" 403 3839 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"

3.3. ファイルの削除

ファイルの削除

コマンド
aws s3 rm --recursive s3://${BUCKET_NAME}/
結果
(省略)
コマンド
cd ..
rm -r data03

以上

続きを読む

[JAWS-UG CLI] Amazon Kinesis Firehose re:入門 (3) レコードの登録

この記事について

JAWS-UG CLI専門支部 #90 Kinesis Firehose 復習編で実施するハンズオン用の手順書です。

前提条件

必要な権限

作業にあたっては、以下の権限を有したIAMユーザもしくはIAMロールを利用してください。

  • 以下のサービスに対するフルコントロール権限

    • Kinesis Firehose
    • IAM
    • EC2
    • S3
    • CloudWatch Logs
    • STS
    • (Lambda)
      • データの変換を行う場合
    • (KMS)
      • データの暗号化を行う場合

0. 準備

0.1. リージョンを指定

オレゴンリージョンで実施します。(東京マダー?)

コマンド
export AWS_DEFAULT_REGION="us-west-2"

0.2. 資格情報を確認

コマンド
aws configure list

インスタンスプロファイルを設定したEC2インスタンスでアクセスキーを設定せずに実行した場合、以下のようになります。

結果
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************QSAA         iam-role
secret_key     ****************c1xY         iam-role
    region                us-west-2              env    AWS_DEFAULT_REGION

0.3. バージョン確認

コマンド
aws --version
結果
aws-cli/1.11.129 Python/2.7.12 Linux/4.9.38-16.33.amzn1.x86_64 botocore/1.5.92

0.4. バージョンアップ(必要に応じて)

コマンド
sudo pip install -U awscli

0.5. 変数の確認

コマンド
cat << ETX

    DELIVERY_STREAM_NAME: ${DELIVERY_STREAM_NAME}
    BUCKET_NAME: ${BUCKET_NAME}

ETX

1. 単一レコードの登録

1.1. データの生成

ファイル名の指定

コマンド
SINGLE_RECORD_FILE_NAME="record.json"

ファイルの生成

コマンド
cat << EOF > ${SINGLE_RECORD_FILE_NAME}
{
  "Data": "blobn"
}
EOF

cat ${SINGLE_RECORD_FILE_NAME}

ファイルの検証

コマンド
jsonlint -q ${SINGLE_RECORD_FILE_NAME}

1.2. データの登録

変数の確認

コマンド
cat << ETX

    DELIVERY_STREAM_NAME: ${DELIVERY_STREAM_NAME}
    SINGLE_RECORD_FILE_NAME: ${SINGLE_RECORD_FILE_NAME}

ETX
結果

    DELIVERY_STREAM_NAME: jawsug-cli-stream
    SINGLE_RECORD_FILE_NAME: record.json

データの登録

コマンド
aws firehose put-record 
    --delivery-stream-name ${DELIVERY_STREAM_NAME} 
    --record file://${SINGLE_RECORD_FILE_NAME}
結果
{
    "RecordId": "********************************************************************************************************************************************************************************************************************************"
}

1.3. データの確認

ファイルの確認

1分(BUFFER_INTERVALで指定した時間)待ちましょう。

コマンド
aws s3 ls s3://${BUCKET_NAME} --recursive
結果
2016-11-05 07:21:54          4 2016/11/05/07/jawsug-cli-stream-1-2016-11-05-07-21-53-60e3ea4c-5e75-4fbd-8ce2-11406f55a930

ファイルのダウンロード

コマンド
mkdir data01
cd data01
コマンド
aws s3 sync s3://${BUCKET_NAME} .
結果
download: s3://jawsug-cli-firehose-************/2016/11/23/11/jawsug-cli-stream-1-2016-11-23-11-18-58-947ea60d-041c-4750-ab31-cff260b7cf58 to 2016/11/23/11/jawsug-cli-stream-1-2016-11-23-11-18-58-947ea60d-041c-4750-ab31-cff260b7cf58

ファイルの確認

コマンド
cat (ダウンロードしたファイルのパス)
結果
blob

1.4. ファイルの削除

ファイルの削除

コマンド
aws s3 rm --recursive s3://${BUCKET_NAME}/
結果
delete: s3://jawsug-cli-firehose-************/2016/11/05/07/jawsug-cli-stream-1-2016-11-05-07-21-53-60e3ea4c-5e75-4fbd-8ce2-11406f55a930
コマンド
cd ..
rm -r data01

2. 複数レコードの一括登録

2.1. データの生成

ファイル名の指定

コマンド
MULTI_RECORDS_FILE_NAME="records.json"

ファイルの生成

コマンド
cat << EOF > ${MULTI_RECORDS_FILE_NAME}
[
  {
    "Data": "blob1n"
  },
  {
    "Data": "blob2n"
  },
  {
    "Data": "blob3n"
  },
  {
    "Data": "blob4n"
  }
]
EOF

cat ${MULTI_RECORDS_FILE_NAME}

ファイルの検証

コマンド
jsonlint -q ${MULTI_RECORDS_FILE_NAME}

2.2. データの登録

コマンド
aws firehose put-record-batch 
    --delivery-stream-name ${DELIVERY_STREAM_NAME} 
    --records file://${MULTI_RECORDS_FILE_NAME}
結果
{
    "FailedPutCount": 0,
    "RequestResponses": [
        {
            "RecordId": "********************************************************************************************************************************************************************************************************************************"
        },
        {
            "RecordId": "********************************************************************************************************************************************************************************************************************************"
        },
        {
            "RecordId": "********************************************************************************************************************************************************************************************************************************"
        },
        {
            "RecordId": "********************************************************************************************************************************************************************************************************************************"
        }
    ]
}

2.3. データの確認

ファイルの確認

1分(BUFFER_INTERVALで指定した時間)待ちましょう。

コマンド
aws s3 ls s3://${BUCKET_NAME} --recursive
結果
2016-11-23 11:33:36         24 2016/11/23/11/jawsug-cli-stream-1-2016-11-23-11-33-35-e3f2b6dd-7923-4f54-aeff-301ddc998006

ファイルのダウンロード

コマンド
mkdir data02
cd data02
コマンド
aws s3 sync s3://${BUCKET_NAME} .
結果
download: s3://jawsug-cli-firehose-************/2016/11/23/11/jawsug-cli-stream-1-2016-11-23-11-18-58-947ea60d-041c-4750-ab31-cff260b7cf58 to 2016/11/23/11/jawsug-cli-stream-1-2016-11-23-11-18-58-947ea60d-041c-4750-ab31-cff260b7cf58

ファイルの確認

コマンド
cat (ダウンロードしたファイルのパス)
結果
blob1
blob2
blob3
blob4

2.4. ファイルの削除

ファイルの削除

コマンド
aws s3 rm --recursive s3://${BUCKET_NAME}/
結果
delete: s3://jawsug-cli-firehose-************/2016/11/23/11/jawsug-cli-stream-1-2016-11-23-11-33-35-e3f2b6dd-7923-4f54-aeff-301ddc998006
コマンド
cd ..
rm -r data02

以上

続きを読む

[JAWS-UG CLI] Amazon Kinesis Firehose re:入門 (2) Delivery Streamの作成

この記事について

JAWS-UG CLI専門支部 #90 Kinesis Firehose 復習編で実施するハンズオン用の手順書です。

前提条件

必要な権限

作業にあたっては、以下の権限を有したIAMユーザもしくはIAMロールを利用してください。

  • 以下のサービスに対するフルコントロール権限

    • Kinesis Firehose
    • IAM
    • EC2
    • S3
    • CloudWatch Logs
    • STS
    • (Lambda)
      • データの変換を行う場合
    • (KMS)
      • データの暗号化を行う場合

0. 準備

0.1. リージョンを指定

オレゴンリージョンで実施します。(東京マダー?)

コマンド
export AWS_DEFAULT_REGION="us-west-2"

0.2. 資格情報を確認

コマンド
aws configure list

インスタンスプロファイルを設定したEC2インスタンスでアクセスキーを設定せずに実行した場合、以下のようになります。

結果
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************QSAA         iam-role
secret_key     ****************c1xY         iam-role
    region                us-west-2              env    AWS_DEFAULT_REGION

0.3. バージョン確認

コマンド
aws --version
結果
aws-cli/1.11.129 Python/2.7.12 Linux/4.9.38-16.33.amzn1.x86_64 botocore/1.5.92

0.4. バージョンアップ(必要に応じて)

コマンド
sudo pip install -U awscli

0.5. 変数の確認

コマンド
cat << ETX

    ROLE_ARN: ${ROLE_ARN}
    BUCKET_NAME: ${BUCKET_NAME}

ETX

1. Delivery Streamの作成

1.1. 設定ファイルの作成

Delivery Stream名の指定

コマンド
DELIVERY_STREAM_NAME="jawsug-cli-stream"

定義ファイル名の指定

コマンド
S3_DESTINATION_FILE_NAME="s3_destination_configuration.json"

バッファサイズの指定

コマンド
BUFFER_SIZE=1

バッファインターバルの指定

コマンド
BUFFER_INTERVAL=60

ロググループ名およびログストリーム名の指定

コマンド
LOG_GROUP_NAME="/aws/kinesisfirehose/${DELIVERY_STREAM_NAME}"
LOG_STREAM_NAME="S3Delivery"

変数を確認

コマンド
cat << ETX

    S3_DESTINATION_FILE_NAME: ${S3_DESTINATION_FILE_NAME}
    ROLE_ARN: ${ROLE_ARN}
    BUCKET_NAME: ${BUCKET_NAME}
    BUFFER_SIZE: ${BUFFER_SIZE}
    BUFFER_INTERVAL: ${BUFFER_INTERVAL}
    LOG_GROUP_NAME: ${LOG_GROUP_NAME}
    LOG_STREAM_NAME: ${LOG_STREAM_NAME}

ETX
結果

    S3_DESTINATION_FILE_NAME: s3_destination_configuration.json
    ROLE_ARN: arn:aws:iam::XXXXXXXXXXXX:role/service-role-firehose
    BUCKET_NAME: firehose-jawsug-cli-s3bucket-134czh3hcofqz
    BUFFER_SIZE: 1
    BUFFER_INTERVAL: 60
    LOG_GROUP_NAME: /aws/kinesisfirehose/jawsug-cli-stream
    LOG_STREAM_NAME: S3Delivery

定義を生成

コマンド
cat << EOF > ${S3_DESTINATION_FILE_NAME}
{
  "RoleARN": "${ROLE_ARN}",
  "BucketARN": "arn:aws:s3:::${BUCKET_NAME}",
  "Prefix": "",
  "BufferingHints": {
    "SizeInMBs": ${BUFFER_SIZE},
    "IntervalInSeconds": ${BUFFER_INTERVAL}
  },
  "CompressionFormat": "UNCOMPRESSED",
  "EncryptionConfiguration": {
    "NoEncryptionConfig": "NoEncryption"
  },
  "CloudWatchLoggingOptions": {
    "Enabled": true,
    "LogGroupName": "${LOG_GROUP_NAME}",
    "LogStreamName": "${LOG_STREAM_NAME}"
  }
}
EOF

cat ${S3_DESTINATION_FILE_NAME}
結果
{
  "RoleARN": "arn:aws:iam::************:role/service-role-firehose",
  "BucketARN": "arn:aws:s3:::jawsug-cli-firehose-************",
  "Prefix": "",
  "BufferingHints": {
    "SizeInMBs": ,
    "IntervalInSeconds":
  },
  "CompressionFormat": "UNCOMPRESSED",
  "EncryptionConfiguration": {
    "NoEncryptionConfig": "NoEncryption"
  },
  "CloudWatchLoggingOptions": {
    "Enabled": true,
    "LogGroupName": "jawsug-cli-firehose",
    "LogStreamName": "handson"
  }
}

JSONファイルを検証

コマンド
jsonlint -q ${S3_DESTINATION_FILE_NAME}

1.2. Delivery Streamの作成

パラメータの確認

コマンド
cat << ETX

   DELIVERY_STREAM_NAME: "${DELIVERY_STREAM_NAME}"
   S3_DESTINATION_FILE_NAME: "${S3_DESTINATION_FILE_NAME}"

ETX
結果

   DELIVERY_STREAM_NAME: "jawsug-cli-stream"
   S3_DESTINATION_FILE_NAME: "s3-destination.json"

Delivery Streamの作成

コマンド
aws firehose create-delivery-stream 
    --delivery-stream-name ${DELIVERY_STREAM_NAME} 
    --s3-destination-configuration file://${S3_DESTINATION_FILE_NAME}
結果
{
    "DeliveryStreamARN": "arn:aws:firehose:us-west-2:************:deliverystream/jawsug-cli-stream"
}

Delivery Streamの確認

デリバリーストリームのステータスがACTIVEになってから次の手順を実行してください。

コマンド
aws firehose describe-delivery-stream 
    --delivery-stream-name ${DELIVERY_STREAM_NAME}
結果
{
    "DeliveryStreamDescription": {
        "HasMoreDestinations": false,
        "VersionId": "1",
        "CreateTimestamp": 1478329794.659,
        "DeliveryStreamARN": "arn:aws:firehose:us-west-2:************:deliverystream/jawsug-cli-stream",
        "DeliveryStreamStatus": "ACTIVE",
        "DeliveryStreamName": "jawsug-cli-stream",
        "Destinations": [
            {
                "DestinationId": "destinationId-000000000001",
                "S3DestinationDescription": {
                    "RoleARN": "arn:aws:iam::************:role/service-role-firehose",
                    "Prefix": "",
                    "BufferingHints": {
                        "IntervalInSeconds": 60,
                        "SizeInMBs": 1
                    },
                    "EncryptionConfiguration": {
                        "NoEncryptionConfig": "NoEncryption"
                    },
                    "CompressionFormat": "UNCOMPRESSED",
                    "CloudWatchLoggingOptions": {
                        "Enabled": true,
                        "LogStreamName": "handson",
                        "LogGroupName": "jawsug-cli-firehose"
                    },
                    "BucketARN": "arn:aws:s3:::jawsug-cli-firehose-************"
                }
            }
        ]
    }
}

以上

続きを読む

[JAWS-UG CLI] Amazon Kinesis Firehose re:入門 (1) 事前準備(Source(Kinesis Agent)およびDestination(S3)の作成)

この記事について

JAWS-UG CLI専門支部 #90 Kinesis Firehose 復習編で実施するハンズオン用の手順書です。

前提条件

必要な権限

作業にあたっては、以下の権限を有したIAMユーザもしくはIAMロールを利用してください。

  • 以下のサービスに対するフルコントロール権限

    • Kinesis Firehose
    • IAM
    • EC2
    • S3
    • CloudWatch Logs
    • STS
    • (Lambda)
      • データの変換を行う場合
    • (KMS)
      • データの暗号化を行う場合

0. 準備

0.1. リージョンを指定

オレゴンリージョンで実施します。(東京マダー?)

コマンド
export AWS_DEFAULT_REGION="us-west-2"

0.2. 資格情報を確認

コマンド
aws configure list

インスタンスプロファイルを設定したEC2インスタンスでアクセスキーを設定せずに実行した場合、以下のようになります。

結果
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************QSAA         iam-role
secret_key     ****************c1xY         iam-role
    region                us-west-2              env    AWS_DEFAULT_REGION

0.3. バージョン確認

コマンド
aws --version
結果
aws-cli/1.11.129 Python/2.7.12 Linux/4.9.38-16.33.amzn1.x86_64 botocore/1.5.92

0.4. バージョンアップ(必要に応じて)

コマンド
sudo pip install -U awscli

1. 管理対象の構築

CloudFormationを利用して、Source(Kinesis AgentをインストールしたEC2インスタンス)とDestination(S3バケット)を作成します。

1.1. KeyPairの作成

EC2インスタンス用にKeyPairを作成します。

KeyPairの名前を指定

コマンド
AWS_ID=$(aws sts get-caller-identity 
    --query "Account" 
    --output text) 
    && echo ${AWS_ID}
コマンド
KEY_PAIR_NAME="${AWS_ID}_firehose_jawsug_cli"
KEY_MATERIAL_FILE_NAME=${KEY_PAIR_NAME}.pem

同名KeyPairの不存在を確認

コマンド
aws ec2 describe-key-pairs 
    --query "KeyPairs[?KeyName==`${KEY_PAIR_NAME}`]"
結果
[]

KeyPairの作成

コマンド
aws ec2 create-key-pair 
    --key-name ${KEY_PAIR_NAME} 
    --query "KeyMaterial" 
    --output text 
    > ~/.ssh/${KEY_MATERIAL_FILE_NAME} 
    && cat ~/.ssh/${KEY_MATERIAL_FILE_NAME}

KeyPairの存在を確認

コマンド
aws ec2 describe-key-pairs 
    --query "KeyPairs[?KeyName==`${KEY_PAIR_NAME}`]"
結果
[
    {
        "KeyName": "XXXXXXXXXXXX_firehose_jawsug_cli",
        "KeyFingerprint": "xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
    }
]

秘密鍵のPermissionを変更

コマンド
chmod 600 ~/.ssh/${KEY_MATERIAL_FILE_NAME}
ls -al ~/.ssh/${KEY_MATERIAL_FILE_NAME}
結果
-rw------- 1 ec2-user ec2-user 1671 Aug  5 18:33 /home/ec2-user/.ssh/788063364413_firehose_jawsug_cli.pem

1.2. CloudFormation テンプレートの生成

テンプレートの作成

コマンド
CF_TEMPLATE_FILE_NAME="firehose_jawsug_cli.yml"
コマンド
cat << EOF > ${CF_TEMPLATE_FILE_NAME}
AWSTemplateFormatVersion: "2010-09-09"
Description: JAWS-UG CLI Kinesis Firehose Hands-on

Parameters: 
  VPCNetworkAddress: 
    Type: String
    Description: "Network Address on AWS"
    MinLength: 9
    MaxLength: 18
    # AllowedPattern: "(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})"
    Default: "10.0.0.0/16"
  PublicSubnetAddr: 
    Type: String
    Description: "Network Address on AWS"
    MinLength: 9
    MaxLength: 18
    # AllowedPattern: "(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})"
    Default: "10.0.0.0/24"
  KeyPairName:
    Type: AWS::EC2::KeyPair::KeyName


Resources:
  S3Bucket: 
    Type: "AWS::S3::Bucket"
  IAMRole: 
    Type: "AWS::IAM::Role"
    Properties: 
      RoleName: "service-role-firehose"
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - 
            Effect: "Allow"
            Principal: 
              Service: 
                - "firehose.amazonaws.com"
            Action: 
              - "sts:AssumeRole"
      Path: "/"
  IAMPolicy:
    Type: "AWS::IAM::Policy"
    Properties: 
      PolicyName: "service-policy-firehose"
      PolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - 
            Effect: "Allow"
            Action: 
              - "s3:AbortMultipartUpload"
              - "s3:GetBucketLocation"
              - "s3:GetObject"
              - "s3:ListBucket"
              - "s3:ListBucketMultipartUploads"
              - "s3:PutObject"
            Resource:
              - !GetAtt S3Bucket.Arn
              - Fn::Join: 
                - "/"
                - 
                  - !GetAtt S3Bucket.Arn
                  - "*"
          - 
            Effect: "Allow"
            Action: 
              - "logs:PutLogEvents"
            Resource: "*"
      Roles:
        - Ref: IAMRole

  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCNetworkAddress
      Tags: 
        - 
          Key: "Name"
          Value: "KinesisFirehoseClient"
  IGW:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags: 
        - 
          Key: "Name"
          Value: "KinesisFirehoseClient"
  AttachIGW:
      Type: AWS::EC2::VPCGatewayAttachment
      Properties:
          VpcId:
              Ref: VPC
          InternetGatewayId:
              Ref: IGW
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties: 
      AvailabilityZone: 
        Fn::Select: 
          - 0
          - Fn::GetAZs: ""
      CidrBlock: !Ref PublicSubnetAddr
      MapPublicIpOnLaunch: true
      VpcId: 
        Ref: VPC
      Tags: 
        - 
          Key: "Name"
          Value: "Public"
  PublicRT:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: VPC
      Tags: 
        - 
          Key: Name
          Value: Public
  PublicDefaultRoute:
    Type: AWS::EC2::Route
    Properties: 
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: 
        Ref: IGW
      RouteTableId: 
        Ref: PublicRT
  PublicSubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId:
        Ref: PublicSubnet
      RouteTableId:
        Ref: PublicRT
  SecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties: 
      GroupDescription: WebServer
      SecurityGroupEgress:
        - 
          IpProtocol: "-1"
          CidrIp: "0.0.0.0/0"
      SecurityGroupIngress:
        - 
          IpProtocol: "tcp"
          FromPort: 80
          ToPort: 80
          CidrIp: "0.0.0.0/0"        
        - 
          IpProtocol: "tcp"
          FromPort: 22
          ToPort: 22
          CidrIp: "0.0.0.0/0"
      VpcId:
        Ref: VPC    
  InstanceRole: 
    Type: "AWS::IAM::Role"
    Properties: 
      RoleName: "instance-role"
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - 
            Effect: "Allow"
            Principal: 
              Service: 
                - "ec2.amazonaws.com"
                - "ssm.amazonaws.com"
            Action: 
              - "sts:AssumeRole"
      Path: "/"
      ManagedPolicyArns: 
        - "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
        - "arn:aws:iam::aws:policy/AmazonKinesisFirehoseFullAccess"
  InstanceProfile: 
    Type: "AWS::IAM::InstanceProfile"
    Properties: 
      Path: "/"
      Roles: 
        - !Ref InstanceRole
  Instance:
    Type: "AWS::EC2::Instance"
    Properties:
      KeyName: 
        Ref: KeyPairName
      ImageId: ami-6df1e514
      InstanceType: t2.micro
      SecurityGroupIds: 
        - Ref: SecurityGroup
      SubnetId:
        Ref: PublicSubnet
      IamInstanceProfile:
        Ref: InstanceProfile
      BlockDeviceMappings: 
        - DeviceName: "/dev/sdm"
          Ebs: 
            VolumeType: "gp2"
            DeleteOnTermination: "true"
            VolumeSize: "8"
      UserData:
        Fn::Base64: |
          #!/bin/bash
          cd /tmp
          sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
          sudo yum install -y aws-kinesis-agent
          sudo chkconfig aws-kinesis-agent on
          sudo service aws-kinesis-agent start
          sudo yum install -y httpd
          sudo chkconfig httpd on
          sudo service httpd start
          sudo yum install npm --enablerepo=epel -y
          sudo npm install -g jsonlint

Outputs:
  S3BucketName:
    Value:
      Ref: S3Bucket
  IAMRoleARN:
    Value: !GetAtt IAMRole.Arn
  PublicIP:
    Value: !GetAtt Instance.PublicIp
EOF

cat ${CF_TEMPLATE_FILE_NAME}

CloudFormation テンプレートの検証

コマンド
aws cloudformation validate-template 
    --template-body file://${CF_TEMPLATE_FILE_NAME}
結果
{
    "CapabilitiesReason": "The following resource(s) require capabilities: [AWS::IAM::InstanceProfile, AWS::IAM::Role]",
    "Description": "JAWS-UG CLI Kinesis Firehose Hands-on",
    "Parameters": [
        {
            "NoEcho": false,
            "ParameterKey": "KeyPairName"
        },
        {
            "DefaultValue": "10.0.0.0/16",
            "NoEcho": false,
            "Description": "Network Address on AWS",
            "ParameterKey": "VPCNetworkAddress"
        },
        {
            "DefaultValue": "10.0.0.0/24",
            "NoEcho": false,
            "Description": "Network Address on AWS",
            "ParameterKey": "PublicSubnetAddr"
        }
    ],
    "Capabilities": [
        "CAPABILITY_NAMED_IAM"
    ]
}

1.3. CloudFormation Stackの作成

CloudFormation Stack名の指定

コマンド
CF_STACK_NAME="firehose-jawsug-cli"

同名CloudFormation Stackの不存在を確認

コマンド
aws cloudformation describe-stacks 
    --query "Stacks[?StackName==`${CF_STACK_NAME}`]"
結果
[]

CloudFormation Stackの作成

コマンド
aws cloudformation create-stack 
    --stack-name ${CF_STACK_NAME} 
    --template-body file://${CF_TEMPLATE_FILE_NAME} 
    --capabilities "CAPABILITY_NAMED_IAM" 
    --parameters ParameterKey=KeyPairName,ParameterValue=${KEY_PAIR_NAME},UsePreviousValue=false
結果
{
    "StackId": "arn:aws:cloudformation:us-west-2:XXXXXXXXXXXX:stack/firehose-jawsug-cli/8812e540-7a0e-11e7-aac3-50a68d01a68d"
}

CloudFormation Stackの作成完了を待機

5分程度で作成が完了すると思います。

コマンド
aws cloudformation wait stack-create-complete 
    --stack-name ${CF_STACK_NAME}
結果
(返値無し)

CloudFormation Stackの存在を確認

“StackStatus”が”CREATE_COMPLETE”になっていることを確認します。

コマンド
aws cloudformation describe-stacks 
    --stack-name ${CF_STACK_NAME}
結果
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:us-west-2:XXXXXXXXXXXX:stack/firehose-jawsug-cli/4043bde0-7a16-11e7-8701-50a686be73ba",
            "Description": "JAWS-UG CLI Kinesis Firehose Hands-on",
            "Parameters": [
                {
                    "ParameterValue": "XXXXXXXXXXXX_firehose_jawsug_cli",
                    "ParameterKey": "KeyPairName"
                },
                {
                    "ParameterValue": "10.0.0.0/16",
                    "ParameterKey": "VPCNetworkAddress"
                },
                {
                    "ParameterValue": "10.0.0.0/24",
                    "ParameterKey": "PublicSubnetAddr"
                }
            ],
            "Tags": [],
            "Outputs": [
                {
                    "OutputKey": "PublicIP",
                    "OutputValue": "54.191.102.113"
                },
                {
                    "OutputKey": "IAMRoleARN",
                    "OutputValue": "arn:aws:iam::XXXXXXXXXXXX:role/service-role-firehose"
                },
                {
                    "OutputKey": "S3BucketName",
                    "OutputValue": "firehose-jawsug-cli-s3bucket-134czh3hcofqz"
                }
            ],
            "CreationTime": "2017-08-05T19:42:44.440Z",
            "Capabilities": [
                "CAPABILITY_NAMED_IAM"
            ],
            "StackName": "firehose-jawsug-cli",
            "NotificationARNs": [],
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false
        }
    ]
}

1.4. パラメータの確認

以降の手順で必要になるパラメータを抽出します。

  • IAMロールARN
  • S3バケット名
  • パブリックIPアドレス
コマンド
OUTPUTKEY_ROLE_ARN="IAMRoleARN"
OUTPUTKEY_BUCKET_NAME="S3BucketName"
OUTPUTKEY_PUBLIC_IP_ADDRESS="PublicIP"
コマンド
ROLE_ARN=$(aws cloudformation describe-stacks 
    --stack-name ${CF_STACK_NAME} 
    --query "Stacks[].Outputs[?OutputKey==`${OUTPUTKEY_ROLE_ARN}`].OutputValue[]" 
    --output text) 
    && echo ${ROLE_ARN}
結果
arn:aws:iam::XXXXXXXXXXXX:role/service-role-firehose
コマンド
BUCKET_NAME=$(aws cloudformation describe-stacks 
    --stack-name ${CF_STACK_NAME} 
    --query "Stacks[].Outputs[?OutputKey==`${OUTPUTKEY_BUCKET_NAME}`].OutputValue[]" 
    --output text) 
    && echo ${BUCKET_NAME}
結果
firehose-jawsug-cli-s3bucket-134czh3hcofqz
コマンド
PUBLIC_IP_ADDRESS=$(aws cloudformation describe-stacks 
    --stack-name ${CF_STACK_NAME} 
    --query "Stacks[].Outputs[?OutputKey==`${OUTPUTKEY_PUBLIC_IP_ADDRESS}`].OutputValue[]" 
    --output text) 
    && echo ${PUBLIC_IP_ADDRESS}
結果
54.191.***.***

動作確認

パブリックIPアドレスにブラウザでアクセスします。

以上

続きを読む