faultline v1.0.0 をリリースした

残念ながら2018年に入りましたが、リリースできました。

github.com

v1になって何が変わったのか?

基本的に機能追加などはありませんが、v0からいくつかBREAKING CHANGEが入りました。

BREAKING - レスポンスフォーマットを変更した

faultline v1で絶対にやりたかったところがコレでした。

RubyKaigi2017でonkさんの発表を聞いてとても勉強になりました。

RubyKaigi 2017 でどんな発表をしたか - onk.ninja

そして、fautlineのレスポンスフォーマットにしっくりきていなかったので、懇親会で質問させてもらってアドバイスをもらいました。ありがとうございました。

質問内容としては「レスポンスフォーマットを決める際に、何か参考になる情報もしくは標準的な仕様はありますか?」で、「あまりない、けど例えばGraphQLではResponseのフォーマットが定義されているよ」とアドバイスをもらっていろいろ調べた上でこれにしようということになりました。

BREAKING - FAULTLINE_* なenvを追加/デフォルト値を変更した

https://github.com/faultline/faultline/blob/master/docs/env.md に詳細を書いていますが、いくつかenvに手をいれました。

大きいのは

  • FAULTLINE_STAGE のデフォルト値を dev にした
  • FAULTLINE_DYNAMODB_TABLE_SUFFIX ( DynamoDBのテーブル名のサフィックス値)
  • FAULTLINE_ERROR_DATA_RETENTION_IN_DAYS ( fautlineに保存するエラー情報のTTL設定 ) を追加
  • FAULTLINE_DYNAMODB_READ_CAPACITY_UNITS
  • FAULTLINE_DYNAMODB_WRITE_CAPACITY_UNITS

などです。

これによりv0からv1にマイグレーションをしたい場合にはいくつか気をつけることがあります。

各ハンドラを middy でラップした

github.com

PrivateなSlackで @horike37 さんが紹介していたので見てみて、良さそうだったので採用してみました。

実際にはこんな感じ で、1つのハンドラでもミドルウェア層ができるだけでいろいろスッキリしました。

v0からv1へのマイグレーション方法

v0から使っている方は、APIエンドポイントのURLや蓄積したエラーデータなどをそのままにアップデートしたい方もいると思います。

Migration Guide: from v0.x to v1.x

a. 新しいfautlineスタックを作成してデータを移行する場合

新しいfautlineスタックを作る場合は、APIエンドポイントのURLは変わってしまいます。 S3のデータ構造やDynamoDBのデータ構造はv0と変わりませんので、awscliなどを利用してデータを移行してください。

b. v0のスタックをそのまま利用する場合

v0のスタックをそのまま利用する場合はAPIエンドポイントのURLも蓄積したエラーデータもそのままにできます。

v0のスタックをそのままにv1にマイグレーションしたい場合は、FAULTLINE_STAGEFAULTLINE_DYNAMODB_TABLE_SUFFIX を設定する必要があります(config.ymlで設定している場合は stagedynamodbTableSuffix になります)。

FAULTLINE_STAGE はv0と同様に(デフォルト値であれば v0 )に、 FAULTLINE_DYNAMODB_TABLE_SUFFIX は空値 ( '' ) にすればOKです。

fautlineのエンドポイントを同じにできれば、各アプリケーションに組み込んだfautlineのSDKの設定は更新する必要はありません。

fautline-webuiを使っている場合

v1ではレスポンスフォーマットが変更になっているので、fautline-webuiもv1にアップデートしてください

fautlineのこれから

機能面については最低限運用に耐えうるものができて一段落と思っています。

今回のアップデートで内部実装も結構リファクタリングできたので、機能追加もしやすくなりました。

もし次何か機能を追加するとしたらfautline自体をモニタリングする何かかなとか考えています。

というか、CloudWatchのダッシュボードの共有機能まだかな。。。

utsusemiという静的サイト生成用クローラを作った(作っていた)

github.com

昨年からサーバーレスな勉強会で何回か紹介していましたが、ちゃんとエントリを書いていなかったので書いておきます。

これは何?

1つのオリジナルサイトをクロールしてS3上に(S3の静的ウェブサイトホスティング機能で)静的サイトを構築してしまうServerlessなツールです。

さらに、構築したS3上の静的ページを任意のタイミングで更新できるようになります。

どんな時に使えるの?

以下の2つの要件を実現したいときに使えると思っています。

  1. コンテンツはCMSなど便利なWebアプリケーションで更新をし続けたい。
  2. 実際にアクセスされる公開側は(可用性、信頼性やセキュリティを理由に)S3の静的ウェブサイトホスティングで実現したい。

utsusemiのアーキテクチャ

f:id:k1LoW:20180124215620p:plain

utsusemiはAWS上で実現される、いわばサーバーレスアプリケーションです。

utsusemiをデプロイすると、オリジナルサイトをクロールするクローラ(AWS Lambda + Amazon SQS)と、クロールした結果の静的コンテンツを置くS3をAWS上に展開します。

クローラにはAPIAPI Gateway)を通じて命令を送ることができ、クロールした結果は「リンクなどが切れないように書き換えた上で(ここが泥臭い)」S3に設置されます。

CMSでコンテンツを更新したタイミングでutsusemiのAPIを叩くようにすれば、「CMSから更新可能なS3静的ウェブサイトホスティング」の出来上がりというわけです。

あとはS3側だけを公開するような形にしておけば、CMSの可用性を考える必要もないですし、S3ならセキュリティ的にも安心です。

URLの問題だけですのでDNSいじることができるのあれば、既に運用しているCMSにも適用できるかもしれないという良さもあります。

静的ウェブサイトホスティングのためにURLを書き換えるという仕組み

utsusemiはクロールしたコンテンツをただ保存することを目的にしているのではなく、クロールした結果を静的サイトとしてリンク切れなくホスティングすることを目的としているので、主にURLをガンガン書き換えています。

例えば、

  • aタグやlinkタグの href 属性
  • scriptタグやimgタグなどの src 属性
  • CSS内の url()
  • タグに直接書かれた style 属性内の url()
  • CSS内の @import

などを泥臭く、パス解決だけでなくクエリストリングやハッシュも良い感じに書き換えています。

というわけで

なかなか使いどころあると思っているのですがいかがでしょうか?

ちなみに

utsusemiという名前の命名は奥さんです(ヒント: FFXIユーザ)。

Serverless Frameworkで静的サイトをBASIC認証付きでホスティングするためのボイラープレートを作った

※注意 2018/1/18時点ではCloudFrontに紐付けたLambda@Edgeを削除することができなくなります(結果Serverless Framework内で動いているCFnスタックの削除などにも失敗します)。 https://forums.aws.amazon.com/thread.jspa?threadID=260242&tstart=0#jive-message-824818

ときどきページデザインなどの確認のためにモックサイトを作成することがあったりします。

動くモックが必要なのであれば(PHPRubyを動かすために)サーバの用意が必要ですが、静的サイトなのであればS3の静的ウェブサイトホスティングの機能を使いたいところです。

ただ、確認用ページをパブリックに公開するのもアレなので、BASIC認証くらいは欲しいです。

というわけで

  1. S3静的ウェブサイトホスティング環境
  2. 1のS3バケットにコンテンツを同期アップロードするためのコマンド
  3. 1の環境にBASIC認証を付与

という環境を一撃で構築するためのServerless Frameworkのボイラープレートを作りました

github.com

使い方

インストール

serverlessコマンドを利用するか、git cloneでインストールします

$ serverless install --url https://github.com/k1LoW/serverless-static-hosting-with-basic-auth --name my-static-page
or
$ git clone https://github.com/k1LoW/serverless-static-hosting-with-basic-auth.git ./my-static-page

BASIC認証のUSERNAMEとPASSWORDを設定する

handler.js 内のBASIC_AUTH_USERSにBASIC認証のUSERNAMEとPASSWORDを設定します。

const BASIC_AUTH_USERS = {
    k1low: 'passpass'
};

認証ユーザは複数設定できます。

デプロイ

S3のバケット名を環境変数で指定しつつ( WEBSITE_S3_BUCKET_NAME )静的ウェブサイトホスティング環境をデプロイします。

$ npm install
$ AWS_PROFILE=XxxxxXXX WEBSITE_S3_BUCKET_NAME=sls-static-basic npm run deploy

CloudFrontの設定やLamda@Edgeの設定も含まれるので少し時間がかかります。

デプロイが完了すると src/ 内のコンテンツがS3バケットに同期されて、CloudFront経由でBASIC認証付きの静的サイトの確認をすることができるようになります。

コンテンツの再同期

コンテンツを再度同期したいときは npm run sync コマンドで同期します( WEBSITE_S3_BUCKET_NAME の指定は忘れずに )。

$ AWS_PROFILE=XxxxxXXX WEBSITE_S3_BUCKET_NAME=sls-static-basic npm run sync

まとめ

Lambda@Edge面白いですね。

2017年の振り返りと2018年の抱負

明けました

2017年の振り返り

2016年と同様に継続したアウトプットはできたかと思います。

しかし、エンジニアとしての成長があったか?というとなかなかに微妙だったと感じています。

PHP、Serverless、Rubyという別のカンファレンスで発表ができたのは嬉しかったですが、これが今の自分の技術スタックでの限界だとも思っています。これ以上の幅は今なさそう。

2017年の目標は「チャレンジ」でした。

年末に大きな決断をしたので、そういった意味ではよくやったと言いたいです。ただ吉とでるか凶とでるかは2018年にかかっています。

OSS活動

いろいろ作りましたが、サーバーレスに関係するものが多かったという印象です(とうとうCakePHP Pluginがなくなりました)。

faultlineのv1は出しきりませんでした。マイグレーション関係で考えてきれていないことが多く、もう少しかかりそうです。

発表

最後の最後でawspecの発表ができたのが嬉しかったです。それ以外はサーバーレスおじさんですね。

2018年の抱負

数年ぶりの大吉。書いてある文章にも気合がはいる

2017年にした「チャレンジ」を次につなげられるように、今年は「努力を積み重ねる」です(本当は奥さんが絵馬に書いた文章の1つなのですが、今の自分の課題を良く表していると思ったので個人抱負にも採用しました)。

努力を意識して継続できるように2018年を過ごしていこうと思います。

というわけで

今年もどうぞよろしくお願いします。

MarkdownからWordやPDF生成ができるようにする (またはPandoc環境の構築方法) (2017/12版)

かつて、Pandoc環境の構築方法についてエントリを書いたこともありました。

qiita.com

2017年も終わる今では brew install pandoc で簡単にPandoc環境のインストールもできます。

しかし!我々が欲しいのは「Pandoc環境」ではなくて「Markdownから日本語なPDFを生成できる環境」なのですよ!

2017年最新のPandoc環境構築手順はコレだ!

$ docker pull k1low/alpine-pandoc-ja

これで終わり!

これでMarkdownから日本語なPDFを生成できます!

https://hub.docker.com/r/k1low/alpine-pandoc-ja/hub.docker.com

ちなみにDocker Hubデビュー作です。

使い方

使い方は、例えば以下のとおり

$ docker run -it --rm -v `pwd`:/workspace k1low/alpine-pandoc-ja pandoc input.md -f markdown -o output.pdf -V documentclass=ltjarticle -V classoption=a4j -V geometry:margin=1in --pdf-engine=lualatex

これで手元の環境を汚さずにMarkdownからPDFの出力が可能です。

http://smellman.hatenablog.com/entry/2017/05/23/044642 のエントリにあるようにテンプレートを変更して、良さ気なフォーマットでのPDFの生成もできますよ!

$ mkdir templates
$ wget https://raw.githubusercontent.com/Wandmalfarbe/pandoc-latex-template/master/eisvogel.tex -O templates/eisvogel.tex
$ docker run -it --rm -v `pwd`:/workspace -v `pwd`/templates:/root/.pandoc/templates k1low/pandoc:latest pandoc input.md -f markdown -o output.pdf -V documentclass=ltjarticle -V classoption=a4j -V geometry:margin=1in -V CJKmainfont=IPAexGothic --pdf-engine=lualatex --template eisvogel.tex --listings

Markdownバンザイ!

hubedit.comにMarkdown Editorを設置してみた

会社の開発合宿で自身専用メモサービスhubedit.comにMarkdown Editorを設置してみました。

hubedit.com

今回の目的は2つです。

  1. Markdown Editorを設置して自身のhubeditライフを便利にする
  2. Serverless Frameworkでデプロイし、ドメインACMも設定して運用しているようなサービスで
    • 次期本番環境を構築して sls deploy できるようにする
    • 本番環境を次期検証環境に切り替えてみる

Markdown Editorの選定

Markdownの表記はそのまま表示されてstyleだけ変化があるものを探しました。

Markdownの表記が消えてしまうタイプのWISYWIGなEditorは多かったが表記がそのまま残るようなEditorは少なかったです。

探したものとしては

などですが、とりあえず導入して使い勝手を見たかったので、 最も導入しやすかった+スマホでも使えた SimpleMDE を設置してみました。

Serverless Frameworkで検証環境を作る

hubeditはServerless Frameworkでデプロイできるように構築されており、AWS上では1つのCloudFormationのスタックとして管理されています。

f:id:k1LoW:20170712231630p:plain

また、GitHubのアクセストークンを一時的に保存する場所としてS3を利用しています。

ドメイン割り当て(Route53)とSSL証明書ACM+CloudFront)はServerless Framework管理外で設定しています。

スタック切り分けによる検証環境を作るのは簡単

本番で稼働しているスタックと別のスタックで動かすために、stage の切り替えで対応しました。

具体的には sls deploy -s v2 などで検証用スタックが実現できます。

serverless.yml の servicehubedit だったとしたら v2-hubedit という新しいスタックが作成されます。

この状態で新機能を追加していって、実装を進めました。

そして最終的にAPI Gatewayのカスタムドメインの向き先を変更することで、検証環境を本番環境に昇格させました。

永続データをどうするか

今回の切り替えの方法では、検証環境はCFnのスタック単位で、API GatewayAWS LambdaやS3は全く別に新しく構築することになりました。

hubeditは永続データはGitHubリポジトリのみなので問題なく切り替えは可能でしたが、永続データがあったときはどうすればいいのでしょうか?

  1. 永続データの保存先はServerless Frameworkでは管理しない(hubeditがたまたまコレ)
    • 2つのCFnに分けて永続データは永続データ用CFnで保持する
  2. API GatewayのStageで切り替えることができればあるいは。。。
    • 1つのCFnスタックに2種類以上のAPIコレクションを持つことは可能?

ここらへんはまだ個人的ベストな方法は見つかっていません。 Serverless Frameworkで永続データの管理運用をどうするのが良いか、何か良いアイデアあるかた教えて下さい。

hubedit.comの今後

とりあえず、今のところ普通に使えているのであとはAPIリクエストに伴う読み込みの遅さをいい感じで解消していきたいです。

Serverless Ninja Tips "Instant Job Queue" をしっかり紹介してみる

このエントリは、Serverless Advent Calendar 2017Fusic Advent Calendar 2017の5日目となります。

PHPカンファレンスや、Serverlessconf Tokyo 2017でも紹介したServerless Ninja Tips(名前だけかっこいい)ですが、その中で、説明するたびに伝わっていない感がある "Instant Job Queue" について紹介したいと思います。

想定するユースケース「クローラ」

サーバーレスアーキテクチャでWebページのクローラを実装するとします。

まずは、以下のような1つのLambdaファンクション(今回はWorkerと呼びます)を考えるでしょう。

  1. URLを入力として受け取って、URLにアクセスしてHTMLパース、次のURLをリストアップする
  2. リストアップしたURLを次のLambdaファンクションの入力としてinvokeする

これでだいたいクローラとしては動きそうですが、実際に動かすとどうなるでしょうか?

f:id:k1LoW:20171205093634p:plain

無限ループになってしまいます。 さらに、同時実行されるLambdaファンクションはURLをリストアップする度にどんどん多くなり、対象サーバにDoSを仕掛けてしまうことになってしまいます。 これではマズいですね。

  1. 無限ループになる
  2. 同時実行数がどんどん大きくなる

この2つを解決したいと思います。

無限ループを回避する

無限ループを回避するのは簡単です。

URLと同時に深さ( depth ) をLambdaファンクションに与えて、深さが規定に達したら次のURLのリストアップとinvokeをやめて終了すればOKです。

同時実行数を制御する "Instant Job Queue"

次は同時実行数です。

"Instant Job Queue" は、再帰構造になっているLambdaファンクションにおいて、同時実行数を簡易的に制御するためのTipsです。

f:id:k1LoW:20171205093337p:plain

フロー

仕組みとしては以下のようになります。

まず、WorkerだけでなくStarterと呼ぶLambdaファンクションを用意します。そして仕組みの真ん中にSQS(キュー)を配置します。

  1. まずStarterがURLを深さの対をエンキューする
  2. StarterはWorkerをinvoke
  3. Workerはデキューしようとする
  4. Workerはキューがなければ自身を終了する。URLと深さを受け取って、深さが規定に達していても終了する
  5. 深さ++
  6. WorkerはURLにアクセスしてHTMLパース、次のURLをリストアップする
  7. WorkerはリストアップしたURLとインクリメントした深さをそれぞれ対にしてエンキューする
  8. WorkerはWorkerをinvokeして自身を終了する

特徴

AWSのマネージドサービスのみで実現しているので「キュー待ちするWorkerのプロセス管理」などが必要ありません。

また、(本来なら採用したほうが良いであろう)Step Functions よりも安い料金で実現可能です。

具体的な実装

"Instant Job Queue" を実際に組み込んでいる実装として utsusemi があります。

github.com

(utsusemiについてもいつか紹介エントリを書こうと思います)

というわけで

"Instant Job Queue" についての紹介でした。