「Microservices Meetup vol.6」に行ってきた

2017/1/19のデイリーストックランキングにランクインしました。

【毎日自動更新】Qiitaのデイリーストックランキング!ウィークリーもあるよ_-_Qiita.png


いままでの。
「Microservices Meetup vol.2」行ってきたメモ。
「Microservices Meetup vol.4」に行ってきた

図らずして1回おきに参加してますね。

Connpassのイベントページ

少し間が空いてしまったがまた定期的に開催していきたいです。
登壇したいよーって人は直接リプ投げてください
by @qsona さん

Microservices on AWS by @Keisuke69 さん

Keisuke Nishitani @ AWS

Specialist Solutions Architect

サーバーレスアプリケーション開発ガイド 2月発売

マイクロサービスのポイント

  • 管理運用まで含めて分散型
  • 各コンポーネントが独立している
    • 単独で実行できないのは適切に設計されていない

独立して分散していると負荷の高い機能の単位でスケールさせられる=コスト効率が良い

  • 一つのことをうまくやる

    • 複雑化したら分割する
  • 多言語

    • チーム(機能)にはそれぞれの問題に対して適切なツールを選択する自由がある
    • OS、言語、各種ツールに至るまで最適なアプローチを目指せる
  • 検索:Elasticsearch / Solr

  • ソーシャル:グラフDB

  • ログデータ:Cassandra

  • セッション:Redis

†AWSでは:AWSには100ちょいのサービスがあって、その中で更にチームが分かれている。
各チームに社内標準の開発プロセスは存在しない。

  • ブラックボックス

    • 詳細は外部のコンポーネントに公開されない
  • DevOps
    • マイクロサービスにおける組織原理

†AWSでは:運用のみのチームはない。オンコールも開発チームが請け負う

  • 俊敏性

    • 狭い範囲のコンテキストで活動=サイクルタイムが短い
    • システムもシンプル
    • パラレルな開発とデプロイが可能
  • イノベーション

    • 選択に対する権限と責任を持つのでイノベーションを起こしやすい
    • DevとOpsの対立がないため、効率化やイノベーションが起こしやすい
  • 拡張性

    • 適切に非干渉化されてていることで水平方向に単独にスケールできる
  • 可用性

    • ヘルスチェック、キャッシング、隔壁、サーキットブレーカーと言った仕組みは全体の可用性を向上させる

課題

  • 分散型であることは難しい

    • システム数が増える
    • 協調動作の難しさ
    • コンポーネント間のコミュニケーションメッセージ増によるレイテンシ低下
    • ネットワークの信頼性は無限ではない、帯域も無限ではない
  • 移行が大変
    • モノリシックなシステムの分割は難しい
  • 組織
    • 組織体制の変更が必要になるが、それは大変なこと
  • アーキテクチャの難易度
    • 非同期通信
    • データ整合性
    • やっぱりココが一番の課題
    • サービスディスカバリ
    • 認証
  • 運用の複雑さ

アーキテクチャ

一番シンプルなパターン

CloudFront – ALB – ECS – datastore(ElastiCache, Dynamo, )
|
S3

  • バックエンドをRESTfulなAPIにしたSPA
  • 静的なコンテンツはS3とCloudFront
    • CDN通すことでレイテンシが上がることもある
    • キャッシュとの併用を検討
  • ECSとAutoScalingをALBとともに使うことが多い
    • ALB(L7LB)でアプリレベルの情報をルーティング
    • コンテナインスタンスにリクエストを分散
    • ECSのコンテナを負荷に応じてスケールアウト/インする

コンテナのメリット

  • Portable
  • Flexible
  • Fast
    • 軽量で早い
    • ポータビリティと関連して開発サイクルも早く
  • Efficient

  • 一貫性のある環境

  • バージョン管理出来る

Dockerの特徴

  • Package
  • Ship
  • Run

ECS

  • 複数のコンテナをEC2のクラスタ上で一元管理

    • まだTokyoにきてないけど、FargateでEC2の管理もいらなくなるよ
    • EKS(Kubernetes)も発表されています

データストア

  • インメモリ

    • Memcached, Redis
    • ElastiCache
    • DB負荷の軽減
  • RDBMS
    • 無限のスケーリングには向いていない
    • Amazon RDS
  • NoSQL
    • 水平スケーリングをサポートするものが多い
    • テーブル結合ができないのでロジックの実装が必要になる場合も
    • Amazon DynamoDb, KynamoDB Accelarator(DAX)

APIの実装

  • APIの設計、改善、デプロイ、モニタリング、保守派手間がかかる
  • 異なるバージョンが混在すると大変

Amazon API Gateway

  • 複数バージョンとステージ
  • Cognite User Poolsと連携して認証を追加
  • スロットリング、モニタリング
  • バックエンドとしてLamdbaが使える

サーバーレス

  • サーバーはないに越したことはない
  • スケーリングと高可用性の担保が大変
CloudFront - API Gateway - Lamdba - datastore
   |                            (ElastiCache, Dynamo)
   |
  S3

課題をAWSでどうするか

サービスディスカバリ

  • お互いの死活確認や発見
  • ハードコードするとスケールできない

    • メタデータをどこに置くか
  • ALBを利用したサービスディスカバリ

  • DNS(Route53)のサービスディスカバリ

    • VPC単位の振り分け
  • ECSイベントストリームを使用したサービスディスカバリ

    • CloudWatchイベントで拾ってキック
    • LamdbaでRoute53に登録
    • これが一番多いかも
  • DynamoDBを使用したサービスディスカバリ

    • DNSキャッシュの問題がない
    • 自由度が高い
    • 実装が大変
    • DynamoDBストリームを活用して他のサービスへステータス変更を反映
  • イベントベースのアーキテクチャ

    • イベントで処理する
    • いわゆる結果整合性とも関連
    • Dual Write Problem
    • Event Sourcing
      • 状態の記録ではなく状態の変更「イベント」を記録
      • Amazon Kinesis
      • kinesisにpublishして他サービスはsubscribe
      • S3にログを残す
      • トランザクションログの仕組み

モニタリング

  • CloudWatch

    • ログファイルの一元化
    • CloudWatch LogsかS3に保存可能
    • ECSはCloudWatch Logsに一元化できる

分散トレース

  • AWS X-Ray
  • 複数サービスに分散したリクエスト処理を透過的に追える

LogWatchの先に Kinesis FireHorse – ほにゃほにゃ

スロットリング

  • 大事だよ

リトライ

  • 多くのエラーはリトライでカバーできるものが多い
  • リトライ多発で過負荷になることがある
    • Exponential back offもしくはフィボナッチ数列を利用したリトライ感覚の調整
    • 更に乱数でゆらぎを付けて重ならないように

LT:クラウド型医療系業務システムと Microservices への歩み by @hashedhyphen さん

https://speakerdeck.com/hashedhyphen/kuraudoxing-dian-zi-karutesisutemuto-microservices-hefalsebu-mi

クラウド型電子カルテシステムの話

  • メインロジックをRails
  • 常時接続をNode.js
  • バックエンドをScala
  • 基盤はAWS

ここに至る道のり

ファーストリリース前

  • レコメンドは大量のデータが必要

  • メインロジックで実現させようとすると厳しかった

    • Threadとか試したけど……
    • 別アプリケーションとして分離
    • JVM上でScala + Skinnyでスレッドアプリケーションンを実装
    • Microservicesちっくな構成へ
  • 障害検知時

    • メインロジック内のプロトタイプ版が動く!

会計機能リリース前

  • お金を扱う機能は安定性が欲しい
  • Scala + Cats による実装を別エンドポイントとして実装
  • マイクロサービスっぽい作りになっていたから自由度のある技術選択が出来た

まとめ

  • ちょっとマイクロサービス化したことで自由度が上がった
  • 原理主義的にならなくても恩恵がある
  • エンジニアの伸びしろ!

FrontEndからみるmicroserviceとBackendからみるmicroservice by @taka_ft さん

Takahiro Fujii @ Rakuten Travel

楽天内でも採用アーキテクチャはサービスによって異なる。

サービスとしては

  • コンシューマ向け
  • Extranet
  • In-house
  • other
    • ここまではWEBとモバイルがあって、100以上のAPIを利用する
  • API(内部APIを直接利用)

Phase 1

  • 大きなモノリシックなアプリだった
  • 機能がどんどん増えていく
    • 機能別で複数のモノリシックなアプリに分割
    • その後フロントエンドとバックエンドに分割

Phase 2

  • ドメインモデルを整理
  • なるべくRESTfulで作るようになっていった
  • 大きなAPIから小さなAPIに分離
  • I/Fの決定に時間がかかるようになった
  • API呼び出しが大変になった
  • Microservicesっぽくなってきた 2014年くらい

  • 国内予約、海外予約で多言語化だけではない商習慣に根ざしたドメインの差異による重複ロジックの増殖が起きた

  • Microservicesっぽくなってきたが、どんどん品質が下がっていった

Phase 3

(ちょうど前日にプレスリリース)サイト前面刷新に向けての取り組み

  • FrontendsはJavaScriptに刷新
  • API GatewayにKong

組織

  • フロントエンドチームが2人から始まって半年でReactエンジニアを集めて20人以上に

    • 日本人は2, 3人

UI Component

  • SpringからJavaScriptでSPAに変更
  • zeplinのデザインモックからUI Componentを実装するようになった
  • Storyboardを使ってUI Coponentを管理
  • ドメインを含むUI Componentはドメインと結び付きが強いことが多い=専用のオーケストレーションAPIを用意してUI Componentないで処理を閉じることが出来る
  • レスポンシビリティを明示的に定義

    • どこまでフロントエンドでやるか、どこからAPIからもらうか
  • フロントエンドの「使いやすいレスポンス」の要求

  • バックエンドの「汎用的でシンプルなレスポンス」の希望

    • これらのバランスを取る
  • API Gatewayはフロントエンド(UI)チームの管轄

    • ただし状況によってはバックエンド側に持っていくことも検討するつもり

LT: “マイクロサービスはもう十分”か? by @qsona さん

https://speakerdeck.com/qsona/enough-with-the-microservices

POSTDに投稿していた翻訳記事。

スタートアップ企業のほとんどはマイクロサービスをさいようすべきではない

銀の弾丸はない。

「チーム間の依存性」の解決にマイクロサービスというアプローチは違う。疎結合と分散は別。

組織が大きくなると、複数チームが1つのコードベースを触るようになる。そしてマイクロサービス化したくなる。

しかし、モノリスの分割で十分。

チームとは何か

  • 自律的に動けるべき

    • チームが増えるとコミュニケーションコストや、しがらみ
  • チームの分割は目的にそった分割を行う

  • 悪い分割の例: Dev / Ops

  • 依存度が低いほど自律的に動ける

  • High Output という本

  • 使命型組織/技術型組織

    • Micorservicesは使命型組織
    • 組織間が密ならサービス間も密になる

話戻して

  • スタートアップは組織をキレイに分割することが難しい
  • 分割しても密になってしまう

  • 大きなモノリスになるとやはり分割は難しい

    • ドメインの意識は必要
  • マイクロサービス設計しなくても「マイクロサービス精神」で開発すると効果的なのではないか

FiNCが初期からマイクロサービスでやってた理由

  • 単独の事業にできるような一つ一つのサービスを組み合わせて提供してきたから

あとで読み返して修正します。
資料パスの追加とかも。

続きを読む

SSL証明書の有効期限監視をLambda+CloudWatchで実装する

SSL証明書の有効期限をLambdaで取得し、CloudWatchにカスタムメトリクスを送り、CloudWatch Alarmで通知する

AWS上のEC2インスタンスや各種サービスの監視を行う際、CloudWatch Alarmを活用しているケースは多いと思います。
このような場面を想定し、Lambdaで毎日SSL証明書の有効期限チェックを行い、CloudWatchに各ドメインの残日数を送り、その日数をターゲットとしたCloudWatch Alarmを設定することができるようにしたいと思います。

環境

ランタイム:node.js 6.10
開発環境:AWS Cloud9

監視対象の管理

監視対象のドメインは適宜増減することが想定されます。
これらを簡単に管理するために、今回はAWS Systems Manager のパラメータストアにて管理を行います。

パラメータストアに、下記のようなパラメータを登録します。

項目 内容
キー名 /monitor/certificate/domains
タイプ 文字列
[ “hogehoge.com”, “example.com” ]

上記のようにチェックを行うドメインをJSON配列形式で設置します。

Lambdaコード

下記ので実装できます。
※child-process-promise を使用していますが、モジュールのインストールを別途行わなくてもよい
 child_processを使っても良いと思います。(全てをPromiseで統一したかったのであえてchild-process-promiseを使っています)

index.js
const AWS = require('aws-sdk');
var SSM;
var CW;

exports.handler = (event, context, callback) => {
  if(SSM===undefined){
    SSM = new AWS.SSM({region: 'ap-northeast-1'});
  }
  if(CW===undefined){
    CW = new AWS.CloudWatch({region: 'ap-northeast-1'});
  }

  Promise.resolve()
  .then(()=>{
    return new Promise((resolve)=>{
      let ssm_params = {
        Name: "/monitor/certificate/domains"
      };
      let ssm_parameter = SSM.getParameter(ssm_params).promise();
      ssm_parameter.then((data)=>{
        resolve(JSON.parse(data.Parameter.Value));
      });
    });
  })
  .then((domains)=>{
    return new Promise((resolve)=>{
      let check_expire_list = [];
      domains.forEach((domain)=>{
        check_expire_list.push(checkExpire(domain));
      });
      Promise.all(check_expire_list)
      .then((result_valid)=>{
        resolve(result_valid);
      });
    });
  })
  .then((valid_list)=>{
    return new Promise((resolve)=>{
      let metric_list = [];
      valid_list.forEach((result)=>{
        var params = {
          MetricData: [
            {
              MetricName: 'valid_days',
              Dimensions: [
                {
                  Name: 'domain',
                  Value: result.domain
                }
              ],
              Unit: 'None',
              Value: result.valid_days
            }
          ],
          Namespace: 'SSLCertificate'
        };
        metric_list.push(CW.putMetricData(params).promise());
      });
      Promise.all(metric_list)
      .then((data)=>{
        resolve();
      });
    });
  })
  .then(()=>{
    callback();
  });
};

var checkExpire = (domain)=>{
  return new Promise((resolve)=>{
    let exec = require('child-process-promise').exec;
    let cmd = "openssl s_client -connect " + domain + ":443 -servername " + domain + " < /dev/null 2> /dev/null | openssl x509 -text | grep Not | sed -e 's/^  *//g' | sed -e 's/Not.*: //g'";
    let now = new Date();
    exec(cmd)
    .then((result)=>{
      let not = result.stdout.split("n");
      let expire_date = new Date(not[1]);
      let valid_days = Math.floor((expire_date - now) / 1000 / 3600 / 24);
      console.log(domain+" の残り日数は "+valid_days + " です");
      resolve({'domain': domain,'valid_days': valid_days});
    });
  });
};

SAM Template(CloudFormation)

上記のコードをデプロイするためのSAMテンプレートとして、下記のテンプレートでデプロイすることで、CloudWatchEventsにて毎日実行する設定を同時に行われます。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: SSL certificate monitoring function.
Resources:
  monitorCertExpire:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: monitorCertExpire/index.handler
      Runtime: nodejs6.10
      Description: ''
      MemorySize: 256
      Timeout: 300
      Events:
        CheckExpire:
          Type: Schedule
          Properties:
            Schedule: rate(1 day)
            Input: "{}"

CloudWatch

上記をデプロイすることで、CloudWatchメトリクスに 名前空間:SSLCertificate メトリック:valid_days で有効期限切れまでの残り日数が毎日送信されます。

このメトリックデータを使用し、間隔:1日 統計:最小 期間:1中1のデータポイント にて、アラートさせたい日数をしきい値としてアラームを設定することでこれまで通り他の監視と同様に扱うことができます。

参考にさせていただきました

https://qiita.com/zwirky/items/25b1a66dac534f67ca03
https://blog.manabusakai.com/2016/07/lambda-cert-expire/

続きを読む

AWSとAzureとGCPを比較してみる – FaaS編

FaaSについてAWSとAzureとGCPを比較してみました。

注)

1. FaaS比較表

AWS Azure GCP
Lambda Functions Cloud Functions***
言語 Python,
node.js,
java,
C#,
go
ランタイムバージョン1.X
C#,
JavaScript,
F#,
Python*,
PHP*,
TypeScript*,
バッチ (.cmd、.bat)*,
Bash*,
PowerShell*

ランタイムバージョン2.X
C#**,
JavaScript**,
Java**
node.js***
最大実行時間 5分 10分 (従量課金プラン)
無制限 (App Serviceプラン)
9分
直接HTTPアクセスを受け付けるか 受け付けない(API Gatewayと連携必要) 受け付ける 受け付ける
トリガー Amazon S3,
Amazon DynamoDB,
Amazon Kinesis Data Streams,
Amazon Simple Notification Service,
Amazon Simple Email Service,
Amazon Cognito,
AWS CloudFormation,
Amazon CloudWatch Logs,
Amazon CloudWatch Events,
AWS CodeCommit,
スケジュールされたイベント (Amazon CloudWatch Events を使用),
AWS Config,
Amazon Alexa,
Amazon Lex,
Amazon API Gateway,
AWS IoT ボタン,
Amazon CloudFront,
Amazon Kinesis Data
Blob Storage,
Cosmos DB,
Event Hubs,
HTTP,
Microsoft Graph Events(2.Xのみ),
Queue storage,
Service Bus,
Timer,
Webhooks(1.Xのみ)
HTTP,
Cloud Storage,
Cloud Pub/Sub

*試験段階
**プレビュー
***ベータ

2. 対応言語の比較

言語の種類は試験段階とプレビューを含めればAzureが一番多いのですが、正式リリースされたものに限定すればAWSの方が種類が多いです。
一方GCPは機能自体がベータリリースなので、まだこれからといった感じでしょうか。

AzureはBashにも対応しているのが特徴です。運用系のシェルスクリプトをFaaS化すれば、スクリプト用のサーバが不要になりますね。

3. 最大実行時間

最大実行時間はAzureの10分(要host.jsonのfunctionTimeoutプロパティ変更)、GCPの9分に対しAWS Lamdbaは5分と約半分です。実際にAWS Lambdaを利用していると5分の壁を結構感じます。この点は他クラウドが羨ましいですね。
2017年のRe:InventでAWSはFargateというコンテナのサービスをリリースしましたが、このサービスがlambdaが5分以上実行できないことに対するAWSからの回答のように感じます。

4. 直接HTTPアクセスを受け付けるか

AWS lambdaだけ直接HTTPアクセスを受け付けることができません。HTTPアクセスを受け付けるには、API Gatewayと連携する必要がありますが、多機能な分やや設定が面倒な印象です。(但しAPI経由でLambdaを起動することは可能)

まとめ

AWS Lambdaのリリース後、Azure・GCP・Bluemix(現IBM Cloud)は超特急で追従しました。AWS LambdaがIT業界に与えたインパクトはとても大きかったと思います。
現在は「FaaS無ければばクラウドにあらず」といったところでしょうか。

また、AWS GreengrassやAzure IoT Edge**というエッジにデプロイするサービスも出てきています。
将来AWS LambdaがiPhoneやApple Watchにデプロイできるようにならないかなーと妄想中です。

**プレビュー

続きを読む

AWS初心者がLambdaでLINE BOTを作る

LINE BOTでオウム返しのBOTを作ります。
正直AWSを触ったことが無いので、よく分からず困ったので同じように困る人が出ないように
記事にすることにしました。

言語・ツール選定

私はRaspberry pi & PHPでLine botを作ったことが有る。
内容としては位置情報を渡すと近くのコンビニを教えてくれるものだ。
しかし、Raspberry piでLine botを作ると、常にRaspberry piを起動しておく必要があり電力的に優しくなく、
サーバの構築や認証鍵の設定が面倒だった。
そこでサーバレスのLine Botを作ろうと思いました。
私が選択したのはLambda+Node.js。
選択肢としてGAS(Google App Script)もあったけれど今後の拡張性を考えた時、
ES6が簡単に使えない(変換すれば使えるが面倒な)のが嫌だと思ったのでやめました。

環境構築

LINE Developers
https://developers.line.me/ja/
↑LineBotを作るためにアカウント取得する
【公式】クラウドならアマゾン ウェブ サービス (AWS)
https://aws.amazon.com/jp/
↑AWSの登録する(日本アカウントだと駄目?)

おわり

使用するAWS

初心者なのでLambdaだけで作れると思ってました。
すると、そういう訳じゃなくいくつかサービスを利用しないといけないことが分かりました。

Lambda
サーバレス、コンピューティングサービス。
サーバ構築しなくてもイベントやトリガーで実行出来るサービス。
使用できる言語はNode.js、Java、C#、Python。
無料枠は
月1,000,000リクエスト
秒400GB 月間400,000GB
有料枠は
1,000,000リクエストごとに0.20USD(約22.6円)
他のサービスは別料金

API Gateway
API の作成、配布、保守、監視、保護が出来る。
Lambdaの関数を動作させる(キックする)ために使う。
料金はデータ送出量で変わる、使用する地域ごとに料金が違う。
無料期間が終わったら有料。

IAM (これはサービスではなく仕組み)
アクセスを安全に制御するための仕組み。権限(role)の設定をする。
Lambdaでログを取ったりするときに設定が必要。

CloudWatch Logs
ログを取るために使う。
無料枠Amazon CloudWatch でのメトリックス 10 個、アラーム 10 個、API リクエスト 1,000,000 件
まぁ、サービスがうまく稼働したら止めると思うので有料枠は気にしない。

api Gatewayの設定

+APIの作成からAPI名とエンドポイントタイプを決める。

エンドポイントとは?
ゲートウェイ VPC エンドポイント??

Amazon API Gateway で、REST API およびカスタムドメインの作成時に 2 種類の API エンドポイントから選択できるようになりました。
リージョンの API エンドポイントは、REST API をデプロイするのと同じ AWS リージョンからアクセスできる新しいタイプのエンドポイントです。
これにより、API リクエストが REST API と同じリージョンから発信される場合に、リクエストのレイテンシーを減らすことができます。
さらに、独自の Amazon CloudFront ディストリビューションとリージョンの API エンドポイントの関連付けを選択できるようになりました。
API エンドポイントの 2 つ目のタイプは、エッジ最適化 API です。
エッジ最適化 API は、API ゲートウェイによって作成および管理される CloudFront ディストリビューション経由でアクセスするエンドポイントです。
以前は、エッジ最適化 API は、API ゲートウェイを使用して API を作成する際のデフォルトオプションでした。

つまり、どーいうことだ?
何か、ドメイン関係というのは分かった、
エンドポイントとは?
https://qiita.com/NagaokaKenichi/items/6298eb8960570c7ad2e9

なるほど。
URIの設定のことね。
んで、エンドポイントタイプの違いって具体的に何?

Regional:リージョン(地域が一緒なら早い)
Edge Optimized:エッジ最適化(経由して最適化する)
って感じかな?
今回はAPI GatewayもLambdaも同じハイオワにしたので、リージョンで良さそう。

API 名を決めないと何故かエラーが出る模様。訳が分からない。泣いた。
http://kubotti.hatenablog.com/entry/2017/01/13/161022

リソースで、ポストが出来るように設定しLumbdaの関数が完成したらAPIのデプロイをする。
image.png

設定で、ARNの設定をする。
image.png
Lumbdaへのアクセスできる設定とログが取れるようアクセスを許す設定した物を割り当てる。
あ、後クライアント証明書も作った。

Lamubdaの設定

image.png
実行ロールの設定でログ監視とAPIGatewayからのアクセスが可能なアカウントを設定する。

コードはこんな感じ

index.js
'use strict';

const https = require('https');
const querystring = require('querystring');

exports.myHandler = (event, context, callback) => {
    console.log('EVENT:', event);
    var event_data = JSON.parse(event.body);
    console.log('EVENT:', JSON.stringify(event_data));
    const messageData = event_data.events && event_data.events[0];
    console.log("TEST:" + JSON.stringify(messageData.message.text));
    var id = messageData.source.userId;
    if(messageData.source.groupId != null && messageData.source.groupId.length > 0){ //グループからのメッセージ
        id = messageData.source.groupId;
    }

    if(!check(messageData.message.text)){
        callback(null, 'Success!');
        return;
    }
    var postData = JSON.stringify(
    {
        "messages": [{
            "type": "text",
            "text": getResponseMessage(messageData.message.text)
        }],
        "to": id
    });
        // @TODO KMSで管理
    var ChannelAccessToken = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; //チャンネル設定

    //リクエストヘッダ
    var options = {
        hostname: 'api.line.me',
        path: '/v2/bot/message/push',
        headers: {
            'Content-Type': 'application/json; charset=utf-8',
            'Content-Length': Buffer.byteLength(postData),
            'Authorization': 'Bearer ' + ChannelAccessToken
            },
        method: 'POST',
    };
    console.log(JSON.stringify(options));
    //APIリクエスト
    var req = https.request(options,  function(res){
        res.setEncoding('utf8');
        res.on('data', function (body) {
            console.log(body);
            context.succeed('handler complete');
        });
    }).on('error', function(e) {
        context.done('error', e);
        console.log(e);
    });

    req.on('error', function(e) {
        var message = "通知に失敗しました. LINEから次のエラーが返りました: " + e.message;
        console.error(message);
        context.fail(message);
    });

    req.write(postData);
    req.on('data', function (body) {
            console.log(body);
     });
    req.end();
    console.log("TEST:" + postData);
    callback(null, 'Success!');
};

var getResponseMessage = function(message) {
    message = message.toLowerCase();
    message = message.replace('@bot ', '');
    switch (message) {
        default:
            return message;
    }
};

var check = function(message) {
    message = message.toLowerCase();
    var pattern = '@bot ';
    return message.indexOf(pattern) === 0;
};

・↑ではセキュリティガバガバなので、Lineからのアクセスかどうか検証するためにChannel SecretのIDを見るプログラムと、ChannelAccessTokenは管理するものを入れたほうが良いと思います。
・replyでも良いんですが、処理に時間がかかると処理されないらしいので今後重い処理を入れることを考えてpushにしました。
(参照:https://developers.line.me/ja/docs/messaging-api/reference/)
・グループに突っ込んだ時に関係なく反応するのがうざかったので、@botと頭につくと返すようにしました。

image.png
LINE DevelopersのChannelAccessTokenはここのやつをコピペ。

image.png
上のような形で登録する。(念のため443はつけたほうが良い)

image.png
↑のエラーが出ますが問題なく動きます。

結果

image.png
出来た。

まとめ

AWSのいい勉強になった。
私のセキュリティ意識が低いことが分かった。
よくわからないところからAPIリクエストが飛んで来ていたので気をつけたい。
LineBotはちょっと前とはAPIの書き方が変わっていた&単純にNode.jsに慣れていないというのもあって、ちょっと苦戦した。
今後は、飲み会幹事BOTなどにしていきたい。
たのしかった。

参考

https://qiita.com/akihito_nagai/items/f284ef495da380f368cc
https://qiita.com/ykyk1218/items/232437bc92f13d02a8a2
https://qiita.com/daikiojm/items/c05882bedb82d7ed664e

続きを読む

AWSLambdaがGo言語に対応したのでDynamoDBと絡ませながらデモってみた

はじめに

去年のRe:Inventで「来年の早い時期にLambdaがGoに対応するよ!」なんてアナウンスされた時は、来たかっ!という気持ちになりました。
首を長くして待っていたら、本日サポートしたと発表があったので早速試してみました。

デモdemo

普段Node.jsを使ってLambda+DynamoDBの構成を組んでいるので、今回もDynamoDBを絡めてデモってみました。

公式が出している記事を参考にしていただければいいのですが、
現時点でサポートしているバージョンは 1.x です。
基本的なデプロイの流れは
1. Go書く
2. Linux用にビルドする
3. zipでアップロード
という流れになると思います。

Go書く

基本形は下記のような感じです。

package main

import (
    "github.com/aws/aws-lambda-go/lambda"
    "fmt"
)

type Response struct {
    Message string `json:"message"`
    Ok      bool   `json:"ok"`
}

func Handler() (Response, error) {
    // 処理部分
}

func main() {
    lambda.Start(Handler)
}

lambda.Start(Handler) でLambdaの処理を実行します。
なんか少し違和感があるのは私だけでしょうか…
んで、 Handler の中に実際の処理を書いていく感じになります。

DynamoDB(GetItem, PutItem, Query)

aws-sdk for goを使ってDynamoDBにリクエストを送っていきます。
上記のソースコードに追記したのが下記になります。

package main

import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/dynamodb"
    "github.com/aws/aws-lambda-go/lambda"
    "fmt"
)

type Response struct {
    Message string `json:"message"`
    Ok      bool   `json:"ok"`
}

func Handler() (Response, error) {
    // session
    sess, err := session.NewSession()
    if err != nil {
        panic(err)
    }

    svc := dynamodb.New(sess)

    // GetItem
    getParams := &dynamodb.GetItemInput{
        TableName: aws.String("go-demo"),
        Key: map[string]*dynamodb.AttributeValue{
            "id": {
                S: aws.String("1"),
            },
        },
    }

    getItem, getErr := svc.GetItem(getParams)
    if getErr != nil {
        panic(getErr)
    }
    fmt.Println(getItem)

    // PutItem
    putParams := &dynamodb.PutItemInput{
        TableName: aws.String("go-demo"),
        Item: map[string]*dynamodb.AttributeValue{
            "id": {
                S: aws.String("2"),
            },
            "name": {
                S: aws.String("hoge"),
            },
        },
    }

    putItem, putErr := svc.PutItem(putParams)
    if putErr != nil {
        panic(putErr)
    }
    fmt.Println(putItem)

    // Query
    queryParams := &dynamodb.QueryInput{
        TableName: aws.String("go-demo"),
        KeyConditionExpression: aws.String("#ID=:id"),
        ExpressionAttributeNames: map[string]*string{
            "#ID": aws.String("id"),
        },
        ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
            ":id": {
                S: aws.String("1"),
            },
        },
    }

    queryItem, queryErr := svc.Query(queryParams)
    if queryErr != nil {
        panic(queryErr)
    }
    fmt.Println(queryItem)

    return Response{
        Message: fmt.Sprintln(getItem.Item),
        Ok:      true,
    }, nil
}

func main() {
    lambda.Start(Handler)
}

GetItemで返ってくるレスポンスはこんな感じ

{
  Item: {
    id: {
      S: "1"
    },
    name: {
      S: "test"
    }
  }
}

Queryで返ってくるレスポンスはこんな感じ

{
  Count: 1,
  Items: [{
      id: {
        S: "1"
      },
      name: {
        S: "test"
      }
    }],
  ScannedCount: 1
}

ビルドして、zipに固める

$ go build -o main.go
$ zip deployment.zip main

linux用にビルドしないといけないので、macの方は下記を実行してからzipに固めてください。

$ GOOS=linux go build -o main

Lambdaにデプロイする

Lambdaのコンソールから新しく関数を作成して、ランタイムを Go 1.x を選択します。
アタッチするロールには今回はDynamoDB関係の権限も忘れずに。
スクリーンショット 2018-01-16 15.05.24.png

関数が作成されたら、先ほど作成したZipファイルをアップロードすれば完了です。
スクリーンショット 2018-01-16 15.06.08.png

これでGoを使ってDynamoDBのデータを操作できるぞ!

あとがき

正直Go言語はほとんど触ったことなかったので、ソースコードはきったねぇと思いますがご了承ください。
Node.jsの感覚で実装したら動いたって感じです…(汗)

Node.jsで実装していると「シングルスレッドじゃあしんどいな…」と感じている時もあったりします。
Go言語はNode.jsと違って並列処理に長けているので、ケースバイケースで「Node.jsよりもGoの方がよいんでは?」となりそうなので、今のうちにGo言語に慣れておかなければと実感しました。

ではまた!

続きを読む

AWS SDK で SQS を Python で操作する

今回はPythonのAWS SDKでSQSメッセージの送受信を行います.

前提

  • aws cli の configure を済ませている

ソースコード

設定はconfigparserモジュールを使用します.

config.ini
[sqs]
url : https://sqs.ap-northeast-1.amazonaws.com/YYYYYYY/XXX

それではソースコードです.

sqs.py
# -*- coding: utf-8 -*-

import configparser
import boto3
import json

# configファイルの読み込み
ini = configparser.SafeConfigParser()
ini.read("./config.ini")

sqs = boto3.client('sqs')
url = ini.get("sqs", "url")

# 送信するJSON
body = {"type": "Right", "Action": "On"}

# SQSへJSONの送信
response = sqs.send_message(
    QueueUrl=url,
    DelaySeconds=0,
    MessageBody=(
        json.dumps(body)
    )
)

# SQSからJSONを受信
response = sqs.receive_message(
    QueueUrl=url,
    AttributeNames=[
        'SentTimestamp'
    ],
    MaxNumberOfMessages=1,
    VisibilityTimeout=0,
    WaitTimeSeconds=0
)

message = response['Messages'][0]
body = json.loads(message['Body'])
print(body)

# メッセージを削除するための情報を取得
receipt_handle = message['ReceiptHandle']

# メッセージを削除
sqs.delete_message(
    QueueUrl=url,
    ReceiptHandle=receipt_handle
)

実行します.

$python3 sqs.py
{'Action': 'On', 'type': 'Right'}

無事JSONを受信できました.
Alexaを使って遊ぼうと考えているので今日はその準備にSQSを使用してみました.

参考文献

続きを読む

AWS EC2でHyperledger Fabricを動かす(2.Fabric前提条件の準備)

AWSにUbuntuをセットアップし、FabricをDockerで起動してみたいと思います。

前回は、AWS EC2を用意するところまででした。
https://qiita.com/tmikada/items/a1f22fd5c61c2de71d19

今回は、Fabric導入のための前提条件を準備していきます。

必要なものはこちら

  • curl
  • docker 17.06.2-ce or greater
  • docker-compose 1.14.0 or greater
  • go 1.9.x
  • node.js 6.9.x or greater (7.xは現時点でサポート対象外)
  • npm
  • python 2.7

参照: http://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html

順番に導入していきます。

curl

インストール済み

$ curl --version
curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets 

docker

手順: https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/#install-using-the-repository

$ sudo apt-get update
$ sudo apt-get install 
     apt-transport-https 
     ca-certificates 
     curl 
     software-properties-common

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
OK
$ sudo apt-key fingerprint 0EBFCD88
pub   4096R/0EBFCD88 2017-02-22
      Key fingerprint = 9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid                  Docker Release (CE deb) <docker@docker.com>
sub   4096R/F273FCD8 2017-02-22

$ sudo add-apt-repository 
    "deb [arch=amd64] https://download.docker.com/linux/ubuntu 
    $(lsb_release -cs) 
    stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce
$ apt-cache madison docker-ce

$ docker --version
Docker version 17.12.0-ce, build c97c6d6

docker-compose

手順: https://docs.docker.com/compose/install/#install-compose

$ sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
docker-compose version 1.18.0, build 8dd22a9

go

手順: https://github.com/golang/go/wiki/Ubuntu

$ sudo apt-get install golang-go
$ go version
go version go1.6.2 linux/amd64

# バージョン古いため、新しいのを入れる

$ sudo add-apt-repository ppa:gophers/archive
$ sudo apt update
$ sudo apt-get install golang-1.9-go
$ go version
go version go1.6.2 linux/amd64

# 変わってない。。。
# 手順をよく見ると、1.9はこちらにあるらしい
$ /usr/lib/go-1.9/bin/go version
go version go1.9.2 linux/amd64

# パスを変更します
$ cd /usr/bin/
$ sudo rm go
$ sudo ln -s ../lib/go-1.9/bin/go
$ go version
go version go1.9.2 linux/amd64

GOPATHを設定します

$ mkdir ~/go
$ vi ~/.bashrc

# 以下の2行を追記
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin

$ source ~/.bashrc
$ echo $GOPATH
/home/ubuntu/go

node.js, npm

nodeのバージョン管理は、nを使うことにしてみます
手順: https://qiita.com/seibe/items/36cef7df85fe2cefa3ea

バージョンの組み合わせは
https://nodejs.org/ja/download/releases/
を参照し、nodejs 6.9.5, npm 3.10.10 を選択

$ sudo apt-get install nodejs npm
$ nodejs --version
v4.2.6
$ npm --version
3.5.2

# nをインストールしてnodeの新しいバージョンを導入する
$ npm cache clean
$ sudo npm install -g n
$ n --version
2.1.7

$ sudo n 6.9.5
$ node --version
v6.9.5

# 古いnodejsはまぎらわしいため削除しておく
$ sudo apt-get purge nodejs

# バージョン指定してnpmをインストール
$ sudo npm install -g npm@3.10.10
$ npm --version
3.10.10

Python

2.7がインストールされていました

$ python --version
Python 2.7.12

ここまでで、やっと前提条件の準備が完了です。。。
次回はFabricを動かすところまで書くつもりです。

続きを読む

MonacaからPhoneGap Builderへ移行

なぜ切り替えるに至ったか

Monacaを使っていたものの、公開版を作成するためには有料プログラムにしなくてはならない。
使い始めてた時からわかっていたもの、便利だったのでずーっと問題を放置してきた。
しかし、いよいよ自分が作成したアプリが完成に近づいてきてビルド回数に制約があることも踏まえ、切り替えるのも自分のスキルアップにつながるかなと思ってやってみた。

まとめると

・Monacaありがとう
・riot,AWS,phinaのコンビネーションでもMonacaもPhoneGap Buildもできました
・でも、はまるところもあります

以下、自分の備忘録に近いところもあるけど、吐き出しておく。

Monacaはアプリ開発を加速します

そもそも切り替えるかどうか悩んだのは、やっぱり便利だから。
開発で悩みを減らす、そのことをビジネスにしているのだからそれはそれでいいのだと思う。
ホントありがたいサービスです。
これがなかったら、私はここまでこれませんでした。
費用面がクリアできるなら、Monacaで開発したほうがいいです。
私のように3連休まるまるこの問題解決に使うことなく開発に専念できます。

では切り替えますか…何に?

Monacaはcordovaをベースにしてることは知ってます。
でも、みなさんphonegapに行きつくわけですね。
そこからして無知な私は調べるしかなくて。
調べてた途中でtelerik platformなるサービスも見つけたが、2018年5月でサービスやめるっていうことで、マイグレーションガイドがあってこれが非常にありがたかった。これみれば、イマドキこういうサービスがあるんだと理解できた。やっぱりcordovaかphonegapの2択なんだとわかったので。

クリップボード01.jpg

その2択を調べてみた1ところ…やっぱりよくわからないけど、PhoneGap Buildを使わないと最終的なビルドが面倒そうに見えたので、phonegapにしてみることにした。

Phonegap Builderに切り替えようとしたけど

というわけで、また調べると過去にアプローチした方のを参考にすることにした2

参考にしたいものの、ギャップが大きすぎた。
ここで、今回のアプリと自分がこれまでどうやって開発してきたかを簡単に説明すると…
・riot.js+phina.js+aws(DynamoDB,Coginto Userpool)で作られたゲーム
 ・一部をのぞきcdn参照。
・開発は自分の自宅PC(windows10)
・IDE?そんなもん知らんなぁ(テキストエディタで編集してIISサーバ経由で動作確認)
 ※IISサーバ経由なのはriotが求めるから(XSSが…というのでそれはそれで仕方ない)。
 ※ほんとはpercel出たあたりに期待したのだけど、phinaとの相性3で断念。

そもそもMonacaで動くのか?

つまり、そもそもMonacaですらまともに動くかどうかわからない状態。
というわけで、まずはMonacaに移植することにした。

案の定動かないわけです。
エラーログもはかずに、背景色のみ。
CDNなところはすべて取っ払い、必要なコンポーネントを全部追加して、パスも通しても動かず。

理屈的にはコンポーネントを追加すれば動くはずなんだけど…
今回は必要なライブラリはダウンロードして取り込むことにしました。

回り道したようにも思えましたが、結果として「Androidアプリ設定」などその後の作業がイメージしやすかったです。

動いちゃうと案外満足しちゃうもので、やっぱこのまま…とも一瞬思いました。

いよいよMonacaから旅立つ

でも、ビルドに制約があるので…改めて手順にしたがってphonegapから。
あらかじめnode.js,npmは使える環境にはしていたので、そこは割愛。

1.Phonegapのインストール

npm install -g phonegap

まぁ普通。npm install -g phonegapしたかったので、管理者権限でやったことぐらい?

2.スマホにデバッグツールをインストール

インストール自体は悩まないのだけど…後述しますが、ネットワーク連係するアプリの場合あまり使えないのです…

3.プロジェクトを作成

phonegap create <AppName> --template blank

ここも特にひねりはない。参考例もblankにしているが、下手にhelloworld入っているよりわかりやすいんじゃないかなと思いました。

4.開発

今回はあらかじめ開発してあるので、www以下に開発した成果物を放り込む。
その際に以下を残せというから残した。

<script type="text/javascript" src="cordova.js"></script>

5.モバイルでの確認

$ phonegap serve android

できるんだ!と思ってやってみたところ…できた!
ここまできたら、2.で導入したデバッカーで動作させようとしたところ…

ちーっとも接続しない。
そもそもPC→スマホって接続できてないのでは?
と思って、昔でいうLANボード2枚刺しみたいなことをしようと調べたら…
いまさら SoftAP を使用してWindowsノートマシンを無線親機にする

これこれ。ありました。この手順にしたがって、PCを無線親機化して、スマホ側で認証することでようやく接続できました。
で、画面が表示されてボタンも反応して一安心、と思ってログオン機能を試したところ動かない。
サーバ側のログをみても無反応。

何がまずいのかわからなかったので、またネットでググると
Cordova、IonicでHTTP通信できない・画像とかが読み込めないときの対処法3選
これのホワイトリストの設定ミスの項をみて、そもそもwhitelistのプラグイン入れてない!と気がづき、入れました。

今度は…と思ったら「認証できません」というあらかじめアプリで仕込んだメッセージが。
なんでなん?
と思ってサーバ側のエラーログを見たら

NetworkingError: Network Failure

このキーワードで調べるとCORSConfigurationにぶち当たるのだが、これが曲者。
S3の話はそれで解決するのかもしれないが、実際のところはサーバ側(ここでいえばphonegap serve)の問題とのこと。
(この裏どりだけが再検索しても出てこない…英語のページでnot client sideというようなキーワードがあったはず。)

つまりは

$ cordova serve android

した後、自PCで

http://localhost:3000/

して確認したら、あとは信じるしかない…と割り切って先に進んだ。

6.プラグイン

ここもまぁ普通。あまり悩むことはない。

7.設定の修正

ここはMonacaを経由したおかげで何をすべきかが分かった。
むしろここを見たほうがいい。

8.アイコンの変更

Favicon Generator
である程度作ってくれるのだが、最新のiosに対応してないので自力で作らないところがあるのがつらい。

9.PhoneGap Buildでアプリを作成する

ようやくここまできました。
PhoneGap Build

まずはadobeのIDがなかったので作りました。まぁ悩むところはないが、パスワードの制約が面倒。
そして、やっぱりgithubが必要だというので、これまで避けてきたけどgithubもアカウント作成。

githubを使うのも初めてだったのでプログラムソースのアップロードに四苦八苦。
結局webから登録可能だと知ったのが、調べ始めてから3時間後。
無題.jpg

ネットを見ると、gitから登録する手順はたくさん載っているが、こんなシンプルな方法がなかなか出てない。当たり前だからか?

そこに至るまでにgithubのデスクトップ版入れたりしたが、どうにも使いづらいうえに案外ネットにも情報がない。
結局git for windowsを入れたほうがシンプルで分かりやすい。

10.PhoneGap Buildに鍵を登録する

これも書いてあるとおりなのだが、javaも必要なのか…てかkeytoolだけが必要なんだけど

keytool -genkey -v -keystore [keystore_name].keystore -alias [alias_name] -keyalg RSA -keysize 2048 -validity 10000

このときのエイリアス名、のちに使うので慎重に。

無題.jpg

「アカウントを編集」-「署名キー」-「キーを追加」
このときにタイトルはどうでもいいけど、エイリアスはkeytoolで作成したときに -alias [alias_name]で指定した値と一致しないとエラーになる。(←エラーとなったからわかる。)

果たして動くのか?

そうなんです、ここまで作業したものの最終的に実機確認ができてないので不安でしたが…
動きましたー
・aws cognito userpoolを使った認証
・aws DynamoDBを使ったデータ取得、更新
・riot.js+routerを使ったフレームワーク
・phina.jsの動作
すべて問題なし。

ただ反応が鈍いかな…PC(corei7)とスマホ(arrowsM02)を比較しちゃダメなのかな。

続きを読む

AWSとAzureとGCPを比較してみる – DB編

DBについて、AWSとAzureとGCPを比較してみました。

1. 新世代DB

AWS Azure GCP
新世代DB Aurora Cosmos DB Cloud Spanner
DBの種類 MySQL,
Postgresql
SQL (document DB),
MongoDB (document DB),
Gremlin (graph DB),
Azure Table(KVS),
Cassandra
オリジナルのリレーショナルDB
サーバレスか否か サーバあり サーバレス サーバレス
高可用性構成 / 負荷分散 Auroraレプリカ,
クロスリージョンレプリカ(MySQLのみ)
リージョン間フェイルオーバー,
予約済みスループット
リージョン内レプリケーション,
マルチリージョンレプリケーション
地理的範囲 リージョン(MySQLは別リージョンにレプリケーション可) グローバル グローバル
マルチマスター シングルマスター,
マルチマスター*
マスターになるリージョンは1個 マルチマスター

*プレビュー

DBの種類ですが、Auroraは手堅くMySQLとPostgresql、Cosmos DBはバラエティーにとんでいてドキュメントDB・KVS・グラフDBとCassandra、Cloud SpannerはオリジナルのリレーショナルDBとなっています。
Cloud Spannerはクライアントライブラリが各言語(C#,GO,Java**, node.js**,PHP**, Python**, Ruby)に対し用意されていますが、ORMの対応が気になるところです。
**ベータ

Cosmos DBとCloud Spannerはサーバレスですが、Auroraはインスタンスタイプを指定してインスタンスを構築します。また、拡張機能というよりは別物として、サーバレスタイプのAurora serverless*がプレビュー中です。

高可用性構成と負荷分散ですが、Auroraはリージョン内ではリードレプリカが障害時にマスターに昇格することで対応しています。MySQL版はクロスリージョンレプリケーション構成を取ることができますが、リージョン間で自動フェイルオーバーする仕組みはありません。
また、Auroraはマルチマスター機能であるAurora Multi-Master*が現在プレビュー中ですが、リージョン間でも利用可能になる予定があるとアナウンスされています。リリースされればグローバルで高可用性と負荷分散が簡単に実現できそうです。
Cosmos DBは、1個の書き込みリージョンを持つリージョン間フェイルオーバー***の仕組みで高可用性を実現しています。
Cloud Spannerはリージョン内レプリケーションとマルチリージョンレプリケーションの仕組みで高可用性を実現しています。1つのリージョンで構築する場合は、3個のread-writeレプリカを保持します。複数リージョンで構築する場合は、2個のread-writeレプリカを保持する2個のread-writeリージョン(と場合によってread-onlyリージョン)で構成されます。

***Microsoftのドキュメントではregional failoverをリージョン内フェイルオーバーと訳していますが、意味合いはリージョン間フェイルオーバーなので、ここではそのように表記しています。

2. リレーショナルDB

AWS Azure GCP
MYSQL互換 MySQL
/ MariaDB
Azure Database for MySQL* Google Cloud SQL for MySQL
高可用性構成 Multi-AZ,
クロスリージョンリードレプリカ
フェイルオーバーレプリカ
負荷分散 リードレプリカ,
クロスリージョンリードレプリカ
リードレプリカ
Postgresql Postgresql Azure Database for PostgreSQL* Google Cloud SQL for PostgreSQL**
高可用性構成 Multi-AZ,
クロスリージョンリードレプリカ
リージョナルインスタンス**
負荷分散 リードレプリカ,
クロスリージョンリードレプリカ
リードレプリカ**
SQL Server SQL Server Azure SQL Database
高可用性構成 Multi-AZ アクティブgeoレプリケーション
負荷分散 アクティブgeoレプリケーション
Oracle Oracle
高可用性構成 Multi-AZ
負荷分散

*プレビュー
**ベータ

・各クラウド間での違い-その1

AWSのMulti-AZとGCPのリージョナルインスタンス(PostgreSQL)は、スタンバイ側はリードの機能がないので負荷分散には利用できませんが、GCPのフェイルオーバーレプリカ(MySQL)はリードの機能があるので負荷分散にも利用できます。

3. NOSQL

AWS Azure GCP
KVS・ドキュメント ElastiCache(Memcached, Redis),
DynamoDB
Redis Cache,
Cosmos DB(Azure Table, SQL, MongoDB)
Cloud Datastore,
Cloud Bigtable
グラフ Neptune* Cosmos DB(Gremlin)
Cosmos DB(Cassandra)

*プレビュー

Neptuneの現時点のプレビューのAWSマネジメントコンソール画面はAmazon RDSとよく似ています。また裏でAuroraと同じ仕組みを利用しているそうなので、ひょっとしたらCosmos DBみたいに、Auroraの一機能としてリリースされるかも知れません。

4. まとめ

現在は、MySQL・Postgresqlを利用したければAWSのAuroraかRDS、SQL Serverを利用したければAzureでしょうか。
ただ各クラウドのプレビュー・ベータ提供状況を見ていると、そのうち機能差は無くなるように思えます。

続きを読む

カップル向けのサービスをメンテフリーで有名なserverless構成で出した話

「Glance(グランス)」 ~カップルのためのYes/No枕アプリ~

2018/01/03より、「Yes/No枕をアプリで」というコンセプトの元に作られたアプリをリリースしましたー!

結構、謎仕様が多くて使い所も不明ですが、
9月ぐらいの「八耐|八時間耐久製作会」というイベントでアイデアから本日のリリースに至りました。

itunes.apple.com_jp_app_glance-yes-no%E3%81%BE%E3%81%8F%E3%82%89_id1294641754_l=ja&ls=1&mt=8.png

https://itunes.apple.com/jp/app/glance-yes-no%E3%81%BE%E3%81%8F%E3%82%89/id1294641754?l=ja&ls=1&mt=8

機能

  • アプリアイコンが動的に変わる、Yes/No枕アプリ

特徴

  • iOS10.3からの機能で、アプリアイコンがYes/Noに動的に変わり、お互いにステータスが見れるというコンセプトです。
  • サーバーサイドはserverless frameworkで
    LambdaとDynamoDBを使っており、メンテコストはほぼ0(ゼロ)

構成

  • アプリ Swift4.0
  • サーバー serverless framework
    • DynamoDB
    • Lambda
    • API Gateway

serverless frameworkとは

  • 「AWS Lambda」と「AWS API Gateway」を利用したサーバレスなアプリケーションを構築するためのツールです。
  • AWSコンソールからだとボタン操作の履歴が残らないですが、serverless frameworkだと全てコードベースで管理できます。

サーバーレスのメリット

  • 管理するサーバーが無いのでサーバーダウンの概念がありません。
  • とにかく安い!
  • 保守メンテが楽でセキュリテイパッチやサーバー管理などのメンテが不要
  • 詳しくはserverlessの魅力を御覧ください

Lambda上でNode.js + Expressがおすすめ

  • API Gatewayでpath管理できますが、serverless + expressのプラグインがあるのでそれに任せたほうが圧倒的に楽になります。

serverless.ymlを晒しとく

  • eventsはanyですべてnodeのExpressに投げます。
serverless.yml
service: yesnoapp

custom:
  defaultStage: dev

provider:
  name: aws
  runtime: nodejs6.10
  profile: yesnoapp
  stage: ${opt:stage, self:custom.defaultStage}
  region: ap-northeast-1
  memorySize: 100
  timeout: 2
  iamRoleStatements:
      - Effect: Allow
        Action:
          - dynamodb:DescribeTable
          - dynamodb:Query
          - dynamodb:Scan
          - dynamodb:GetItem
          - dynamodb:PutItem
          - dynamodb:UpdateItem
          - dynamodb:DeleteItem
        Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/*"

package:
  exclude:
    - .serverless
    - .webpack
    - coverage
    - .babelrc
    - .eslintignore
    - .eslintrc
    - .gitignore
    - LICENSE
    - package.json
    - README.md
    - serverless.yml
    - webpack.config.js


functions:
  app:
    handler: handler.app
    events:
      - http: any {proxy+}

resources:
  Resources:
    YesNoAPPDynamoDbTable:
      Type: 'AWS::DynamoDB::Table'
      DeletionPolicy: Retain
      Properties:
        AttributeDefinitions:
          -
            AttributeName: device_token
            AttributeType: S
        KeySchema:
          -
            AttributeName: device_token
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: "Users"

とまあ、こんな感じでExpressが動く!

  • メンテフリー!コストフリー!みんなハッピー!

良かったこと/悪かったこと

ハッカソンのような短期開発には向いている

  • 開発のスタートダッシュが早く、ハッカソンのような短期即本番には向いているといえます。

運用後も安心な価格とコスト

  • ハッカソンで作った作品なので、アクセスはほぼ見込まれません。t2インスタンスなどは、固定でどんどんお金がかかりますが、料金はアクセスが増えた分だけだし、無料枠も十分あるので運用後もずっと残して置けるでしょう。

バズってもなお安心

  • バズることはほぼないですが、もし万が一バズったとしても、サーバーレス設計なら理論上無限スケールで対応することができます。

中盤がきつい

  • スタートダッシュは早いものの、だんだんこだわって作り出すと、Railsだったらこうできるのに…や、DynamoDBだからテーブルわけなくちゃ…NoSQLの苦悩など、中盤のブラッシュアップ期間は忍耐が必要そうです。

まとめ

  • サーバーレス設計は、開発速度が早く安い。とくにハッカソンイベントでは効果を発揮するのでおすすめです!という話でした!

参考

今回参加した八耐の紹介

『八耐』とは

  • 『八耐:八時間耐久作品制作会(仮)』は、8時間でゲームやCG、映像を制作し、参加者全員で発表するイベントです。
  • イベントの最後に発表と試遊会を通じて、新しい繋がりや見知らぬクリエーター同士の交流を深めるイベントにもなっています。
  • 東京と福岡会場があります。私は毎月、東京会場で参加しておりますのでぜひ!
  • http://www.daihachitai.com/index.php/about

続きを読む