27円/月で運用できるAWS Lambda を用いたウェブサイトの外形監視

ウェブサイトの外形監視とは?

 ウェブサイトがユーザーからきちんと閲覧できるかどうかを監視するという至極単純なものが「ウェブサイトの外形監視」です。外形というワードが入っているとおり、ユーザー側から名前解決を正常に行うことができ、宛先にきちんとリクエストを行え、妥当な時間内に正常なレスポンスを受け取ることができるかをチェックすることが目的になると思います。

 したがって、構築されたサーバーとはネットワーク的にも物理的にも独立した場所から監視を行えると良いのですが、そうすると外形監視サーバーのお守りをしなければならず、個人でちゃんとやろうとすると微妙に面倒ではあります。

AWS Lambda を用いたウェブサイトの外形監視

 AWS Lambda は、オンデマンドでコードの断片を実行することができるアプリケーション基盤です。あらかじめサーバーを立てて置かなくても、実行したいコードを配置しておき、実行したいときにサーバーのことなど何も考えずに呼び出すことができます。ウェブサイトの外形監視は、せいぜいリクエストを送ってステータスコードやレスポンスタイムなどを見てあげるだけの簡単な処理であるため、相性がよさそうです。

 サービスを AWS 以外のクラウドや、オンプレミスで運用している場合には物理・ネットワーク的に異なる条件から対象を監視することができます。また、AWS Lambda は複数のリージョンにデプロイすることが可能なため、AWSを利用している場合でも、世界中の様々なリージョンを利用することにより、地理的に異なる場所から対象を監視することが可能です。

 AWS には Route 53 にすでにヘルスチェッカーが存在しているのですが、色々なオプションをちまちまつけていくと少しずつお金を取られていくので(といっても大した額ではないんですが…)、 #okane_nai 勢の私は AWS Lambda の無料利用枠で同じようなことが実現できるのではないかと思い、今回試してみることにしました。

システムの全体像

 AWS Lambda の実行トリガーはイベントソースと呼ばれています。外形監視のイベントソースとしては定期的に実行できる cron のような振る舞いを実現できればよさそうです。AWS CloudWatch Events がちょうどそのようなものに該当しており、cron 式や rate 式によって以下のように簡単にイベント発行のスケジューリングが可能です。

lambda_health_check_01.png

 単純な外形監視の通知先として Slack への通知を考えるとするならば、最小構成としての AWS Lambda と AWS CloudWatch Events を用いた仕組みの全体像と稼働のイメージは以下のような図になります。

lambda_health_check_02.png

 AWS Lambda で動くコードは、自由にカスタマイズできる普通のコードですので、たとえば Twillio API と連携して異常検知時に電話を鳴らしたり、レスポンスに特定の文字列が含まれているかチェックしたりなど様々なことができます。また、Amazon SNS を利用して様々な通知連携を行ったり、DynamoDB などを用いて監視データを蓄積したりすることも可能です。個人でお遊び監視を入れるには監視サーバーをお守りする必要もなく、楽しいおもちゃになるのではないでしょうか。

AWS Lambda を用いた外形監視のコスト見積もり

2018年1月現在、AWS Lambda には以下のような無料枠が設けられています。

  • リクエスト: 月間 1,000,000 件
  • コンピューティング時間: 月間 400,000 GB-秒

したがって、リクエスト数とコンピューティング時間の2つの軸でコストを見積もる必要があります。

また AWS CloudWatch Events については単純に発行するイベント数に応じて課金がなされます。

AWS Lambda リクエスト数の見積もり

 毎分ヘルスチェックをまわすとすれば、 1 (req) * 60 (min) * 24 (hour) * 31 (day) = 44,640 (reqest) となり、無料利用枠の中に余裕を持っておさまります。もし他の用途で無料利用枠を使い切っているとすれば、課金額は 44,640 (request) * 0.0000002 (USD/request) = 0.008928 (USD) となります。

AWS Lambda コンピューティング時間の見積もり

 node.js で動く HTTP リクエストを送る単純なプログラムであるため割り当てメモリは一番小さな 128MB (= 1/8 GB) で十分です。手元で稼働させている実績からほぼ 1000ms 以内にヘルスチェックが完了しているのですが、バッファをとって平均 2000ms かかると仮定して計算するならば、 1/8 (GB) * 2 (sec) * 60 (min) * 24 (hour) * 31 (day) = 11,160 (GB-sec) となり、無料利用枠におさまります。もし他の用途で無料利用枠を使い切っているとすれば、課金額は 11,160 (GB-sec) * 0.00001667 (USD) = 0.1935387 (USD) となります。

AWS CloudWatch Events の見積もり

 AWS CloudWatch Events は $1.00/100万イベントという料金になっているため、単純に 1 (event) * 60 (min) * 24 (hour) * 31 (day) = 44,640 (event) / 1000000 (event/USD) = 0.04464 (USD) のお金が必要です。

総費用の見積もり

 無料利用枠を使っていないのであれば、AWS Lambda の費用はすべて枠内におさまっており、無料で稼働中のサーバーとは地理的に異なる場所に配置できる外形監視を導入することができます。また仮に無料利用枠を使い切っているとしても、0.008928 + 0.1925387 + 0.04464 = 0.24610677 (USD) の課金が発生します。多分 27 円くらい取られます。 お財布には厳しいですが、気合いです。

外形監視のための AWS Lambda 関数の作成

 作るものは非常に単純で、node.js で HTTP リクエストをサーバーに送り、ステータスコードが 200 番台だったらオッケーで、その他の場合は Slack の incomming webhook を利用してメンションを飛ばすだけです。Slack の設定次第では、スマホにプッシュ通知とか飛ばせるので、面倒なこと考えずに手軽に検知手段が欲しいときにこの方法はコスパが良いのではないでしょうか。

 コードなどどうでもいいので、いますぐ試してみたいという方のために、簡単にデプロイできるような形にしておきましたので、こちらの GitHub リポジトリ1 からクローンしてみてください。数ステップで AWS Lambda 上にデプロイしてお試しいただけます。

基本的なコード

 暇人の趣味なので FlowType を使ってます。request を使ってリクエストを送って、ステータスコード見てるだけなので、基本的には以下のような簡単なコードを書いてアレコレしていくだけです。

// @flow

import request from 'request-promise-native';

async getStatus(): Promise<Object> {
   const options = {
     method: 'GET',
     uri: 'https://exapmle.com',
     timeout: 3000,
     headers: {
       'User-Agent': 'Mozilla/5.0 (Oreore Health Checker;)'
     },
     resolveWithFullResponse: true
   };
   try {
     const { statusCode, statusMessage } = await request(options);
     return { statusCode, statusMessage };
   } catch (err) {
     console.log(JSON.stringify(err));
     if (err.response) {
       const statusCode = err.response.statusCode;
       const statusMessage = err.response.statusMessage;
       return { statusCode, statusMessage };
     } else {
       const statusCode = null;
       const statusMessage = err.message;
       return { statusCode, statusMessage };
     }
   }
 }

 ラムダ関数 1つで複数サイトの監視をさせるために、設定ファイルに書いた URL リストを舐めて、それぞれに対して上記のような関数を呼び出し、サービスの状態を並列に確認させています。このような仕組みで、現状手元で 10 エンドポイントくらいを監視させていますが、関数の実行時間はそれほどかわらず、結果としてはレスポンスが一番遅いエンドポイントに引きずられているような挙動に見えます。

Apex を使った AWS Lambda 関数の管理

 AWS Lambda 関数のデプロイをマネジメントコンソールからやるのは面倒なので、Serverless とか Apex などを使うと良いと思います。今回は簡単なものだったので、Apex を利用しました。適切な設定をすると次のようなワンコマンドで、AWS Lambda にデプロイすることができます。

apex deploy

ためしにデプロイした関数を実行したいときも次のようにとてもお手軽です。

apex invoke (関数名)

成果物を俺にも使わせろ

 どうぞどうぞ。こちらの GitHub リポジトリからクローンしてください。使うまでには次のような作業をしてください。

  1. 必要なもの(aws-cli, apex)をインストール
  2. git clone git@github.com:53ningen/sousie.git && cd sousie
  3. マネジメントコンソールからラムダ関数が使う IAM ロールを作る
    • 詳しくはこのあたりの資料を見てください
    • AWS CloudWatch ログ書き込み権限をアタッチする
  4. cp ./project.json.template ./project.json して role の欄に作った IAM Role の ARN を書く
  5. cp ./config.json.template ./config.json して ヘルスチェックしたいエンドポイントや Slack の設定などを行う
  6. apex deploy
  7. AWS CloudWatch Events をマネジメントコンソールから設定して、デプロイした AWS Lambda 関数が定期実行されるようにする

 今後は CLI ベースのセットアップ用ツールの作成、Amazon SNS トピックへの通知や、DynamoDB との連携によるリッチな通知閾値設定、CloudWatch カスタムメトリクスとの連携機能などを実装するつもりです。飽きなければ…。あと基本的に JavaScript 素人なのでおかしなところあったら修正 pull request いただけると嬉しみ〜という感じです。

まとめと展望

  • AWS Lambda を使うと非常に安価に外形監視を行うことができます
  • 個人運用のサービスなどではこのレベルでも十分に役に立つ監視基盤となりうるのではと思います
  • ただの簡単な JavaScript コードであるため複雑なカスタマイズも自由にできます
    • Twillio などを使えば電話も鳴らせます
    • カスタマイズすれば、状況によってなんらかのオペレーションをするみたいな自動復旧の仕組みとかも仕込めそう
  • Amazon CloudWatch カスタムメトリクスや Amazon SNS, AWS Step Functions などと連携すればかなり複雑なこともできるのではないかと思います
  • AWS の無料利用枠を使って快適な人生を送ろう

 あとここまで書いておいてアレなんですが、自分の個人サービスの一部、Route 53 の DNS フェイルオーバー設定入れているので、結局 Route 53 のヘルスチェック使ってます。

Special Thanks

 わたしは JavaScript 素人なので、このまわりのよくわからないことに関しては @nagisio 大先生にご指導いただきました。本当にありがとうございます。


  1. リポジトリの名前は「異世界はスマートフォンとともに。」のキャラクターである、スゥシィ・エルネア・オルトリンデ(CV: 山下七海)様の名前をお借りしました 

続きを読む

最適な製品の選び方チームコラボツール10製品を徹底比較 Slack、Microsoft Teamsを超えるのは? (1/2)

… ツールを紹介する。なお、本稿で取り上げるツールは、Amazon Web Services(AWS)の「Amazon Chime」、Atlassianの「Atlassian Stride」、BroadSoftの「BroadSoft Team-One」、CA Technologiesの「CA Flowdock」、Cisco Systems(Cisco)の「Cisco Spark」、Googleの「Googleハングアウト」、Microsoftの「Microsoft … 続きを読む

AWS Lambda + API Gateway で Slack Bot を動かす

無味乾燥とした Web アプリケーションよりも、SlackBot のほうが使っていて愛着が湧くし、いちいち Web ブラウザを開かなくても良いので、楽だと思うことがあります。 そこで、Slack Bot を簡単に作成でき、安全に動かすことができる構成を考えました。 運用をできるだけ楽にしたいので、AWS Lambda + API Gateway を用いた … 続きを読む

環境構築201801 slackbot

はじめに

環境構築時のメモです。
* Amazon Linux AMI release 2017.09
* nvm 0.33.8 (201712)
* node v9.3.0 (201712) 
* redis v2.4.10(201712)
* hubot-slack v4.4 (201712)
* nginx v1.10.3 (201708)
* pyton v3.6.0 (201712)

初期設定

command
$ cat /etc/system-release1
$ sudo yum update -y
$ sudo yum install -y git

タイムゾーンをJSTに変更する。

command
$ sudo ln -sf  /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
$ sudo vi /etc/sysconfig/clock
---
ZONE="Asiz/Tokyo"
UTC=false
---

OSユーザ(例:hoge)作成

command
$ useradd hoge
$ sudo su - hoge
$ cd /home/hoge
$ mkdir .ssh
$ cd .ssh
$ ssh-keygen -t rsa
$ mv id_rsa.pub authorized_keys
$ chmod 600 authorized_keys
$ cat id_rsa ※内容を接続元PCに保存 hoge.pem
※puttyの場合
・Run PuTTYgenを起動
・Load an existing private file を読み込む(load)
・Save public key hoge.ppk
・上記ファイルを"Private key file for authentication"に設定する。
・wheelユーザに追加およびパスワードなしでsudoを利用できるようにする。
$ vi /etc/group
----
wheel:x:10:ec2-user,hoge
----
$ sudo visudo
---
# %wheel        ALL=(ALL)       NOPASSWD: ALL
%hoge      ALL=(ALL)       NOPASSWD: ALL
---

Nginxインストール

$ sudo useradd www
$ sudo groupadd www
$ sudo yum install nginx
$ sudo cp /etc/nginx/nginx.conf.default /etc/nginx/nginx.conf
$ sudo vi /etc/nginx/nginx.conf
---
server{
   listen    80;
   server_name localhost;
   root ***設置場所***;
   charset utf-8;
   index index.html index.htm index.php;
   access_log /var/log/host.access.log main;
}
---
$ sudo service nginx start
$ sudo chkconfig nginx on

redisインストール

$ sudo yum --enablerepo=epel install redis
$ sudo service redis start
$ sudo chkconfig --level 35 redis on
$ sudo chkconfig --list | grep redis

nodeインストール

$ git clone git://github.com/creationix/nvm.git ~/.nvm
$ vi .bashrc
---
if [ -f ~/.nvm/nvm.sh ];then
        source ~/.nvm/nvm.sh > /dev/null 2>&1
fi
---
$ source ~/.bashrc
$ nvm ls-remote nodeバージョン一覧表示
$ nvm install v6.9.0
$ nvm alias default v6.9.0  #恒久的な切り替え
$ nvm ls-remote
$ node -v
nvm自身のバージョンアップ
text
$ cd ~/.nvm
$ git pull origin master
$ source ~/.bashrc

Python3インストール

text
$ yum install gcc gcc-c++ make git openssl-devel bzip2-devel zlib-devel readline-devel sqlite-devel
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv
$ vi ~/.bashrc
---
export PYENV_ROOT="${HOME}/.pyenv"
if [ -d "${PYENV_ROOT}" ]; then
export PATH=${PYENV_ROOT}/bin:$PATH
eval "$(pyenv init -)"
fi
---
$ sudo yum install patch
$ pyenv install 3.6.0
$ pyenv global 3.6.0
$ pip install --upgrade pip
$ pip install bigquery-python
$ pip install beautifulsoup4
$ pip install jupyter
$ jupyter notebook --generate-config
$ python -c "from notebook.auth import passwd;print(passwd())" ※設定
$ vi ~/.jupyter/ 内に jupyter_notebook_config.py
---
c.NotebookApp.ip = '*'
c.NotebookApp.open_browser = False
c.NotebookApp.password = 'sha1:*******' ※
---

Slackbot構築

Slackにhubotアプリを追加

Add apps| Slack

hubot01png.png

hubot2.png

Hubotインストール

$ cd ~/.nvm/versions/node/(バージョン)/lib/node_modules
$ npm install hubot yo generator-hubot coffee-script hubot-slack
$ cd ~
$ mkdir hello-hubot
$ cd hello-hubot
$ yo hubot
$ vi external-scripts.json
---
heroku packageを削除
---
動作確認
$ vi ./scripts/examples.coffee
---
module.exports = (robot) ->
#(コメントアウトを外す) robot.hear /badger/i, (res) ->
#(コメントアウトを外す) res.send "Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"
---
$ export HUBOT_SLACK_TOKEN=<API Token>
$ ./bin/hubot -a slack 

Slackでbadgerを入力しリプライを確認
hubot3.png

SlackBot設置

slack からgoogle検索ができるか試す。
下記のアンプルコードを scriptsディレクトリに保存し、hubotを起動する。

./bin/hubot -a slack

サンプルコード|SlackBot

slackから作成したアプリに「search is ***」を送信するとreplyが届く。

hubot5.png

続きを読む

そのAWS Lambdaの.NET Core、1.0から2.0にアップデートしませんか?

概要

  • 2018年1月15日、とうとうAWS Lambdaでの.NET Coreで2.0がサポートされるようになりました🎉
  • 早速バージョンアップしてみましょう。

ソリューションのアップデート

細かいことはおいておいて、まずはアップデートしてみましょう。

題材はこれです。

CloudWatch Logsに書き込まれた内容をSlackとGoogle Homeで通知するAWS Lambda using dotnet

がんばった割に鳴かず飛ばずだったこの記事で紹介している、CloudWatch Logsを監視してSlackとGoogle Homeに通知するLambdaです。

https://github.com/toshi0607/ErrorNotificationLambda

プロジェクト構成

ErrorNotificationLambda/
├ErrorNotificationLambda/
│ ├Properties/
│ ├aws-lambda-tools-defaults.json
│ ├ErrorNotificationLambda.csproj
│ ├Function.cs
│ └Readme.md
└ErrorNotificationLambda.Tests/
  ├Properties/
  ├ErrorNotificationLambda.Tests.csproj
  ├FunctionTest.cs
  └LaunchSettingsFixture.cs
“`

変更箇所

csprojを変更します。

ErrorNotificationLambda.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp1.0</TargetFramework>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <WarningLevel>0</WarningLevel>
  </PropertyGroup>

  <PropertyGroup>
    <OutputType>Library</OutputType>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Amazon.Lambda.CloudWatchLogsEvents" Version="1.0.0" />
    <PackageReference Include="Amazon.Lambda.Core" Version="1.0.0" />
    <PackageReference Include="Amazon.Lambda.Serialization.Json" Version="1.1.0" />
  </ItemGroup>

  <ItemGroup>
    <DotNetCliToolReference Include="Amazon.Lambda.Tools" Version="1.8.0" />
  </ItemGroup>

</Project>

これを

<TargetFramework>netcoreapp1.0</TargetFramework>

こう

<TargetFramework>netcoreapp2.0</TargetFramework>

以上。

Visual Studio 2017から編集する場合は、該当プロジェクトを右クリックすると「[プロジェクト名].csprojの編集」が選択できます。

4csproj.PNG

aws-lambda-tools-defaults.jsonにデフォルトのデプロイ設定を書いている場合、そちらもお忘れなく。

Publish to Lambdaするときに設定を保存しても書き換わってくれます。

また、Serverless Applicationのテンプレートからプロジェクトを作成した場合はCloudFormationのリソースもdotnetcore2.0に変更しましょう。

AWS Toolkit for Visual Studio 2017のアップデート

AWS Toolkit for Visual Studio 2017はVisual Studioからデプロイしたり、テンプレートを選択したりできるようにする拡張機能です。

今回.NET Core 2.0系対応が入った拡張機能のバージョンは1.14.0.0ですが、僕のVisual Studioにはまだ更新が降ってきていなかったので、マーケットプレースから直接.vsixをダウンロードし、インストールしました。

現在インストールされているバージョンは「ツール」->「拡張機能と更新プログラム」->「インストール済み」の中にあるAWS Toolkit for Visual Studio 2017を選択すると確認することができます。

61.14.PNG

バージョンアップすることで変更される大事なポイントは次の二点でしょう。

  • Language Runtimeで.NET Core v2.0が選択できる
  • Memoryが3008MBまで選択できる

メモリはまた上限上がったんですねw 年末のLambda共通のアップデート時点ではポータルで選択できる上限が上がっているにもかかわらず、「Upload Lambda Function」ではそれが反映されていませんでした。

72.0.PNG

8memory.PNG

動作確認

ローカルでテスト通るか?

デプロイ後ポータルでのバージョンが2.0になっているか?

82.0.PNG

本番環境のLambdaに対してテストイベントを発行した期待した結果になるか?

9vs.PNG

9slack.PNG

特に問題はなかったです。

アップデートの詳細

You can now develop AWS Lambda functions in C# using the .Net Core 2.0 runtime! Get started easily with the AWS Toolkit for Visual Studio. https://t.co/uxmrKodaUY pic.twitter.com/h442a6DwEZ

— Amazon Web Services (@awscloud) 2018年1月16日

AWS Lambda Supports C# (.NET Core 2.0)

AWS Lambda .NET Core 2.0 Support Released

一番下のが実際に開発してる人が書いた記事です。

aws-lambda-dotnetは大体この人が書いていると言っても過言ではないし、PRを出すととても丁寧に対応してくれます。

https://github.com/aws/aws-lambda-dotnet/graphs/contributors

VSTSのAWS周りタスクがリリースされた記事も英語版が出て2週間後くらいに日本語版が出たので、今回もきっとそのうち日本語版が出ることでしょう。

とても雑にまとめると、

  • .NET Core 2.0サポートすると、.NET Standard 2.0ベースでライブラリを作成するときより多くの.NET APIを利用できるので、既存の.NET資産をより使い回しやすくなる
  • テンプレはもう2.0ベースにアップデートしているので、AWS Toolkitのテンプレート使ってVisual Studioからデプロイしてしまうのが一番楽
  • Amazon.Lambda.Toolsも2.0がリリースされ、パッケージングするにあたって2.0ランタイムで必要となるファイルも生成できる
  • Amazon.Lambda.Templatesも2.0.0(同日に2.0.1がリリースされていた…!)がリリースされ、Visual Studioがなくてもすべてのテンプレがコマンドで利用できるようになった
  • プログラミングモデルは変わっていたいので、既存の1.0系プロジェクトもシュッとアップデートできる
  • AWS Tools for VSTSもアップデートされて2.0対応されたが既存のタスクを更新する必要はない

まとめ

「.NET Core 2.0対応」が目につきますが、実際は周辺のツールのアップデートがとてもとてもいい感じです。

続きを読む

AWS CloudWatchについての記事まとめ

個人メモ用記事

概要

【AWS】CloudWatch
CloudWatch 標準メトリクス(監視項目) 一覧
Black Belt Online Seminar Amazon CloudWatch
AWS Black Belt Techシリーズ Amazon CloudWatch & Auto Scaling
AWS Black Belt Techシリーズ AWS CloudTrail & CloudWatch Logs
AWS Blackbelt 2015シリーズ Amazon CloudWatch & Amazon CloudWatch Logs

ELB

CloudWatchのELB監視項目
あらたにELBを作成する時の、CloudWatch設定メモ
ELBの挙動とCloudWatchメトリクスの読み方を徹底的に理解する
CloudWatchのあるはずのメトリックスが存在しない理由
ELBのHealthyHostCountは全AvailabilityZoneの合計値をモニタリングできない?

EC2

死活監視

AWS CloudWatchでEC2の死活監視

メトリクス監視

新しいCloudWatch AgentでEC2インスタンスのメモリ使用率を監視する
[AWS] CloudWatch でロードアベレージとかメモリ使用量とか監視
ECSクラスタのCPUとメモリをCloudWatchメトリックスで取得してみた
EC2のメモリ使用量とdisk使用量をcollectdでサクッとCloudWatchに登録
AWS CloudWatch で、Amazon Linux のパフォーマンスとログの監視をしてみる
はじめてのCloudWatch(AWS) 〜カスタムメトリクスを作って無料枠でいろいろ監視する〜
AWS CloudWatch シェルだけでPutMetricDataを実行する
AWS CloudWatchでEC2を監視する (プロセス死活監視、ディスク使用率、iノード使用率を監視してアラートメールを送信する)

ログ取得

CloudWatch Logsを使ってログを集める!
CloudWatch Logsのインストール・設定
EC2インスタンスのログをCloudWatchで見る
AWS EC2でメモリ利用率をCloud Watchで監視する
nginxのエラーログをcloudwatch logsに送信する

RDS

Amazon RDS のモニタリング
CloudWatchのRDS監視項目

S3

Amazon CloudWatch を使用したメトリクスのモニタリング
S3のアクセス状況を可視化してみる

Auto Scaling

[翻訳]チュートリアル:CloudWatchアラームによるコンテナインスタンスのスケーリング

アラート設定

CloudWatchでエラーログの内容を通知させたい
CloudWatchアラームでSlackへ通知を行う。
AWS SNS(Amazon Simple Notification Service)の通知設定をしてみる

続きを読む

[AWS]ACMの期限確認を自動にしてSlackに飛ばすようにしてみた

AWSからACMの更新メールが来ないときあるので、念のため作ってみた
速攻作ったので、クレーム一切受け付けません

jq不使用
複数アカウント対応

#!/bin/bash

now=`date "+%s"`
_lockfile_dir=/***/***/.acm-tmp-lock
_lockfile=${_lockfile_dir}/acm_check.lock

[ -d ${_lockfile_dir} ] || mkdir ${_lockfile_dir}

if [ -f ${_lockfile} ]; then
    echo "LOCKED"
    exit 1
fi

#Create LockFile
touch ${_lockfile}

_conf=/***/***/conf/
_date=`date`

for _confgile in `ls -1 ${_conf}|grep knife.rb`
do
    _title=`echo ${_confgile} | sed 's/-knife.rb//g'`
    _region=`grep region ${_conf}${_confgile} | cut -d '=' -f 2 | cut -d '"' -f 2`
    chanel_name='#chanel-name'

    all_region=(us-east-2 us-east-1 us-west-1 us-west-2 ap-south-1 ap-northeast-2 ap-southeast-1 ap-southeast-2 ap-northeast-1 ca-central-1 eu-central-1 eu-west-1 eu-west-2 sa-east-1)
    for region_all in ${all_region[@]}
    do
      for acmid in `aws --profile ${_title} --region ${region_all} acm list-certificates --output text | awk -F " " '{print $2}'`
      do

        certificate_name=`aws --profile ${_title} --region ${region_all} acm describe-certificate --certificate-arn ${acmid} --query Certificate.[DomainName] --output text`
        certificate_use=`aws --profile ${_title} --region ${region_all} acm describe-certificate --certificate-arn ${acmid} --query Certificate.[InUseBy] --output text`
        certificate_unix_time=`aws --profile ${_title} --region ${region_all} acm describe-certificate --certificate-arn ${acmid} --query Certificate.[NotAfter] --output text | awk -F "." '{print $1}'`
        if [ "${certificate_unix_time}" != "None" ]; then
         jst_time=`date -d @$certificate_unix_time`
         rema_check=`expr $certificate_unix_time - $now`
         rema_time=`expr $rema_check / 86400 + 1`
        fi

         if [ $rema_time -lt 40 ] && [ -n "${certificate_use}" ]; then
           curl -X POST --data-urlencode "payload={"channel": "$chanel_name", "username": "ACM-Alert", "text": " Warning remaining $rema_time day $certificate_name $region_all", "icon_emoji": ":warning:"}" https://hooks.slack.com/
         elif [ $rema_time -lt 40 ]; then
           curl -X POST --data-urlencode "payload={"channel": "$chanel_name", "username": "ACM-Alert", "text": " Info remaining $rema_time day $certificate_name but Not Use ACM $region_all", "icon_emoji": ":warning:"}" https://hooks.slack.com/
         else
          echo "[Remaining] ${rema_time}day" #ファイルに吐いてもいいと思う なんでもいい
         fi

      done
   done
done

rm -f ${_lockfile}

動かなくても何も言わないでね!!
そのうちDocker化してみる

続きを読む

How we use Slack to dramatically reduce AWS costs & improve security

Metabase、まじでイケてる。 https://www.metabase.com/ 1日で、Re:Dashから乗り換えました。 Metabaseとは OSSのデータ可視化ツール。Re:Dashとかと同じ類。 AWSとかに乗せて、誰もが見れるダッシュボードを作ったりする時に使うと、俺かっけーってなります。 スクリーンショット 実際に社内で運用している様子を … 続きを読む

S3にCloudFrontを通すことで月20万ぐらい節約した話

開発しているサイトで画像や動画などの静的ファイルをS3に置き、HTMLのimgやvideoタグでS3URLを指定し読み込むということをやっていたんですが、この方法では予想よりもかなりお金がかかったためS3との間にCloudFrontを通したところ料金が激安になったという話です。
最初からCloudFront使っとけって話なんですが、インフラの経験が足りずに一月ぐらい出遅れたという失敗談でもあります。

AWSの料金でDataTransferが急増。タグ付けをすることでどのサービスが原因かを特定する

AWSの利用料金がかなり上がったことは日時でSlackに通知されるようになっているため気づくことができました。
しかし、料金カテゴリにはプロダクト名やサービス名ではなくDataTransferとしか出ていなかったため、どのサービスが原因か特定する必要がありました。

DataTransferということなのでデータ通信に負荷がかかりすぎていることはなんとなく予想できたのですが、とりあえずS3など主要なサービスにタグ付をすることにしました。
S3でのタグ付はバケットに入って、プロパティ > 詳細設定のTagsからすることができます。ひとまずキーにはName、値にはサービス名を設定しました。

これによりAWSのコストエクスプローラーでタグごとの利用料金を計測することができます。
タグはS3のバケットごとに割り振るため、利用料金急騰はどのプロダクトで使用しているS3バケットかまで特定することができました。
S3では置いているだけでもお金がかかりますが、リクエストに対するレスポンスもデータ量に応じてお金がかかるため、動画なんか置いてたらちょっとでも人が来るようになったらヤバイってことですね。

S3の間にCloudFrontをはさむことでS3へのリクエストを減らす

S3からの大量データ送信がまずいわけなのでそれを減らすためにキャッシュサーバであるCloudFrontを導入します。
ユーザーはCloudFrontにデータをリクエストしますが、CloudFrontからデータを送信するコストはS3から送信するコストよりもかなり安く済むので、DataTransferの料金は安くなる上にエッジサーバーから送信されるので速くもなります。
ただし、CloudFront自体の料金もあり、そこのコストによってはS3だけで十分という場合もあるかもしれません。

CloudFrontのディストリビューションを作ること自体はすごく簡単で、基本的にデリバリーメソッドをwebで、OriginDomainNameにS3のホストを入れるだけ。

CloudFrontのキャッシュには気をつける必要がある

CloudFrontを導入したことで安くなり速くなりいいことづくめだったが、キャッシュまわりで少し新たに手を加える必要があった。
というのも、S3に上げた画像や動画は、CloudFront側で自動で検知して更新を反映してくれるわけではないので、画像などを更新したはずがユーザーはCloudFrontの方しか見ないので、いつまでもキャッシュされた古いデータを見てしまうということが起こり得るのだ。

CloudFrontのキャッシュ時間はS3オリジンのCache-ControlとCloudFrontのMIN/MAX/Default TTLから決定されるようだ。
このあたりについては下記URLが参考になった。
【新機能】Amazon CloudFrontに「Maximum TTL / Default TTL」が設定できるようになりました! | Developers.IO

上記の設定も参考にしたが、CloudFrontにはInvalidationというキャッシュを更新する機能が備わっており、今回はそれで問題の解消を図ることにした。
CloudFrontのディストリビューションに入って、Invalidationsタブからパスを指定してInvalidateボタンを押すことでそのパスのオブジェクトのキャッシュが更新される。
全てのオブジェクトを更新したければ/*で更新すればよい。

ただ、頻繁に全てのオブジェクトを更新していてはCloudFrontの効果が薄れるし、何より手動で毎回やるのはめんどくさい。
AWSには当然ながらこういった機能をプログラム側から操作できるAPIも備えており、今回のプロダクトはLaravelだったので、aws-sdk-phpから特定のパスでinvalidationをすることにした。

protected static function cloudFrontInvalidation($paths)
{
    $client = \AWS::createClient('CloudFront');

    $client->createInvalidation([
        'DistributionId' => config('filesystems.cloud_front_distribution_id'),
        'InvalidationBatch' => [
            'Paths' => [
                'Quantity' => count($paths),
                'Items' => $paths,
            ],
            'CallerReference' => time(),
        ],
    ]);
}

このような特定のパスでinvalidationできるメソッドを作成し、S3へのアップロードを行う処理のところに組み込むことで、キャッシュについての問題も解消することができた。
なお、invalidation自体にも料金はかかるが、月に1000invalidationはまでは無料で、それ以後も安い料金だったのでプログラムに組み込むことでその辺りの心配は少なかった。
また、1000invalidationというのは更新されるオブジェクトの数ではなく、あくまでパスベースなのでうまくパスを指定すれば大量オブジェクトのキャッシュ更新を少ないinvalidationで実現することもできる。

参考サイト

【新機能】Amazon CloudFrontに「Maximum TTL / Default TTL」が設定できるようになりました! | Developers.IO

続きを読む