ITと筋トレの二刀流

未だゼロ刀流

Angularのモックサーバーを簡単に実現する

f:id:tatsuyashi:20190127002850p:plain:w200

Angularで開発する際に、バックエンドのAPIがまだ実装されていない状態でAngularの実装を行うことは多いと思います。

その場合にAPIを一旦モックにして進めると思いますが、選択肢としては、

  • モック用のAPIサーバを用意する
  • in-memory-web-apiを使用する
  • serviceメソッドの戻りを固定値にする

などが考えられると思います。

今回の記事では私が実際に行っている方法で、1〜3とは異なるモックの仕組みを紹介したいと思います。

ソースコードは以下で公開してますので、記事を飛ばしたい方はこちらから確認してみてください。

GitHub - tatsuyashi/angular-mock-sample

キモとなるコミットはこちら↓
use mock on dev-server · tatsuyashi/angular-mock-sample@1889bd6 · GitHub

やりたかった事

私がモックの仕組みを作成するにあたり、以下の条件を満たすものを考えました。

  • 他のライブラリに依存しない
  • 実際にHTTP通信を発生させる
  • モック→実APIへの切り替えは設定ファイル以外触らない
  • production環境には一切乗らない(bundleさせない)

モックの仕組み

今回のモックの仕組みを簡単に図にすると以下のようになります。

f:id:tatsuyashi:20190127012006p:plain:w500

ポイントをまとめると、

  • 開発時に起動するdev server上でモックとなるJSONを公開する
  • JSONのパスは /mock/{HTTPメソッド}/{URL}.json とし、APIのメソッドとURLに対応したファイルパスで作成する
  • production時は実APIをそのまま呼び出す
  • 上記の仕組みをHttpInterceptorを使用して実現する

となります。

dev serverをそのままモック置き場として代用することで、別でAPIサーバを立てる必要もないですし、アプリケーションから実際にHTTP通信が行われるようになります。

それでは、次章から実際のコードを基にポイントを説明していきます。

ソースコードはこちら↓
GitHub - tatsuyashi/angular-mock-sample

サンプルアプリケーションの説明

今回のサンプルですが、GET・POSTのボタンからそれぞれGET・POSTのAPIを呼び出し、結果をJSON形式で画面に表示するシンプルなものになります。

f:id:tatsuyashi:20190127013958p:plain:w500

dev serverにモックを公開する

まずはdev server上にモックを公開する手順を説明します。

①モックファイルを作成する

最初にモックとなるファイルを作成して配置します。

APIのメソッドとURLに対応したパスにJSONファイルを作成します。

メソッド URL JSONファイルパス
GET api/guitars src/mock/GET/api/guitars.json
POST api/guitars src/mock/POST/api/guitars.json
src/mock/GET/api/guitars.json

[
  {"maker": "Gibson", "name": "Les Paul"},
  {"maker": "Fender", "name": "Stratocaster"},
  {"maker": "Fender", "name": "Telecaster"}
]
src/mock/POST/api/guitars.json

{"maker": "Gretsch", "name": "Silver Falcon"}

②angular.jsonで公開設定

angular.jsonに下記を追加します。

angular.json

      "architect": {
        "build": {
            (略)
            "assets": [
              "src/favicon.ico",
              "src/assets",
              "src/mock"  ←追加
            ]

これでdev serverで/mockも公開されました。

次にproductionのときに/mockを公開しないように設定します。

angular.json

          "configurations": {
            "production": {
              "assets": [  ←追加
                "src/favicon.ico",  ←追加
                "src/assets" ←追加 (src/mockは書かない)
              ],  ←追加
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              (略)

productionの設定内でassetsを上書き、その際にsrc/mockを含めないようにします。

以上でモックファイルの公開とproductionのときに含めない設定が完了しました。

HTTPリクエストの向き先をモックに変える

モックファイルの公開はできたので、次はAPIのHTTPリクエストをモックに向けるような仕組みを入れていきます。

①環境設定ファイルに項目追加

environment.tsにモックを使用するかどうかの値を保持します。

src/environment/environment.ts (environment.prod.tsも同じ)

export const environment = {
  production: false,
  mock: true  ← environment.prod.tsはfalse
};

②モックに向けるHttpInterceptorの実装

モック使用環境において、APIのリクエストをモックに変える部分はAngularのHttpInterceptorの仕組みを使用します。

Angular 日本語ドキュメンテーション

今回は以下のようにモック用のHttpInterceptorを用意します。

src/app/http-interceptors/mock-http-interceptor.ts

@Injectable()
export class MockHttpInterceptor implements HttpInterceptor {

  intercept(req: HttpRequest<any>, next: HttpHandler):
    Observable<HttpEvent<any>> {
    
    if (environment.production || !environment.mock) {
      return next.handle(req);
    }

    const mockRequest = this.makeMockRequest(req.method, req.url);
    const newReq = req.clone({ ...mockRequest });
    return next.handle(newReq);
  }

  /**
   * make mock method and url.
   * @param method http method
   * @param url request url
   */
  private makeMockRequest(method: string, url: string): { method: string, url: string} {
    // method
    const mockMethod = 'GET';
    // change url
    const mockUrl = `mock/${method}/${url}.json`;

    return {method: mockMethod, url: mockUrl};
  } 


}

解説

makeMockRequestメソッドでモック用のHTTPメソッドとURLのセットを作成しています。

private makeMockRequest(method: string, url: string): { method: string, url: string} {
    // method
    const mockMethod = 'GET';
    // change url
    const mockUrl = `mock/${method}/${url}.json`;

    return {method: mockMethod, url: mockUrl};
  } 

※HTTPメソッドがGET固定になっていますが、これは現在の課題となっていて、GET以外の場合はURLが合っていても404(Not Found)になってしまうため、どんなHTTPメソッドであってもGETに変換するようにしています。

作成したモックのリクエストを返すことで向き先がモックに変わります。

  intercept(req: HttpRequest<any>, next: HttpHandler):
   (略)

    const mockRequest = this.makeMockRequest(req.method, req.url);
    const newReq = req.clone({ ...mockRequest });
    return next.handle(newReq);
  }

production環境の場合や、モックを使用しない設定になっている場合はそのまま返します。

  intercept(req: HttpRequest<any>, next: HttpHandler):
    Observable<HttpEvent<any>> {
    
    if (environment.production || !environment.mock) {
      return next.handle(req);
    }
    (略)

③モック用のHttpInterceptorを有効にする-1

作成したHttpInterceptorを有効にするために、まずHttpInterceptorProvidersを作成します。

src/app/http-interceptors/index.ts

const devHttpInterceptorProviders = environment.production ? [] :  [
  { provide: HTTP_INTERCEPTORS, useClass: MockHttpInterceptor, multi: true },
];

export const httpInterceptorProviders = [
  ...devHttpInterceptorProviders,
  { provide: HTTP_INTERCEPTORS, useClass: XxxInterceptor, multi: true },
];

解説

devHttpInterceptorProvidersという開発環境のみ発動するHttpInterceptorProviderをまとめます。
productionモード時は空配列が返ります。
これを行うことでng build --prodでビルドした際にMockHttpInterceptorがbundleされなくなります。

const devHttpInterceptorProviders = environment.production ? [] :  [
  { provide: HTTP_INTERCEPTORS, useClass: MockHttpInterceptor, multi: true },
];

devHttpInterceptorProvidersとどの環境でも発動するHttpInterceptorProviderをまとめてexportします。
(XxxInterceptorは特に中身はありませんが、何かしらのInterceptorを定義した場合を想定しています)

export const httpInterceptorProviders = [
  ...devHttpInterceptorProviders,
  { provide: HTTP_INTERCEPTORS, useClass: XxxInterceptor, multi: true },
];

③モック用のHttpInterceptorを有効にする-2

exportしたHttpInterceptorProvidersをModuleでproviderとして設定します。

src/app/app.module.ts

  providers: [
    httpInterceptorProviders,
  ],

以上でdev serverを使ったモックの完成となります。

まとめと課題

この仕組みで冒頭に述べたやりたかった事が全て実現できるようになりました。

  • 他のライブラリに依存しない
    →追加ライブラリなし
  • 実際にHTTP通信を発生させる
    →dev server(port 4200)にアクセスする
  • モック→実APIへの切り替えは設定ファイル以外触らない
    →environment.tsの変更のみ。serviceクラスも変更不要
  • production環境には一切乗らない(bundleさせない)
    →モックファイルおよびモックのためのHttpInterceptorクラスはproductionビルド時にはbundleされない

ただ、いくつか課題は残っています。

  • POST、PUTなどのGET以外のAPIはHTTPメソッドを無理矢理GETに変えている
    →POST、PUT、DELETEはそのままリクエストすると404になるので苦肉の策でGETに変えてリクエストしています。
    dev serverの設定を変えればできるのかもしれませんが、方法がわからないため課題となっています。

  • JSON以外のファイル形式に対応していない
    →9割以上のAPIJSONを返すと思うためJSONしか対応していませんでしたが、その他のファイル形式には対応していません。

特に1つ目の課題はトライしましたが全くうまくいかなかったのでわかる方がいれば・・・

最後に、
Angularの開発を行う際にそのプロジェクトに応じた共通基盤を作成すると思いますが、その1つしてモックは出てくると思いますので、 今回紹介した方法がお役に立てれば幸いです。

AWSのサービス名がAWS始まりとAmazon始まりの謎【解決】

だいぶ前にAWSのサービス名についてツイートした以下の件ですが、ようやく納得のいく解を得ました。

AWSのサービス名は、AWS○○とAmazon○○に大別できるのですが、どういう違いがあるかわかりませんでした。

本当に凄く気になって、新しいサービスを見る度に考えていました。

そこで、「さすがに世界のどこかには同じ疑問を持っている人がいるはず」と思い英語でググったところ、有力な情報を発見!!

stackoverflow.com

安定のstack overflowですね。

この質問者さんも私と同じ疑問を抱いています。

回答者さんは、類似質問から回答を引っ張ってきています。

f:id:tatsuyashi:20190121233155p:plain:w500

The pattern is that utility services are prefixed with AWS, while standalone services are prefixed by "Amazon". Services prefixed with AWS typically use other services......

なるほど。
雰囲気的には、

  • それ単体でサービスとして成立するものはAmazon○○
  • 他のサービスを使用するものはAWS○○

って感じですかね。

幾つかのサービスで確認してみます。

  • Amazon EC2 → 単体で仮想サーバーとして成立
  • Amazon ECS → 単体でDockerコンテナサービスとして成立
  • Amazon RDS → 単体でRDMSサービスとして成立
  • AWS Lambda → 他のAWSサービスをトリガーとする
  • AWS CodePipeline → CodeCommit/Build/Deployを組み合わせる
  • AWS CloudFormation → テンプレートで複数のAWSリソースをプロビジョニング

どうでしょう?なんとなくそれっぽくないですか?

まぁ広い意味でいうと、どれも他のサービスを使うのですが、それだけでも成立するかどうかっていうのがミソですかね。

  • 「1人でもやっていけるぜ!」っていう勇者がAmazon
  • 「他のサービスがないと生きていけない!」っていう依存体質がAWS

と私は覚えたので、今後新しいサービスが出てきてもプレフィックスが予想できそうな気がしますね!

GraphQLを5分だけプレゼンできるレベルで学ぶ

f:id:tatsuyashi:20190114232103p:plain:w300

GraphQL

最近ちらほら耳にするようになりました。

少しでも学んだことがある人は、

  • RESTの代わりになる?
  • Facebookが開発している

ぐらいは知っているかもしれません。

とはいえ、特にRESTで困ってないし、まだそこまで主流になっているわけでもないし、あまり深掘りしていない人が実際多いのかなと思います。

そこで今回はそういう人のために、一応名前は聞いたことがあるGraphQLというものについて、5分ぐらいは人に話せるレベルで浅ーーく説明します。

GraphQLって?

GraphQLはFacebook社が開発したAPI向けのクエリ言語です。

RESTとよく比較されますが、厳密にはRESTとは異なる存在です。
RESTはAPI 設計 のことを指しますが、GraphQLは1つの 言語 です。

比較されているのは、「GraphQLを用いたWebAPI」と「RESTful API」ですね。

クエリ言語?

クエリ言語って言われてもピンと来ない人がいるかもしれません。

私が似たようなものでイメージしたのは同じクエリ言語であるSQLです。

SQLがわからない人は、、、スミマセン)

例として、ユーザー情報をデータベースからSQLで取得する場合と、GraphQLを使ってAPIで取得する場合で比較します。

SELECT USER_ID, USER_NAME FROM USERS;

USER_ID USER_NAME
1 孫悟空
2 ベジータ

クエリを発行すると、欲しい結果がデータベースから返ってきます。

  • GraphQL
query {
  users {
    userId
    userName
  }
}

{
  "data": {
    "users" : [
      { "userId": "1", "userName": "孫悟空" },
      { "userId": "2", "userName": "ベジータ" }
    ]
  }
}

こちらもクエリを発行すると、欲しい結果がAPIのレスポンスとしてJSONで返ってきます。

どちらもクエリを発行して結果を得るのは同じですね。

GraphQLが生まれた背景

Facebook社がGraphQLを開発した背景にはFacebookならではの事情があります。

Facebookといえば全世界で利用されているSNSですね。

当然日本やアメリカのような国だけではなくて、全世界、それこそ通信状況の良くない国・地域からもアクセスされます。

通信状況が良くない場所からのアクセスを考えたときに、以下のような問題を解決する必要がありました。

  • 不必要な項目のリクエス
  • 様々なAPIを呼ぶことによる通信オーバーヘッド

これらの問題を解決するためにGraphQLが生まれました。

GraphQLの特徴

新しいものを学ぶときはその特徴を箇条書きで答えられるようになると、説明をしやすいですよね。

GraphQLの特徴としては、

  1. スキーマでの型指定とAPI定義

  2. 利用者が欲しい項目を選択可能

  3. 1度のリクエストで複数リソースを取得可能

の3点が挙げられます。

スキーマでの型指定とAPI定義

GraphQLではスキーマ上で型とAPIの定義を行います。

例として、ユーザーの一覧を返すAPIを考えます。

まず、ユーザを定義します。

type User {
  userId: ID!
  userName: String!
  age: Int!
  sex: String!
}

次に、APIを定義します。

type User {
  userId: ID!
  userName: String!
  age: Int!
  sex: String!
}

↓↓
type Query {
  getUsers: [User]
}

上記は「getUsersというAPIがUser型の配列を返す」ということを示します。

(type Queryについては後述します)

ここに、ユーザーIDを指定するとそのユーザ情報を返すAPIを追加してみます。

type User {
  userId: ID!
  userName: String!
  age: Int!
  sex: String!
}

type Query {
  getUsers: [User]
  getUser(userId: ID!): User   ←←
}

GraphQLではこのようにスキーマで型とAPIを定義します。

型指定しているので、getUsersとgetUser(userId: ID!)で返ってくるユーザー情報は同じ型であることが保証されます。

また、スキーマそのものがAPIのインターフェース仕様書にもなります。

利用者が欲しい項目を選択可能

GraphQLの大きな特徴として、「クエリ発行時に必要な項目を指定する」というものがあります。

先ほどのスキーマの内容でAPIが定義されているとします。

type User {
  userId: ID!
  userName: String!
  age: Int!
  sex: String!
}

type Query {
  getUsers: [User]
  getUser(userId: ID!): User
}

例えば、以下のようなデータ取得パターンがあるとします。

  • 全ユーザーの情報の一覧が欲しい
  • 全ユーザのIDの一覧が欲しい

GraphQLではどちらのケースもgetUsersのAPIで取得できます。

  • 全ユーザーの情報一覧
query {
  getUsers: {
    userId
    userName
    age
    sex
  }
}

{
  "data": {
    "getUsers": [
      { "userId": "1", "userName": "孫悟空", "age": "35", "sex": "MALE" },
      { "userId": "2", "userName": "ベジータ", "age": "38", "sex": "MALE" }
    ]
  }
}
  • 全ユーザーのID一覧
query {
  getUsers: {
    userId  ←userIdのみ指定する
  }
}

{
  "data": {
    "getUsers": [
      { "userId": "1" },  ←userIdのみ返ってくる
      { "userId": "2" }
    ]
  }
}

これにより、必要な項目に絞ってAPIを利用することができるようになります。

1度のリクエストで複数リソースを取得可能

例えば以下のようなユースケースがあるとします。 (例が無理矢理なのはご愛嬌)

指定したユーザーの情報と、全ユーザーの一覧を一画面で表示したい

先ほどの例にあったAPI(全ユーザー一覧取得APIと1ユーザー取得API)がGraphQLとRESTそれぞれで提供されていた場合で比較してみます。

RESTの場合

RESTの場合の選択肢は以下の2つが挙げられます。

  • 全ユーザー一覧APIと1ユーザー取得APIをそれぞれ呼び出す(2リクエスト)
  • 1ユーザー情報と全ユーザー一覧を取得するAPIを用意し、呼び出す(1リクエスト、API追加)

簡単に言うと、APIを2回呼ぶか、セットにした新規APIを作成するかの2択です。

GraphQLの場合

GraphQLの場合、以下のように1度のリクエストで複数のAPIを指定できます。

query {
  getUser(userId: "1") {  ←1ユーザー取得
    userId
    userName
    age
    sex
  }
  getUsers {  ←全ユーザー取得
    userId
    userName
  }
}

{
  "data": {
    "getUser": {
      "userId": "1",
      "userName": "孫悟空",
      "age": "35",
      "sex": "MALE"
    },
    "getUsers": [
      { "userId": "1", "userName": "孫悟空" },
      { "userId": "2", "userName": "ベジータ" }
    ]
  }
}

このように、GraphQLではAPIを組み合わせることで、利用者側の業務に合った情報を効率的に取得することができるようになります。

GraphQLのAPIの種類

GraphQLのAPIは以下の種類が存在します。

  • Query (データ取得)
  • Mutation (データ更新)
  • Subscription (変更検知)

これらはGraphQLスキーマでは予約語になっており、

type Query {
  getUsers: [User]
  getUser(userId: ID!)
}

type Mutation {
  createUser(userId: ID!, userName: String!, age: String!, sex: String!)
}

のようにそれぞれのAPIを定義します。

Subscriptionについて

Subscriptionは公式サイトでは言及されていません。(2019/1/14 現在)

GraphQL | A query language for your API

ただし、GraphQLのRFCではSubscriptionの仕組みについて言及されています。

graphql/Subscriptions.md at master · facebook/graphql · GitHub

概要としては、

  • 特定のMutationを監視する
  • 監視しているMutationが実行されると、実行した結果のオブジェクトが通知される

凄くざっくり図にすると以下のようなイメージになります。

f:id:tatsuyashi:20190115000612p:plain:w500

プログラミング言語のGraphQLのライブラリにおいては、Subscriptionの実装がなされているものが多いので既に利用できるようになっています。

RESTの代わりになりうる?

ここからは個人的な見解となりますが、

RESTの代わりはできるが、RESTを超えるほど広まらない と思っています。

何故かと言うと、逆にRESTがGraphQLの代わりをできる とも言えるからです。

GraphQLの特徴である、

はRESTでもできなくはないです。

  • スキーマによる型定義 → JSONスキーマを使う
  • 項目指定 → 項目を指定するパラメータをクエリに設定 (fieldsが一般的)
  • 1リクエストで複数API → 新規APIとして作成

もちろんGraphQLの方が便利ですし、上記のことが楽に行えるのは事実ですが、RESTでできることを多大な学習コストを払ってまでGraphQLでやるという選択をとることは少ないのかなと思います。(残念なことですが)

ただ、これからGraphQLをもっと簡単に導入できるような仕組みが増えていくと思いますし、GraphQL自体も進化して「GraphQLでしかできないこと」が出てくると形勢も変わってくるのかなと思います。
AWSのフルマネージドGraphQLサービスであるAWS AppSyncでは驚くほど簡単にGraphQLをセットアップできます)

GraphQLについて(まとめ)

今回はGraphQLの概要をメインで書きました。
「とりあえず新しいGraphQLというものを少し覚えたし、知らなそうな人にドヤするか!」ぐらいのことはできると思います。

スキーマの書き方などはもっと様々な手法がありますが、この記事以上に知りたい人はWebにたくさん情報がありますので是非調べてみてください。(人任せ)

無料枠で頑張るためにDynamoDBのキャパシティを理解する

f:id:tatsuyashi:20190108004928p:plain

Amazon DynamoDBはフルマネージドなNo SQLデータベースで、LambdaやAppSyncのデータソースとしてよく使用されています。

私も要件によってはDynamoDBを選択するケースがあるのですが、無料枠の詳細を確認せずテーブルを量産した結果、なんと$30を超える請求が来てしまいました・・

f:id:tatsuyashi:20190108005734p:plain:w150

そこで、今回は同じような失態を防いでもらうために注意すべきことについて説明します。

DynamoDBの無料枠の詳細

公式サイトに記載があります。

aws.amazon.com

DynamoDBの無料枠はというと、、

f:id:tatsuyashi:20190108010204p:plain

「ほぉほぉ。25GBのストレージか。まぁ超えることはないな。」

ここで完全に安心しきっていました。

ただ、この詳細を見てみると次のように書かれています。

f:id:tatsuyashi:20190108010434p:plain

  • 25ユニットの書き込みキャパシティ
  • 25ユニットの読み込みキャパシティ

「んー。よくわからん。」

そこで、一体DynamoDBのどこで無料枠を超過したのか見てみます。 f:id:tatsuyashi:20190108011048p:plain

なにやら、ReadCapacityUnit-HrsとWriteCapacityUnit-Hrsで超過しているのがわかりました。

ではこいつらは一体何者か見ていきましょう。

書き込みキャパシティ、読み込みキャパシティとは

DynamoDBにおけるスループットキャパシティの単位として、書き込みキャパシティユニット読み込みキャパシティユニットを指定します。

キャパシティユニットとは1秒あたりにN回の読み書きできる容量のことです。

1キャパシティユニットでできることは以下のようになっています。(一部簡略化しています)

読み書き 内容
読み込み (強力な整合性) 1秒に1回 (4KBまでは)
読み込み (結果整合性) 1秒に2回 (4KBまでは)
書き込み 1秒に1回 (1KBまでは)

※サイズの上限を超えると、より多くのキャパシティユニットが必要になります。

キャパシティユニットは1テーブルごとに設定するため、

例えば、5ユニットの書き込みキャパシティ/読み込みキャパシティをテーブルに設定すると、

  • 1秒に5KBまでの書き込み (1KB × 5回)
  • 1秒に20KBまでの強力な整合性読み込み (4KB × 5回)
  • 1秒に40KBまでの結果整合性読み込み (4KB × 10回)

というスループットを実現できることになります。

ですので、無料枠の詳細に記載されている

  • 25ユニットの書き込みキャパシティ
  • 25ユニットの読み込みキャパシティ

というのは、

各テーブルに設定した書き込みキャパシティ、読み込みキャパシティの合計がそれぞれ25を超えていないか

ということになります。

キャパシティユニットによる課金の詳細

課金の基準としては、 実際にどれだけのI/Oが発生したかではなく、どれだけのキャパシティを消費したかとなっています。

25ユニットの〜〜とは謳われていますが、25ユニット以上テーブルに設定したら即課金ではなく、

ユニット数 × 24時間 × 31日 (月日数) の値がいくらか

によって決まります。

これが先述したReadCapacityUnit-Hrs、WriteCapacityUnit-Hrsにあたります。

例えば2018年12月の場合、31日まであるので、課金の基準としては

  • 5(ユニット) × 24(時間) × 31(日) → 18,600 CapacityUnit-Hrs

となり、これを超過した分が課金の対象となります。

ちなみに、読み込みと書き込みキャパシティが異なり、

読み書き 課金 (1時間あたり)
読み込み $0.0001484
書き込み $0.000742

と書き込みキャパシティの方が5倍以上高くなっています。

ちなみに私の場合は、

37,735 CapacityUnit-Hrs超過したので、

  • 読み込み:0.0001484 × 37,735 ≒ $5.6
  • 書き込み:0.000742 × 37,735 ≒ $28.0

の課金となりました。

課金されないために考慮すべきこと

DynamoDBの課金としては、キャパシティによる課金の他にストレージ容量やデータ転送量などありますが、やはりキャパシティが一番ハマることが多いと思います。

キャパシティによる課金を抑えるポイントとしては

  • 使っていないテーブルは削除する
  • テーブルのアクセス頻度を考慮したキャパシティユニットの設定をする(デフォルトだと5で作成されている)

ということが言えます。

幸いにも、テーブルのキャパシティユニットの設定は稼働中でも変更可能ですので定期的に見直した方が良いと思います。

仮に今の時点で25ユニットを超えてしまっていても、何時間稼働したかで変わってくるので早めに対処すればするほど課金のリスクは減ります。

最適な設定で高いコストパフォーマンスを

今回の記事では無料枠で収めることを目的に記載しましたが、キャパシティユニットを下げればスループットが落ちるのでパフォーマンスは下がります。

なので最適なキャパシティユニットの設定を行うことが大前提であり、その上で無駄にキャパシティユニットを多く消費することを防ぐことが、高いコストパフォーマンスに繋がると思います。

最適な設定をした上で課金になるのは仕方ありませんし、正しい姿です。

【補足】

DynamoDBの料金体系は

  • プロビジョニング済みキャパシティモード
  • オンデマンドキャパシティモード (2018年12月頃より開始)

の2つがあり、今回の記事ではプロビジョニング済みキャパシティモードについてのお話でした。

(オンデマンドキャパシティモードは無料枠対象外のようなので)

プロビジョニングの方はあらかじめ決まったキャパシティユニットのリソースを確保しますが、オンデマンドの方はキャパシティユニットの設定は必要なく、読み書きのリクエストの応じた従量課金となります。

ケースバイケースでどちらを適用するのかという点も料金・パフォーマンスの最適化を行う上で重要な内容ですので、是非ご検討いただければと思います。

その他

AWSの請求をいち早くキャッチするための設定はこちらの記事をご確認ください↓↓
AWS管理者が最初にやるべき請求アラームの設定 - Tatsuyashi's Blog

AWS管理者が最初にやるべき請求アラームの設定

f:id:tatsuyashi:20190106022257p:plain:w300

AWSに登録すると1年間の無料枠が使用できますが、この無料枠の詳細を正しく押さえていないと痛い目に遭います。

請求が確定してからでは後の祭りなので、この記事では早い段階で請求を察知するためのアラームの設定について説明します。

AWSの管理者は必ず行ってください!!

AWS無料枠の詳細

AWSの無料枠については公式サイトを参考にしてください。

aws.amazon.com

超ざっくり代表的なサービスについてまとめると

サービス 無料枠詳細
EC2 t2.micro 750時間
S3 5GBのストレージ、20,000件のGET、2,000件のPUT
RDS t2.micro 750時間、20GBのストレージ
Lambda 100万件のリクエスト、320万秒のコンピューティング時間

他にも多くのサービスで無料枠が設定されています。

AWSの請求について

無料枠について記載しましたが、

はっきり言って全部覚えられません!

いや、覚えろよ!って言われそうですが、新しいものとかマイナーなものもありますし、

なにより監視するのが大変です。

「S3のストレージが4.5GBまできているからやばいな・・」
「RDSに大量にデータ入れたから容量があと2GBしかない・・」

とかいちいち見てられないですよね。

しかも、今回説明する請求アラームの設定をせず、更にコンソール上でもチェックしていないとすると、

次に気付けるタイミングはAWSからの請求メールです。

f:id:tatsuyashi:20190105022811p:plain:w400

これはもう確定した後なのでもっと早く気付けるようになる必要があります。

AWSでは請求情報に関するアラームを設定することで通知を行う仕組みが用意されているので、次章より設定していきます。

ユーザに請求情報へアクセスできるようにする

請求情報のアクセス権

請求やコストの情報については、通常の管理者権限(AdministratorAccessなどのフル権限)では見ることができません。

これらについては以下の2種類のユーザが見ることができます。(厳密にはもう少し種類が分かれます)

  1. アカウント所有者
  2. 請求へのアクセス許可がされたIAMユーザ

「ほな、1で見りゃええやん!」

そう言っちゃう人はもう1度IAMのベストプラクティスを読み直しましょう。

docs.aws.amazon.com

1のユーザは使わないのが基本です。
たとえ1人でやっていたとしてもそこはきちんとIAMユーザを作成するべきです。

なので、請求関連の操作はIAMユーザにアクセス許可をしてから行いましょう。

アクセス権の付与

アクセス権の付与はアカウント所有者で行います。

IAMユーザ/ロールへのアクセス許可 の許可

アカウント所有者でログインし、右上のユーザ名を押下して開いたメニューの「アカウント」を押下します。

f:id:tatsuyashi:20190106014240p:plain:w500

中段ぐらいにある「IAM ユーザー/ロールによる請求情報へのアクセス」を展開し、「編集」リンクを押下します。

f:id:tatsuyashi:20190106014651p:plain:w500

「IAMアクセスの有効化」にチェックを入れ「更新」ボタンを押下します。

f:id:tatsuyashi:20190106015042p:plain:w500

これでIAMユーザやロールへ請求情報へのアクセス許可ができるようになりました。

この内容については公式サイトにも記載されています。

docs.aws.amazon.com

IAMユーザへのアクセス許可

続いて、実際に請求情報へのアクセスを許可するユーザに対して権限を付与していきます。

IAMコンソールを開き、対象のユーザを選択します。(IAMコンソールはわかる前提で手順を一部端折っています。)

「アクセス権限の追加」を押下します。

f:id:tatsuyashi:20190106015628p:plain:w500

「既存のポリシーを直接アタッチ」を選択し、ポリシーの一覧から「Billing」を選択します。

f:id:tatsuyashi:20190106015921p:plain:w500

選択したポリシーをアタッチしたら「Billing」ポリシーが適用され、該当ユーザで請求情報へアクセスできるようになります。

f:id:tatsuyashi:20190106020155p:plain:w500

【注意点】
請求情報はお金に関わる情報のため、アクセス許可を行うユーザの選定は慎重に行ってください。 AWSが管理者権限と請求情報の権限を分けている意味を考えると、その重要性はわかると思います。

AWSの請求アラームの設定

①請求ダッシュボードへ遷移

まずはIAMユーザでAWSコンソールへログインし、右上のユーザ名を押下して開いたメニューの「請求ダッシュボード」がアクティブになっているので押下します。

f:id:tatsuyashi:20190106003352p:plain:w500

以下のように請求ダッシュボード画面へ遷移します。

f:id:tatsuyashi:20190106003616p:plain:w500

②アラーム通知の設定

左のメニューから「設定」を押下し、設定画面を表示します。

表示後

  • 無料利用枠の使用のアラートの受信
  • 請求アラートを受け取る

の2つをチェックして、設定を保存します。

f:id:tatsuyashi:20190106004557p:plain:w500

③請求アラームの設定

通知の設定は終わったので、請求アラームの設定を行います。

まずはCloud Watchコンソールを表示します。

【注意点】
AWSの請求データは米国東部 (バージニア北部) リージョンに保存されているため、請求アラームの設定時はリージョンを「バージニア北部」へ変更してください。
(それ以外のリージョンだとアラートが表示され、バージニア北部へ自動で切り替わります)

左のメニューから「請求」をクリックして請求アラームの設定画面を表示します。

f:id:tatsuyashi:20190106005920p:plain:w500

「アラームの作成」ボタンを押下してアラーム作成画面を表示します。

通知する基準となる金額と通知先を入力して、アラームを保存します。

f:id:tatsuyashi:20190106010928p:plain:w500

アラームの作成をするとメールアドレスの確認待ちダイアログが表示されます。

f:id:tatsuyashi:20190106011327p:plain:w500

メールに記載されているリンクをクリックすると、ダイアログの表示が切り替わるので「アラームの表示」を押下します。

f:id:tatsuyashi:20190106011621p:plain:w500

画面を更新すると作成したアラームが表示されます。

f:id:tatsuyashi:20190106011758p:plain:w500

AWSの請求アラームの設定について(まとめ)

以上で設定は完了です。

もちろんもっと細かな設定をしたりSlackに通知したりできますが、最低限の設定としては今回の内容が必須となりますね。

無料枠だからどうこうというわけではなく、システムオーナからするとシステムにかかる費用は非常にシビアになるところですので、「どのサービスにいくらかかっているか」は常に意識して効率の良いクラウドライフを送ってもらうきっかけになればと思います。

エニタイムフィットネスを退会しました(筋トレは辞めない)

f:id:tatsuyashi:20181126233042p:plain

表題の通りです。

エニタイムフィットネスを退会しました!

とは言っても別にジムが気に入らなくて辞めたわけではありません。

引越し先にエニタイムがなかったのです・・

まぁ色々な事情で退会したい方がいると思いますが、実際やってみて驚くほど簡単だったのでちゃちゃっと紹介します。

退会期限

公式サイトによると、

よくあるご質問|エニタイムフィットネス

f:id:tatsuyashi:20181126233635p:plain

ポイントとしては、

  • 当月末での解約は10日まで(10日がノースタッフデーなら前営業日まで)
  • 10日を超えて解約すると翌月末の解約

とあるので、その月に解約したい方は10日までに手続きが必要です。

退会方法

あくまでも私が通っていた店舗での話になりますが、

【退会場所】 店舗

【必要なもの】 なし

でしたw

何も調べず手ぶらでとりあえず店舗へ行ってみたらそのまま手続きできました。 ※もちろん入店にはセキュリティーキーが必要です。

店舗でやることとしては、

  • スタッフに解約したい旨を伝える
  • 解約書類を渡されるので記入する(とはいえ、名前だけだったような・・・)
  • 書類をスタッフに渡し5分程待つ
  • 手続きOKをもらったら帰宅して良し。もちろんそのままトレーニングしても良し。

以上、所要時間7分ぐらいです。

退会後、セキュリティーキーは特に返さなくて良いそうでした。 そのまま破棄してくださいとのこと。
※ここらへんは店舗により差があるかもしれないので確認してくださいね

どうですか?
すごく簡単ですよね。

エニタイムフィットネスって海外発のサービスなので、退会とか難しくなってるのかなーと思いきや拍子抜けするほど簡単でした。

まぁ永久に退会するとも限らないのでまたご縁があれば利用させていただきたいと思います。

ちなみに、引っ越しの影響でストップしましたが、筋トレは辞めません!

また新たな形で筋トレログを再開しますので少々お待ちくださいませ。

筋トレログ その14

更新が遅れました。水曜日のトレーニングメニューです。胸がメインです。

レッグプレス (太もも前、臀部)

セット 重量(kg) 回数
1 105 15
2 125 15
3 145 10

チェストプレス (胸)

セット 重量(kg) 回数
1 20 15
2 30 15
3 60 10

初めて60kgに成功!

バタフライマシン(のようなもの) (胸-内側)

セット 重量(kg) 回数
1 20 15
2 30 15
3 45 10

ショルダープレス (三角筋前部)

セット 重量(kg) 回数
1 10 15
2 15 15
3 30 10

チェストプレス (胸)

セット 重量(kg) 回数
1 20 20
2 20 20
3 20 20

バタフライマシン(のようなもの) (胸-内側)

セット 重量(kg) 回数
1 20 20
2 20 20
3 20 20

ショルダープレス (三角筋前部)

セット 重量(kg) 回数
1 10 20
2 10 20
3 10 20

有酸素運動 (リカンベントバイク)

30分