Subscribed unsubscribe Subscribe Subscribe

Hatena Developer Blog

はてな開発者ブログ

はてなブログのシンタックス・ハイライト機能に対応する言語を募集します

こんにちは、ブログチームの id:masawada です!

今回は、はてなブログのシンタックス・ハイライト機能について紹介します。はてなブログでは「はてな記法」モードおよび「Markdown」モードの場合に、ソースコードを色付けするシンタックス・ハイライト機能を利用することができます。

対応言語の追加について

このたび、対応する言語に「Kotlin」「Elixir」「Crystal」「Dart」「Nim」の5つを追加しました。どうぞご利用ください。すでにHatena Developer BlogでもKotlinの記事が書かれており、シンタックス・ハイライトが適用されています。

developer.hatenastaff.com

※これまでに保存された記事については、編集画面を開いて記事を更新することで適用することができます。

対応してほしい言語を募集します

シンタックス・ハイライト機能はC、Perl、JavaScript、Goなど多くの言語に対応しています。しかし、まだ対応していない言語も多く、はてなブログではそれらにもできるだけ対応していきたいと考えています。

そこで、シンタックス・ハイライト機能で対応してほしい言語を募集いたします。マイお題「シンタックス・ハイライト機能で対応してほしい言語」を作成しましたので、是非はてなブログにてご回答ください。ご意見として参考にさせていただきます。言語に対する熱い思いをお待ちしています。

※極力多くの言語を追加したいと考えておりますが、言語により対応しかねる場合があります。ご了承ください。

マイお題は先日はてなブログに追加した新機能です。利用方法は以下のヘルプをご覧ください。

また、現在対応している言語については以下のヘルプをご覧ください。

シンタックス・ハイライト機能の利用方法について

シンタックス・ハイライト機能は、編集画面が「はてな記法」モードおよび「Markdown」モードのときに利用できます。はてな記法のスーパーpre記法や、Markdownのコードブロックにおいて、記述したコードがどの言語かを指定します。

はてな記法でシンタックス・ハイライト機能を利用する方法

「はてな記法」モードの場合は、スーパーpre記法で戦闘の先頭の>||の2本のパイプ(||)の間に言語を指定します。例として、JavaScriptの場合は以下のように記述することでシンタックス・ハイライト機能を利用することができます。

>|javascript|

console.log('Hello, World!');

||<
Markdownでシンタックス・ハイライト機能を利用する方法

「Markdown」モードの場合は、バッククオート(`)を3つ続けた```で囲まれたコードブロック(Fenced Code Blocks)において、先頭のバッククオートの最後に言語を指定します。例として、JavaScriptの場合は以下のように記述することでシンタックス・ハイライト機能を利用することができます。

```javascript

console.log('Hello, World!');

```

はてなダイアリー・はてなグループでは

はてなダイアリー・はてなグループでもシンタックス・ハイライト機能をご利用いただけますが、対応する言語が異なります。また、今回募集する言語は、はてなブログでの対応のみとなります。詳しくは次のヘルプを参照してください。

さいごに

株式会社はてなでは、プログラミング言語に対する熱い思いを持っているエンジニアを募集しています。なお,私は東京でアプリケーションエンジニアをしています。東京で働きたい!というエンジニアも絶賛募集中です。

hatenacorp.jp

【Google I/O 2016参加レポート】Android開発者向けオススメセッション 2日目

こんにちは、アプリケーションエンジニアのid:takuji31です。

昨日に引き続き、2日目の19日に私が見たセッションの中から、Android開発者の皆様にオススメのものを紹介します。

f:id:takuji31:20160519085202j:plain

What's new in Android development tools

www.youtube.com

最新のAndroidの開発環境、特にAndroid Studio 2.2 previewについてかなり詳細に紹介されています。

私が特に注目しているのは、

  • APK analyzer
  • Constraint Layout
  • Project Structure Dialog
  • Samples Browser
  • Espresso Test Recorder

の5つです。

APK analyzerは、apkファイルの中身を覗くことができ、リソースやIDの一覧、メソッド数などの情報を閲覧できます。

今まで専用のツールを使ったり、apkファイルをunzipして中身を見ていたのをAndroid Studioに簡単にできるようになり、便利ですね。

Constraint Layoutは昨日も紹介していますが、今までよりレイアウトを簡単に高速に作ることができるようになるようです。

Project Structure Dialogは今までもありましたが、Android Studio 2.2でかなり強化され、依存ライブラリーのアップデート表示や、依存ライブラリーの追加を今までより更に簡単に行えるようになりました。

Samples Browserは、公開されているサンプルから簡単に目的のコードを探し出すことができます。もうわざわざWebで検索する必要はありません。

Espresso Test Recorderは、EspressoのUIテストをエミュレーターの操作で自動生成できます。これはかなり便利ですね!

この他にもInstant Runの強化や、エミュレーターの更なる高速化など、開発効率を上げるための変更が多数あり、これはもはやバージョン2.2ではなく、3.0ではないのかと思っています。

また、動画だけでなく公式ブログでも変更点が紹介されていますので、こちらもご覧ください。

http://android-developers.blogspot.jp/2016/05/android-studio-22-preview-new-ui.html

最新のAndroidの開発環境を一通り確認したい方にオススメです。

Advanced Espresso

www.youtube.com

UIテストフレームワークのEspressoについて紹介されています。

Espressoの基本的な使い方や、使う上でのTipsがまとめられています。

UIテストは一見難しくコストパフォーマンスが悪いと思われがちでなかなか導入が進まないこともあると思いますが、Espressoはかなり直感的に書けますし、Espresso Test Recorderの登場で、導入コストも難易度も大きく下がるように感じます。

私はこれを機会にEspressoでテストを書こうと思っています。

Espressoについて詳しく知りたい方にオススメです。

Notifications: Everything you need in 45 minutes

www.youtube.com

Androidの通知についてとりあえずこれを聞いておけば完璧だよ、というセッションかと思って入ってみたら、Keynoteで発表された「Firebase Notifications」の紹介でした。

なぜ通知なのか、Firebase Notificationsで通知を送るにはどう実装するか、Firebase NotificationsとFirebase Analyticsとの組み合わせなどについて紹介されています。

Firebase NotificationsもFirebase Analyticsもクロスプラットフォームで、無料無制限で利用できる便利なツールですね。

内容とは関係ありませんが、やたら空気鉄砲らしきものでTシャツが発射されているのが少し気になりました。

Firebase Notificationsに興味がある、通知を簡単に実装したい、といった方にオススメです。

2日目を終えて

昨日と比べて気温がかなり下がり、昼間は暑いが夕方辺りからものすごく寒くなりました。

参加者も昨日と比べてかなり減っていましたが、やはりAndroid向けのセッションは人気が高く、行列ができていました。

現地の気候は昼と夜の気温の差が大きいので、来年以降参加する際は、少し厚めの上着が必要だということを覚えておくとよいでしょう。

まとめ

2日目のオススメセッションを紹介しました。

明日3日目は最終日、オススメセッションだけでなく、現地の雰囲気も写真付きで紹介したいと思います。

こちらの記事は帰国後公開予定となっております、しばしお待ちください。

最後に、はてなではGoogle I/Oに参加してAndroidやiOSのネイティブアプリ開発を行うスマートフォンエンジニアの募集を行っています。

一緒に最高のモバイルアプリを作ったり、Google I/Oに参加しましょう!

hatenacorp.jp

【Google I/O 2016参加レポート】Android開発者向けオススメセッション 1日目

こんにちは、アプリケーションエンジニアのid:takuji31です。

私は今、5月18日〜20日開催のGoogle I/O 2016に参加しています。

今回は会社からの派遣ということで、知見を持ち帰るべくサンフランシスコにやってきました。私としても念願のGoogle I/O初参加となり、興奮が収まりません。

f:id:takuji31:20160518084525j:plain

1日目の18日に私が見たセッションの中から、Android開発者の皆様にオススメのものを紹介します。

Keynote

www.youtube.com

言わずと知れた基調講演です。毎年ライブストリーミングを徹夜で見る方も多いのではないでしょうか。

以下のようなものが発表されています。

  • Google Assistant
  • Google Home
  • Google Assistant搭載メッセンジャーアプリ「Allo」
  • シンプルなビデオ通話アプリ「Duo」
  • Android N の名前を募集
  • VRプラットフォーム「Daydream」
  • Android Wear 2.0
  • Android Studio 2.2 preview
  • Firebase Analytics
  • Android Instant Apps

私自身は、開発者視点ではAndroid Studio 2.2やAndroid Instant Appsに注目しています。

Android Studio 2.2では、Instant Runやエミュレーターが更に高速化されます。

Android Instant Appsでは、Deep Linkから(対応していれば)未インストールのアプリの一部を直接開くことができ、今までより更にWebアプリとネイティブアプリの境界線が曖昧になり、使いやすくなっていくでしょう。

ユーザー視点では、Google HomeやAlloが気になっています。

Google HomeはGoogle Assistantが生活を支えるプラットフォームになり得るデバイスですね。

また、Alloは返信を書くために言葉を選ぶ、詳細を調べるといったようなことを全てGoogle Assistant任せにでき、円滑にコミュニケーションが取れるメッセージングアプリではないでしょうか。

見ることで新しいものの概要をざっくりつかめますので、興味がある方もない方も是非一度ご覧ください。

What's new in Android

www.youtube.com

Android Nや新しいバージョンのSupport Libraryなど、最近の変更について詳しく紹介されています。

中でも注目はAndroid Studio 2.2 previewの新機能であるConstraint Layoutでしょうか。

イメージとしてはiOSのAuto Layoutに近いように感じます。

Android 2.3以上から利用でき、Android Studio 2.2上で直感的にレイアウトが作成できます。

新しいAndroidの機能を一通り触ってみたい方にオススメです。

What's new in the support library

www.youtube.com

Support Libraryのバージョン23.2、23.3や23.4、現在alpha版の24.0での変更点が紹介されています。

私は、24.0から追加される、ColorStateListのlayout attributeサポート、StateListAnimatorのstate_collapsible state_collapsed属性の追加に注目しています。

また、Support Libraryの将来についても少しだけ紹介されています。

他にもVector Drawable Support Libraryの使い方や、24.0の新機能が紹介されていますので、Support Libraryの動向を追えていない方、最近の変更をまとめて見たい方にオススメです。

What the Fragment?

www.youtube.com

Fragmentについてのセッションです。

なぜFragmentを使うのか、Fragmentを使う上でのセオリーなどが紹介されています。

何となくFragmentを使っているがどうするのが正しいのか分からない、Fragmentは不要だ、全部Activityでいいのではないか、と思っている方は一度ご覧ください。

私もFragmentの利用について、いくつか思い悩むところがありますので、このセッションを参考に解決していきたいと思います。

1日目を終えて

今年の発表は全体的にモバイルが中心の構成になっているように感じました。

参加者もおそらく半数以上がAndroid開発者だと思われます(What's new in Androidの発表時にKeynoteと同じ会場の席が半分以上埋まっていたため)。

そのためか会場の熱気は大変高まっていました。

余談ですが、気温も高く陽射しも強かったので、私は午前中に日焼けで顔が真っ赤になってしまいました。

明日はきっちり日焼け止めを塗って参加しようと思います。

明日もはてなTシャツを着て参加しておりますので、現地で見かけましたら、是非お声がけください!

まとめ

1日目のオススメセッションを紹介しました。

2日目の明日も、Android開発者向けのオススメセッションを紹介します。

それではまた明日お会いしましょう。

最後に、はてなではAndroidやiOSのネイティブアプリ開発を行うスマートフォンエンジニアの募集を行っています。

一緒に最高のモバイルアプリを作ったり、Google I/Oに参加しましょう!

hatenacorp.jp

「ペパボ・はてな技術大会 〜インフラ技術基盤〜」を福岡と京都で開催!

こんにちは、はてなウェブオペレーションエンジニアの id:y_uuki です。

GMOペパボ株式会社さんとの共同で「ペパボ・はてな技術大会」を福岡と京都で開催します。
今回は、ペパボさんとはてなのインフラエンジニア・ウェブオペレーションエンジニアが集まり、インフラ技術基盤をテーマとした様々なトピックについてご紹介する予定です。

「Webサービスの運用管理からの解放」、「STNSで実現する次世代ユーザー管理」、「システムを改善する行動ログ 」、「WebサービスにおけるOSとミドルウェアのパフォーマンス改善」といったテーマによるトークを予定しています。
さらに、ペパボさんとはてなの若手インフラエンジニア・ウェブオペレーションエンジニアによる座談会も予定しています。

日程と場所

  • はてな・ペパボ技術大会: 7月2日(土)@はてな京都オフィス
  • ペパボ・はてな技術大会: 7月9日(土)@ペパボ福岡支社

開催場所にかかわらず、イベント内容は基本的に同じものになる予定です。
ペパボさんが主催される場合は「ペパボ・はてな技術大会」、はてなが主催する場合は「はてな・ペパボ技術大会」という名称になります。

参加者募集

6月上旬に、connpassにて参加者を募集します。connpassグループのメンバー登録をしていただくと、募集開始のお知らせを受け取ることができます。

福岡での開催は GMOペパボ株式会社 - connpass、京都での開催は Hatena Engineer Seminar - connpass になります。ぜひご登録ください。学生の方の参加も歓迎です。

HTMLのpattern属性とJavaScript正規表現のunicodeオプション

こんにちは、Webアプリケーションエンジニアのid:nanto_viです。みなさんHTMLのフォーム検証機能は使っていますか? 近年は各Webブラウザの対応も進み、お手軽にフォームの利便性を高められるようになっています。

そんなフォーム検証機能のひとつがinput要素のpattern属性です。pattern属性の値にJavaScriptの正規表現パターンを指定することで、ユーザーの入力が意図しないものであった場合、フォーム送信ができなくなります。下図は5桁の数字の入力が求められるところに3桁しか入力せずフォーム送信しようとしたところです。ブラウザに組み込みのエラー表示が出現し、またそのメッセージにtitle属性の値が使われていることを確認できるでしょう。(pattern属性を指定する際には、title属性に書式の説明を記述することが推奨されています。)

<input type="text" name="code" pattern="[0-90-9]{5}"
       title="5桁の数字を入力してください">

f:id:nanto_vi:20160428155855p:plain

pattern属性に指定したパターンは全体一致で評価されるので、わざわざパターンの先頭・末尾に^$をつける必要はありません。逆に部分一致で指定したいとなったら先頭・末尾に.*?.*を明示的につける必要があります。

さて、pattern属性を使って「3文字以内の文字列」という制限をかけるにはどうしたらいいでしょうか? 改行を除く任意の文字を表すメタ文字.を使って以下のように書けるはずです。

<input type="text" name="food" pattern=".{0,3}"
       title="3文字以内で入力してください">

ところが、ここに「🍣🍡🍵」の3文字を入力してみると、ブラウザによっては検証が通りません。なぜでしょうか? 困ったときは仕様を見るのが一番です。

If an input element has a pattern attribute specified, and the attribute's value, when compiled as a JavaScript regular expression with only the "u" flag specified,

4.10.5.3.6 The pattern attribute - HTML Standard

pattern属性の値が/uフラグ付きの正規表現としてコンパイルされると書いてありますね。/uフラグ(unicodeオプション)はECMAScript 2015 (ES6)で導入された正規表現のオプションで、マッチする単位を「UTF-16の符号単位」から「Unicodeの符号位置」に変更するなどの効果があります。

JavaScriptの文字列はUTF-16符号化形式で表現されます。UTF-16において多くの文字はひとつの符号単位(16ビット符号なし整数値)で表現されますが、BMP(基本多言語面)外の文字はサロゲートペアと呼ばれるふたつの符号単位の組み合わせで表現されることになります。従来のJavaScript正規表現では.がひとつの符号単位にマッチするため、それが必ずしも「1文字」(ひとつの符号位置)にマッチするとは言えない状況でした。/uフラグを使うことで.が「1文字」にマッチするようになります。(ここで「結合文字や異体字セレクタは?」と思った方は、この記事がなくても大丈夫そうですね😜)

/^.$/.test('🍣');   // => false
/^.$/u.test('🍣');  // => true

各ブラウザが/uフラグをサポートしたのは比較的最近のことなので、ちょっと古めのブラウザだとpattern属性の値が/uフラグなしの正規表現パターンとして扱われます。「🍣🍡🍵」はいずれもBMP外の文字であり、計6個の符号単位からなる文字列なので検証に失敗していたのです。

ではそのようなブラウザでも「3文字以内」を表現するためにはどうしたらいいでしょうか? サロゲートペアに使われる領域(U+D800U+DFFF)に文字が割り当てられていないことを考えると、以下のように書けます。

<input type="text" name="food"
       pattern="(?:[\uD800-\uDBFF][\uDC00-\uDFFF]|.){0,3}"
       title="3文字以内で入力してください">

/uフラグに対応した環境では前半([\uD800-\uDBFF][\uDC00-\uDFFF])にマッチする文字は存在せず、後半(.)に改行以外の文字がマッチします。/uフラグに対応していない環境では前半にBMP外の文字がマッチし、後半に改行以外のBMP内の文字がマッチすることで、やはり「1文字」ごとにマッチを進めていけるのです。

任意の文字を表す正規表現パターン

以上では改行にマッチさせる必要がないため.を用いましたが、改行にもマッチさせようと思ったら.の部分を[\S\s]などに置き換える必要があります。/uフラグ付きなら[\u{0}-\u{10FFFF}]とも書けます。

ちなみに、Perlでは/sフラグを指定することで.が改行にもマッチするようになります。

maxlength属性

「3文字以内」と聞いてmaxlength属性のことを思い浮かべた方も多いでしょう。しかし、maxlength属性にはいくつかの注意事項があり、何文字以内という制約を表すのには使いづらい面があります。

  1. ブラウザによっては、日本語入力時の変換前の文字までmaxlength属性の制約を受けてしまいます。
  2. maxlength属性の値はUTF-16の符号単位の数を表しており、BMP外の文字に対しては期待通り機能しません。

ASCIIの範囲内での入力を求めるのならmaxlength属性でもよいでしょうが、そうでないなら上で述べたようにpattern属性を使ったほうがユーザーにとってより使いやすいかもしれません。

終わりに

絵文字の隆盛もあって今やBMP外の文字は広く巷に流通するところですが、それを扱うソフトウェア側では特別な注意が必要なことも多々あります。はてなでは、ユーザーから多彩な入力を受け付け世界に伝えるべく、バリエーション豊かなエンジニアを募集しています。

hatenacorp.jp

リモートワークにおけるSlack Call活用と終業15分前の雑談

ウェブオペレーションエンジニアの id:y_uuki です。リモートワーク環境でのSlack Callの活用を紹介します。

はてなのシステムプラットフォーム部(いわゆるインフラ部に相当)には現在9名在籍しており、一人だけ東京オフィス勤務で、残りは京都オフィスに勤務しています。

京都・東京でオフィスが離れているため、リモート環境でのコミュニケーションが必要です。普段はSlackによるチャット、はてなグループの日記やキーワード、GitHub EnterpriseのissueやPull Requestが主なコミュニケーション手段です。

しかし、テキストをタイプする必要があるため、コミュニケーション時間が長くなり、こみいった話が難しいこともあります。Slack でもちろん雑談はするものの、忙しいとタイミングを逸してしまいがちです。

口頭コミュニケーションのために、いくつかのボイスチャット、ビデオチャットサービスを使っていました。Google Hangoutsやzoomなどです。いずれのアプリケーションも動作が重かったり、音声ミュートの有効・無効をブラウザやアプリケーションに移動して切り替えなければならず、作業しながらチャットしたりする場合に不便でした。音声を有効にしたまま、手元でタイピングしてしまって、タイプ音がうるさいといったことがあります。

小さな不満も蓄積されていくと、そもそもチャットを開始すること自体が億劫になります。

そこで、最近リリースされた機能であるSlack Callを試したところ、非常に使いやすいと感じました。Slack Callは最近リリースされたSlackのボイスチャット機能です。特徴を以下にあげてみます。

  • 音声のみのせいか動作が軽い
  • Slackに統合されているため、下の写真のようにシームレスにチャットに移行できる
  • 他のアプリケーションにフォーカスを変更しても、右上に下の2番目の写真のようなポップアップが表示されたままになるため、音声ミュートの有効無効がやりやすい (これはMac OSXのアプリケーション版だけの機能かもしれない)
  • Slackに統合されているため、サービスを利用するための追加のアカウント作成が不要

f:id:y_uuki:20160428124200p:plain

f:id:y_uuki:20160428124133p:plain

他のサービスでもありますが、たまに音声が切れる、人数が多くなると途中で勝手に退室してしまうというような不具合もあったりします。一応、フォールバック先として、Google Hangoutsも用意はしています。Slack Callは執筆時点でまだβ版なので、これからよくなっていくだろうと期待しています。

気軽になったとはいえ、チャットの開始タイミングは難しいものです。

そこで、日報のタイミングとあわせて、Slack Callで雑談を開始しようと思いました。

チームでは、終業15分前から日報を書くようにしています。終業15分前になったらHubotが以下のようにリマインドしてくれます。
f:id:y_uuki:20160428124239p:plain

日報を書くのでどうせ手を止めますし、日報を書いているとその日のことを思い出すので、自然と雑談も弾みます。具体的には、さっきSlackに貼ったAWSの新サービスおもしろそうだったとか、昨日の勉強会どうだったとか、今日の進捗やばいとか、おなかすいたとかそんな感じです。

このような活動をしていると、Slackのチャンネルで様子がみれるので、自然と他のチームにも広がっていきました。チームによっては、話題がなくて、雑談できないという声も聞いたりします。日報を導入していないチームもあるので、日報と同じタイミングでやるというのが重要なのかもしれません。

ウェブオペレーションエンジニアの普段の仕事のワークフローについては下記の記事もご覧ください。
はてなにおける日々の仕事の中にあらわれるMackerelの活用 - Mackerel ブログ #mackerelio

はてなでは東京でも京都でもウェブオペレーションエンジニアを募集しています。
hatenacorp.jp

AWSでのHTTP/2 or SPDY運用の課題とPROXY protocol

東京でウェブオペレーションエンジニアをしている id:dekokun です。

本記事ではAWSでELBを使用してHTTP/2 or SPDYを運用する上で直面する問題としてのクライアントIPが分からなくなる問題の紹介を行い、その後に解決策としてのPROXY protocolの紹介・PROXY protocolの設定方法について記載します。

この記事は先日公開しましたAWS EC2でのHTTP/2 or SPDY導入方法 - Hatena Developer Blog (以下、"前回の記事"と呼びます) の続編となります。

ELBのTCPモードにおける問題点

さて、前回の記事にてELBをTCPモードで動かすことによってHTTP/2 or SPDY対応を行う方法を紹介しましたが、この方法では1つ大きな問題点があります。 それは、nginxがクライアントのIPアドレスを取得することができなくなってしまう(nginxはELBのIPアドレスを取得してしまう)ということです。

クライアントのIPアドレスを取得することができないことによって、具体的には以下のような問題が起きます。

  • アクセスログに記載されるIPアドレスがクライアントのIPアドレスではなくなるため何か調査の必要が発生した際に詳しい調査を行うことができなくなります
  • IPアドレスによるアクセス制御ができなくなります
    • 具体的には「特定のIPアドレスからのアクセスだけ許可したい」「ngx_http_limit_req_moduleなどを使用してあるIPからの接続数が急増した際に一時的なアクセス制限を入れたい」などができなくなります

解決策としてのPROXY protocol

PROXY protocolとは、ロードバランサがクライアントのIPをupstreamサーバに伝えることができるものです。TCPレイヤで動く、X-Forwarded-Forのようなものともいえます。 PROXY protocolを使うことで、upstreamサーバがクライアントのIPを取得することができるようになり、上記問題を解決することができます。

PROXY protocolが必要となる技術的背景及びPROXY protocolの動作

この節では、なぜTCPモードのロードバランサがクライアントのIPアドレスを取得できないのか及び、ELB等関係なくそもそもPROXY protocolがどのようにしてその問題を解決しているのかを説明します。

なんらかのロードバランサ(ELBやhaproxy等)からTCPモードでupstreamのサーバに対してパケットを転送する時、基本的にはupstreamサーバ(今回の例だとnginx)に届けるパケットはTCP/IP上でのアクセス元IPアドレスをロードバランサのIPに変換することになります。それにより、upstreamのサーバが認識する"アクセス元のIPアドレス"は、上記ELBやhaproxyのIPアドレスとなってしまい、upstreamのサーバはロードバランサと通信しているクライアントのIPアドレスを取得することができません。

[クライアント(PCとかスマートフォンとか)] <- upstreamサーバは本当ならこいつのIPアドレスを知りたい
       ↓
       ↓
       ↓
[ロードバランサ]
クライアントから来たパケットを転送する際にTCP/IPレイヤでアクセス元IPアドレスを自分のIPアドレスに変換する
       ↓
       ↓
       ↓
[upstreamサーバ]
パケットのアクセス元IPアドレスがロードバランサのIPアドレスに変換されているためクライアントのIPアドレスが分からない

ここで、「アクセス元のIPをupstreamのサーバに伝えてあげる」と聞いてパッと思い浮かぶのは、例えばhttpだと"X-Forwarded-For"を付与する等の、L7のプロトコルを使ってupstreamに対してIPアドレスを伝えてあげる手法かと思います。ELBのhttpモード使用等のL7レイヤのロードバランサであれば特に問題なくその方法を使えばいいかと思います。 しかしTCPモードで"httpだった場合はX-Forwarded-Forを付与する"というようなことを行おうとすると、以下2つを実施する必要が出てきます。

  1. TCP上で流れているL7レイヤのプロトコルを判別
  2. それぞれのプロトコルに応じて、必要なヘッダを挿入する(HTTPだったらX-Forwarded-Forを挿入)などしてアクセス元のIPアドレスを伝える

1. は、世の中に数多あるL7レイヤのプロトコルのどれであるかを正確に判断することになるので、非常に困難であることが容易に想像できます。 "このロードバランサはHTTPしか考えなくて良い"という制約を課して1. の問題を回避したとしても、2. の問題が依然として残ります。 2. を解決するにはL7レイヤのパーサをロードバランサが用意しなくてはならず実装が大変になってしまいますし、動作時の負荷も非常に大きく増えてしまいます。

というわけで上記のような問題を解決するために、TCPレイヤでの"X-Forwarded-For"的なものとして出てきたのがPROXY protocolです。ロードバランサがPROXY protocolでアクセス元の情報を伝えることにより、upstreamのサーバがアクセス元のIPアドレスやポートを知ることができるようになります。

この一連の流れ及びPROXY protocolの仕様についてはThe PROXY protocol により詳しく記載してあります。

なお、上記で"基本的にはupstreamサーバ(今回の例だとnginx)に届けるパケットはTCP/IP上でのアクセス元IPアドレスをロードバランサのIPアドレスにすることになります"と書きましたが、そうならない例としては、LVSでDSRを使用するなど(追記 ブログ下部にも記載しましたが、LVSでNATを使用した場合でもアクセス元IPは変換されないようでした)アクセス元IPアドレスを変換しないようなロードバランサを使う場合が考えられます。そのような場合はPROXY protocolなしでupstreamサーバはクライアントのIPアドレスを取得することができます。

ELB + nginx構成でのPROXY protocolの設定方法

以下では実際にどのように設定を行うことでPROXY protocolを使うことができるのかを記載します。

ELBの設定

PROXY protocolに対応させるにはELB側でも設定が必要です。前回の記事 にてTCPモードの設定について記載しましたが、その上でAWS CLIを使用して以下のようにPROXY protocol対応させる必要があります

以下は nginx-testという名前のELBで443 portに対して設定する場合の設定方法です。

$ aws elb create-load-balancer-policy --load-balancer-name nginx-test --policy-name EnableProxyProtocol --policy-type-name ProxyProtocolPolicyType --policy-attributes AttributeName=ProxyProtocol,AttributeValue=true
$ aws elb set-load-balancer-policies-for-backend-server --load-balancer-name nginx-test --instance-port 443 --policy-names EnableProxyProtocol

設定が完了したかどうかは、jqコマンドを使用して以下のように確認することができます。

$ aws elb describe-load-balancers --load-balancer-name nginxtest | jq '.LoadBalancerDescriptions[].BackendServerDescriptions[] | select(.InstancePort == 443)'
{
  "InstancePort": 443,
  "PolicyNames": [
    "EnableProxyProtocol"
  ]
}

nginxの設定

前回の記事にて「TLS対応さえ済めば後はlistenディレクティブにて"spdy"または"http2"と記述するだけです」と記載しましたが、PROXY protocol対応は更にその上に以下3点を行う必要があります。

  1. proxy_protocol という記述を追加
  2. real_ip_header proxy_protocol; という記述を追加
  3. set_real_ip_from にロードバランサのIPレンジを追加
~略~

server {
  set_real_ip_from x.x.x.x/x;
  real_ip_header proxy_protocol;
  listen       443 ssl http2 proxy_protocol;

~略~

あとがき

前回の記事にも記載しましたが、この記事は以下3本についての連載の2作目となります。

  • AWS EC2上の環境へのHTTP/2 or SPDY対応の導入方法
  • HTTP/2 or SPDY運用の課題とその解決方法としてのPROXY protocolについての解説
  • PROXY protocol自体の運用の課題と解決案

3作目は監視周りについて書く予定です。3作目もお楽しみに!!

はてなでは、HTTP/2を導入していくぜ!というエンジニアを募集しています。 あと、私、東京でインフラエンジニアしています。東京で働きたいぜ!というエンジニアも絶賛募集中です。

追記/修正事項

  • "IPと略さないほうがいいのではないか"というブコメでのご指摘いただきました。確かに、インターネット・プロトコルの意味での"IP"という用語もこの記事内に存在することもあることから略さないほうが良いですね。IPアドレスの意味で"IP"としている部分を"IPアドレス"に書きかえました。ご指摘ありがとうございます
  • ブコメでLVS/NATでもIPアドレスが取得できるのではないかという点、ご指摘頂き調べたところ、LVSについてはNATでもhalfnatとして動作するためアクセス元IPアドレスを書き換えないようだということがわかりました。LVSの記述について訂正してあります。また実際に構築するなどして詳しく調べてブログにしたいところです。ご指摘ありがとうございます