14Room

みんな泣きながらオトナになったんだ。

LambdaでRDSを定期的にスケールアップ・ダウンさせてみた

概要

普段はmicroインスタンスで十分だけど、重いSQLを実行するときだけsmallにしたいという要件を満たすために、 Lambdaを使ってサーバレスでRDSを定期的にスケールアップさせてみました。

ここではスケールアップする方法のみ記述してますが、業務時間終了後またmicroに戻す処理も実装してコストの上昇を最小限に止めてみました。

設定

Lambda

AWS-Services-Lambdaで「Create a Lambda Function」をクリック。 f:id:naked123:20160211213910j:plain

ひな形になる「hello-world-python」を選択。 「Name」をScaleUpReadDBとし、「Runtime」にはpython 2.7を選択。

肝心の「Lambda function code」はEdit code inlineで直接下記のコードを入力しました。

import boto3
 
def lambda_handler(event, context):
    client = boto3.client('rds')
    response = client.modify_db_instance(
        DBInstanceIdentifier='readonlyrds',
        DBInstanceClass='db.t2.small',
        ApplyImmediately=True
    )
    print response

readonlyrdsは実際にスケールアップさせたいRDSの名前です。ちなみにApplyImmediately=Trueを指定しないとコマンドは成功しても変更が即時反映されないため気を付けましょう。

f:id:naked123:20160211220249j:plain

「Role」では「Basic execution role」を新規で作ります。詳細については次のIAM roleで述べます。

また「Timeout」はデフォルトで3sとなってますが、時々3秒以内に処理が終わらずエラーとなるので10sを設定しました。

IAM role

Lambda Function作成時にBasic execution roleを新規作成すると下記の画面に移りますので「Hide Policy Document」をeditして適切な権限を付与します。

f:id:naked123:20160211220906j:plain

今回は下記のような感じにしてみました。

 {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "rds:*",
                "cloudwatch:DescribeAlarms",
                "cloudwatch:GetMetricStatistics",
                "ec2:DescribeAccountAttributes",
                "ec2:DescribeAvailabilityZones",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSubnets",
                "ec2:DescribeVpcs",
                "sns:ListSubscriptions",
                "sns:ListTopics",
                "logs:DescribeLogStreams",
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "logs:GetLogEvents"
            ],
            "Resource": "arn:aws:rds:ap-northeast-1:xxxxxx123456789:db:readonlyrds"
        }
    ]
}

IAM roleを作成するとLambda作成画面に戻るので、そのままnextをクリック、詳細確認して作成。

Lambdaのcron実行指定

Lambdaは作成しただけでは実行されないので、cronで実行時刻を指定します。 作成したLambdaの「Event Sources」で「Add event source」をクリック。 「Event source type」で「CloudWatch Events - Schedule」を選択すると下記のようなダイアログが出現するので設定して「Submit」して終了。

f:id:naked123:20160211234256j:plain

上の例では月曜日から金曜日の日本時間の朝9時1分(UTC 0:01)にLambda Functionが実行されます。

あとがき

やってみると意外と簡単だなというのが正直な感想です。普段コードを書かないインフラエンジニアでもワンパス通せば雰囲気も掴めて、いろんな事に応用できそうだと思ってもらえるはずです。

StatusCakeからslackにアラートを飛ばしてみる

概要

URL監視を手軽にする際にStatusCakeは便利です。設定は簡単だし、監視対象URL数もフリープランで20個以上軽く行けますし。 今回はStatusCakeからslackにアラートを飛ばしてみようとした際にしょうもないところでハマったのでソレについて述べます。

slack側設定

いつものように通知先のchannelのwebhookを用意します。(今回は割愛します)

StatusCake側設定

Contacts - Integrations

アラート送信先として外部サービス(slack)を登録します。 f:id:naked123:20160207185258j:plain ContactsのIntegrationsで[ADD NEW 3RD PARTY SERVICE]でslackを選択して上の図のようにwebhookを設定。 この時[Alias]を設定しないと後でアラート送信先としてslackが選択できなくなるので注意です。

Contacts - Create Groups

アラート送信先を実際に設定します。

f:id:naked123:20160207190104j:plain

グループ名を適当に設定し、アラートの飛ばし先としてEmailとslackを設定しますが、slackの設定はwebhook、、、ではなく[Push Notifications]欄をクリックすると先ほどIntegrationsでaliasに設定した名前が選択できます。(自分はここでハマりました)。

Tests - New Test

最後に監視対象URLを設定します。

f:id:naked123:20160207190946j:plain

設定項目は一目瞭然なので割愛します。Contact Groupに上で作成したグループを選択して終了。

実際に障害を疑似的に起こしてテストしてみると

f:id:naked123:20160207191536j:plain

ちゃんとslackに通知されました。

Google Developers Launchpadで$100,000 GETした時の思い出

概要

Google Developers Launchpadに選出され$100,000 GETした時の流れを簡単にまとめました。

自分たちがGoogle Developers Launchpadに挑戦した時(2015/4)と状況が変わっているので、今はちょっと違うかもしれませんが誰かの参考になればイイなと。

流れ

2015/4

  • Google Developers Launchpadの情報をキャッチ。
  • androidアプリ開発のアドバイス、GCPの$100,000 credit、等々魅力的な特典満載なのでダメもとで応募することに。
  • 会社情報やサービス内容など必要情報を整理してwebフォームから応募。

2015/5

  • We are happy to welcome <company_name> to Google Developers Launchpad program. みたいなメールが来て、めでたく参加決定。やったー!
  • 再度、Google Cloud Credits($100,000)を貰うため会社規模や売上げ額などの情報を求められるので、フォームに入力。

2015/6

  • 前のフォーム入力はなんか上手くいかなかったので、もう一度より詳しい情報(公開してるアプリ情報、開発言語、GCPで使いたい機能)を入力せよ!とメールが来る。
  • フォームに入力すべきIDなど不明箇所があったのでメールで質問する。そのやりとりの中でbut please know that not every startup receives the credits と言われ激しく意気消沈。
  • とりあえず必要事項を全て入力して様子を見守る。

2015/7

  • You will have the opportunity to speak directly 1:1 with GCP for Startups program manager and Solution Architect みたいなメールが来て最終面談へ。実際は米国の昼時間帯にビデオハングアウト。つまり日本時間深夜にビデオハングアウト。偉い外人さんと英語でビデオハングアウトォーーorz
  • アジェンダとか特に言われませんでしたが、間が持たないんじゃないかと不安だったのでプレゼン資料を事前に先方に共有しておきました。
  • 実際のMTG時間は1時間ほど。
  • 先方からGoogle Developers Launchpadの簡単な説明後、こちらから現在やってるサービスとそれを支える技術の説明。グローバル展開してるところをアピールしてみました。
  • 質疑応答
  • ビデオハングアウトの最後で「OK, Google Cloud Creditsを受け取りたまえ」みたいな話になって無事終了。

2015/8

  • Accepted - Welcome to Google Cloud Platform for Startupsという題名のメールが到着。内容は下記の通りで、「Redeem now」をクリックすると自動的に$10,000づつ振り込まれていきます。

f:id:naked123:20160129094602p:plain

2015/9

  • 実際に「Redeem now」をクリックしてcreditsをもらい始める。以後、google developer consoleのホーム画面の請求は$0のまま。

f:id:naked123:20160128184607p:plain

2015/10

  • GCPにインフラの大半を引っ越して実運用開始。

その他

  • フォーム入力後、2週間くらい放置されることが多々ありますので、可能な限り手を尽くして関係者を捕まえましょう。そしてプッシュしましょう。そうしないと中々進みません。
  • 基本的にすべて英語のやり取りでした。Google Developers Launchpadに関しては日本法人のサポートもありませんので、腹を決めて取り組みましょう。

Shinjuku.rb #33 でspot instanceについてLTさせてもらった時の資料

概要

Shinjuku.rb #33 ではLTのお題目に縛りが無かったのでインフラっぽいことを喋らせてもらいました。

資料

ubuntuでセキュリティアップデートを自動で行う。

概要

unattended-upgradesを導入してdpkgで管理されてるアプリのセキュリティアップデートを自動で行います。

インストール

apt-get install unattended-upgrades

設定

/etc/apt/apt.conf.d/50unattended-upgradesの下記のコメントアウトを外す

Unattended-Upgrade::Automatic-Reboot "false";

sudo dpkg-reconfigure -plow unattended-upgrades

YESを選択

unable to resolve hostのエラーを抑制する。

概要

sudoコマンドを実行した際などホスト名が解決できないと

sudo: unable to resolve host

と出力されますが、ウザいので抑制したいです。

対処法

下記のスクリプトで起動時にhostnameを/etc/hostsに追記する。

--------------
#! /bin/sh
### BEGIN INIT INFO
# Provides: rc.boot
# Required-Start: $all
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop:
# Short-Description: Run /etc/rc.boot if it exist
### END INIT INFO

do_start() {
echo "127.0.0.1 `hostname`" >> /etc/hosts
##su - ubuntu -c 'cd /home/ubuntu/taptrip2;bundle exec cap ROLES=app local_staging deploy'
return 0
}

case "$1" in
start)
do_start
;;
restart|reload|force-reload)
echo "Error: argument '$1' not supported" >&2
exit 3
;;
stop)
;;
*)
echo "Usage: $0 start|stop" >&2
exit 3
;;
esac

/etc/rc2.dで下記のようにシムリンク作成。

lrwxrwxrwx 1 root root 17 Aug 26 09:45 S19boot -> ../init.d/rc.boot

起動時に自動的にhostsにホスト名が追記されます。

mysqldumpslowの結果をslackに投げてみた

概要

以前、mysqlのslow query数をslackに投稿させていましたが、数だけでなく質も見ないとダメだなということで、今回はmysqldumpslowによる統計結果を投稿させるようにしました。

mysqldumpslow

MySQLに付属しているツールで、スロークエリログを集計してくれます。

mysqldumpslow実行

例)

mysqldumpslow -s t mysql-slow.log

mysqldumpslow実行結果

回数、平均実行時間などを総消費時間数順に表示してくれます。

Reading mysql slow query log from mysql-slow.log
Count: 1179  Time=1.88s (2222s)  Lock=0.00s (0s)  Rows=10.0 (11790), naked[naked]@33hosts
  SELECT  `timeline_threads`.* FROM `timeline_threads` INNER JOIN `naked_friends` ON `naked_friends`.`naked_id` = N and `naked_friends`.`friend_naked_id` = `timeline_threads`.`naked_id` WHERE `timeline_threads`.`deleted_at` IS NULL ORDER BY `timeline_threads`.`created_at` DESC, `timeline_threads`.`id` DESC LIMIT N

Count: 88  Time=17.08s (1502s)  Lock=0.00s (0s)  Rows=1.0 (88), naked[naked]@24hosts
  SELECT COUNT(DISTINCT `naked_items`.`id`) FROM `naked_items` INNER JOIN `naked_item_countries` ON `naked_item_countries`.`naked_item_id` = `naked_items`.`id` LEFT OUTER JOIN `nakeds` ON `nakeds`.`id` = `naked_items`.`naked_id` WHERE `naked_item_countries`.`country_id` = 'S' AND `nakeds`.`banned_at` IS NULL AND `nakeds`.`deleted_at` IS NULL AND `naked_items`.`target_type` != 'S' AND (`naked_items`.deleted_at IS NULL)

Count: 76  Time=9.09s (690s)  Lock=0.00s (0s)  Rows=0.8 (59), naked[naked]@[10.10.0.4]
  SELECT  `nakeds`.* FROM `nakeds`  WHERE `nakeds`.`reset_password_token` = 'S' LIMIT N

・
・
・
・
・

slack.sh

mysqldumpslowの結果を全部送ると見切れないので上から3つまでの結果をmessageに入れて投稿するシェルスクリプトを作りました。

#!/bin/bash
date=`date '+%Y-%m-%d'`
server_name=`hostname`
url="https://hooks.slack.com/services/zzzzzzz/xxxxxx/123456789aaa?parse=full"

num=`mysqldumpslow -s t /var/log/mysql/mysql-slow.log | head -8`
message="($date)  $server_name のslow-query top3は\n \`\`\` $num \`\`\` です。"
payload="payload={\"text\": \"${message}\", \"username\": \"naked\"}"
curl --data "${payload}" ${url}

定期実行

cronで定期実行します。

# 
# m h  dom mon dow   command
30 6 * * * /root/work/slack.sh

あとがき

この仕組みで今度こそ他のメンバーの興味を引ければと考えています。。。