AtlassianのLocalStackを使ってみてなんとなく理解するまでのお話

Atlassianが「LocalStack」なんてとても便利そうなものを出していたけど、なかなか使い方を解説しているページが見つからなかったので、とりあえず使いながらなんとなく中身を理解するまでのお話。

https://github.com/atlassian/localstack
スクリーンショット 2017-04-23 17.53.59.png

起動

いくつかGithubで利用方法が紹介されていますが、今回はdockerでの利用をしてみます。

$ docker run -it -p 4567-4578:4567-4578 -p 8080:8080 atlassianlabs/localstack
2017-04-23 08:50:15,876 INFO supervisord started with pid 1
2017-04-23 08:50:16,879 INFO spawned: 'dashboard' with pid 7
2017-04-23 08:50:16,885 INFO spawned: 'infra' with pid 8
(. .venv/bin/activate; bin/localstack web --port=8080)
. .venv/bin/activate; exec localstack/mock/infra.py
Starting local dev environment. CTRL-C to quit.
 * Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)
 * Restarting with stat
Starting local Elasticsearch (port 4571)...
Starting mock ES service (port 4578)...
Starting mock S3 server (port 4572)...
Starting mock SNS server (port 4575)...
Starting mock SQS server (port 4576)...
Starting mock API Gateway (port 4567)...
Starting mock DynamoDB (port 4569)...
Starting mock DynamoDB Streams (port 4570)...
Starting mock Firehose (port 4573)...
Starting mock Lambda (port 4574)...
Starting mock Kinesis (port 4568)...
Starting mock Redshift server (port 4577)...
 * Debugger is active!
2017-04-23 08:50:18,537 INFO success: dashboard entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2017-04-23 08:50:18,538 INFO success: infra entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
 * Debugger PIN: 844-652-544
Ready.

とりあえず起動はしたみたい。で、http://localhost:8080/にアクセスしてみたけど、こんな感じで何も表示されず。

スクリーンショット 2017-04-23 17.59.04.png

使ってみてわかりましたが、要は本当に各種サービスが以下のアドレスで利用できるようにしてくれたもののようです。

全部試すのもアレなので、とりあえず馴染み深いDynamoDBとS3を使ってみる。

DynamoDBのテーブル作成

全然関係ないですが、http://localhost:4569/にアクセスすると以下のレスポンスをもらえます。デフォルトはus-east-1で動いている想定のようで。(Githubページにも書いてあった。バインドすればいくつか設定を変更できるようですね。)

healthy: dynamodb.us-east-1.amazonaws.com 

では早速テーブルをCLIから作ってみます。一応作成前にlist-tablesをしてみますが、もちろん何も登録されていません。

$ aws --endpoint-url=http://localhost:4569 dynamodb list-tables
{
    "TableNames": []
}

こちらを参考にさせていただいて、create-tableコマンドを発行します。

$ aws --endpoint-url=http://localhost:4569 dynamodb create-table --table-name test --attribute-definitions AttributeName=testId,AttributeType=S --key-schema AttributeName=testId,KeyType=HASH --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:us-east-1:000000000000:table/test", 
        "AttributeDefinitions": [
            {
                "AttributeName": "testId", 
                "AttributeType": "S"
            }
        ], 
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0, 
            "WriteCapacityUnits": 1, 
            "ReadCapacityUnits": 1
        }, 
        "TableSizeBytes": 0, 
        "TableName": "test", 
        "TableStatus": "CREATING", 
        "KeySchema": [
            {
                "KeyType": "HASH", 
                "AttributeName": "testId"
            }
        ], 
        "ItemCount": 0, 
        "CreationDateTime": 1492937089.534
    }
}

なんか作られたっぽいですね。もう一度list-tablesをしてみます。

$ aws --endpoint-url=http://localhost:4569 dynamodb list-tables
{
    "TableNames": [
        "test"
    ]
}

出来上がってますね。なるほど、本当にAWS上でやる操作をEndpointURLを変更するだけで操作できてしまうようです。これは思っていたよりも便利かも。

S3のバケットを作成してみる

S3のバケットも作成できるのか試してみます。まずバケットのリストを見てみますが、当然何もありません。

$ aws --endpoint-url=http://localhost:4572 s3 ls
(何も表示されず)

では作成してみます。

$ aws --endpoint-url=http://localhost:4572 s3 mb s3://kojiisd-test/
make_bucket: s3://kojiisd-test/
$ aws --endpoint-url=http://localhost:4572 s3 ls
2006-02-04 01:45:09 kojiisd-test

まじか、これは便利。ただdockerでサービス起動したら停止時に中身が消えてしまうから、できれば作成したものが残るような起動方法の方が色々試そうとしたら適していそうですね。
(作成時間がはちゃめちゃですが、とりあえずそこまで問題にはならないかな)

ちなみにDynamoDBのテーブルとS3のバケットを作成してから気づきましたが、http://localhost:8080/にアクセスしたら、作成したものが表示されていました。なるほど、そのためのDashBoardだったのか。素敵。

スクリーンショット 2017-04-23 18.20.02.png

まとめ

どれくらいどこまで何ができるのかは気になりますが、一般的なことであればだいたいローカルでできるような気がします。しかもEndpointURLを変更するだけで良さそうなので、これはかなり便利かも。今度作成したアプリを全てLocalStackで動かしてみるとかやってみようかな。

とりあえず、もっとこれは知られるべきと、思いました。

続きを読む

CloudFormerのちょっとした落とし穴

はじめに

同じ内容で2回もハマってしまったのでメモ。

CloudFormerで既存のAWS構成をテンプレートに落とした時、CloudFormationの構文エラーになるJSONが吐かれる事があるという話です。

本題

文字列の配列でなければならないプロパティーが、単一の文字列になってしまいます。

CloudFormerの出力
{
    "s3policyxxxbucket": {
      "Type": "AWS::S3::BucketPolicy",
      "Properties": {
        "Bucket": {
          "Ref": "s3xxxbucket"
        },
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Id": "Policy-xxx",
          "Statement": [
            {
              "Sid": "xxxxxxxxxxxx",
              "Effect": "Allow",
              "Principal": "*",
              "Action": "s3:GetObject",
              "Resource": "<省略>",
              "Condition": {
                "IpAddress": {
                  "aws:SourceIp": "0.0.0.0/0"
                }
              }
            }
          ]
        }
      }
    }
}

上記の"Action": "s3:GetObject"が問題で、正しくは"Action": [ "s3:GetObject" ]です。

最後に

CloudFormerで既存のAWS構成をテンプレートに落とすことが出来るのは便利ですが、それを使う時にはちょっと注意が必要ですね。

それと、CloudFormationのエラー出力がもう少し情報を出してくれれば..と思います。今回もInvalid Resource ...ぐらいしか言ってくれなかったので、他の箇所を疑ってしまい、解決するまでに時間を浪費しました。

とは言え、CloudFormerの出力はそのまま使うなと公式にも注意書きしてあった気がするので、よく確認しなかった自分が悪いのですが。

続きを読む

CloudFormationの特徴とはじめ方

はじめに

本記事はCloudformationを始めようとしている人向けです。
細かい技術的な話よりは、特徴だったり始め方の手順だったりが書かれています。
公式ドキュメントを舐めるのが面倒な人はちょうどいいです。

概要

インフラ環境をテンプレート化し、何度実行しても同じ環境を簡単に構築することができる。
AWSのアイコンをペタペタ並べていくことでテンプレートを新規作成する「Design Template」機能や、既存のインフラ環境を自動でテンプレート化してくれる「CloudFormer」という機能がある。
また、コードでテンプレートを作成することも可能であり、デフォルトの言語はJSONとなっている。

メリット

大きな特徴として、以下が挙げられる。

  1. インフラがコードで管理できること
  2. 作成・削除・更新が容易であること

何がもたらされるのか

  • コードで管理できるということは、バージョン管理が容易になる。
    「インフラの成長過程がわかる」とよく言われる所以
  • オペレーションミスなし、作業者の技術力に依存しない環境構築が可能になる
  • 運用中、値変更があってもリスクなしでアップデートできる
  • 開発環境など限定的にしか使用しないインフラのランニングコストを削減できる
  • 既存のインフラ環境をすぐに可視化できる(構成図を作成・更新する工数削減)

CloudFormationの金額

無料で使用できる。立ち上がったリソースに対して課金が発生する。

機能

CloudFormation Designer

おなじみのAWSアイコンを配置し、繋いでいくことでテンプレートが作成できる。
作成したDesignは保存、ダウンロード、ローカルから開く、などができる。
アイコンは単純なAWSサービスだけではなく、ルートテーブルやVPCEndpointなど、普段は見ないアイコンも存在する。
理由は、この機能は構成図を作成するためのものではなく「テンプレートを作成する」機能のため、詳細なポリシーまで指定する必要がある。

CloudFormer

既存で構築されているインフラ環境をテンプレートに落とし込める機能。
自動でCloudFormation用のインスタンスを作成し、テンプレート作成準備を数分で構築する。
すべてのCloudFormationのリソースをサポートしている。
注意点としては、新規インスタンスを一台起動させて実行するため、課金が発生する。

詳しい特徴は以下の通り

  • どのリソースをテンプレートに含めるか制御可能
  • リソースを選択すると、従属するリソースも自動選択(変更可能)
  • EC2インスタンスを選択すると、そのインスタンスが起動された元のAMIが指定される

CloudFormerで生成されたテンプレートを手修正し、最終的なテンプレートとして利用することを推奨している

開始手順

CloudFormerスタックを作成する

  1. Cloudformation画面にて「Create New Stack」をクリック
  2. 「Select a sample template」のプルダウンから「Cloudformer」を選択
  3. 「Next」で次ページ
  4. 必要な情報を入力する
  5. Stack Name CloudFormerのスタック名
  6. Password CloudFormerにてテンプレートを作成するページへログインするためのパスワード
  7. Username CloudFormerにてテンプレートを作成するページへログインするためのユーザ名
  8. VPCSelection CloudFormer用インスタンスが立ち上がるVPC。特に変更はしない

  9. 「Next」で次ページ

  10. 必要な情報を入力する(特に設定しなくても進められる)

  11. TagとKeyの設定。リソースにタグを適用できるため、識別や分類したい場合は設定する

  12. Permissionsの権限がないとCloudformationは実行できないため、必ず実行権を持ったロールアカウントにする

  13. 「Next」で次ページ

  14. サマリを確認後、「Create」をクリック

  15. スタック作成が実行されるため、起動完了の「CREATE_COMPLETE」となるまで待機

Cloudformationテンプレートを作成する

  1. CloudFormerのスタックを選択し、「Outputs」タブを選択
  2. 「Value」に表示されるURLを踏み、テンプレート作成画面へ飛ぶ
  3. 「アクセス保護されてないページ」の警告を通過する
  4. テンプレート化を実施するリージョンを選択し「Continue」をクリック
  5. テンプレートに含めたいリソースの選択が続く。含める含めないを考慮しながら「Continue」をクリックしていく
  6. サマリを確認後、「Done」をクリック
  7. テンプレートが作成されているので、S3のどのバケットに保存するか選択する
  8. 終了

Cloudformerスタックを削除する

  1. テンプレート化が確認されたらスタックを削除(インスタンス分が課金されている)
  2. 終了

JSONテンプレート

テンプレートはデフォルトでJSON形式で記述される。
いくつかのセクションに分かれており、そのうち「Resources」セクションのみ必須で記述する必要がある。

セクションは以下の通り

  • Format Version(任意)

    CloudFormationのテンプレートバージョンを指定する
    
  • Description(オプション)
    テンプレートを説明するテキスト文字列。テンプレートのパラメータ等を入力する際に表示される
    
  • Metadata(オプション)
    テンプレートに関する追加情報を提供する
    
  • Parameters(任意)
    実行時にユーザに入力を求めるパラメータを定義する。インフラ構成は変えず、IPやインスタンスタイプを変えたいなどの運用で便利。
    
  • Mappings(任意)
    HashTableのようなもの。条件パラメータ値の指定に使用できる。リージョンやユーザ入力パラメータによって値が変わるものに利用する。Mappingsを利用することでテンプレートの再利用性が向上する
    
  • 条件(オプション)
    条件つきのリソースの制御が可能
    
  • 変換
    サーバレスアプリケーションの場合は、使用するAWS SAMのバージョンを指定する
    
  • Resources(必須)
    インスタンスやS3など、使用するリソースを指定する。
    
  • Output(任意)
    スタック構築後にCloudFormationから出力させる値(DNS名やEIP値など)
    

テンプレート作成のためのいくつか注意点(共通)

  1. CloudFormation Designerでアイコンを並べていくだけではテンプレートとして機能しない
  2. テンプレート作成し保存しただけではCloudFormationは実行できない
  3. 立ち上げたいインフラ環境のすべてをひとつのテンプレートとして作成すべきではない

1. CloudFormation Designerに関わらず、CloudFormationテンプレートではリソース同士の「依存関係」が重要になる

  • ここで言う依存関係とは、リソースを作成する順序
  • AリソースがBリソースを依存関係に指定している場合、Bリソースが作成されるまでAリソースは作成されない
  • この依存関係は、リソースを構築する上で避けて通ることができない
    ※備考※
    VPC内の一部リソースはゲートウェイを必要とする。
    VPC、ゲートウェイ、ゲートウェイアタッチメントを AWS CloudFormation テンプレートで定義する場合、
    ゲートウェイを必要とするリソースはすべて、そのゲートウェイアタッチメントに依存することになる。
    たとえば、パブリック IP アドレスが割り当てられている Amazon EC2 インスタンスは、
    同じテンプレートで VPC リソースと InternetGateway リソースも宣言されている場合、VPC ゲートウェイのアタッチメントに依存する。
    

現在、次のリソースは関連付けられたパブリック IP アドレスを持ち、VPC 内にある場合VPC ゲートウェイのアタッチメントに依存する。(2017年4月現在)

・Auto Scaling グループ
・Amazon EC2 インスタンス
・Elastic Load Balancing ロードバランサー
・Elastic IP アドレス
・Amazon RDS データベースインスタンス
・インターネットゲートウェイを含む Amazon VPC のルート

2. テンプレート作成後、スタックとして成立させる

  • パラメータを設定すること

    インスタンスタイプなどの値はスタック作成時に設定するケースが多い
    

3. 削除したくないリソースを予め決定しておくこと

  • CloudFormationで起動させたインフラ環境を停止する場合、インフラ環境を削除することになる

    削除対象のテンプレート内に固定IPが割り振られてたインスタンスがあった場合、インフラ環境を再構築した際に割り振りが変更してしまう。
    普遍なリソースはテンプレートを別にする
    

参考

AWS Cloudformationユーザガイド
http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/Welcome.html

CloudFormation超入門
http://dev.classmethod.jp/beginners/chonyumon-cloudformation/

AWS Black Belt Tech シリーズ 2015 – AWS CloudFormation
https://www.slideshare.net/AmazonWebServicesJapan/aws-black-belt-tech-2015-aws-cloudformation?qid=9c031227-6000-4a12-bf18-49cda2c6bfe9&v=&b=&from_search=1

続きを読む

AWS Transit VPCソリューションを使って 手軽に マルチリージョン間 VPN環境を構築してみる

Transit VPC とは

AWS の VPC 間 VPN 接続を自動化するソリューションです。
高度なネットワークの知識がなくても、超カンタンに、世界中の リージョンにまたがる VPC を接続するネットワークを構築することができます。

概要


ある VPC を転送専用の VPN HUB(Transit VPC)として作成することで、他のVPCからのVPN接続を終端し、スター型のトポロジを自動作成します。
利用している AWSのアカウントに紐づいた VPC で VGW を作成すれば、HUBルーターに自動的に設定が投入され、VPNの接続が完了します。

予めテンプレートが用意されているので、ルーターの細かい設定を行う必要がありません。

また、高度な設定が必要な場合も、Cisco CSR1000V を利用しているので、Cisco IOS の機能は自由に利用することも可能です。

Adobe社では、大規模なネットワークを、AWS上の CSR1000V で構築しています。
https://blogs.cisco.com/enterprise/adobe-uses-cisco-and-aws-to-help-deliver-rich-digital-experiences

仕組み

  • AWS CloudFormation を使って、Transit VPC の CSR1000v のプロビジョニングが非常に簡単に行えるようになっています。

  1. VGW Poller という Lambda ファンクションが用意されており、Amazon CloudWatch を使って、Transit VPC に接続すべき VGW が存在するかを常に確認しています。
  2. VGWが存在する場合、VGW Poller が必要な設定を行い、設定情報を Amazon S3 bucket に格納します
  3. Cisco Configurator という名前の Lambda ファンクションが用意されており、格納した設定情報から、CSR1000v 用の設定を作成します
  4. Cisco Configurator が Transit VPC の CSR1000v へ SSH でログインし設定を流し込みます。
  5. VPN接続が完了します。

詳細については、下記、ご参照ください。
– AWS ソリューション – Transit VPC
https://aws.amazon.com/jp/blogs/news/aws-solution-transit-vpc/
– Transit Network VPC (Cisco CSR)
https://docs.aws.amazon.com/solutions/latest/cisco-based-transit-vpc/welcome.html

Transit VPC 構築方法

基本は、Wizard に従い、3(+1)ステップで設定が可能です。

事前準備 – CSR1000V用 Key Pair の作成

CSR1000V へログインする際に使う、Key Pair を EC2 で一つ作っておきましょう。
EC2 > Network & Security > Key Pairs から作成できます。名前はなんでもいいです。

.pem ファイルが手に入るので、後ほど、CSR1000V へログインする際にはこれを使います。

Step 1. Cisco CSR1000v ソフトウェア利用条件に同意

AWS マーケットプレイスの下記のページから、リージョンごとの値段が確認できます。

https://aws.amazon.com/marketplace/pp/B01IAFXXVO

  • For Region で 好きなリージョンを選択
  • Delivery Method で Transit Network VPC with the CSR 1000v を選択

その後 Continue

  • Manual Launch タブが選択されていること
  • Region / Deployment Options が先に設定したものとなっていること

上記を確認し、Accept Software Terms をクリックします。

Step 2. Transit VPC スタックの起動

下記のページより、Transit VPC 用の CloudFormation を起動することで、Transit VPC に必要な CSR1000v をセットアップすることができます。

http://docs.aws.amazon.com/ja_jp/solutions/latest/cisco-based-transit-vpc/step2.html

上記ページから Launch Solution をクリックします。
CloudFormation のページが立ち上がるので、まず、VPN HUB を 設置するリージョンになっているか確認します。
このソリューションは、Lambda を使うので、Transit VPC を設置できるのは、Lambda が使えるリージョンに限ります。東京は対応してます。
Lambda 対応リージョンは、こちらで確認できます。
https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/

正しいリージョンになっていたら、設定を進めます。

2-1. Select Template

テンプレートがすでに選択された状態になっていると思うので、特に設定の必要なし

Next をクリック

2-2. Specify Details

幾つかのパラメーターがありますが、最低限下記を変更すれば、動作します。

  • Specify Details

    • Stack name を設定します。
  • Parameters
    - Cisco CSR Configuration

    • SSH Key to access CSR で、事前準備で作成した key を選択します。
    • License Modelで、BYOL (Bring Your Own License) もしくは License Included を選択します。

CSR1000v のライセンスについて、Cisco から購入したものを使う場合は、BYOL を選択します。
ライセンス費用も利用料に含まれた利用形式が良ければ、License included version を選択します。
検証ライセンスがあるので、テストの場合は、BYOL で良いかと思います

入力が完了したら、 Next

2-3. Options

特に設定の必要なし Next をクリック

2-4. Review

  • 設定を確認して、一番下の acknowledge のチェックボックスをクリック

その後、Create で CSR1000V のインスタンス作成・セットアップが始まります

5分ほどすると、CSR1000V が 2インスタンス 立ち上がります。

事後設定(オプション)

起動した CSR1000V は デフォルトで、Lambda ファンクションからのログインのみを許可する設定になっているので、ssh で CLI にアクセスしたい場合は、Security Group の設定を変更します。

EC2 のダッシュボードから CSR1000V を選択し、Security Group の設定で SSH を許可します。
すべてのPCからSSHを受ける場合は、ソースアドレスとして 0.0.0.0/0 を指定します。

設定後、ssh でログインするには、事前準備で作成した キーペアで取得した .pem ファイルのパーミッションを変更します。

chmod 400 <キーペア名>.pem

これを使って、下記のコマンドで CSR1000V にログインできます

ssh -i <キーペア名>.pem <CSR1000V のパブリックIP>

ログインすれば、CSR1000v であることがわかると思います。

ip-XXX-XXX-XXX-XXX #sh ver
Cisco IOS XE Software, Version 16.03.01a
Cisco IOS Software [Denali], CSR1000V Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.3.1a, RELEASE SOFTWARE (fc4)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2016 by Cisco Systems, Inc.
Compiled Fri 30-Sep-16 02:53 by mcpre

<省略>

Step 3. スポーク VPC のタグ付け

上記、CSR1000V が立ち上がれば、あとは、Spoke VPC の VGW でタグを付けるだけで、CSR1000V への VPN 接続が完了します。

3-1. Spoke VPC の作成

新たに Spoke VPC を作成する場合は、下記の手順で作ります。

  • 好きなリージョンに、VPC を作成します。

    • VPC Dashboard > Virtual Private Cloud > Your VPC > Create VPC で作成します。
  • Virtual Private Gateway(VPG) を作成します。
    • VPC Dashboard > VPN Connection > Virtual Private Gateways > Create Virtual Private Gateway で作成します。
  • 作成した VPG を、先程作成した VPCにアタッチします。
    • VPC Dashboard > VPN Connection > Virtual Private Gateways > Attach to VPC  から、VPCへVGWをアタッチします。

3-2. VGW のタグ付け

  • 先程作成した VGW を選択し、下部の Tags タブを選択します。

    • Edit をクリックし Tag を追加します。

デフォルトの設定では、下記のタグを利用する設定になっていますので、下記タグを追加します
Key = transitvpc:spoke
Value = true

上記の設定が完了すると、VGWと Step2. で作成した、2台の CSR1000Vの間で自動的に VPN 接続が確立します。

http://docs.aws.amazon.com/ja_jp/solutions/latest/cisco-based-transit-vpc/step3.html

Step 4. 他の AWS アカウントからの接続設定 (オプション)

http://docs.aws.amazon.com/ja_jp/solutions/latest/cisco-based-transit-vpc/step4.html

まとめ

AWS の Transit VPC を使えば、世界中 にまたがる AWS の 各リージョンのVPCを簡単に VPN 接続できます。

また、VPN HUB ルーターは Cisco CSR1000v なので、企業内のシスコルーターと VPN 接続すれば、DC を AWS にして、世界中にまたがる VPN ネットワークを構築することができます。
ダイレクトコネクトとも連携可能です。

参考

On board AWS TransitVPC with Cisco CSR1000v (英語ですが、手順がわかりやすいです)

Cisco CSR 1000v: Securely Extend your Apps to the Cloud
https://www.slideshare.net/AmazonWebServices/cisco-csr-1000v-securely-extend-your-apps-to-the-cloud

続きを読む

AWS CloudFormation(CFn) ことはじめ。(とりあえずシンプルなEC2インスタンスを立ててみる)

AWS CloudFormation(CFn) ことはじめ。(とりあえずシンプルなEC2インスタンスを立ててみる)

まえおき

  • 世のはやりは Infrastructure as Code なのです (博士)
  • AWS でもやって当然なのです (助手)

前提

目的

  • 趣味で AWS いじる範囲だと GUI で EC2 インスタンス建てるのに慣れてしまっていつしか EC2 インスタンスに必要な要素を忘れがちではないですか?

    • セキュリティグループ
    • デフォルトサブネット有無
    • パブリック自動IP付与
    • etc …
  • コード化の際にいろいろ気付きもあり、あとでコードを見返せば必要な要素を一覧することもできるという一挙両得
  • ひとり適当運用で セキュリティグループ や キーペア ぐっちゃぐちゃに増えていってませんか? (自分だけ?)
  • 運用をコード化しつつ見直して行きましょう

今回は CFn の練習がてら EC2 に以下の要素を盛り込んでいきます

  1. AMI

    • Amazon Linux
  2. タイプ
    • t2.micro
  3. 手元の作業PCのから SSH 接続出来るようにする
    • サブネット

      • パブリックIP自動付与
    • キーペア
  4. セキュリティグループ
    • 22 番ポートが開いている
  5. IAM プロファイル(適宜)

実行環境

  • AWS CLI を利用します
  • 適宜 pip 等でインストールして下さい

ref. https://github.com/aws/aws-cli

テンプレートを準備する

  • JSON, YAML などで記載します
  • 自分で使いやすい方を選びましょう
  • JSON は(一般に)コメントが利用できないため、コメントを書き込みたい場合は YAML を選択しましょう

ref. http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/cfn-whatis-concepts.html

1. CFn の構文とプロパティ(EC2インスタンス)

ref. http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-formats.html

  • 基本は以下の入れ子構造になります

  • Resources

    • {リソース名}

      • Type
      • Properties
        • {各プロパティ}
  • YAML の場合は以下 (注意: デフォルトサブネットを削除している場合などで以下のサンプルをそのまま使うと失敗します)

Resources:
        myec2instance:
                Type: "AWS::EC2::Instance"
                Properties:
                        ImageId: "ami-859bbfe2" #Amazon Linux AMI
                        InstanceType: "t2.micro"
  • JSON の場合は以下のようになります (注意: デフォルトサブネットを削除している場合などで以下のサンプルをそのまま使うと失敗します)
{
"Resources" : {
    "myec2instance" : {
        "Type" : "AWS::EC2::Instance",
        "Properties" : {
            "ImageId" : "ami-859bbfe2",
            "InstanceType" : "t2.micro"
            }
        }
    }
}

2. 必要なプロパティを収集しましょう

ref. http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#aws-properties-ec2-instance-prop

必要な機能 プロパティ名 タイプ 種別
AMIイメージID ImageId String ami-859bbfe2 既定値
インスタンスタイプ InstanceType String t2.micro 既定値
サブネットID SubnetId String subnet-f7ea1081 ユーザ個別
キーペア KeyName String aws-tokyo-default001 ユーザ個別
セキュリティグループ SecurityGroupIds List sg-f9b58f9e ユーザ個別
IAMロール名 IamInstanceProfile String ec2-001 ユーザ個別

2-1. AWS CLI (と jq コマンド)を利用すると以下のように AMIイメージID を検索できます

ref. http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-images.html
ref. http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/finding-an-ami.html#finding-an-ami-aws-cli

% aws ec2 describe-images --owners amazon \
--filters "Name=name,Values=amzn-ami-hvm-2017*x86_64-gp2" \
| jq '.Images[] | { Name: .Name, ImageId: .ImageId }'
{
  "Name": "amzn-ami-hvm-2017.03.rc-1.20170327-x86_64-gp2",
  "ImageId": "ami-10207a77"
}
{
  "Name": "amzn-ami-hvm-2017.03.0.20170401-x86_64-gp2",
  "ImageId": "ami-859bbfe2"
}
{
  "Name": "amzn-ami-hvm-2017.03.rc-0.20170320-x86_64-gp2",
  "ImageId": "ami-be154bd9"
}

2-2. サブネットも同様に

ref. http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-subnets.html

% aws ec2 describe-subnets \
| jq '.Subnets[] | { CIDR: .CidrBlock, PublicIPMapping: .MapPublicIpOnLaunch, SubnetId: .SubnetId }'
{
  "CIDR": "172.31.0.192/26",
  "PublicIPMapping": true,
  "SubnetId": "subnet-7bf8a60d"
}
{
  "CIDR": "172.31.0.128/26",
  "PublicIPMapping": true,
  "SubnetId": "subnet-f7ea1081"
}

2-3. キーペア名

ref. http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-key-pairs.html

% aws ec2 describe-key-pairs \
> | jq '.KeyPairs[].KeyName'
"aws-tokyo-default001"

2-4. IAM (以下手抜き)

ref. http://docs.aws.amazon.com/cli/latest/reference/iam/list-roles.html

% aws iam list-roles | jq '.Roles[]'

2-5. セキュリティグループ

ref. http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-security-groups.html

% aws ec2 describe-security-groups | jq '.SecurityGroups[]'

3. テンプレートを書きます

JSONの場合
% cat cloudformation-study.json
{
    "Description" : "test template",
    "Resources" : {
        "myec2instance" : {
            "Type" : "AWS::EC2::Instance",
            "Properties" : {
                "ImageId" : "ami-859bbfe2",
                "InstanceType" : "t2.micro",
                "SubnetId" : "subnet-f7ea1081",
                "KeyName" : "aws-tokyo-default001",
                "SecurityGroupIds" : [ "sg-f9b58f9e" ],
                "IamInstanceProfile" : "ec2-001"
            }
        }
    }
}
YAMLの場合
% cat cloudformation-study.yaml
Resources:
        myec2instance:
                Type: "AWS::EC2::Instance"
                Properties:
                        ImageId: "ami-859bbfe2" #Amazon Linux AMI
                        InstanceType: "t2.micro"
                        SubnetId: "subnet-f7ea1081"
                        KeyName: "aws-tokyo-default001"
                        SecurityGroupIds: [ "sg-f9b58f9e" ]
                        IamInstanceProfile: "ec2-001"

4. では実行します

4-1. ユニークなスタック名を確認します

スタックが1個もない場合の出力例
% aws cloudformation describe-stacks
{
    "Stacks": []
}

4-2. 実行

コマンド
% aws cloudformation create-stack --stack-name create-ec2-001 --template-body file://cloudformation-study.json
実行結果
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:942162428772:stack/create-ec2-001/1b059fa0-1dbc-11e7-9600-50a68a175ad2"
}

4-3. 実行ステータスはマネコン(WEB GUI)か、さきほど実行したコマンドで確認できます

  • “StackStatus”: “CREATE_COMPLETE” を確認
% aws cloudformation describe-stacks
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:942162428772:stack/create-ec2-001/1b059fa0-1dbc-11e7-9600-50a68a175ad2",
            "Description": "test template",
            "Tags": [],
            "CreationTime": "2017-04-10T07:05:40.261Z",
            "StackName": "create-ec2-001",
            "NotificationARNs": [],
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false
        }
    ]
}

4-4. EC2 インスタンスが作成されていて、SSH で接続可能なことを確認します

% aws ec2 describe-instances --filter "Name=instance-state-name,Values=running"
以下の例はキーファイルがあるディレクトリで実行したもの
% ssh -i "aws-tokyo-default001.pem" ec2-user@ec2-hogehoge.ap-northeast-1.compute.amazonaws.com

5. テンプレートの更新

5-1. AMI イメージID を ami-0099bd67 に変更してみましょう

% aws cloudformation update-stack --stack-name create-ec2-001 --template-body file://cloudformation-study.json
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:942162428772:stack/create-ec2-001/1b059fa0-1dbc-11e7-9600-50a68a175ad2"
}
% aws cloudformation describe-stacks
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:942162428772:stack/create-ec2-001/1b059fa0-1dbc-11e7-9600-50a68a175ad2",
            "Description": "test template",
            "Tags": [],
            "CreationTime": "2017-04-10T07:05:40.261Z",
            "StackName": "create-ec2-001",
            "NotificationARNs": [],
            "StackStatus": "UPDATE_IN_PROGRESS",
            "DisableRollback": false,
            "LastUpdatedTime": "2017-04-10T07:20:37.436Z"
        }
    ]
}

5-2. 何が起こったか確認できましたか?

Screenshot 2017-04-10 16.22.28.png

からの

Screenshot 2017-04-10 16.22.56.png

最初に作成した EC2インスタンス は自動シャットダウンからターミネートされ、あたらしい EC2インスタンス が起動しました

5-3. はい、そういうことですね

% aws cloudformation describe-stack-events --stack-name create-ec2-001 \
| jq '.StackEvents[] | { ResourceStatus: .ResourceStatus,Timestamp: .Timestamp }'

(snip)

{
  "ResourceStatus": "DELETE_COMPLETE",
  "Timestamp": "2017-04-10T07:22:47.470Z"
}
{
  "ResourceStatus": "DELETE_IN_PROGRESS",
  "Timestamp": "2017-04-10T07:21:40.963Z"
}

(snip)

6. おわり

7. おまけ

  • コードですので github などに置いて差分管理するとなお良いかと
  • 認証情報などをコード内に書かないように注意

https://github.com/hirofumihida/my-cfn

続きを読む

[stripe][AWS] Stripe の Webhook を API Gateway で受け取って Lambda で処理する

Serverless Framework 使って Stripe の Webhook からのメッセージを処理するサンプル書いたので、使い方とか解説。
コード自体は Serverless Examples にプルリクしてマージしてもらってあるので、そちらを取ってきてください。
https://github.com/serverless/examples/tree/master/aws-node-stripe-integration

これは Stripe の Webhook から投げられるメッセージを AWS API Gateway 経由で AWS Lambda で処理したい時に使います。

セットアップ

Serverless Framework のインストール方法は割愛。
Installing The Serverless Framework を参考にしてね。

サンプルコードの取得

https://github.com/serverless/examples/ を git clone するなりしてから、aws-node-stripe-integration ディレクトリを持ってきてください。

追記: GitHub 上のプロジェクトは serverless install で一発コピーできるそうです。thx @horike37

$ serverless install --url https://github.com/serverless/examples/tree/master/aws-node-stripe-integration
Serverless: Downloading and installing "aws-node-stripe-integration"...
Serverless: Successfully installed "aws-node-stripe-integration"

依存 npm パッケージのインストール

この example では、npm パッケージ config, js-yaml, stripe を使ってるので、まずは npm install で依存パッケージをインストール。

npmパッケージのインストール
$ npm install

Stripe API Key の書き換え

Stripe の API Key を config/local.yaml ってファイルに書いてください。
ソースを GitHub 等で公開しないのであれば、config/default.yaml の中身を書き換えてもいいよ。

config/local.yaml
stripe:
    test_sk: 'Stripe_Test_Secret_Key_here'
    live_sk: 'Stripe_Live_Secret_Key_here'

サンプルコードの解説

event object の取得

実際に Webhook から送られたデータを処理しているのは handler.js です。
Webhook 経由で event object が投げられると event.body に JSON 形式でセットされてくるので、最初にそれを JSON.parse() してます。
https://github.com/serverless/examples/blob/master/aws-node-stripe-integration/handler.js#L18

event object の構造は、Stripe API リファレンスを参考にしてください。
https://stripe.com/docs/api#event_object

event object の正当性チェック

events.retrieve() で、受け取った event object が正当なものかをチェックしてます。
https://github.com/serverless/examples/blob/master/aws-node-stripe-integration/handler.js#L22

events.retrieve() から呼び出される callback 関数内では err だった場合の処理を入れてないので、これは実装してください。

event type ごとの処理

受け取った event の種類は stripeEvent.type を見ればわかります。
それに合わせて Slack 通知するなりなんなりの処理を実装してくださいね。
https://github.com/serverless/examples/blob/master/aws-node-stripe-integration/handler.js#L33-L40

event type のリストは、Stripe API リファレンスを参考にしてください。
https://stripe.com/docs/api#event_types

デプロイ!

AWS API Gateway エンドポイントの作成

まずは、そのまま sls deploy すると Test 環境用の一式がデプロイされます。

Test環境用
$ serverless deploy
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading service .zip file to S3 (2.15 MB)...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.....
Serverless: Stack update finished...
Serverless: Removing old service versions...
Service Information
service: aws-node-stripe-integration
stage: development
region: us-east-1
api keys:
  None
endpoints:
  POST - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/test/stripe/incoming
functions:
  incoming: aws-node-stripe-integration-test-incoming

Stack Outputs
ServiceEndpoint: https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/test
ServerlessDeploymentBucketName: aws-node-stripe-integration-serverlessdeploymentbuck-xxxxxxxxxxxx
IncomingLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-1:000000000000:function:aws-node-stripe-integration-test-incoming:20

endpoints ってのが、API Gateway の endpoint になります。

本番環境( Live )用の API Gateway endpoint を作成するには --stage live をつけてデプロイ

Live環境用
$ serverless deploy --stage live

Stripe Webhook の設定

Stripe の管理画面から Webhook URL を設定します。
https://dashboard.stripe.com/account/webhooks の「Add endpoint」をクリック。
Screen Shot 2017-04-07 at 12.58.07.png

Test 環境用の Webhook を設定したい場合は「Mode」Test を、Live 環境用の Webhook を設定したい場合は「Mode」Live を選択して「URL」欄に先ほど serverless deploy した時に作成された API Gateway の endpoint を入力して「Create endpoint」をクリックするだけです。

Serverless Framework のおかげで、簡単にできちゃいますねー。
現場からは以上です。

続きを読む