Amazon Athena の API を使ってみた (2017/05)

http://docs.aws.amazon.com/athena/latest/ug/release-notes.html#may-18-2017

2017年5月18日に Amazon Athena にて API が公開されました。
managed presto としての魅力を感じつつも API が存在しないということで original の presto を使っている人にとっては魅力が薄かったサービスですが、 API が公開されることでできることも増えました。

この記事では、 Amazon Athena の API の使い勝手について概観してみようと思います。

API で出来ること

公式ドキュメントにあるように、 API 経由で出来ることは以下になります。

http://docs.aws.amazon.com/athena/latest/APIReference/API_Operations.html

  • BatchGetNamedQuery
  • BatchGetQueryExecution
  • CreateNamedQuery
  • DeleteNamedQuery
  • GetNamedQuery
  • GetQueryExecution
  • GetQueryResults
  • ListNamedQueries
  • ListQueryExecutions
  • StartQueryExecution
  • StopQueryExecution

いくつか API がありますが、出来ることは大別して以下の3つです。

  • Query の実行に関する操作

    • ***QueryExecution
  • Query の実行結果に関する操作
    • GetQueryResults
  • NamedQuery (SavedQuery) に関する操作
    • ***NamedQuery

AWS CLI のセットアップ

この記事では Amazon Athena の API の呼び出しはすべて cli 経由で例示します。
Amazon Athena の API 呼び出しを行うために、あらかじめ awscli を最新版にアップデートしておきます。

$ pip install -U awscli --ignore-installed six
(snip.)
$ aws --version
aws-cli/1.11.90 Python/2.7.10 Darwin/16.5.0 botocore/1.5.53

また、現時点(2017年5月23日)では Amazon Athena は Tokyo Region に来ていないため、region の設定を Athena が動作する region に設定しておく必要があります。

$ cat ~/.aws/config
[default]
region = us-east-1

サポートしていない region を指定して Amazon Athena の cli を実行すると、処理がフリーズし応答がなくなります。(これは、エラーメッセージが表示された方が親切だと思います。)

QueryExecution

StartQueryExecution

http://docs.aws.amazon.com/athena/latest/APIReference/API_StartQueryExecution.html

任意の Presto Query を実行します。
以下からの例では、再現性を考慮しあらかじめ最初から用意されているサンプルデータベースのテーブルを対象にします。
(sampledb.elb_logs)

$ aws athena start-query-execution 
  --query-string 'select * from sampledb.elb_logs limit 1;' 
  --result-configuration OutputLocation=s3://hogehoge/athena-execution-result/
{
    "QueryExecutionId": ".........."
}

--query-string に実行する Presto Query を指定します。
--result-configuration OutputLocation=..... で指定した S3 Bucket に実行結果を保存します。

API の結果として返却される QueryExecxutionId という値を使用して、当該 Query については以後操作することになります。

GetQueryExecution

http://docs.aws.amazon.com/athena/latest/APIReference/API_GetQueryExecution.html

実行した Query の状態などの情報を取得します。

$ aws athena get-query-execution 
  --query-execution-id ()
$ aws athena get-query-execution 
>   --query-execution-id ..........
{
    "QueryExecution": {
        "Status": {
            "SubmissionDateTime": 1495539953.596, 
            "State": "SUCCEEDED", 
            "CompletionDateTime": 1495539955.596
        }, 
        "Query": "select * from sampledb.elb_logs limit 10", 
        "Statistics": {
            "DataScannedInBytes": 850058, 
            "EngineExecutionTimeInMillis": 1651
        }, 
        "ResultConfiguration": {
            "OutputLocation": "s3://hogehoge/athena-execution-result/...........csv"
        }, 
        "QueryExecutionId": ".........."
    }
}

この API の結果からは、Query の現在の状況(実行中か、完了しているか)、開始 / 終了時間などが取得できます。
状態の種類については以下公式ドキュメントに記載されています。
http://docs.aws.amazon.com/athena/latest/APIReference/API_QueryExecutionStatus.html

QUEUED | RUNNING | SUCCEEDED | FAILED | CANCELLED

個人的に、当該 API を cli から使用するときは、 StartQueryExecutionGetQueryExecutionjq コマンドを用いて pipe で繋いで、正しく実行されているかどうかをひと目で確認できるようにしています。
(毎回手で実行するのは手間なので、 warpper shell を用意しています)

$ aws athena get-query-execution 
  --query-execution-id  
  `aws athena start-query-execution --query-string 'select * from kuso_query;' --result-configuration OutputLocation=s3://hogehoge/athena-execution-result/ | jq -r '.QueryExecutionId'`
{
    "QueryExecution": {
        "Status": {
            "SubmissionDateTime": 1495540557.77, 
            "State": "FAILED", 
            "CompletionDateTime": 1495540557.914, 
            "StateChangeReason": "Database, table or column name not found. Please check your query."
        }, 
        "Query": "select * from kuso_query", 
        "Statistics": {
            "DataScannedInBytes": 0, 
            "EngineExecutionTimeInMillis": 67
        },
(snip.)
}

ListQueryExecutions

http://docs.aws.amazon.com/athena/latest/APIReference/API_ListQueryExecutions.html

過去に実行した Query の履歴が取得できます。
特に request parameter で検索条件が指摘できないため、基本的に登録された日時が新しいものから順に取得されます。

$ aws athena list-query-executions 
  --max-results 3
{
    "NextToken": "......", 
    "QueryExecutionIds": [
        "........", 
        "........", 
        "........"
    ]
}

こちらも結果として QueryExecutionId しか返却されず可読性が悪いので、以下のように jq で pipe してみます。
GetQueryExecution には複数の QueryExecutionId が渡せる BatchGetQueryExecution が存在するのでこちらを用います。

$ aws athena batch-get-query-execution  
  --query-execution-ids 
  `aws athena list-query-executions --max-results 3 | jq -r ".QueryExecutionIds[]" | tr 'n' ' '`
{
    "UnprocessedQueryExecutionIds": [], 
    "QueryExecutions": [
        {
            "Status": {
                "SubmissionDateTime": 1495540557.77, 
                "State": "FAILED", 
                "CompletionDateTime": 1495540557.914, 
                "StateChangeReason": "Database, table or column name not found. Please check your query."
            }, 
            "Query": "select * from kuso_query", 
(snip.)
    ]
}

このような形で、直近の Query の実行状況を 1 liner で確認することができます。

GetQueryResults

http://docs.aws.amazon.com/athena/latest/APIReference/API_GetQueryResults.html

実行した Query のデータを取得することができる API です。

$ aws athena get-query-results  
  --query-execution-id ........
{
  "ResultSet": {
    "Rows": [
      {
        "Data": [
          {
            "VarCharValue": "request_timestamp"
          },
          {
            "VarCharValue": "elb_name"
          },
          {
            "VarCharValue": "request_ip"
          },
(snip.)
        ]
      },
      {
        "Data": [
          {
            "VarCharValue": "2015-01-06T12:00:01.612598Z"
          },
          {
            "VarCharValue": "elb_demo_006"
          },
          {
            "VarCharValue": "243.72.152.87"
          },
(snip.)
    "ResultSetMetadata": {
      "ColumnInfo": [
        {
          "Scale": 0,
          "Name": "request_timestamp",
          "Nullable": "UNKNOWN",
          "TableName": "",
          "Precision": 1073741824,
          "Label": "request_timestamp",
          "CaseSensitive": true,
          "SchemaName": "",
          "Type": "varchar",
          "CatalogName": "hive"
        },
(snip.)
}

ただしこの結果内容は、プログラムで扱う分にはまだ良いですが、awscli から扱うには直感的な内容とはい言えないです。

awscli からは、StartQueryExecution 時に指定した OutputLocation から S3 経由で取得する、という方が楽かもしれません。

$ aws s3 cp  
  `aws athena get-query-execution --query-execution-id ........ | jq -r ".QueryExecution.ResultConfiguration.OutputLocation"` ./result.csv

download: s3://hogehoge/athena-execution-result/...........csv to ./result.csv

***NamedQuery

NamedQuery という用語が聞きなれなかったので何を指しているかよくわからなかったのですが、これは Amazon Athena の画面上では Saved Query と表現されているもののようです。

Athena ではよく使う Query などをあらかじめ登録しておくことができる機能がありますが、当該 API はその SavedQuery を操作する API になります。

CreateNamedQuery

http://docs.aws.amazon.com/athena/latest/APIReference/API_CreateNamedQuery.html

$ aws athena create-named-query 
  --name test --description 'for test'  
  --database sampledb  
  --query-string 'select * from sampledb.elb_logs limit 10;' 
{
    "NamedQueryId": "........"
}

QueryExecution と同じような形で NamedQueryId という ID が返却されます。

ListNamedQueries

http://docs.aws.amazon.com/athena/latest/APIReference/API_ListNamedQueries.html

登録されている SavedQuery (NamedQuery) の一覧を取得できます。
特に request parameter で検索条件が指摘できないため、基本的に登録された日時が新しいものから順に取得されます。namedescription などで絞込はできません。

$ aws athena list-named-queries 
  --max-results 3
{
    "NamedQueryIds": [
        "........", 
        "........", 
        "........"
    ], 
    "NextToken": "....."
}

GetNamedQuery

http://docs.aws.amazon.com/athena/latest/APIReference/API_GetNamedQuery.html

あらかじめ登録されている SavedQuery (NamedQuery) の情報を取得できます。
NamedQueryId のみを検索条件に指定可能で、 namedescription などで絞込はできません。

NamedQueryId があらかじめわかっている場合は、以下のような形で pipe で繋ぐことで Query を 1 liner で発行することは一応できます。

$ aws athena start-query-execution 
  --query-string "`aws athena get-named-query --named-query-id ........ | jq -r ".NamedQuery.QueryString"`"  
  --result-configuration OutputLocation=s3://hogehoge/athena-execution-result/
{
    "QueryExecutionId": "........"
}

個人的な感想

ここまで、だらだらと各 API について awscli の例をもとに書いてきました。

いままで JDBC 経由、もしくは Amazon Athena の web console 経由でしか使用ができなかった状況にくらべると格段と可能性は広がったように思えますが、個人的には以下の点で物足りなさを感じています。

  • 全体的に API のインターフェースが気がきいてない
  • ListQueryExecutions API で所定の条件で絞込、ならびに並び替えができない
    • たとえば、実行中の Query だけ取得する、実行時間が長い Query を取得する、ということが API 単体ではできない。
  • ListQueryExecutions の返却結果が QueryExecutionId だけで、情報量が少ない
  • GetQueryResults の使い勝手が悪い
  • 基本的に API の数が少ない
  • このタイミングで Amazon Athena 自身の機能拡張は特に無かった

などなど。

正直、今の機能では積極的にシステム・サービスに組み込んで行くには不足している点が多いと思いますが、期待されているサービスでもありますので今後の進化を期待したいと思います。

個人的に想像しているユースケース

Amazon Athena の API が出る、という話を聞いて、個人的に以下のようなユースケースで使いたいなと感がていました。蛇足になりますが、以下列挙します。

実行時間が長い Query を検知して stop する

現状の API では使い勝手が良くないですが、以下の API を組み合わせることで実現可能です。

  • ListQueryExecutions
  • BatchGetQueryExecution
  • StopQueryExecution

where 句に partition が指定されていない Query を検知して stop する

2017年5月22日現在、Amazon Athena は Tokyo Region に来ていないため、 Tokyo Region の S3 を Athena で使用する場合はどうしても転送量が発生します。

ものすごい巨大なデータ群が入っている S3 Bucket を data source にしている場合、partition を設定していなかったり、もしくは Query に partition 情報が含まれていない場合、膨大な転送量が発生してクラウド破産をしてしまう恐れがあります。
そのため、partition が指定されていない Query を検知し次第、stop をする、というようなユースケースが考えられます。

本来は、Amazon Athena 単体でこのような機能が備わっていてほしいですが、 API を用いることで実現することは可能です。

レポーティングバッチ

おそらくアプリケーション使用用途で一番うれしいのはこのケースだと思います。

レポーティングバッチから Amazon Athena を呼び出して何かしらのレポート処理を行いたい場合、JDBC 経由で対話的に Amazon Athena に繋ぐしか無い状況下では、 Query 実行結果に引きづられてずっとプロセスが待機する必要があったと思います(作りによりますが)

API が提供されたことで、 Query を submit する処理と結果を polling する処理を別に分けることもできますし、そもそも標準機能で実行結果を自動的に S3 にアップできるようにもなりました。

まとめにかえて

長々と書いてきましたが、Amazon Athena は期待の大きいサービスでもありますので、本体の機能も、API の機能についても、より使いやすいものに進化してもらえると、ユーザーとしては嬉しく感じます。

続きを読む

いますぐ使う CloudFront

CloudFrontとは

台数不明で性能不明ですが、グローバルに配置された、キャッシュサーバー。

効果

CloudFrontをリバースプロキシキャッシュとして立ててみました。お問い合わせページなど動的ページを除いて、ほぼ全部のリクエストをCloudFrontが捌いてくれてます。

d0ff6181-11f1-d277-eee8-2d5999566133.jpg

※効果には個人差がございます

課金ポイント

  • 料金 – Amazon CloudFront | AWS

    • データ転送料金
    • キャッシュクリア料金
      • 1ファイル1回クリアが、月間1000回までは無料。以降は0.005 USD

        • リリースとかでこまめに大量のファイルをクリアすると、金かかる
        • キャッシュ有効期限は24時間。24時間ほっとけるならキャッシュクリア料金かからない

用語整理

  • ひとつのCloudFrontは「ディストリビューション」。

    • EC2やRDSが「インスタンス」と呼んだように。
  • キャッシュルールは「ビヘイビア」
  • キャッシュ元データを配信するサーバーを「オリジン」
    • ELB、EC2、S3、その他のサーバー
  • キャッシュクリアは「インバリデート」
    • 「無効化リクエスト」と書いてある文書もある

CloudFront の設置場所

CloudFront無しの構成

EC2のローカルディスクにすべてがあります。静的コンテンツ、動的ページ、すべてのアクセスを、EC2が捌く必要があります。ApacheとかNginxでキャッシュを効かせると、負荷は軽くなるかも。みたいな涙ぐましいノウハウがあったのです。

f65e1219-60fe-d83f-c483-73b133b04544.jpg

横に置く

昔のCloudFrontは、GETとHEADしか受け付けなかったため、JS/CSS/画像/添付ファイルなどを配信するS3を別立てにして、その手前にCloudFrontを置いていました。HTMLの実装では、cssとかjs、画像のタグに書くのリンクを xxxxxxxx.cloudfront.com にしておくことで、こうできます。図ではS3に置くことにしていますが、リリースでのCSSやJSの同期とか、何かと状況が複雑になりがちです。

40904824-cf46-b636-e04c-ee2462471b96.jpg

前に置く

CloudFrontの2013年10月のアップデート から、すべてのHTTPメソッドを受けてくれるため、ウェブアプリサーバーの手前に置くことができます。この場合は、静的コンテンツはCloudFrontのキャッシュでリクエストを捌き、動的ページはCloudFrontはスルーさせて、EC2で処理させます。

626b87d4-abd6-5ba8-6835-b3319f2722c0.jpg

今からやるなら「前に置く」構成

CloudFront無しの構成に導入するなら、断然「前に置く」構成です。

ウェブアプリのソース改修不要で、CloudFrontを適切に設定して配置するだけでOKなので、面倒がないです。

ただし、特定のページだけIP制限してたりすると、ApacheやNginxの設定を変更する必要があります。

とりあえずCloudFrontを立てる

必須項目だけ埋めて、あとで直せばOKです。

  • AWSコンソールにはいる
  • CloudFrontのページに行く
  • Create Distribution
    • Webを選ぶ(RTMPは動画配信とかに使う用)

      • Origin Settings

        • Origin Domain Name

          • ELBエンドポイントURL、BeanstalkエンドポイントURL、S3エンドポイントURL、EC2 DNS名など
          • IPアドレスでなければOK
      • Default Cache Behavior Settings
        • あとで変えるので放置
      • Distribution Settings
        • Alternate Domain Names(CNAMEs)

          • このディストリビューションに当てる予定のドメイン名。
          • 「前に置く」構成なら、これまでELBに当てていたドメイン名を指定。
          • 「横に置く」構成なら、空欄でOK
      • 他はあとで変えればOKなので放置
      • Create Distributionボタン押す
  • ディストリビューションは全世界に分散して立つのと、微妙にダサい仕様のため、しばらく時間がかかります

ビヘイビアの掟

  • ビヘイビアリストの上から順に評価されます。
  • Default (*)は、
    • 一番下から動かせません。
    • 削除できません。
    • どのビヘイビアにも当たらなかった場合のため存在します。
  • パスパターンにマッチしたら、そのビヘイビアだけに従って、キャッシュを見たり、オリジンにスルーしたりする
    • なので、ビヘイビアの上下の並び順は重要

ビヘイビアの設定方針

下記のどちらか。後からでも変更はできますが、どっちで行くかを考えるために、先に切り分けておくと良いです。

  • Default (*)を「キャッシュする」で書く。他のパスパターンは「キャッシュしない」で書く。
  • Default (*)を「キャッシュしない」で書く。他のパスパターンは「キャッシュする」で書く。

キャッシュしないページの設定

  • Path Pattern

    • 仮に http://hoge.example.com/contact/piyo.jpg みたいなとき

      • /contact/piyo.jpg
      • /contact/*.jpg
      • *.jpb
    • みたいに、そのキャッシュルールを適用するパスパターンを指定します。
  • Allowed HTTP Methods
    • 全部入りのを指定
  • Forward Headers
    • 「all」を指定
  • Object Caching
    • Customize
    • TTL(min, max, default)
      • ぜんぶゼロを指定
  • Forward Cookies
    • 「all」を指定
  • Query String Forwarding and Caching
    • 「forward all, cache based on all」を指定

キャッシュするページの設定

  • Path Pattern

    • 仮に http://hoge.example.com/contact/piyo.jpg みたいなとき

      • /contact/piyo.jpg
      • /contact/*.jpg
      • *.jpb
    • みたいに、そのキャッシュルールを適用するパスパターンを指定します。
  • Allowed HTTP Methods
    • GET,HEAD を指定
  • Forward Headers
    • 「Host」は必須。他にも必要なものがあれば追加。
  • Object Caching
    • Use Origin Cache Headers
    • Customizeにして、TTLを入れてもOK
  • Forward Cookies
  • Query String Forwarding and Caching
    • 「forward all, cache based on all」を指定

DNS設定

ビヘイビアふくめて、ディストリビューションの設定が完成したら、DNSの設定を書き換えます。

ディストリビューションには、「d1lxxxxxxxxx.cloudfront.net」のような、一意なドメイン名が発行されます。

Alternate Domain Names (CNAMEs)に入れたドメイン名のCNAMEとして、ディストリビューションのドメイン名を向けた、DNS CNAMEレコードを作成します。

動作確認

サイトにアクセスして、期待したとおりにビヘイビアが設定できているか、確認しましょう。

ChromeのデベロッパーツールのNetworkタブで、個々のファイルのレスポンスヘッダーに下記のようなのがあれば、CloudFrontを経由しています。

Via:1.1 41f313008af830d498dcb13814523bd7.cloudfront.net (CloudFront)
X-Amz-Cf-Id:xcP_6KiTFG_guNA9dRA-KOW6pg740-3mP1SvSrt2NqKGndWGPJKVuA==
X-Cache:Hit from cloudfront

X-Cacheに、キャッシュヒットしたかしてないかが記載されます。HitとMiss、ほかにもいくつかありますが、、、

  • X-Cache:Hit from cloudfront

    • CloudFrontにあるキャッシュが返っています
  • X-Cache:Miss from cloudfront
    • CloudFrontにキャッシュがなく、オリジンから返っています

HitとMissが想定と異なる場合は、ビヘイビアの調整が必要です。がんばりましょう。

その他、TIPS

制限、仕様

導入前に、CloudFrontというプロダクトの制限と仕様が、プロダクトの制限と仕様にマッチするのか、検討が必要です。

参考文書

続きを読む

RDSで急にパフォーマンスが悪くなったらIOPSを確認!

本番運用しているRDSのパフォーマンスが最近悪くなっている。
スロークエリを確認すると、処理時間が非常に遅いときがある。(Procedure)
とあるProcedure処理が以前は15分くらいで完了していたのだが、遅い時には100分近くかかっている。。。
処理内容は変えていないのに。。。

CPU使用率を比較してみる

グラフの凡例

  • 青線:正常
  • 赤線:処理時間が遅い時

正常時は処理が終わるとCPU使用率は下がっていた。
しかし、処理時間が遅い時は負荷が上がっている時間が短く、CPU使用率も下がりきっていない。
スクリーンショット 2017-05-22 15 (7).png

処理時間が遅いのはCPUがサボっているかららしい(笑)
なぜ、違う動きをしているのか?
実際に処理した件数はどうなっているのか?

IOPSを比較してみる

書き込み(WriteIOPS)

正常時には次の処理が走っているが、それ以外に大きな差はなさそう。
スクリーンショット 2017-05-22 15 (11).png

読み込み(ReadIOPS)

一定時間経過後にIOPSが300で横ばいとなっている。
スクリーンショット 2017-05-22 16.png

Amazon EBS ボリュームとパフォーマンス

色々と調べたところこのページに行き着きました。
http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/EBSVolumeTypes.html#EBSVolumeTypes_gp2

超ざっくりまとめると…

  • ボリュームサイズによりベースラインパフォーマンスが決まる
  • バーストすることで最大3,000 IOPSまで一時的に性能をあげられる
  • バーストするにはクレジットバランスを消費する
    • クレジットバランスは初期に配られる
    • クレジットバランスはバーストしない間に補充される
  • クレジットバランスを使い切った場合のパフォーマンスはベースラインにとどまる

自分の環境に当てはめる

私の環境はボリュームタイプが「汎用SSD」、ボリュームサイズが「100GiB」なので
ベースラインパフォーマンスは300 IOPSとなっています。

どうやらクレジットバランスを使い切ったため300 IOPSしか性能が出ていなかったようです。。。
ちなみに残クレジットバランスの確認方法はわかりませんでした。(あったら教えてください)

対応方法

対応方法として以下になると思います。
私は後者(処理間隔を空けること)で対応しています。

  • ボリュームサイズを増やす。 ※後から減らせないので要注意!
  • クレジットバランスが補充されるまで待つ

まとめ

INDEXやら色々調べてみてもわからず、この結論に行くまでに時間がかかりました。
普段、意識していない部分だと思うので何かのヒントになれば幸いです。

続きを読む

デプロイ方法のメモ

はじめてデプロイ作業したのでその時につまづいたところをまとめました。

pipのインストール

pipはPythonのパッケージ管理システムです
標準で入ってるらしいですが、自分のPCには入ってなかったので、
入れ方から使い方までメモしました。

Pythonが入ってることを確認しましょう

$ python -V

次にpipが入ってるか確認しましょう。

$ python -m pip -V

python初めての人入っていないので、
https://bootstrap.pypa.io/get-pip.py
ここからpip.pyをダウンロードしてください。

$ sudo python get-pip.py

でインストール。入ったことを確認したら

$ sudo pip install -U pip

でpipをアップデートします。

aws-cli をインストールする

コマンドラインからAWSを操作できる公式のコマンドラインツールです。
http://docs.aws.amazon.com/ja_jp/streams/latest/dev/kinesis-tutorial-cli-installation.html

$ sudo pip install awscli

でインストールできますが、

DEPRECATION: Uninstalling a distutils installed project (six) has been deprecated and will be removed in a future version. This is due to the fact that uninstalling a distutils project will only partially uninstall the project.

というエラーが出ました。どうやらSixというのが邪魔してるみたいです。
SixはPython 2と3の互換性ライブラリのことです。

$ sudo pip install awscli --upgrade --ignore-installed six

これでインストールできます。

セットアップ

aws configure

と打つと対話形式で
AWSの設定を打ち込んでいきます。

AWS Access Key ID [None]:アクセスキーID
AWS Secret Access Key [None]:シークレットアクセスキー
Default region name [None]: ap-northeast-1は東京のこと
Default output format [None]:無視

~ $ aws s3 ls

で確認

あとは、公開したいサイトのディレクトリーに入り
deploy.shファイルを作成し。

./deploy.sh

でファイル一覧がでてきて
yesで
デプロイ完了です。

続きを読む

IPv6でアクセスすると"via IPv6"って出るやつ

IPv6でアクセスすると”via IPv6″って出る例のやつ作りました。
(HTMLタグ貼るだけのやつが見つからなかったので)

表示してみる

IPv6から繋ぐと
Screen Shot 2017-05-22 at 3.19.22.png
が表示されます。

IPv4から繋ぐと
Screen Shot 2017-05-22 at 3.19.41.png
が表示されます。

使い方

<span id="kibousoft-viav6"></span>
<script type="text/javascript">
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://viav6.kibousoft.co.jp/', true);
xhr.onreadystatechange = function(){
if (xhr.readyState === 4 && xhr.status === 200){
   var dom = document.getElementById('kibousoft-viav6');
   dom.innerHTML = xhr.responseText;
 }
};
xhr.send(null);
</script>

ソースコード

汚いですが直書きです。大したことしてない。

index.php
<a href="https://github.com/kibousoft/viav6_web/" style="text-decoration: none; color: white;">
<?php
$ip = $_SERVER['REMOTE_ADDR'];
$headers = apache_request_headers();
if ($headers['X-Forwarded-For']) {
    $ip = $headers['X-Forwarded-For'];
}

if (preg_match('/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/', $ip)) {
    echo '<div style="background: linear-gradient(#FF0000, #FF99CC); padding: 5px; border: 1px solid #333333; border-radius: 3px; font-size: 13px; width: 50px; text-align: center; font-family: sans-serif;">via IPv4</div>';
} else {
    echo '<div style="background: linear-gradient(#0000FF, #99CCFF); padding: 5px; border: 1px solid #333333; border-radius: 3px; font-size: 13px; width: 50px; text-align: center; font-family: sans-serif;">via IPv6</div>';
}
?>
</a>

CORSの話

外部からXHRで取得される可能性のあるサイトでは、
Access-Control-Allow-Origin , Access-Control-Allow-Methods ヘッダーを返す必要があります。
.htaccessで以下を設定しました。

.htaccess
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET"

インフラの話

最初Amazon API Gatewayでやろうとしたんですが、API GatewayはIPv6対応していませんでした。
なので、OpsWorksでPHP App Serverを立てて動かしています。
OpsWorksにも以下の問題がありました。

  • Application Load Balancer(IPv6対応)には対応していない
  • EC2へのIPv6アドレスのアタッチには対応していない
  • セキュリティグループでIPv6のTCP 80番が許可されていない

そのため、上記の設定は手動で行いました。

備考

  • Happy Eyeballsの関係で、サイトにはIPv4で繋がって、XHRはIPv6で繋がるケースもあるよねとか細かい話はなしで。

続きを読む

aws周りのメモ2

postgresqlを使う

RDSへpostgresqlをいれて立ち上げ

認証と接続

import-key-pair — AWS CLI 1.11.87 Command Reference
http://docs.aws.amazon.com/cli/latest/reference/ec2/import-key-pair.html

cd $HOGE
openssl genrsa -out my-key.pem 2048
openssl rsa -in my-key.pem -pubout > my-key.pub
# IAMのコンパネで*.pubを入力
# 多分、権限があれば以下でもいける
# aws iam upload-ssh-public-key

【AWS 再入門】EC2 + RDS によるミニマム構成なサーバー環境を構築してみよう – NET BIZ DIV. TECH BLOG
https://tech.recruit-mp.co.jp/infrastructure/retry-aws-minimum-vpc-server-environment/

便利

無料枠

無料のクラウドサービス | AWS 無料利用枠
https://aws.amazon.com/jp/free/

AMI

AWS Marketplace: Search Results
https://aws.amazon.com/marketplace/search/results?x=14&y=18&searchTerms=&page=1&ref_=nav_search_box

CFテンプレート

サンプルコード & テンプレート – AWS CloudFormation | AWS
https://aws.amazon.com/jp/cloudformation/aws-cloudformation-templates/

ec2 ami tool & ec2 api tool

Mac で Amazon EC2 API Toolsを設定する – サーバーワークスエンジニアブログ
http://blog.serverworks.co.jp/tech/2013/01/31/mac-amazon-ec2-api-tools-setup/

ec2 api toolは若干心配。

VPCを使う

接続の際に、sshを経由したい。sslでもいいけどなんかsshがいいなと。
パスワードよりkeyのほうがセキュアだからかな。

0から始めるAWS入門①:VPC編 – Qiita
http://qiita.com/hiroshik1985/items/9de2dd02c9c2f6911f3b

導入

Amazon VPC とは? – Amazon Virtual Private Cloud
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_Introduction.html

公式のいろいろ

料金 – Amazon VPC | AWS
https://aws.amazon.com/jp/vpc/pricing/

基本は無料だけどNATとVPNは別課金。

【AWS 再入門】VPC 環境に踏み台サーバーを構築して SSH 接続してみよう – NET BIZ DIV. TECH BLOG
https://tech.recruit-mp.co.jp/infrastructure/retry-aws-bastion-host-vpc/#i-3

ec2(Bastion)を配置する必要がありそう。

【AWS 再入門】EC2 + RDS によるミニマム構成なサーバー環境を構築してみよう – NET BIZ DIV. TECH BLOG
https://tech.recruit-mp.co.jp/infrastructure/retry-aws-minimum-vpc-server-environment/

VPC に推奨されるネットワーク ACL ルール – Amazon Virtual Private Cloud
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_Appendix_NACLs.html

vpcでのネットワークのポリシーの例

Default VPC

AWSのDefault VPCを削除して困った話 – MikeTOKYO Developers
http://blog.miketokyo.com/post/49939300091/aws-default-vpc

デフォルトvpcは削除したらダメか。使い分けがわからん。

Amazon EC2 と Amazon Virtual Private Cloud – Amazon Elastic Compute Cloud
http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-vpc.html

基本の機能はデフォルトとそうじゃないvpcは同じだけど、
デフォルトvpcがないとちゃんと機能しない。
デフォルトの属性によって、指定がないとipを紐付けたりする。

VPCネットワーク設計

これだけ押さえておけば大丈夫!Webサービス向けVPCネットワークの設計指針 | eureka tech blog
https://developers.eure.jp/tech/vpc_networking/

ネットワークは一度稼働させると移行が大変なので、初期設計が非常に重要になります。

わかりやすい。図が特に。

  • Bastion
  • NAT
  • Security Group

ENI

インフラエンジニアに贈るAmazon VPC入門 | シリーズ | Developers.IO
http://dev.classmethod.jp/series/vpcfor-infra-engineer/

サブネットで指定したIPアドレスのうち、先頭4つと末尾の1つはVPCで予約されるため使用できません。

VPCでは常にDHCP有効とするのがポイントです。

また、DHCPサービスで伝えられる情報(DHCPオプション)は、変更することもできます。

仮想マシンにひもづくENIにより、DHCPサーバーから毎回同じMACアドレス、IPアドレスが付与されます。これは、仮想マシンの状態に依存しないため、仮想マシンを再起動しようと、一旦シャットダウンしてしばらくしてから起動した場合でも必ず同じアドレスが付与されます。

ENI(Elastic Network Interface)か。。なるほど。でも、使うことはなさそうだな。

NAT

IPマスカレードが使えないVPC
NATは、Static(静的・サーバー用途)とElastic(仮想・クライアント用途)がある。
個人的には、このNATインスタンスの実装は、あまり好きではありません。動きがややこしいですし、ユーザーが自分でNATインスタンスの管理をしなければならないのも煩雑な印象を受けます。VPCのネットワークサービスの一つとして提供される機能であれば、ユーザーからはなるべく抽象化され仮想マシンとして意識されないようにするべきと考えます。
ただ、ユーザーから仮想マシンとして見える分、機能・実装が具体的に把握できる点やカスタマイズ性が高い点は良いとも思っています。

NAT インスタンスと NAT ゲートウェイの比較 – Amazon Virtual Private Cloud
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/vpc-nat-comparison.html

なるほど。。

Bastion

AWSで最低限セキュアな構成を組む – Qiita
http://qiita.com/ausuited/items/09b626fa5264f0c650fd

パブリックSubnetにEC2インスタンス(踏み台サーバーとして)
NATインスタンスを作成した要領で、パブリックSubnetにEC2インスタンスを作成する。Security groupは新規に作成してSSHをAnywhereに。Key pairは厳重に管理。尚、踏み台サーバーは、使用する時以外はStoppedにしておく事で、さらにセキュアな状態とする。このデザインパターンをOn Demand Bastionパターンと呼ぶらしい。

詳しい。「On Demand Bastionパターン」か。なるほど。

vpcへの踏み台サーバー
ポートフォワーディング、トンネルなどと同じ意味。

Network ACL

インスタンス単位じゃなくサブネット単位でより制限してセキュアにしたい場合に使うのかな。

安全なVPC設計 — Commerce Hack
http://tech.degica.com/ja/2016/01/07/designing-vpc-and-subnets/


結局どうするのか、、ひとまずNATはつかわずに、Bistionをつくってみる感じかな。

アベイラビリティーゾーン

リージョンごとでの、障害などで全部やられないように物理的にセグメントされた範囲の単位かな。
RDSではセグメントグループに2つ以上のゾーンを含める。でも、一つしか使わなくていい。ということか。s

RDSのVPC間の移動

サブネットグループの関連付けを変えればいいらしい。間違って設定したので移動した。

【小ネタ】知っていましたか?RDSを別のVPCに移動できることを | Developers.IO
http://dev.classmethod.jp/cloud/aws/rds_can_move_to_another_vpc/

Bastion作成作業をしてみる

主に下記を参考。

【AWS 再入門】EC2 + RDS によるミニマム構成なサーバー環境を構築してみよう – NET BIZ DIV. TECH BLOG
https://tech.recruit-mp.co.jp/infrastructure/retry-aws-minimum-vpc-server-environment/

  • サブネットってなんだっけとか復習。
  • ストレージはどうするのか。
    • とりあえずssdにしたけどマグネティックでよかったかなあ。

      • ssd:$0.12 : 1 か月にプロビジョニングされたストレージ 1 GB あたり
      • マグネティック: 0.05 USD/GB-月
  • public IPは設定必要だよね
  • market placeからamiを取得した方がいいの?
    • とりあえず公式のウィザードを使ったけど。
  • 認証にIAMが追加されていたので使ってみた
    • これとは別にキーペアは必要ってことかな。
  • CFnテンプレート(CloudFormationテンプレート)というのがあるらしい。。
    • これでつくりなおそうかな。。
  • サブネットとかいろいろネットワーク系の設定
    • なんだかんだいっていろいろあった
  • セキュリティグループ
    • エイリアスみたいなセキュリティグループにできたらいいのに。タグや名前で明示化かな。
    • bastionは22をあけて、rdsは5432をbastionからのみあける
  • ログイン
  • DNS
    • あれ、パブリックDNSがうまく割り振ってないな。。
      AWSでPublic DNS(パブリックDNS)が割り当てられない時の解決法 – Qiita
      http://qiita.com/sunadoridotnet/items/4ea689ce9f206e78a523
    • RDSのDNS
      • nslookupしたら内部ipがかえってくるのね。接続できないけどなんか気持ち悪いな。これかな。。
        外部からdnsを引けることを気にしている人は見かけなくて便利だからって話なのかね。
        【AWS】VPC内でPrivate DNSによる名前解決 – Qiita
        http://qiita.com/y_takeshita/items/2eb5e6abb5eb5516d1de

やってるうちはいいけど、しばらくやらないと設定の方法とか忘れそう。。こういうのは学習コストだけじゃないな。

PlantUMLで図にしておく

Kobito.hQIwJs.png

VPC内のRDSへLambdaから接続。。

しまった!アンチパターンだそうだ。。

Lambda+RDSはアンチパターン – Qiita
http://qiita.com/teradonburi/items/86400ea82a65699672ad

Lambda + RDS benchmark – Qiita
http://qiita.com/taruhachi/items/3f95ae3e84f56edb3787

新し目の記事でIAM認証でクリアできそうな。。

【全世界待望】Public AccessのRDSへIAM認証(+ SSL)で安全にLambda Pythonから接続する – サーバーワークスエンジニアブログ
https://blog.serverworks.co.jp/tech/2017/04/27/rds-iam-auth-lambda-python/


セキュアに接続するのと速度のトレードオフになっていたのが
IAM認証のおかげで両方可能になったということっぽい。
でも、ネットのスループット、コネクション数(料金・負荷)、など、、ほかにも気にすることが出て来そうで若干不安。
非同期でよければキューイングして一回投げっぱなしすればどうだろう。
もしくは、似てるけど、Lambdaから一回値を返してもらってからRDSへ投げ直す。
これでいっかなあ。。Lambdaの意味がなくなる?うーん。

今後

  • 疑問としてrdsなど内部向けのdnsを外から見れなくできないものか。
  • というか、rdsのエンドポイントって再起動したら変わったりしないかね。ipは固定されるのか。
    • たぶん、サブネット内でdhcpになるのでipは変動するけどエンドポイントは固定。。じゃないかしら。

posgresqlをつかうための情報

Amazon RDS 上の PostgreSQL – Amazon Relational Database Service
http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts.General.SSL

続きを読む

EC2 instance起動時にtagをつけるTagSpecifications

AWSCLIでEC2 instance起動時に同時にタグをつける方法としては、instance起動してinstance-idを取得しておいて、パイプでつないでtagをつけたり、スクリプトの中で後でタグ付けする方法があったと思います。
http://kurochan-note.hatenablog.jp/entry/2017/01/08/220155

AWSCLI EC2 Run-Instanceのなかに–tag-specificationsというoptionが入って、run-instancesの中でタグが作成できるようになりました。地味なアップデートかもしれませんが、結構うれしいです。

instanceの詳細はjsonに記述して、下記のように指定して実行します。

aws ec2 run-instances --cli-input-json file://instance.json

EC2は山ほど設定項目があるので、generate-cli-skeltonでフォーマットを出力して、必要な項目だけ入力して、不必要なものは消すとinstanceの詳細を記述したjsonの完成です。Gitにでも入れておきましょう。
http://docs.aws.amazon.com/cli/latest/userguide/generate-cli-skeleton.html

aws ec2 run-instances --generate-cli-skeleton

Instanceの設定詳細を記述したjsonサンプル

instance.json
{
    "ImageId": "<image-id>",
    "KeyName": "<my-key>",
    "SecurityGroupIds": [
        "<my-sgid>"
    ],
    "InstanceType": "<instance-type>",
    "BlockDeviceMappings": [
        {
            "VirtualName": "Root",
            "DeviceName": "/dev/sda1",
            "Ebs": {
                "VolumeSize": 100,
                "DeleteOnTermination": true,
                "VolumeType": "gp2"
            }
        }
    ],
    "Monitoring": {
        "Enabled": false
    },
    "SubnetId": "<subnet-id>",
    "DisableApiTermination": false,
    "IamInstanceProfile": {
        "Name": "<instance-iam-role>"
    },
    "TagSpecifications":[
        {
            "ResourceType": "instance",
            "Tags": [
              {
                "Key": "Name",
                "Value": "<server-name>"
              },
              {
                "Key": "ClusterName",
                "Value": "<cluster-name>"
              },
              {
                "Key": "Application",
                "Value": "<myapp>"
              },
              {
                "Key": "CostCenter",
                "Value": "<my-cost-center>"
              },
              {
                "Key": "Environment",
                "Value": "Test"
              },
              {
                "Key": "User",
                "Value": "<user-name>"
              }
            ]
        },
        {
          "ResourceType": "volume",
          "Tags": [
            {
              "Key": "Device",
              "Value": "<device-name>"
            },
{
              "Key": "CostCenter",
              "Value": "<my-cost-center>"
            },
            {
              "Key": "backup_key",
              "Value": "true"
            }
          ]
        }
    ]
}

続きを読む

EC2のボリューム(EBS)容量拡張方法検証 (AmazonLinux)

結論を3行で

検証

【遂に来た!】EBS でボリュームサイズを変更できるようになりました(ボリュームタイプ変更も) | Developers.IO を参考に、稼働中のインスタンスにアタッチ済みのボリュームのサイズを増やしてみます。

今回ボリュームを増やしたいインスタンスはこのような感じです。

インスタンス的には/dev/xvdaというところに30GBのボリュームがあります。

ec2-user@ip-172-31-10-224 ~ $  df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       30G  3.8G   26G  13% /
devtmpfs        490M   56K  490M   1% /dev
tmpfs           499M     0  499M   0% /dev/shm

ec2-user@ip-172-31-10-224 ~ $  lsblk
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvda    202:0    0  30G  0 disk
└─xvda1 202:1    0  30G  0 part /

ほとんど元記事のとおりですが以下のような感じです。

スクリーンショット_2017-05-18_11_30_15.png

Modify Volumeを押します

スクリーンショット 2017-05-18 11.30.31.png

今回は 30GB -> 100GBにします

スクリーンショット 2017-05-18 11.32.51.png

パフォーマンスが変更されるまで時間がかかるとのこと。。yesを押す。

スクリーンショット 2017-05-18 11.33.00.png

完了。

スクリーンショット 2017-05-18 11.34.08.png

ボリュームの状態は optimizing...0% という表示になりますが、もうこの状態で ディスクの拡張は終わっています。

スクリーンショット 2017-05-18 11.34.46.png

awscli的には $ aws ec2 describe-volumes-modifications と叩くと進捗が表示されます(引数なしでOK)

$ aws ec2 describe-volumes-modifications
{
    "VolumesModifications": [
        {
            "TargetSize": 100,
            "TargetVolumeType": "gp2",
            "ModificationState": "optimizing",
            "VolumeId": "vol-0e92fb2e26dfd9687",
            "TargetIops": 300,
            "StartTime": "2017-05-18T02:34:07.151Z",
            "Progress": 0,
            "OriginalVolumeType": "gp2",
            "OriginalIops": 100,
            "OriginalSize": 30
        }
    ]
}

"Progress": 0 ですが、lsblk を叩くともう反映されていることがわかります。

ec2-user@ip-172-31-3-117 ~ $  lsblk
NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
xvda    202:0    0  100G  0 disk             # <- 100になってる
└─xvda1 202:1    0   30G  0 part /

次に resize2fs すればよいのですが、以下のような感じで怒られます。

resize2fs 1.42.12 (29-Aug-2014)
resize2fs: Device or resource busy while trying to open /dev/xvda
Couldn't find valid filesystem superblock.

今回はパーティションの設定がされているためと思われます。パーティションを利用している場合の設定はこちら。http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/storage_expand_partition.html
ただルートパーティションの場合は面倒そうなので、起動時に実行されるresize2fsに任せることにしました。

見たところAmazonLinuxの場合 /etc/cloud/cloud.cfg.d/00_defaults.cfg の中で resize2fs の記述があるので、再起動時に実行されるようです。

こうして、何も考えずにrebootすることにより、dfの結果が変わりました :tada:

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       99G  9.1G   90G  10% /           # <- 99GBに増えてる
devtmpfs        490M   56K  490M   1% /dev
tmpfs           499M     0  499M   0% /dev/shm

続きを読む

〇FLAGの中の人に憧れてMastodon×AWSでモンストドン作ってみた

Mastodon立ち上げたらいい会社に入れると聞いて、邪な気持ちで。。。いや、Mastodonとモンストって相性よさそうだなぁと思いたち、少し乗り遅れた感をかもしだしながら、フルにAWSを使って規模拡大しても大丈夫な構成で作ってみた。

モンストドン (https://monstdn.com)

構成

monstdn.png

最小構成のざっくり料金($1=113円、1ヶ月30日計算)

サービス 単価 月額料金
ALB 1台 × $0.0243/1H + データ転送的なの  約2000円 + α
EC2 2台(t2.nano) × $0.008/1H + データ転送的なの 約1300円 + α
RDS 1台(db.t2.micro シングルAZ) $0.028/1H + データ転送的なの 約2300円 + α
ElasticCache 1台(cache.t2.micro) $0.026/1H + データ転送的なの 約2100円 + α
S3Bucket $0.025/GB + リクエスト数的なの + α
SES $0.10/1,000通あたり + データ転送的なの + α
合計     ( 約7700円 + α なので ) ざっくり1万ぐらい

※無料枠があるので1年目はもう少しやすくできそう

やったこと

  • AWSのアカウント作成
  • IAMの作成とアカウントの初期設定(二段階認証とか、パスワードポリシーとか)
  • Route53でドメインを買う
  • SESでメール設定と制限解除申請
  • ACMの取得(無料でHTTPS通信)
  • S3バケット作成(画像とかのアップロードファイルの配信用)
  • VPCとセキュリティグループの作成
  • SES、S3へアクセスする為のIAMユーザの作成
  • ElasticCacheでRedisの作成
  • RDSでPostgreSQLの作成
  • EC2でCentOSを使ってMastodonの構築(下に詳細)とイメージ(AMI)の作成
  • AutoScallingの設定
  • ALB(ApplicationLoadBalancer)の作成(ACMをつける)
  • Route53でHostZoneのレコード設定

CentOSでのMastdon構築(20170517現在)

sudo su -
yum -y update
yum -y install vim

localectl set-locale LANG=ja_JP.utf8
localectl set-keymap jp106
localectl status

timedatectl set-timezone Asia/Tokyo
timedatectl status

dd if=/dev/zero of=/mnt/swapfile bs=1M count=2560
mkswap /mnt/swapfile
swapon /mnt/swapfile
chmod 0644 /mnt/swapfile
echo "/mnt/swapfile                             swap                    swap    defaults                0 0" >> /etc/fstab
free

vim /etc/sysconfig/selinux
 SELINUX=enforcing
 ↓
 SELINUX=disabled

systemctl disable postfix
systemctl disable auditd.service

yum -y install libxml2-devel ImageMagick libxslt-devel git curl nodejs file
yum -y install epel-release
rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm
yum -y install ffmpeg ffmpeg-devel

yum -y group install "Development tools"
curl -sL https://rpm.nodesource.com/setup_4.x | sudo bash -

yum -y install nodejs
npm -g install yarn

yum -y install postgresql postgresql-contrib postgresql-devel
yum install -y openssl-devel readline-devel

useradd mastodon
passwd mastodon
su - mastodon
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
cd ~/.rbenv && src/configure && make -C src && cd ~
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile && source ~/.bash_profile
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
rbenv install 2.4.1 && rbenv global $_ && rbenv rehash

# 確認
ruby -v

cd ~
git clone https://github.com/tootsuite/mastodon.git live
cd live
git checkout $(git tag | tail -n 1)

gem install bundler
bundle install --deployment --without development test
yarn install --pure-lockfile

cp .env.production.sample .env.production
sed -i "/^PAPERCLIP_SECRET=$/ s/$/`rake secret`/" .env.production
sed -i "/^SECRET_KEY_BASE=$/ s/$/`rake secret`/" .env.production
sed -i "/^OTP_SECRET=$/ s/$/`rake secret`/" .env.production

vim .env.production
#Redis,Postgresql,言語,SMTP,S3の設定

RAILS_ENV=production bundle exec rails db:setup
RAILS_ENV=production bundle exec rails assets:precompile

exit

cat << "_EOF_" > /etc/systemd/system/mastodon-web.service
[Unit]
Description=mastodon-web
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="PORT=3000"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
_EOF_


cat << "_EOF_" > /etc/systemd/system/mastodon-sidekiq.service
[Unit]
Description=mastodon-sidekiq
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=5"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
_EOF_

cat << "_EOF_" > /etc/systemd/system/mastodon-streaming.service
[Unit]
Description=mastodon-streaming
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="NODE_ENV=production"
Environment="PORT=4000"
ExecStart=/usr/bin/npm run start
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
_EOF_

systemctl enable mastodon-{web,sidekiq,streaming}
systemctl start mastodon-{web,sidekiq,streaming}

cat << "_EOF_" | crontab -
RAILS_ENV=production
@daily cd /home/mastodon/live && /home/mastodon/.rbenv/shims/bundle exec rake mastodon:daily > /dev/null
_EOF_

yum -y install nginx

cat << "_EOF_" > /etc/nginx/conf.d/mastodon.conf
map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

server {
  listen 80;
  listen [::]:80;
  server_name {domainName};

  keepalive_timeout    70;
  sendfile             on;
  client_max_body_size 0;

  root /home/mastodon/live/public;

  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

  add_header Strict-Transport-Security "max-age=31536000";

  location / {
    try_files $uri @proxy;
  }

  location @proxy {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Proxy "";
    proxy_pass_header Server;

    proxy_pass http://127.0.0.1:3000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    tcp_nodelay on;
  }

  location /api/v1/streaming {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Proxy "";

    proxy_pass http://localhost:4000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    tcp_nodelay on;
  }

  error_page 500 501 502 503 504 /500.html;
}
_EOF_

systemctl enable nginx
systemctl start nginx

# ユーザ登録後 admin設定
RAILS_ENV=production bundle exec rails mastodon:make_admin USERNAME={UserName}

メモ

EC2のDiskはSSDで(swapで使う)
ロードバランサーはApplicationの方じゃないとwebSocketがうまくいかない
コミュニティベースのシステムだからCloudFrontはあまり必要性感じなかったので使わなかった
(日本向けだしS3のバケット東京リージョンにあるし、S3もかなり性能いいし)
もしCloudFrontを使うなら、websocketできないからS3の前に置く感じ
今回CloudFrontの利点があるとすれば”ドメイン”が自分の使えることぐらいかな
CentOSじゃなくてAmazonLinux使いたかったけど、ffmpeg入れるのにやたら時間かかったからやめた。一応動いたけど(純正AWSが。。。)
DockerはDeployまで楽そうだけど、効率よくなさそうだったのでやめた
AWSでDocker使うならECSでやってみたいけど、Mastodonはすんなりできるのかなー
セキュリティ的にはロードバランサーからの80番ポートしか受け付けないように制御してるから大丈夫かな。
sshでのログインは同じVPC内に踏み台サーバ立ててと。

最後に

ここまで読んで頂きありがとうございます。
技術的なことを投稿するのはこれが初めてですが、だれかのお役にたてれたら嬉しいです。
普段はPHPとAWS少しいじる程度なのでいい勉強になりました。
ほとんど公開されている文献をもとにプラモデル感覚で作りましたので、ご指摘等あればコメント頂ければと思います。
個人でのサイト運用となりますので、落ちたらごめんなさい。

続きを読む