PyQSでお気軽Task Queue構築

PythonでQueue制御をする場合、Celeryなどが定番ですが、Amazon SQSを使ったPyQSというのを見つけたのでちょっと使ってみました。READMEとは微妙に挙動が異なるので苦労しましたが、非常にお気軽なTask Queue構築が可能なのはありがたいです。

設置

設置は簡単でpipコマンド一発です。
pip install pyqs

環境変数

以下の環境変数が必要です。

  • AWS_ACCESS_KEY_ID AWSS_SECRET_ACCESS_KEY…Amazon SQSへのRead/Write権限を備えていること
  • PYTHONPATH…Queueで実行するPythonスクリプトを参照できるようにしておきます

タスク

pyqsからデコレーターtaskをインポートして、Queueに登録したい関数に載せます。

qqq/tasks.py
from pyqs import task


@task('queue0')
def another_task(message):
    print "another_task: message={}".format(message)


@task('queue0')
def send_email(subject):
    print "send_email: subject={}".format(subject)

Queueへの登録

add_queue.py
from qqq.tasks import another_task, send_email
from settings import config

for i in range(0, 100):
    send_email.delay(subject='hogehoge')
    another_task.delay(message='hogehogehoge')

Workerの起動

run_queue.sh
#! /bin/bash

export PYTHONPATH=`pwd`
export QUEUE='queue0'
pyqs $QUEUE

GithubのREADMEによればQueue名は「queue0.tasks.send_email」とか「queue.tasks.another_task」になるはずですが、実際のSQSはQueue名にピリオドは許してくれないので、@taskデコレータで宣言したqueue0がQueue名になります。ここを理解するまでに2時間くらいソース追いかけましたよ。

まとめ

自力でメッセージブローカーを設定しなくても、Amazon SQSへのアクセス権があれば即Task Queueを作れるのは魅力的です。あとSQSはタダ同然なのもありがたいですね。

 Github

ソースは こちら

続きを読む

AWSの各サービスを雑に紹介する

えー、投稿しておいて何ですが、本稿本当に雑ですので、ご利用にあたってはあくまで自己責任ということで、よろしくお願いします。

コンピューティング

  • Elastic Compute Cloud (EC2)
    仮想専用サーバ、従量課金制 ≫公式

  • EC2 Container Registry (ECR)
    DockerHubみたいなやつ ≫英語公式 / Google翻訳 ≫Developers.IO

  • EC2 Container Service (ECS)
    Dockerオーケストレーション(デプロイ、起動停止制御) ≫公式 ≫@IT

  • Lightsail
    仮想専用サーバ、定額制 ≫公式

  • AWS Batch
    ECS対応バッチジョブスケジューラ ≫公式 ≫公式 ≫Developers.IO

  • Elastic Beanstalk
    プログラム実行環境 (Java, PHP, .NET, Node.js, Python, Ruby)、EC2を使用 ≫公式 ≫YouTube

  • AWS Lambda
    プログラム実行環境 (Node.js, Java, C#, Python)、サーバレス ≫公式

  • Auto Scaling
    EC2対応オートスケール制御 ≫公式

  • Elastic Load Balancing
    負荷分散、BIG-IPとかその手のヤツのクラウド版 ≫公式 ≫@IT

ストレージ

  • Amazon Simple Storage Service (S3)
    オブジェクトストレージ。ファイルサーバとしても一応使える ≫公式

  • Amazon Elastic Block Store (EBS)
    ブロックデバイス ≫CodeZine

  • Elastic File System (EFS)
    ファイルサーバ ≫公式

  • Glacier
    バックアップストレージ ≫公式

  • Snowball
    HDDをFedExで送るオフラインデータ転送

  • Storage Gateway
    バックアップデバイスはお客様各自のオンプレミスにてご用意下さい、AWSは対向するインターフェースを提供します、というもの ≫CodeZine ≫Developers.IO

データベース

ネットワーキング & コンテンツ配信

移行

  • Application Discovery Service
    オンプレミスサーバの構成管理情報を収集する ≫公式

  • Database Migration Service (DMS)
    RDBをオンプレミスからAWSへ乗り換えるときに使う支援ツール

  • Server Migration Service (SMS)
    サーバをオンプレミスからAWSへ乗り換えるときに使う支援ツール

開発者用ツール

  • CodeCommit
    GitHubみたいなやつ

  • CodeBuild
    従量課金制ビルド

  • CodeDeploy
    コードデプロイ

  • CodePipeline
    Continuous Integration (CI) オーケストレーション。ビルド→デプロイの自動実行フロー定義。

  • AWS X-Ray
    分散アプリケーションのトレース ≫Serverworks

管理ツール

セキュリティ、アイデンティティ、コンプライアンス

  • AWS Identity and Access Management (IAM)
    AWSの認証、権限管理単位 ≫Developers.IO

  • Inspector
    脆弱性検出 ≫公式

  • Certificate Manager
    X.509証明書の管理 ≫公式

  • AWS Cloud Hardware Security Module (HSM)
    秘密鍵の保管(暗号、署名) ≫公式

  • AWS Directory Service
    Active Directory ≫Developers.IO

  • AWS Web Application Firewall (WAF)
    ファイアーウォール ≫公式

  • AWS Shield
    DDoS対策 ≫公式

分析

人工知能

IoT

ゲーム開発

モバイルサービス

  • Mobile Hub
    AWSのいろんなmBaaS系サービスを統合的に使えるコンソール画面 ≫Qiita

  • Cognito
    ソーシャル認証+データ同期。FacebookログインとかTwitterログインとか ≫Cookpad

  • AWS Device Farm
    テスト環境。Android, iOSの実機にリモートアクセスしてテストができる ≫公式

  • Mobile Analytics
    アプリの使用データの測定、追跡、分析 ≫公式 ≫Developers.IO

  • Pinpoint
    プッシュ ≫Qiita

アプリケーションサービス

  • Step Functions
    フローチャートみたいなビジュアルワークフローを画面上に描いて分散アプリケーションを構築する、というもの ≫公式

  • Amazon Simple Workflow (SWF)
    旧世代サービス。現在はStep Functionsを推奨 ≫公式

  • API Gateway
    HTTP API化 ≫公式

  • Elastic Transcoder
    動画、音声のフォーマット変換。つんでれんこaaSみたいなヤツ ≫Serverworks

メッセージング

  • Amazon Simple Queue Service (SQS)
    メッセージキュー ≫公式

  • Amazon Simple Notification Service (SNS)
    プッシュ ≫公式

  • Amazon Simple Email Service (SES)
    E-mail配信。メルマガとか ≫公式

ビジネスの生産性

デスクトップとアプリケーションのストリーミング

  • Amazon WorkSpaces
    仮想デスクトップ ≫impress

  • Amazon WorkSpaces Application Manager (WAM)
    Amazon WorkSpaces端末にアプリを配信するツール ≫serverworks

  • AppStream 2.0
    Citrix XenAppみたいなやつ ≫Developers.IO

参考文献

AWS ドキュメント
https://aws.amazon.com/jp/documentation/

AWS re:Invent 2016 発表サービスを三行でまとめる
http://qiita.com/szk3/items/a642c62ef56eadd4a12c

続きを読む

Serverless FrameworkとS3で超簡単な投票システムを作った話

はじめに

社内でいつも通り仕事をしていると、約1週間で簡単な投票アプリを作ってくれないか?というオファーを受け、構成を考えているときに「Serverless Frameworkを使えばいいじゃん」と神のお告げが降ってきましたので、触ってみることにしました。

最終目標

スマホから投票できて、最終的にCSVでまとまった投票データを吐き出す

構成はこんな感じ

青枠の部分がServerlessFramework

serverless-img.PNG

大まかな流れ

  1. S3に投票フォームをアップロードしてバケットごとWeb公開する
  2. フォームの投票内容をAPIGateWayに向かってPOSTする
  3. APIGateWayがLambdaをキックする
  4. Lambdaが受け取ったJSONをDynamoDBに書き込む
  5. 完了!

さあ、はじめてみようか

書いていく前に・・・今回ServerlessFrameworkを触るにあたって@hiroshik1985様のとことんサーバーレス①:Serverless Framework入門編を参考にさせていただきました。

ServerlessFrameworkのインストール

npmで入れちゃいます

$ npm install -g serverless

AWS Credentialsを設定する

ServerlessFramework用のIAMを作成して、AWSConfigureに登録します

$ aws configure
AWS Access Key ID [None]: 先ほど作成したIAMのアクセスキー
AWS Secret Access Key [None]: 先ほど作成したIAMのシークレットアクセスキー
Default region name [None]: ap-northeast-1
Default output format [None]: ENTER

プロジェクト作成

serverless用のディレクトリを作成し、そのディレクトリの中で下記のコマンド実行
今回はnode.jsで
※serverlessコマンドはインストール時に用意されるslsエイリアスを使うと便利です

$ sls create --template aws-nodejs --name vote
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.8.0
 -------'

Serverless: Successfully generated boilerplate for template: "aws-nodejs"

こんなのが表示されたら成功。なんかかっこいい・・・
これでディレクトリ内にhandler.jsやserverless.ymlが作成される

はじめてのデプロイ

デプロイのコマンドはこちら

$ sls deploy -v

特に怒られれなければデプロイ成功です。AWSのコンソール画面ですでにLambda等が立ち上がっていると思います

Lambdaファンクションを書くよ

Lambdaファンクションは基本的にhandler.jsに書きます。
たとえばこんな風に

handler.js
import AWS from 'aws-sdk'

AWS.config.update({region: 'ap-northeast-1'})

const db = new AWS.DynamoDB.DocumentClient()

export const register = (event, context, callback) => {
    const body = JSON.parse(event.body)
    const params = {
        TableName: "names",
        Key: {
            id: body.employeeNumber
        },
        UpdateExpression: "set #Group1 = :vote1, #Group2 = :vote2, #Group3 = :vote3",
        ExpressionAttributeNames: {
            "#Group1": "voteGroup1",
            "#Group2": "voteGroup2",
            "#Group3": "voteGroup3"
        },
        ExpressionAttributeValues: {
            ":vote1": body.voteGroup1,
            ":vote2": body.voteGroup2,
            ":vote3": body.voteGroup3
        },
        ReturnValues: "UPDATED_NEW"
    }



    try {
        db.update(params, (error, data) => {
            if (error) {
                callback(null, {
                    statusCode: 400,
                    headers:{ "Access-Control-Allow-Origin" : "*" },
                    body: JSON.stringify({message: 'Failed.', error: error, params: params})
                })
            }
            callback(null, {
                statusCode: 200,
                headers:{ "Access-Control-Allow-Origin" : "*" },
                body: JSON.stringify({message: 'Succeeded!', params: params})
            })
        })
    } catch (error) {
        callback(null, {
            statusCode: 400,
            headers:{ "Access-Control-Allow-Origin" : "*" },
            body: JSON.stringify({message: 'Failed.', error: error, params: params})
        })
    }
}

フォームからPOSTメソッドでJSON形式のデータをDynamoDBに格納します
送られてくるJSONデータは{“employeeNumber”: “001”, “voteGroup1”: “1”, “voteGroup2”: “2”, “voteGroup3”: “3”}のような形で送られてくることを想定しています

そのほか設定を書くよ

serverless.ymlにDynamoDBやiamRoleなどの設定を書きます
たとえばこんな風に

serverless.yml

service: vote

provider:
  name: aws
  runtime: nodejs4.3
  stage: dev
  region: ap-northeast-1
  iamRoleStatements:
    - Effect: "Allow"
      Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/*"
      Action:
        - "dynamodb:*"

plugins:
  - serverless-webpack

functions:
  register:
    handler: handler.register
    events:
      - http:
         path: names
         method: post
         cors: true

resources:
  Resources:
    hello:
      Type: "AWS::DynamoDB::Table"
      Properties:
        TableName: names
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S
        KeySchema:
          - AttributeName: id
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1

これで再度デプロイするとLambdaファンクションが設定され、DynamoDBにテーブルが作成されます

試しに実行だ

デプロイ後に表示されるAPIGateWayのエンドポイントに対してcurlでリクエストを送信します
※「 https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/names 」はAPIGateWayのエンドポイントです


curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"employeeNumber": "001", "voteGroup1": "1", "voteGroup2": "2", "voteGroup3": "3"}'  https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/names

問題なくリクエストが送信されれば、DynamoDBにテータが格納されていると思います

フォームの作成

あまり手の込んだフォームをコーディングしている時間がなかったので、シンプルにまとめました
CSSは「Material Design Lite」というCSSフレームワークを使用し、AjaxでAPIGatewayのエンドポイントに対してHTTPリクエストを投げています

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>投票アプリ</title>
    <script type="text/javascript" src="jquery-3.1.1.min.js"></script>
    <script type="text/javascript" src="vote.js"></script>
    <script type="text/javascript" src="mdl/material.min.js"></script>
    <link rel="stylesheet" href="mdl/material.min.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
    <link rel="stylesheet" href="common.css">
</head>
<body>

<!-- Always shows a header, even in smaller screens. -->
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
    <header class="mdl-layout__header">
        <div class="mdl-layout__header-row">
            <!-- Title -->
            <span class="mdl-layout-title">投票アプリ</span>
            <!-- Add spacer, to align navigation to the right -->
            <div class="mdl-layout-spacer"></div>
        </div>
    </header>
    <main class="mdl-layout__content">
        <div id="page-content" class="mdl-grid">
            <div class="mdl-cell mdl-cell--12-col">
                社員番号:<br>
                <select name="employee_number" class="employee-number">
                    <option value="">選択してください</option>
                    <option value="001">001</option>
                    <option value="002">002</option>
                    <option value="003">003</option>
                    <option value="004">004</option>
                    <option value="005">005</option>
                    <option value="006">006</option>
                </select>
                <span class="font-red">※必須</span>
            </div>
            <div class="mdl-cell mdl-cell--12-col">
                投票するグループを<span class="font-red">3つ</span>選択してください<span class="font-red">※必須</span>
                <br>
                1位:
                <select name="vote_group1" class="vote-group1">
                    <option value="">選択してください</option>
                    <option value="1">グループ1</option>
                    <option value="2">グループ2</option>
                    <option value="3">グループ3</option>
                    <option value="4">グループ4</option>
                    <option value="5">グループ5</option>
                    <option value="6">グループ6</option>
                    <option value="7">グループ7</option>
                    <option value="8">グループ8</option>
                    <option value="9">グループ9</option>
                </select>
                <br>
                <br>
                2位:
                <select name="vote_group2" class="vote-group2">
                    <option value="">選択してください</option>
                    <option value="1">グループ1</option>
                    <option value="2">グループ2</option>
                    <option value="3">グループ3</option>
                    <option value="4">グループ4</option>
                    <option value="5">グループ5</option>
                    <option value="6">グループ6</option>
                    <option value="7">グループ7</option>
                    <option value="8">グループ8</option>
                    <option value="9">グループ9</option>
                </select>
                <br>
                <br>
                3位:
                <select name="vote_group3" class="vote-group3">
                    <option value="">選択してください</option>
                    <option value="1">グループ1</option>
                    <option value="2">グループ2</option>
                    <option value="3">グループ3</option>
                    <option value="4">グループ4</option>
                    <option value="5">グループ5</option>
                    <option value="6">グループ6</option>
                    <option value="7">グループ7</option>
                    <option value="8">グループ8</option>
                    <option value="9">グループ9</option>
                </select>
                <br>
            </div>
            <div class="mdl-cell mdl-cell--12-col">
                <button id="vote-button"
                        class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--colored">投票
                </button>
            </div>

            <div class="mdl-cell mdl-cell--12-col">
                <textarea id="response" disabled></textarea>
            </div>

        </div>
    </main>
</div>
</body>
</html>
common.css

.font-red {
    color: red;
    font-weight: bold;
    font-size: 16px;
}
vote.js

$(function () {
    $("#response").html("Response Values");

    /**
     * 投票ボタンを押したときの処理
     */
    $("#vote-button").click(function () {
        var url = 'https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/names';

        var employeeNumber = $(".employee-number").val();
        if (employeeNumber === "") {
            alert("社員番号は必須です");
            return;
        }

        /**
         * 選択肢の登録数のバリデーション
         */
        var voteGroup = {
            group1: $(".vote-group1").val(),
            group2: $(".vote-group2").val(),
            group3: $(".vote-group3").val()
        };

        var count = 0;
        $.each(voteGroup, function (key, val) {
            if (val !== "") {
                count++;
            }
        });
        if (count < 3) {
            alert("グループを3つ選択してください");
            return
        }

        /**
         * 重複チェック
         */
        if(voteGroup.group1 === voteGroup.group2){
            alert("同じクループは選択できません");
            return
        }
        if(voteGroup.group1 === voteGroup.group3){
            alert("同じクループは選択できません");
            return
        }
        if(voteGroup.group2 === voteGroup.group3){
            alert("同じクループは選択できません");
            return
        }

        var JsonData = {
            employeeNumber: employeeNumber,
            voteGroup1: voteGroup.group1,
            voteGroup2: voteGroup.group2,
            voteGroup3: voteGroup.group3
        };

        alert(JSON.stringify(JsonData));

        $.ajax({
            type: 'post',
            url: url,
            data: JSON.stringify(JsonData),
            contentType: 'application/JSON',
            dataType: 'JSON',
            scriptCharset: 'utf-8',
            success: function (data) {
                window.location.href = "thankYou.html";
            },
            error: function (data) {

                // Error
                alert("error");
                alert(JSON.stringify(data));
                $("#response").html(JSON.stringify(data));
            }
        });
    });

});

これらのファイルをWeb公開したS3バケットにアップロードし、S3のエンドポイントにアクセスし画面を確認します
あとはフォームの項目を入力し、「投票ボタン」をクリックすると・・・
無事成功すればDynamoDBにPOSTしたJSONが追加されています
また要望により、同じ社員番号で投票すると内容を更新できるようにしています

さいごに

いかんせん1週間とはいえ通常業務の合間を縫ってやっていたので、かなり雑な処理になっていると思います(汗)
しかも最後のCSV吐き出しはコンソールから生成するというなんともいけてない感じ・・・
次回いつ使うかわからないけど、改善に励んでいこうとおもっております!

ちなみにServerlessFrameworkで作成した環境を消去するときは下記を実行すればよいみたいです


sls remove

もっといい感じになったらまた記事書き直すんだ・・・

続きを読む

EC2インスタンスを時刻指定で起動する

概要

スケジューリングはCloudWatchを使って、実際の起動はLambdaを使って実現します。Lambdaでのスクリプト実行のために必要なロールの作成についても説明します。

起動用ロールを作成する

AWSコンソールにログインしたら画面左上の「サービス」をクリックして、サービスの一覧を開きます。その中から「IAM」を選択してください。
スクリーンショット 2017-03-17 11.35.46.png

画面左部分に並ぶメニューから「ロール」を選択して、ロールの一覧を表示します。一覧の上にある青いボタン「新しいロールの作成」をクリックしてください。
スクリーンショット 2017-03-17 11.38.12.png

手順 1 : ロール名の設定

ロール名の設定をします。EC2起動に関するロールとして分かり易い任意の名称を設定してください。入力したら「次のステップ」ボタンをクリックします。

項目名 設定値 備考
ロール名 Start_EC2_Instance_Lambda

スクリーンショット 2017-03-17 11.40.15.png

手順 2 : ロールタイプの選択

今回、EC2インスタンスの起動にはLambdaを利用します。AWSサービスロールから「AWS Lambda」を選択してください。

スクリーンショット 2017-03-17 11.45.07.png

手順 3 : 信頼性の確立

ここは何故がスキップされました。作成後に「信頼されたエンティティ」が「ID プロバイダー lambda.amazonaws.com」となっていたのでバックグラウンドで何か処理が走っているんでしょうか?ご存知の方、コメントをお願いします。

手順 4 : ポリシーのアタッチ

後ほどインラインポリシーを設定するので、ここでは何も選択せずに「次のステップ」ボタンをクリックしてください。スクリーンショット 2017-03-17 11.51.44.png

手順 5 : 確認

入力した内容を確認して「ロールの作成」ボタンをクリックします。
スクリーンショット 2017-03-17 11.54.34.png

インラインポリシーを設定する

いま作成したロールが一覧に表示されるので、作成したロール名をクリックしてください。スクリーンショット 2017-03-17 11.56.59.png

概要が表示されるので、アクセス許可のタブから「インラインポリシー」の詳細を開き、「ここをクリックしてください」の文字をクリックします。スクリーンショット 2017-03-17 11.58.12.png

カスタムポリシーを設定します。「カスタムポリシー」をクリック、その後「選択」ボタンをクリックしてください。スクリーンショット 2017-03-17 11.59.51.png

ポリシー名には任意の名称を、ポリシードキュメントには以下の内容を入力します。入力したら「ポリシーの適用」ボタンをクリックします。

項目名 設定値 備考
ポリシー名 Start_EC2_Instance_Lambda
ポリシードキュメント
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "ec2:StartInstances"
            ],
            "Resource": [
                "arn:aws:logs:*:*:*",
                "arn:aws:ec2:*"
            ]
        }
    ]
}

スクリーンショット 2017-03-17 12.07.19.png

長くなりましたが、ロールの作成は以上です。

Lambdaで起動用スクリプトを作成する

まずAWS Lambdaの画面に移動します。画面左上の画面左上の「サービス」をクリックして、サービスの一覧を開きます。その中から「Lambda」を選択してください。
スクリーンショット 2017-03-17 11.35.46.png

「今すぐ始める」ボタンをクリックしてください。
スクリーンショット 2017-03-17 12.10.43.png

設計図の選択

新しくLambda関数を作成するので、「ブランク関数」をクリックします。
スクリーンショット 2017-03-17 12.11.24.png

トリガーの設定

起動はスケジュールで行うので、トリガーとして「CloudWatch イベント – スケジュール」を選択します。スクリーンショット 2017-03-17 12.12.35.png

入力欄が出現するので、以下のとおりに入力します。

項目名 設定値 備考
ルール名 Start_webserver この値は任意です。分かり易い名称にしてください。
ルールの説明 webサーバを起動する この値は任意です。分かり易い説明にしてください。
スケジュール式 cron(0 17 ? * MON-FRI *) 左記は月〜金の17時にEC2インスタンスを起動する例です。
トリガーの有効化 チェック

入力を終えたら「次へ」ボタンをクリックします。
スクリーンショット 2017-03-17 12.46.22.png

関数の設定

EC2インスタンスを起動するためのスクリプトを指定します。

項目名 設定値 備考
名前 Start_webserver この値は任意です。分かり易い名称にしてください。
説明 webサーバを起動する この値は任意です。分かり易い説明にしてください。
ランタイム Node.js 4.3
コードエントリタイプ コードをインラインで編集
const INSTANCE_ID = 'i-xxxxxxxxxxxxxxxxx'; // 対象のEC2インスタンスIDを指定する

var AWS = require('aws-sdk'); 
AWS.config.region = 'ap-northeast-1'; // 対象のEC2が所属するリージョンを指定する

function ec2Start(cb){
    var ec2 = new AWS.EC2();
    var params = {
        InstanceIds: [
            INSTANCE_ID
        ]
    };

    ec2.startInstances(params, function(err, data) {
        if (!!err) {
            console.log(err, err.stack);
        } else {
            console.log(data);
            cb();
        }
    });
}
exports.handler = function(event, context) {
    console.log('start');
    ec2Start(function() {
        context.done(null, 'Started Instance');
    });
};

スクリーンショット 2017-03-17 12.29.11.png

さきほど作成したロールを指定します。

項目名 設定値 備考
ハンドラ index.handler
ロール 既存のロールを選択
既存のロール Start_EC2_Instance_Lambda ここで作成したロール名を指定します

スクリーンショット 2017-03-17 12.29.20.png

詳細設定は行いません。「次へ」ボタンをクリックしてください。
(念のため、詳細設定のデフォルト値が確認できるスクリーンキャプチャを掲載します)
スクリーンショット 2017-03-17 12.29.29.png

確認画面が表示されるので、内容を確認して問題なければ「関数の作成」ボタンをクリックします。スクリーンショット 2017-03-17 12.43.39.png

Lambda関数の作成は以上です。
作成したLambda関数の詳細(トリガータブ)が開いていると思いますので、「テスト」ボタンをクリックして、さらに「保存してテスト」ボタンをクリックすると、作成したLambda関数が実行されます。指定したEC2インスタンスが起動されたかを確認してください。
スクリーンショット 2017-03-17 12.50.12.png

続きを読む

RedashをDockerで起動する(2017年3月版)

やったこと

  • Redashをローカル環境のDockerで起動する
  • ローカル環境(Dockerホスト)でリッスンしているMySQLへ接続する
  • Amazon Athenaへ接続する

TL;DR

とにかくRedashをDockerで起動してみたいんだけど、どうしたらいいの? (これだけだとAmazon Athenaは使えません)

  1. 作業ディレクトリを作って、そこへ移動する
  2. 下にある docker-compose.yml ファイルをコピーして、そのディレクトリへ配置する
  3. docker-compose run --rm server create_db する
  4. docker-compose up -d する
  5. http://localhost:28080 へアクセスする

起動

redashディレクトリを作成して、その下にリポジトリをcloneする。Amazon Athenaを使いたいのでそのためのリポジトリもクローンしている。こんな感じの構成にする。

redash/
    `-- https://github.com/getredash/redash.git (v1.0.0-rc.2)
    `-- https://github.com/getredash/redash-amazon-athena-proxy.git (95a9850)
    `-- docker-compose.yml (作成)

redashリポジトリの docker-compose.production.yml をコピーして docker-compose.yml を作り、変更する。(今回redashリポジトリで必要なのはこのymlファイルだけ)

主な変更点:

  • redashのイメージをbuildするようになっていたが、Docker Hub:redash/redashにイメージが上がっているのでimageを指定
  • ホスト側のポートは重複があるようなら変更
  • スキーマキャッシュの時間を5分に
  • 日付フォーマットを指定
  • Amazon Athenaを使うためにproxyサービスの追加・環境変数の追加
  • Postgresのデータを保存するvolumeは名前付きボリュームに
  • ゲートウェイのアドレスを固定するためにネットワーク設定をする(ゲートウェイへ接続するとホストに接続できる)

結果的にこんな感じになった。

docker-compose.yml
version: '2'
services:
  server:
    image: redash/redash:1.0.0.b2804
    command: server
    depends_on:
      - postgres
      - redis
    ports:
      - "5000:5000"
    environment:
      PYTHONUNBUFFERED: 0
      REDASH_LOG_LEVEL: "INFO"
      REDASH_REDIS_URL: "redis://redis:6379/0"
      REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
      REDASH_COOKIE_SECRET: veryverysecret
      REDASH_SCHEMAS_REFRESH_SCHEDULE: 5
      REDASH_DATE_FORMAT: YYYY/MM/DD
      # for Amazon Athena
      # REDASH_ADDITIONAL_QUERY_RUNNERS: redash.query_runner.athena
      # ATHENA_PROXY_URL: http://redash-amazon-athena-proxy:4567/query
  worker:
    image: redash/redash:1.0.0.b2804
    command: scheduler
    environment:
      PYTHONUNBUFFERED: 0
      REDASH_LOG_LEVEL: "INFO"
      REDASH_REDIS_URL: "redis://redis:6379/0"
      REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
      QUEUES: "queries,scheduled_queries,celery"
      WORKERS_COUNT: 2
      REDASH_SCHEMAS_REFRESH_SCHEDULE: 5
      REDASH_DATE_FORMAT: YYYY/MM/DD
      # for Amazon Athena
      # REDASH_ADDITIONAL_QUERY_RUNNERS: redash.query_runner.athena
      # ATHENA_PROXY_URL: http://redash-amazon-athena-proxy:4567/query
  redis:
    image: redis:2.8
  postgres:
    image: postgres:9.3
    volumes:
      - postgres-data:/var/lib/postgresql/data
  nginx:
    image: redash/nginx:latest
    ports:
      - "28080:80"
    depends_on:
      - server
    links:
      - server:redash
  # for Amazon Athena
  # redash-amazon-athena-proxy:
  #   build: redash-amazon-athena-proxy
volumes:
  postgres-data: {}
networks:
  default:
    ipam:
      config:
        - subnet: 172.31.0.0/16
          gateway: 172.31.0.1

こうしておいて下記のコマンドを順に実行すると、Redashが起動する。
docker-compose run --rm server create_db
docker-compose up -d

ホスト側のポート28080をwebサーバに割り当てているので、下記URLへアクセスするとRedashの初期画面が開く。
http://localhost:28080

Amazon Athenaへ接続できるようにする

Javaプロキシを立てて接続する方式になっている。上記ymlファイルで # for Amazon Athena とコメントアウトしているところをコメント解除するとAmazon Athenaが使えるようになる。(コメント解除後に再度 docker-compose up -d が必要)

参考にした情報

クエリランナーの有効化の方法とプロキシのURLがわからなくて苦労したので、辿ったファイルをメモしておく。

公式ブログ:

redashリポジトリ:

redash-amazon-athena-proxyリポジトリ:

接続設定(データソースの作成)

次の迷いポイントは接続設定だと思う。

MySQL

ホスト側でリッスンしているMySQLに接続するには、dockerネットワークのゲートウェイを指定する。
Host: 172.31.0.1
他はMySQLの設定に準ずる。

Amazon Athena

Amazon AthenaのテーブルはAWSコンソールなりで別途作成する必要がある。(事前に作成してなくても、接続自体は可能)

Redash側の設定に必要なもの:

  • AWSのアクセスキーID
  • AWSのシークレットアクセスキー
  • 利用するリージョン
  • Amazon Athena用stagingバケット

破棄

起動したRedashを停止するには、
docker-compose down

Postgresに保存したデータを含めて削除するには、
docker-compose down --volumes

環境

試した環境は下記の通り

  • macOS Sierra 10.12.3
  • Docker version 1.13.1
  • docker-compose version 1.11.1

続きを読む

AWS g2インスタンスにCUDAを入れる際の落とし穴(2017年3月版)

概要

chainer/Tensorflowで使うことを目的に、g2インスタンスにCUDAをインストールしました。

もちろん既にCUDAインストール済みのAmazonLinuxを使用するという選択肢もありますが、今回はUbuntuが使いたかったためまっさらの状態からCUDAを入れました。その際にハマった箇所をメモします。

※ 本手順ではCUDA7.5を指定しましたが、CUDA8.0でも同様と思います。

EC2インスタンスの構成

CUDAのインストールを始める前に、この作業を行ったEC2のインスタンスの設定は以下の通り。

  • AWS EC2のインスタンス(g2.2xlarge)
  • AMIはUbuntu Server 14.04 LTS (HVM)

【参考】Ubuntu14.04にcuda 7.5をインストール

注意点としては、EBSの領域(OSが入る領域)がデフォルトで8GBです。作業領域はS3をマウントするにしても、後々窮屈になるので16GBへの変更がオススメです。

【参考】http://qiita.com/pyr_revs/items/e1545e6f464b712517ed

基本的なインストールの流れ

基本的に流れは、以下いずれかの手順の通りです。

【参考】Ubuntu14.04にcuda 7.5をインストール
もしくは
【参考】 http://www.cs.stevens.edu/~kbatsos/awscudasetup.html

なお、Nvidiaグラフィックドライバは最新のものではなく、Version367系の最後のものを選びます。理由は後述。

落とし穴

上記いずれの手順でも、CUDAインストール後 deviceQuery でCUDAの動作確認をする段階で、

$ cd /usr/local/cuda/samples/1_Utilities/deviceQuery
$ sudo make
$ ./deviceQ uery
./deviceQuery Starting...

CUDA Device Query (Runtime API) version (CUDART static linking)

cudaGetDeviceCount returned 30
-> unknown error
Result = FAIL

といったエラーになります。その他、以下のようなエラーが確認できます。

$ dmesg
(中略)
[ 568.286327] NVRM: The NVIDIA GRID K520 GPU installed in this system is
[ 568.286327] NVRM: supported through the NVIDIA 367.xx Legacy drivers. Please
[ 568.286327] NVRM: visit http://www.nvidia.com/object/unix.html for more
[ 568.286327] NVRM: information. The 375.26 NVIDIA driver will ignore
[ 568.286327] NVRM: this GPU. Continuing probe...
$ nvidia-smi

NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.
$ sudo modprobe nvidia

modprobe: ERROR: could not insert 'nvidia_375': No such device

原因

  1. g2インスタンスのGPUであるK520は、NVIDIAグラフィックドライバーVersion367.xxまでしか対応していない
  2. CUDAインストーラは、CUDAを入れるついでにNVIDIAグラフィックドライバーを最新(367.xxより新しいもの)に更新してしまう。GPUの対応状況を確認せずに! ← コイツがお馬鹿

というコンボにより、上記の現象が発生します。

対処法

対処はシンプルで、上記の落とし穴にはまった後、以下のコマンドでドライバをVersion367へ戻すことで解消します。

$ sudo apt-get install -y nvidia-367

【参考】 https://github.com/NVIDIA/nvidia-docker/issues/319

対処した後の確認結果

成功した場合、以下のような表示となります。

cd /usr/local/cuda/samples/1_Utilities/deviceQuery
sudo make
./deviceQuery
(中略)
deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 8.0, CUDA Runtime Version = 7.5, NumDevs = 1, Device0 = GRID K520
Result = PASS
$ sudo modprobe nvidia
(何もメッセージが出ない)
$ sudo dpkg -l | grep nvidia

ii nvidia-367 367.57-0ubuntu0.14.04.1 amd64 NVIDIA binary driver - version 367.57
rc nvidia-375 375.26-0ubuntu1 amd64 NVIDIA binary driver - version 375.26
ii nvidia-modprobe 375.26-0ubuntu1 amd64 Load the NVIDIA kernel driver and create device files
ii nvidia-opencl-icd-367 367.57-0ubuntu0.14.04.1 amd64 NVIDIA OpenCL ICD
rc nvidia-opencl-icd-375 375.26-0ubuntu1 amd64 NVIDIA OpenCL ICD
ii nvidia-prime 0.6.2.1 amd64 Tools to enable NVIDIA's Prime
ii nvidia-settings 375.26-0ubuntu1 amd64 Tool for configuring the NVIDIA graphics driver

※ iiはインストール済み、rcは削除済みだがconfigは残ってる の意味

【おまけ】 CUDAインストールの後の手順のハマりどころ

cuDNNを入れた後、tensorflow/chainerのGPUインストールが上手くいかないのは大抵、下記のいずれかが原因

  • 環境変数の設定が足りない。 → 公式のインストール手順を再確認
  • 一般ユーザの.bashrcに環境変数の設定をしておいて、sudo pip install している。pip install –user chainer でユーザ単位でインストールするか、virtualenvを使うのが簡単

感想など

対策をサラッと書いてますが、これに気付くまでが結構長かった。何か手順を間違えたかとやり直したり、ドライバのバージョンが原因と気付いてもどのタイミングで最新にされてしまうのかが分からずで半日以上潰しましたよね orz

結局 ググってヒットした上記のgithubのissueで、「オレも、オレも同じ感じでダメ!」って質問したらNVIDIAの中の人が即レスしてくれて一発解決&感謝だったわけですが… うーん 複雑な気持ち^^;

【追記】既に同じような記事が…

Twitterのツイート検索をしてみたところ、AWS E2 G2インスタンス上にKeras環境を構築する 2017年2月版 同様の手順を実施されている記事がありました。タイトルの最後に~年~月版と入れているところがソックリで笑ってしまいました^^;

この方の場合は、CUDAのインストール → Nvidiaグラフィックドライバの順にインストールを行っているので、この記事で起きているような現象に出遭わずに済んでいるようです。このやり方がスマートかも。

続きを読む

lambda入門(Node) – serverless flameworkを使ってみる

こんにちわ、lambdaとslackを連携させて
あれこれやってみたいと思っている@smith_30 です

ひとまず今回は、lambdaを使うにあたりやったことを書き残しておきたいと思います

使ったもの

OS: Mac

  • Node
    私がlambdaを書くに当たってつかえるのはjavascriptだけだったので。

  • phpstorm
    php書く際にお世話になっています、
    フロントエンド範囲だったら大体なんでも便利にしてくれます。

  • eslint
    lambdaがサポートしているNodeのバージョンはv4なので
    es6で書けるため。
    phpstormに読み込ませて、文法を校正してもらう。

  • serverless flamework
    https://github.com/serverless/serverless

準備

phpstorm にeslintの設定を行う

eslintの設定は、google javascript style guideのものを使う

  • インストール
$ npm install -g eslint eslint-config-google
  • 設定ファイル作成
eslintrc.json
{
  "parserOptions": {
    "ecmaVersion": 6
  },
  "extends": ["google"],
  "rules": {
    // Additional, per-project rules...
  }
}
  • phpstormに読ませる

e3d10d243ff703bb8347a2eb1956646e.png

serverless flamework

amazonが出しているserverless flamework的なやつもあるのですが
gcpとかその他クラウドサービスでもserverlessで何かという場合に
柔軟でありたいと思いこちらにしました。

serverless.ymlのproviderのnameあたりいじればいい。
awsでないsampleはこちらから

  • インストール
$ npm install -g serverless
  • awsのIAMを操作。Credential作成
  1. IAMのページにアクセス→ユーザータブをクリック→ユーザーを追加をクリック

  2. アクセスの種類は「プログラムによるアクセス」

  3. 既存のポリシーを直接アタッチ、AdministratorAccessを選択

  4. ユーザーの作成を実行

  • マシンに環境変数を設定
export AWS_ACCESS_KEY_ID=<your-key-here>
export AWS_SECRET_ACCESS_KEY=<your-secret-key-here>
  • プロジェクト作成(スクラッチで始める)
  • Or Existing Servicesから既存のプロジェクトを持ってきて使える
$ serverless create --template aws-nodejs --path testProject
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/serverless/testProject"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  ___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.8.0
 -------'

Serverless: Successfully generated boilerplate for template: "aws-nodejs"

  • サービスのデプロイ
$ serverless deploy -v

プロジェクト内の全ての変更を反映させたいとき
(serverless.ymlの変更など)

serverless.ymlで指定されているデフォルトのリージョンはus-east-1なので
好きなところに編集しておくとよろしいかと。

  • lambda function のデプロイ
$ serverless deploy function -f hello

ここ以降のhelloは、プロジェクト作成時に入っているファイルを指す

handler.js
'use strict';

module.exports.hello = (event, context, callback) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Go Serverless v1.0! Your function executed successfully!',
      input: event,
    }),
  };

  callback(null, response);

  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
  // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
};
  • lambda function を実行してデバッグ(AWSで行われる)
$ serverless invoke -f hello -l

こんな感じでレスポンス返ってきます。

{
    "statusCode": 200,
    "body": "{"message":"Go Serverless v1.0! Your function executed successfully!!","input":{}}"
}
--------------------------------------------------------------------
START RequestId: 264f962d-0808-11e7-8ff3-1f23314ea4ee Version: $LATEST
END RequestId: 264f962d-0808-11e7-8ff3-1f23314ea4ee
REPORT RequestId: 264f962d-0808-11e7-8ff3-1f23314ea4ee  Duration: 2.02 ms   Billed Duration: 100 ms     Memory Size: 1024 MB    Max Memory Used: 15 MB  
  • function の実行ログを取得
$ serverless logs -f hello -t
  • プロジェクトの削除
$ serverless remove

まとめ

予想以上にseverless flameworkが便利、
簡単にlambdaでの開発が進みそう。

phpstorm で編集→エディタのターミナルからデプロイのサイクルが
回せるのは楽だなーと。

また、lambdaってデバッグとかどうすんだろーとか
デプロイいちいちzipにしなきゃいけないのかなーとかが明らかになった。

デプロイコマンド打つとs3にzipがアップされるのでこいつを
lambda作成時に指定してやればいいのかな。

今後作りたいものは、dynamoDBとlambdaの連携とかしたいので
ローカルで開発どうすんだろーとか考えていきたい。
あと、slackからのリクエストをローカルでモックして開発とかか。
APIGateWayだっけか、そこと組み合わせるだろうから勉強しないと。。

続きを読む

2017/3/11 JAWS DAYS 2017 参加メモ

http://jawsdays2017.jaws-ug.jp/

赤ドクロ Presents 『AWSでアプリ開発するなら 知っておくべこと』

https://www.slideshare.net/keisuke69/aws-73040279

アーキテクチャのベストプラクティス

  • Design for failure

    • 単一障害点をなくす、すべてが失敗し得るという前提で考える

      • 最初に1ホストを複数に分割する⇒Webとデータベース(RDS)
      • 複数のWebインスタンスを異なるAZで
      • RDSはMulti-AZ
      • ELBを利用して負荷分散
  • Build Security Every Layer
    • 通信経路および保存されたデータの暗号化、IAM/セキュリティグループ
  • Leverage Many Storage Options
    • 万能なデータストアは存在しない、特性に応じて使い分ける
    • Storage
      • Object Storage: S3, Glacier
      • File/Block Storage: EFS(NFS、共有ディスク), EBS
    • Database
      • NoSQL: ElastiCache, DynamoDB
      • SQL: RDS(トランザクション処理), Redshift(DWH)
      • 静的コンテンツはS3に
      • セッションやステートはDynamoDB
      • DBのキャッシュはElastiCache
  • Implement Elasticity
    • IPアドレスで参照しない(名前ベースで)、分散させる
  • Think Prallel
    • EMRを用いて並列のMapReduceジョブを実行、ELB、1つのKinesis Streamと複数のKCLアプリケーション、バックエンドとしてのLambda
    • 1インスタンスでN時間 = N台を1時間 ⇒ コストは同じ
  • Loose Coupling
    • コンポーネント間の結合度が緩やかになるほど、スケーラビリティは高まる
    • すべてのコンポーネントはブラックボックスとしてデザイン(APIアクセス、DNS名でアクセスなど)
    • Queueを使って疎結合に(部分的なretryがしやすくなる、重たい処理だけをスケールする)
    • Service Discovery
      • 各サービスで増えたリソース、減ったリソースに対して透過的にアクセス
      • Auto Scalingを使ったELB自動登録、Consulなど
    • Asynchronous Integration
      • 同期処理である必要がなければ非同期にする(その処理、本当にレスポンス必要ですか?)
      • アプリケーションがブロックされない
      • スケーラビリティ&高可用性
      • Frontendを停止することになくBackendを容易にメンテナンス可能
      • リクエストの処理順序やリトライ等の制御が容易に(一方、数珠つなぎで全体の見通しは悪くなる)
  • Don’t Fear Constraints
    • より多くのメモリが必要?⇒負荷分散、キャッシュ
    • データベースのIOPSが必要?⇒リードレプリカ、シャーディング、データベースのキャッシング
    • 問題のあるインスタンスを破棄し、置き換える

The Twelve-Factor App

  • Dockerによるアプリケーション開発やLambdaのようなサーバレスコンピュートの普及に伴い、改めて重要性が増しつつある
  • Codebase
    • デプロイされているアプリとコードベースは常に1:1であるべき
  • Dependencies
    • 依存関係を明示的に宣言し分離する
    • 特定の環境に暗黙的にインストールされているパッケージやツールに依存せず、アプリに同梱する
    • 例:gemとbundler
  • Config
    • OSレベルの環境変数によって注入されるべき
    • 設定ファイルは言語/フレームワークの環境依存になる
  • Backing Service
    • ネットワーク越しに使うものはすべてリソースとして扱い(URLのように)、データベースはアタッチされたリソースとして扱う
    • リソースの切替はリソースハンドルの切替(URLの切替)とする
  • Build
    • build、リリース、実行の3つのステージを厳密に分離する
    • すべてのリリースは一意のIDを持つべき(どの環境にどのIDがdeployされているか)
  • Process
    • アプリケーションをStatelessなプロセスの組み合わせとして実行!
    • スケールアウトの単位としてプロセスモデルは分かりやすい(スレッドはメモリ共有するなどで管理が複雑)
    • 永続化する必要のあるデータ(次のリクエストでも利用するデータ)はDBなどstatefullな外部サービスを利用
    • ローカルディスクのファイル、メモリ上のデータはあくまでもキャッシュとして扱う
  • Dsiposability
    • グレースフルシャットダウン
  • Dev/prod parity
    • 開発・ステージング・本番環境をできるだけ一致させ、CI/CDの効果を発揮する
  • Log
    • 出力ストリームの保存先やルーティングにアプリは関与しない(標準出力に吐き出すだけにする)
    • 収集、保存、インデックス化し分析する環境をアプリの外に用意する
  • Stateless
    • ステートフルにになる要素を水平スケールするリソースの外部に配置
    • Session情報(スケールアウトすると新しいインスタンスから見えない)⇒DynamoDBに見にいってローカルにキャッシュ

DevOps

  • 無駄やボトルネックを取り除くことで、ライフサイクル(フィードバックループ)を効率化し、高速化する
  • Cluture:End to EndでOne teamであること、主体的なオーナーシップ、行われた作業の結果に対する可視性を高める
  • Practice:Automate Everything、Test Everything, CI/CD/Infrastructure as a code, etc…
    • 自動化と構成管理:プロビジョニング、設定、オーケストレーション、レポーティング
    • ApplicationとInfrastructureをいずれも、バージョン管理し、build&testし、成果物を登録し、デプロイする
    • 繰り返し継続的に行う
  • Tool

DevOps tool on AWS

  • ほとんどのサービスにAPIが用意されている⇒プログラミングの文脈でインフラを制御する

    • 各言語のSDKが用意されている(IDE向けのプラグインも用意されている)
  • Cloud formation
  • Jenkinsを使ったデプロイ

ベストプラクティス

  • 自動ロールバック:まずはロールバックし、その後ログ/グラフなどを用いてデバッグする
  • ダッシュボードで通常時と異常時を把握する

AWS SECURITY DEATH m/ ~セキュ鮫様からのお告げ~ by Security-JAWS

ネットワーク

  • public subnet / private subnet

    • public subnet: インターネットに直接接続可能なサブネット(公開サーバを置く、EIPとの紐づけもできる)
    • private subnet: NATゲートウェイを経由して内⇒外のインターネット通信は可能
  • statefull / stateless
    • NAT配下のクライアントのSource Portはハイポート(1024-65535)からランダムに設定される
    • Statefull: 戻りの通信もよろしくしてくれる
    • Stateless:内⇒外も書かないといけない(1024-65535/tcp)
    • Security GroupはStatefull⇔Network ACL(subnet単位で通信を制御)はStateless
  • VPN
    • ユースケース

      • Webサーバ/DBサーバのメンテナンスはプライベートネットワーク経由で行いたい(平文でインターネットを通さない)
      • 社内システムで事業所とAWSの間(Direct Connectは品質を高めることもできる)
      • AWSを既存システムの拡張リソースとして使用するような場合(繁忙期など)
    • VPNの場合、AWS側には2つのVPNエンドポイントが用意される(Customer Gateway側で2つのトンネルを張る必要がある)
      • static routingもしくは、BGPによるダイナミックルーティング(対応機種のFAQ参照)
  • Direct Connect(専用線接続)
    • 宅内~接続ポイント⇒一般的には通信キャリア
    • 接続ポイント~AWS⇒AWSが提供
    • VLAN分けをできるキャリアと、できないサービスがある
    • TOKAIコミュニケーションズ、Colt(旧KVH)

WAF/DDoS

  • 全脳アーキテクチャ若手の会
    #### DDoS
  • DDoS対策(コストがかかる)、DDoSをあえて受ける(落ちてもいいサイトであれば、放置するのも一つ)
    • L3/L4:Infrastructure
    • L7: Application
  • AWS Shield
    • CloudFrontを使って、Shieldオプションを有効化
    • Shieldの後ろはAWSでも、オンプレでも対策可能
    • 防御対象:CloudFront, ELB, ALB, Route53
    • 監視:常にモニタリングしてベースラインの作成、異常検出
    • Basicは無料で利用可能、AdvancedはDRT付き
    • Billing Protection
    • DRT:WAFのチューニングやルール作成もやる
    • CloudFrontさえ入っているなら、導入しておかない手はない!

WAF

  • FWやIDS/IPSでは防ぐことができない不正な攻撃を遮断(アプリケーション脆弱性など)

    • PCI-DSS 6.6にもWAF導入について明記されている
  • AWS WAF
    • カスタムルール(IPアドレス制限/文字列制限)、SQLI/XSSといった基本的な対策が可能
    • 構成:CloudFront, ELB, ALBに仕込めるマネージドWAF
    • ルールを正規表現で書けない、WAF検知ログは100件まで
  • AWS WAF / WAF on AWS / SaaS WAF / Cloud WAFの比較
    • SaaS WAF / Cloud WAF: 正常な通信の確認、DNSの向き先変更程度で導入できる
    • WAF on AWSはオートスケールに対応している製品が多い
    • AWS WAFはセキュリティ面では物足りない
  • 「セキュリティ開発」はなぜ浸透しないのか

AWS Config

ごちゃごちゃしやすいAWSリソースを簡単に「見える化」できる

  • 構成管理、変更管理のためのサービス(よく使うサービスは対応済)

    • 構成情報のスナップショットの取得
    • 変更内容を追うことができる、SNSを使った通知も可能
    • AWSリソース間の関係性の確認(EC2とVPC/Security Group/ALBとの関係)
    • EC2 Systems Manager: エージェントを入れると、OSの中の情報を取れる、コンソールからコマンドを発行⇒OS上の変更管理が可能になった
    • IAMの構成管理
  • ユースケース
    • AWSリソースの一覧でAWSリソースを確認できる、削除されたリソースについても追跡可能
    • いつ、どのように変更されたかを記録するので証跡として利用可能
    • 関連するAWSリソースも辿れるのでトラブルシュートしやすい
  • AWS Confing Rules
    • AWS Configで記録した設定が正しいかを判定するルールを定義できる
      • セキュリティグループがフルオープン
      • MFA設定していない
      • ACMの証明書の有効期限があと少し
  • マネージドルール
    • Instanceにtagをつけているか?(billingのために、作った人/プロジェクト名をつける)
    • SecurityGroupがフルオープンになっているか?
  • カスタムルール
    • 判定機構はLambdaで実装⇒極論、修正することもできる
    • awslabsにカスタムルールが公開されている(現在34)
  • AWS Configを有効化して可視化
    • Auto Scalliingで、頻繁にインスタンスの起動/削除をしていなければ、課金額は大きくない

Chat bots with Amazon Lex

  • Amazon Lex:音声/テキスト処理

    • Alexaと同じ技術で提供されている
    • 音声認識+自然言語処理
  • コンポーネント
    • ユーザ入力⇒出力
    • Intents:意図(Utterance/Slots)
    • Fulfillment:処理
  • Utterance
    • Intent(例:RegisteruserForEvent)に対してユーザ入力を紐づける
    • Sample utteranceを複数事前に定義する
    • 反復して学習することによってユーザ入力の言い回しの揺れを吸収(徐々に改善していく)
  • Slot
    • SLOT NAME: eventDate, SLOT TYPE: AMAZON.DATE
    • 12 March 2017 / tomorrowみたいな揺れを吸収できる
  • Fulfilment
    • AWS Lambdaとの統合⇒クライアントにレスポンスを返す
  • 複数のintentをflowにすることで、より自然な対話が可能になる
    • もう少し知りたいですか? ⇒ yes ⇒ 次のintentに繋げる
    • 曖昧な答えの場合は、プロンプトを出す(「”yes”か”no”で答えてください」)
  • Lambdaとの統合
    • Lexがユーザ入力をparseし、intent/slotsを渡してlambdaを起動、lambdaからレスポンスを返す
    • dialogAction:会話の流れをつかさどる(例:ConfirmIntent)
    • facebookの場合、Response cardを返すこともできる(ユーザに選択肢リストを提示)
  • Lambda Functionの実装例
    • switchでintentごとの処理を定義して、1 functionで複数intentを処理
    • LexResponseBuilderでレスポンスをbuild
  • English Onlyでlaunchするが、複数言語をサポートするロードマップ
    • 開発者からAWS Japanへプレッシャーを!
  • 最初はよくテストして、エラーが多いようであればintentを細かく設定するなどの工夫が必要

サーバレスの今と未来

https://www.slideshare.net/YoshidaShingo/serverlessnowandthen

サーバレス

  • パラダイムシフト

    • サーバが要らないということではなく、開発者はサーバについて「考えなくてもよくなる」
    • 2014年末のre:InventにてLambdaの発表
    • 最大の特徴は、課金は使った分だけ(メモリ×時間×実行回数)
  • Function as a Service
    • アーキテクチャにおける責務

      • Stateful >> Stateless
      • 永続データ >> 揮発性
      • バッチ >> イベントドリブン
  • Lambda goes everywhere
    • コンテナベースの実行環境はportabilityが高いので、いろいろなところにデプロイできる
    • Athenaの基盤もLambda
    • Greengrass(AWS IoT)
    • CloudFrontのEdgeの上

代表的なサーバレスアーキテクチャ

  • UIドリブンアプリケーション

    • 認証ロジックをBaaS、DynamoDBにクライアントから直接アクセス、SPA+API Gateway
  • メッセージドリブンアプリケーション
    • オンライン広告システム
    • コンテンツのサムネイル作成(image magicを載せたlambda)
    • ログのストリームプロセッシング(kinesis/kafkaから取って、加工して、S3やDynamoに入れる)

エコシステム

  • プラットフォーム事業者、フレームワークやツール、アプリケーション開発者

    • アプリケーション開発者のノウハウ発信が足りない
    • cloud packの毎日放送事例
  • Serverless framework, Apex, Lamvery, Swagger, AWS Serverless Application Model(SAM), Postman…
  • SAM
    • CloudFormationテンプレートで管理できる
    • lambda, API Gateway, DynamoDBがサポートされている
    • app-spec.yaml -> CloudFormation(codeはS3経由でデプロイされる)

サーバレスだからこそできることをやる

  • 10X Product Development

    • TypeScriptしか書かず、あとは外部のサービスを使っている
    • firebase(auth), Netlify(static site hosting), Cloudinary(画像管理), Algolia(検索)
  • Serverless, NoOpes and the Tooth Fairy
    • 来るサーバーレスな未来では、アプリケーション開発者が運用に責任を持つ
    • プロバイダの技術情報や、内部技術が何に依存しているか理解する
    • 可視性が下がる、自分自身で問題をfixできないし新機能を実装することもできない
    • 売れていないサービスはシャットダウンされるかも
  • 日経新聞事例(紙面ビューアー)
    • 最大18,000回/1分間のinvocation
  • システムをリアクティブに設計する
    • イベントの発火やwebhookなどに対応している周辺のマネージドサービスとうまくつないでいる
    • シンプルなマイクロサービスとして
    • 一度トライアルしておき、いざ活用する前にはまりどころなど判断

SPAの開発の流れ

  • ビュー/アプリ(js)開発

    • ビューの作成
    • テスト駆動でアプリコードを追加(テストがないと、統合時に問題が起こったときの切り分けが困難)
    • 例:jQuery+Jasmine
    • ローカルで開発可能、チーム開発がはじまったらS3で
    • テスト時のブラウザキャッシュに注意(chromeの開発者ツールでdisable cacheするとか)
    • AWSに繋ぐ前に、1行書いたら1行テスト
  • Cognitoを使った認証+フェデレーション
    • 例:Google+
    • Googleで認証してIDが払い出される
    • ブラウザがCognitoにJSでアクセス、CognitoがGoogleに検証、OKであればDynamoDB書き込み権限を払い出す
  • DynamoDBを使ったデータの管理
  • Lambdaでシステム強化
    • DynamoDB直接読み書きでは仕組みとしてできてしまう、「不正なクエリからの保護」(lambdaでvalidationするなど)
    • 「ユーザ全員分の集計」などの情報提供のため
  • Serverless Single Page Apps
    • Ben Rady著、Step by Stepガイド(日本語版が間もなく出る予定)

参考(ところどころで言及されていた別発表)

[AWSワークショップ] Amazon Kinesis Analyticsを触ってみよう

kinesis

  • モチベーション

    • 処理した結果を複数システムに送る必要がある

      • kafka or Kinesis Streams
    • しかも機械学習を行なう
      • Spark Streaming or Storm
  • Kinesis
    • Streams

      • マネージドkafkaのイメージ:入出力に制限はある(入力:秒間1MBまたは1,000put)
    • Firehose:S3, Redshiftへ簡単に配信
    • Analytics:SQLクエリー
  • Stream Source/Destination(StreamかFirehose)
    • 入力側を決定する(Strems or firehouse)
    • 入力データの型定義をおこなう
    • SQL分を作成、デプロイ
    • 出力先を決定する(Strems or firehouse)
  • kinesis demo stremasは良く停止するので注意・・・
    • データ定義は大文字で定義(もしくはselect句をダブルクォーテーションで挟む)

Windowの概念

  • Tumbling Window(例:1分ごとに出力)

    • FLOOR((“SOURCE_SQL_STREAM_001”.ROWTIME – TIMESTAMP ‘1970-01-01 00:00:00’) SECOND / 10 TO SECOND)
    • 10 TO SECOND⇒10秒間隔
  • Sliding Window(データが流れてきたら出力を開始する)
    • Time(60sec:レコード受信をトリガーに直近60sec分を集計)
    • Row(2rows:自分+直近2レコード)
    • 1つのdestinationに対して、TimeとRowを両方設定できる

Reference Dataの追加

  • AWS CLIでのみ追加が可能
  • 例:S3のファイルを見る
  • 現状、Reference Dataを追加すると動作しない(サポート確認中)

まとめ

  • Firehose -> Elastic Search -> KibanaとすべてAWSコンソールで設定可能
  • 構築は非常に楽、標準SQL、Firehoseで接続が簡単
  • バグが多い、性能評価がしにくい
  • kinesis streamsはzookeeperの管理が不要、KPLと併用すれば非常に安い
  • Analyticsは簡単な集計処理ならよいが、複雑な処理はSpark Streaming等を利用したほうがよい

[Alexaハンズオン] Alexa Skills Kit で遊ぼう【基礎編】

続きを読む

フォームから画像を挿入してサムネイルを表示、同時にAWS S3へデプロイする

ちょっとやりたいことがあったので調査がてら。

やること

* フォームから画像をアップロードして、S3バケットへデプロイ
* JavaScript で実装する

挙動は以下の通り

  1. ファイルが挿入できるフォームを表示
  2. コンピュータから画像を挿入
  3. サムネイルを生成してフォーム画面上に表示
  4. 挿入した画像をAWS S3へデプロイ

実装の流れ

  • S3バケットとIAMを準備
  • JavaScript SDKをつかって実装

S3バケットとIAMを準備

  • S3でバケットを作る
  • IAMでS3専用のユーザーを作成する
  • S3へのフルアクセス権限を設定

概ね以下の記事の通り。
http://qiita.com/TakeshiNickOsanai/items/ab17c9f28b9f4ee399c3

S3のバケットへCORSの設定をしておく。

CORSの設定

<!-- Sample policy -->
<CORSConfiguration>
  <CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
      <AllowedHeader>Content-*</AllowedHeader>
        <AllowedHeader>Host</AllowedHeader>
        <AllowedHeader>*</AllowedHeader>
    <AllowedHeader>Authorization</AllowedHeader>
  </CORSRule>
</CORSConfiguration>

JavaScript SDKを使って実装

<!DOCTYPE html>
<html lang="ja">
<head>
  <title>AWS S3へ画像をアップロード</title>
  <meta charset="utf-8">
  <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
  <script src="https://sdk.amazonaws.com/js/aws-sdk-2.12.0.min.js"></script>
</head>
<body>

  <div class="container" id="container">
    <h2>画像をS3へアップロード</h2>
    <div id="content">
      <p><input id="fileToUpload" name="upload" type="file"></p>
    </div>
    <div id="thumbnail"></div>
  </div>

<script>

// AWS Configure 設定

  AWS.config.update({
    accessKeyId: 'アクセスキー',
    secretAccessKey: 'シークレットキー',
    region: 'us-east-1', // S3バケットのリージョンを指定する
  });

// API のバージョンを指定

  AWS.config.apiVersions = {
    rekognition: '2016-06-27',
  };

// s3 に画像をアップロードする関数 UploadToS3を定義

  const UploadToS3 = function() {
    const s3BucketName = 'バケット名';
    const s3 = new AWS.S3({
      params: {
        Bucket: s3BucketName,
        Region: s3BucketName
      }
    });
    const s3file = document.getElementById('fileToUpload').files[0];
    if (s3file) {
      s3.putObject({
        Key: s3file.name,
        ContentType: s3file.type,
        Body: s3file,
        ACL: "public-read"
      }, function(err, data) {
        if (data !== null) {
          console.log("upload completed");
        };
      });
    }
  }

// 画像の挿入時にサムネイル表示と、S3へのデプロイを行う

  $(function() {
    $("#thumbnail").prepend('<span id="image"></span>');

// アップロードするファイルを選択

    $('input[type=file]').change(function() {
      const file = $(this).prop('files')[0];
      if (!file.type.match('image.*')) {
        $(this).val('');
        $('span').html('');
        return;
      }

// 画像表示

      const reader = new FileReader();
      reader.onload = function() {
        const img_src = $('<img height="300">').attr('src', reader.result);
        $('span').html(img_src);
      }
      reader.readAsDataURL(file);
      UploadToS3();
    });
  });
</script>

</body>
</html>

注意

サンプル実装なので、アクセスキーとシークレットキーを直接記述しましたが、目に見える形で2つのキーを記述するのは危険です。ご注意ください。

参考

http://php.o0o0.jp/article/jquery-preview_thumbnail
http://dev.classmethod.jp/cloud/aws-s3-direct-upload/
https://www.lancork.net/2013/11/aws-sdk-for-javascript-in-the-browser-sample/

続きを読む